001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.messaging.jmf.codec.std.impl;
023
024 import java.io.IOException;
025 import java.io.OutputStream;
026
027 import org.granite.messaging.jmf.DumpContext;
028 import org.granite.messaging.jmf.InputContext;
029 import org.granite.messaging.jmf.OutputContext;
030 import org.granite.messaging.jmf.codec.std.LongCodec;
031
032 /**
033 * @author Franck WOLFF
034 */
035 public class LongCodecImpl extends AbstractStandardCodec<Long> implements LongCodec {
036
037 public int getObjectType() {
038 return JMF_LONG_OBJECT;
039 }
040
041 public Class<?> getObjectClass() {
042 return Long.class;
043 }
044
045 public int getPrimitiveType() {
046 return JMF_LONG;
047 }
048
049 public Class<?> getPrimitiveClass() {
050 return Long.TYPE;
051 }
052
053 public void encode(OutputContext ctx, Long v) throws IOException {
054 writeLongData(ctx, JMF_LONG_OBJECT, v.longValue());
055 }
056
057 public Long decode(InputContext ctx, int parameterizedJmfType) throws IOException {
058 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
059
060 if (jmfType != JMF_LONG_OBJECT)
061 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
062
063 return Long.valueOf(readLongData(ctx, parameterizedJmfType));
064 }
065
066 public void encodePrimitive(OutputContext ctx, long v) throws IOException {
067 writeLongData(ctx, JMF_LONG, v);
068 }
069
070 public long decodePrimitive(InputContext ctx) throws IOException {
071 int parameterizedJmfType = ctx.safeRead();
072 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
073
074 if (jmfType != JMF_LONG)
075 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
076
077 return readLongData(ctx, parameterizedJmfType);
078 }
079
080 public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
081 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
082
083 switch (jmfType) {
084 case JMF_LONG:
085 ctx.indentPrintLn("long: " + readLongData(ctx, parameterizedJmfType));
086 break;
087 case JMF_LONG_OBJECT:
088 ctx.indentPrintLn(Long.class.getName() + ": " + Long.valueOf(readLongData(ctx, parameterizedJmfType)));
089 break;
090 default:
091 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
092 }
093 }
094
095 protected void writeLongData(OutputContext ctx, int jmfType, long v) throws IOException {
096 int l = 7; // --> Long.MIN_VALUE
097 int s = 0x00;
098 if (v != Long.MIN_VALUE) {
099 if (v < 0) {
100 s = 0x80;
101 v = -v;
102 }
103 l = lenghtOfAbsoluteLong(v);
104 }
105
106 final OutputStream os = ctx.getOutputStream();
107
108 os.write(s | (l << 4) | jmfType);
109 switch (l) {
110 case 7:
111 os.write((int)(v >> 56));
112 case 6:
113 os.write((int)(v >> 48));
114 case 5:
115 os.write((int)(v >> 40));
116 case 4:
117 os.write((int)(v >> 32));
118 case 3:
119 os.write((int)(v >> 24));
120 case 2:
121 os.write((int)(v >> 16));
122 case 1:
123 os.write((int)(v >> 8));
124 case 0:
125 os.write((int)v);
126 break;
127 }
128 }
129
130 protected int lenghtOfAbsoluteLong(long v) {
131 if (v <= 0x00000000FFFFFFFFL) {
132 if (v <= 0x000000000000FFFFL)
133 return (v <= 0x00000000000000FFL ? 0 : 1);
134 return (v <= 0x0000000000FFFFFFL ? 2 : 3);
135 }
136
137 if (v <= 0x0000FFFFFFFFFFFFL)
138 return (v <= 0x000000FFFFFFFFFFL ? 4 : 5);
139 return (v <= 0x00FFFFFFFFFFFFFFL ? 6 : 7);
140 }
141
142 protected long readLongData(InputContext ctx, int parameterizedJmfType) throws IOException {
143 long v = 0;
144
145 switch ((parameterizedJmfType >> 4) & 0x07) {
146 case 7:
147 v |= ((long)ctx.safeRead()) << 56;
148 case 6:
149 v |= ((long)ctx.safeRead()) << 48;
150 case 5:
151 v |= ((long)ctx.safeRead()) << 40;
152 case 4:
153 v |= ((long)ctx.safeRead()) << 32;
154 case 3:
155 v |= ((long)ctx.safeRead()) << 24;
156 case 2:
157 v |= ((long)ctx.safeRead()) << 16;
158 case 1:
159 v |= ((long)ctx.safeRead()) << 8;
160 case 0:
161 v |= ctx.safeRead();
162 }
163
164 if ((parameterizedJmfType & 0x80) != 0)
165 v = -v;
166
167 return v;
168 }
169
170 public void writeVariableLong(OutputContext ctx, long v) throws IOException {
171
172 final OutputStream os = ctx.getOutputStream();
173
174 if (v == Long.MIN_VALUE)
175 os.write(0x80);
176 else {
177 int sign = 0x00;
178 if (v < 0) {
179 sign = 0x80;
180 v = -v;
181 }
182
183 int bytesCount = lengthOfVariableAbsoluteLong(v);
184 v -= deltaForVariableAbsoluteLongLength(bytesCount);
185
186 switch (bytesCount) {
187 case 0:
188 os.write(sign | (int)v);
189 break;
190 case 1: case 2: case 3: case 4: case 5: case 6: case 7:
191 os.write(sign | 0x40 | (int)(v >> (bytesCount * 7)));
192 for (int i = bytesCount - 1; i > 0; i--)
193 os.write(0x80 | (int)(v >> (i * 7)));
194 os.write(0x7F & (int)v);
195 break;
196 case 8:
197 os.write(sign | 0x40 | (int)(v >> 57));
198 os.write(0x80 | (int)(v >> 50));
199 os.write(0x80 | (int)(v >> 43));
200 os.write(0x80 | (int)(v >> 36));
201 os.write(0x80 | (int)(v >> 29));
202 os.write(0x80 | (int)(v >> 22));
203 os.write(0x80 | (int)(v >> 15));
204 os.write(0x80 | (int)(v >> 8));
205 os.write((int)v);
206 break;
207 }
208 }
209 }
210
211 public long readVariableLong(InputContext ctx) throws IOException {
212 long v = ctx.safeRead();
213
214 if (v == 0x80L)
215 v = Long.MIN_VALUE;
216 else {
217 boolean opposite = ((v & 0x80L) != 0);
218 boolean readNext = (v & 0x40L) != 0;
219
220 v &= 0x3FL;
221
222 if (readNext) {
223 int l = 1;
224 for (int i = 1; i <= 7; i++) {
225 long u = ctx.safeRead();
226 v = (v << 7) | (u & 0x7FL);
227 if ((u & 0x80L) == 0) {
228 readNext = false;
229 break;
230 }
231 l++;
232 }
233 if (readNext)
234 v = (v << 8) | ctx.safeRead();
235 v += deltaForVariableAbsoluteLongLength(l);
236 }
237
238 if (opposite)
239 v = -v;
240 }
241
242 return v;
243 }
244
245 protected static final long[] VARIABLE_LONG_DELTAS = new long[9];
246 static {
247 VARIABLE_LONG_DELTAS[0] = 0L;
248 for (int i = 1; i < VARIABLE_LONG_DELTAS.length; i++)
249 VARIABLE_LONG_DELTAS[i] = (VARIABLE_LONG_DELTAS[i-1] << 7) | 0x40L;
250 }
251
252 public int lengthOfVariableAbsoluteLong(long abs) {
253 for (int i = 1; i < VARIABLE_LONG_DELTAS.length; i++) {
254 if (abs < VARIABLE_LONG_DELTAS[i])
255 return (i - 1);
256 }
257 return 8;
258 }
259
260 protected static long deltaForVariableAbsoluteLongLength(int len) {
261 return VARIABLE_LONG_DELTAS[len];
262 }
263 }