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