001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.transport.codec;
022
023 import java.io.UnsupportedEncodingException;
024
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.LinkedHashMap;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.UUID;
031
032 import org.apache.qpid.transport.Binary;
033 import org.apache.qpid.transport.RangeSet;
034 import org.apache.qpid.transport.Struct;
035 import org.apache.qpid.transport.Type;
036
037 import static org.apache.qpid.transport.util.Functions.*;
038
039
040 /**
041 * AbstractDecoder
042 *
043 * @author Rafael H. Schloming
044 */
045
046 abstract class AbstractDecoder implements Decoder
047 {
048
049 private final Map<Binary,String> str8cache = new LinkedHashMap<Binary,String>()
050 {
051 @Override protected boolean removeEldestEntry(Map.Entry<Binary,String> me)
052 {
053 return size() > 4*1024;
054 }
055 };
056
057 protected abstract byte doGet();
058
059 protected abstract void doGet(byte[] bytes);
060
061 protected byte get()
062 {
063 return doGet();
064 }
065
066 protected void get(byte[] bytes)
067 {
068 doGet(bytes);
069 }
070
071 protected Binary get(int size)
072 {
073 byte[] bytes = new byte[size];
074 get(bytes);
075 return new Binary(bytes);
076 }
077
078 protected short uget()
079 {
080 return (short) (0xFF & get());
081 }
082
083 public short readUint8()
084 {
085 return uget();
086 }
087
088 public int readUint16()
089 {
090 int i = uget() << 8;
091 i |= uget();
092 return i;
093 }
094
095 public long readUint32()
096 {
097 long l = uget() << 24;
098 l |= uget() << 16;
099 l |= uget() << 8;
100 l |= uget();
101 return l;
102 }
103
104 public int readSequenceNo()
105 {
106 return (int) readUint32();
107 }
108
109 public long readUint64()
110 {
111 long l = 0;
112 for (int i = 0; i < 8; i++)
113 {
114 l |= ((long) (0xFF & get())) << (56 - i*8);
115 }
116 return l;
117 }
118
119 public long readDatetime()
120 {
121 return readUint64();
122 }
123
124 private static final String decode(byte[] bytes, int offset, int length, String charset)
125 {
126 try
127 {
128 return new String(bytes, offset, length, charset);
129 }
130 catch (UnsupportedEncodingException e)
131 {
132 throw new RuntimeException(e);
133 }
134 }
135
136 private static final String decode(byte[] bytes, String charset)
137 {
138 return decode(bytes, 0, bytes.length, charset);
139 }
140
141 public String readStr8()
142 {
143 short size = readUint8();
144 Binary bin = get(size);
145 String str = str8cache.get(bin);
146 if (str == null)
147 {
148 str = decode(bin.array(), bin.offset(), bin.size(), "UTF-8");
149 str8cache.put(bin, str);
150 }
151 return str;
152 }
153
154 public String readStr16()
155 {
156 int size = readUint16();
157 byte[] bytes = new byte[size];
158 get(bytes);
159 return decode(bytes, "UTF-8");
160 }
161
162 public byte[] readVbin8()
163 {
164 int size = readUint8();
165 byte[] bytes = new byte[size];
166 get(bytes);
167 return bytes;
168 }
169
170 public byte[] readVbin16()
171 {
172 int size = readUint16();
173 byte[] bytes = new byte[size];
174 get(bytes);
175 return bytes;
176 }
177
178 public byte[] readVbin32()
179 {
180 int size = (int) readUint32();
181 byte[] bytes = new byte[size];
182 get(bytes);
183 return bytes;
184 }
185
186 public RangeSet readSequenceSet()
187 {
188 int count = readUint16()/8;
189 if (count == 0)
190 {
191 return null;
192 }
193 else
194 {
195 RangeSet ranges = new RangeSet();
196 for (int i = 0; i < count; i++)
197 {
198 ranges.add(readSequenceNo(), readSequenceNo());
199 }
200 return ranges;
201 }
202 }
203
204 public RangeSet readByteRanges()
205 {
206 throw new Error("not implemented");
207 }
208
209 public UUID readUuid()
210 {
211 long msb = readUint64();
212 long lsb = readUint64();
213 return new UUID(msb, lsb);
214 }
215
216 public String readContent()
217 {
218 throw new Error("Deprecated");
219 }
220
221 public Struct readStruct(int type)
222 {
223 Struct st = Struct.create(type);
224 int width = st.getSizeWidth();
225 if (width > 0)
226 {
227 long size = readSize(width);
228 if (size == 0)
229 {
230 return null;
231 }
232 }
233 if (type > 0)
234 {
235 int code = readUint16();
236 assert code == type;
237 }
238 st.read(this);
239 return st;
240 }
241
242 public Struct readStruct32()
243 {
244 long size = readUint32();
245 if (size == 0)
246 {
247 return null;
248 }
249 else
250 {
251 int type = readUint16();
252 Struct result = Struct.create(type);
253 result.read(this);
254 return result;
255 }
256 }
257
258 public Map<String,Object> readMap()
259 {
260 long size = readUint32();
261
262 if (size == 0)
263 {
264 return null;
265 }
266
267 long count = readUint32();
268
269 if (count == 0)
270 {
271 return Collections.EMPTY_MAP;
272 }
273
274 Map<String,Object> result = new LinkedHashMap();
275 for (int i = 0; i < count; i++)
276 {
277 String key = readStr8();
278 byte code = get();
279 Type t = getType(code);
280 Object value = read(t);
281 result.put(key, value);
282 }
283
284 return result;
285 }
286
287 public List<Object> readList()
288 {
289 long size = readUint32();
290
291 if (size == 0)
292 {
293 return null;
294 }
295
296 long count = readUint32();
297
298 if (count == 0)
299 {
300 return Collections.EMPTY_LIST;
301 }
302
303 List<Object> result = new ArrayList();
304 for (int i = 0; i < count; i++)
305 {
306 byte code = get();
307 Type t = getType(code);
308 Object value = read(t);
309 result.add(value);
310 }
311 return result;
312 }
313
314 public List<Object> readArray()
315 {
316 long size = readUint32();
317
318 if (size == 0)
319 {
320 return null;
321 }
322
323 byte code = get();
324 Type t = getType(code);
325 long count = readUint32();
326
327 if (count == 0)
328 {
329 return Collections.EMPTY_LIST;
330 }
331
332 List<Object> result = new ArrayList<Object>();
333 for (int i = 0; i < count; i++)
334 {
335 Object value = read(t);
336 result.add(value);
337 }
338 return result;
339 }
340
341 private Type getType(byte code)
342 {
343 Type type = Type.get(code);
344 if (type == null)
345 {
346 throw new IllegalArgumentException("unknown code: " + code);
347 }
348 else
349 {
350 return type;
351 }
352 }
353
354 private long readSize(Type t)
355 {
356 if (t.fixed)
357 {
358 return t.width;
359 }
360 else
361 {
362 return readSize(t.width);
363 }
364 }
365
366 private long readSize(int width)
367 {
368 switch (width)
369 {
370 case 1:
371 return readUint8();
372 case 2:
373 return readUint16();
374 case 4:
375 return readUint32();
376 default:
377 throw new IllegalStateException("illegal width: " + width);
378 }
379 }
380
381 private byte[] readBytes(Type t)
382 {
383 long size = readSize(t);
384 byte[] result = new byte[(int) size];
385 get(result);
386 return result;
387 }
388
389 private Object read(Type t)
390 {
391 switch (t)
392 {
393 case BIN8:
394 case UINT8:
395 return readUint8();
396 case INT8:
397 return get();
398 case CHAR:
399 return (char) get();
400 case BOOLEAN:
401 return get() > 0;
402
403 case BIN16:
404 case UINT16:
405 return readUint16();
406
407 case INT16:
408 return (short) readUint16();
409
410 case BIN32:
411 case UINT32:
412 return readUint32();
413
414 case CHAR_UTF32:
415 case INT32:
416 return (int) readUint32();
417
418 case FLOAT:
419 return Float.intBitsToFloat((int) readUint32());
420
421 case BIN64:
422 case UINT64:
423 case INT64:
424 case DATETIME:
425 return readUint64();
426
427 case DOUBLE:
428 return Double.longBitsToDouble(readUint64());
429
430 case UUID:
431 return readUuid();
432
433 case STR8:
434 return readStr8();
435
436 case STR16:
437 return readStr16();
438
439 case STR8_LATIN:
440 case STR8_UTF16:
441 case STR16_LATIN:
442 case STR16_UTF16:
443 // XXX: need to do character conversion
444 return new String(readBytes(t));
445
446 case MAP:
447 return readMap();
448 case LIST:
449 return readList();
450 case ARRAY:
451 return readArray();
452 case STRUCT32:
453 return readStruct32();
454
455 case BIN40:
456 case DEC32:
457 case BIN72:
458 case DEC64:
459 // XXX: what types are we supposed to use here?
460 return readBytes(t);
461
462 case VOID:
463 return null;
464
465 default:
466 return readBytes(t);
467 }
468 }
469
470 }
|