/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using org.apache.qpid.transport.util; namespace org.apache.qpid.transport.codec { /// /// AbstractDecoder /// public abstract class AbstractDecoder : IDecoder { private readonly Dictionary str8cache = new Dictionary(); protected abstract byte DoGet(); protected abstract void DoGet(byte[] bytes); public abstract bool HasRemaining(); protected byte Get() { return DoGet(); } protected void Get(byte[] bytes) { DoGet(bytes); } protected Binary Get(int size) { byte[] bytes = new byte[size]; Get(bytes); return new Binary(bytes); } protected short Uget() { return (short) (0xFF & Get()); } public virtual short ReadUint8() { return Uget(); } public abstract int ReadUint16(); public abstract long ReadUint32(); public int ReadSequenceNo() { return (int) ReadUint32(); } public virtual long ReadUint64() { long l = 0; for (int i = 0; i < 8; i++) { l |= ((long) (0xFF & Get())) << (56 - i*8); } return l; } public abstract short ReadInt8(); public abstract int ReadInt16(); public abstract long ReadInt32() ; public abstract long ReadInt64(); public abstract float ReadFloat() ; public abstract double ReadDouble() ; public long ReadDatetime() { return ReadUint64(); } private static String Decode(byte[] bytes, int offset, int length, Encoding encoding) { return encoding.GetString(bytes, offset, length); } private static String Decode(byte[] bytes, Encoding encoding) { return Decode(bytes, 0, bytes.Length, encoding); } public String ReadStr8() { short size = ReadUint8(); Binary bin = Get(size); String str; if (! str8cache.TryGetValue(bin, out str)) { str = Decode(bin.Array(), bin.Offset(), bin.Size(), Encoding.UTF8); str8cache.Add(bin, str); } return str; } public String ReadStr16() { int size = ReadUint16(); byte[] bytes = new byte[size]; Get(bytes); return Decode(bytes, Encoding.UTF8); } public byte[] ReadVbin8() { int size = ReadUint8(); byte[] bytes = new byte[size]; Get(bytes); return bytes; } public byte[] ReadVbin16() { int size = ReadUint16(); byte[] bytes = new byte[size]; Get(bytes); return bytes; } public byte[] ReadVbin32() { int size = (int) ReadUint32(); byte[] bytes = new byte[size]; Get(bytes); return bytes; } public RangeSet ReadSequenceSet() { int count = ReadUint16()/8; if (count == 0) { return null; } RangeSet ranges = new RangeSet(); for (int i = 0; i < count; i++) { ranges.Add(ReadSequenceNo(), ReadSequenceNo()); } return ranges; } public RangeSet ReadByteRanges() { throw new Exception("not implemented"); } public UUID ReadUuid() { long msb = ReadUint64(); long lsb = ReadUint64(); return new UUID(msb, lsb); } public String ReadContent() { throw new Exception("Deprecated"); } public Struct ReadStruct(int type) { Struct st = Struct.Create(type); int width = st.GetSizeWidth(); if (width > 0) { long size = ReadSize(width); if (size == 0) { return null; } } if (type > 0) { int code = ReadUint16(); Debug.Assert(code == type); } st.Read(this); return st; } public Struct ReadStruct32() { long size = ReadUint32(); if (size == 0) { return null; } int type = ReadUint16(); Struct result = Struct.Create(type); result.Read(this); return result; } public Dictionary ReadMap() { long size = ReadUint32(); if (size == 0) { return null; } long count = ReadUint32(); Dictionary result = new Dictionary(); for (int i = 0; i < count; i++) { String key = ReadStr8(); byte code = Get(); QpidType t = GetType(code); Object value = Read(t); result.Add(key, value); } return result; } public List ReadList() { long size = ReadUint32(); if (size == 0) { return null; } long count = ReadUint32(); List result = new List(); for (int i = 0; i < count; i++) { byte code = Get(); QpidType t = GetType(code); Object value = Read(t); result.Add(value); } return result; } public List ReadArray() { long size = ReadUint32(); if (size == 0) { return null; } byte code = Get(); QpidType t = GetType(code); long count = ReadUint32(); List result = new List(); for (int i = 0; i < count; i++) { Object value = Read(t); result.Add(value); } return result; } private QpidType GetType(byte code) { return QpidType.get(code); } private long ReadSize(QpidType t) { return t.Fixed ? t.Width : ReadSize(t.Width); } private long ReadSize(int width) { switch (width) { case 1: return ReadUint8(); case 2: return ReadUint16(); case 4: return ReadUint32(); default: throw new Exception("illegal width: " + width); } } private byte[] ReadBytes(QpidType t) { long size = ReadSize(t); byte[] result = new byte[(int) size]; Get(result); return result; } private Object Read(QpidType t) { switch (t.Code) { case Code.BIN8: case Code.UINT8: return ReadUint8(); case Code.INT8: return Get(); case Code.CHAR: return (char) Get(); case Code.BOOLEAN: return Get() > 0; case Code.BIN16: case Code.UINT16: return ReadUint16(); case Code.INT16: return (short) ReadUint16(); case Code.BIN32: case Code.UINT32: return ReadUint32(); case Code.CHAR_UTF32: case Code.INT32: return (int) ReadUint32(); case Code.FLOAT: return (float)BitConverter.Int64BitsToDouble(ReadUint32() << 32); case Code.BIN64: case Code.UINT64: case Code.INT64: case Code.DATETIME: return ReadUint64(); case Code.DOUBLE: return BitConverter.Int64BitsToDouble(ReadUint64()); case Code.UUID: return ReadUuid(); case Code.STR8: return ReadStr8(); case Code.STR16: return ReadStr16(); case Code.STR8_LATIN: case Code.STR8_UTF16: case Code.STR16_LATIN: case Code.STR16_UTF16: // XXX: need to do character conversion return Encoding.UTF8.GetString(ReadBytes(t)); case Code.MAP: return ReadMap(); case Code.LIST: return ReadList(); case Code.ARRAY: return ReadArray(); case Code.STRUCT32: return ReadStruct32(); case Code.BIN40: case Code.DEC32: case Code.BIN72: case Code.DEC64: // XXX: what types are we supposed to use here? return ReadBytes(t); case Code.VOID: return null; default: return ReadBytes(t); } } } }