blob: 2e9e587407de90f55c415fdc33d8ec7dd22b4339 [file] [log] [blame]
/*
*
* 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
{
/// <summary>
/// AbstractDecoder
/// </summary>
public abstract class AbstractDecoder : IDecoder
{
private readonly Dictionary<Binary, String> str8cache = new Dictionary<Binary, String>();
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<String, Object> ReadMap()
{
long size = ReadUint32();
if (size == 0)
{
return null;
}
long count = ReadUint32();
Dictionary<String, Object> result = new Dictionary<String, Object>();
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<Object> ReadList()
{
long size = ReadUint32();
if (size == 0)
{
return null;
}
long count = ReadUint32();
List<Object> result = new List<Object>();
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<Object> ReadArray()
{
long size = ReadUint32();
if (size == 0)
{
return null;
}
byte code = Get();
QpidType t = GetType(code);
long count = ReadUint32();
List<Object> result = new List<Object>();
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);
}
}
}
}