diff options
Diffstat (limited to 'dotnet/client-010/client/transport/codec/AbstractEncoder.cs')
-rw-r--r-- | dotnet/client-010/client/transport/codec/AbstractEncoder.cs | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/dotnet/client-010/client/transport/codec/AbstractEncoder.cs b/dotnet/client-010/client/transport/codec/AbstractEncoder.cs new file mode 100644 index 0000000000..eb8bdae80a --- /dev/null +++ b/dotnet/client-010/client/transport/codec/AbstractEncoder.cs @@ -0,0 +1,590 @@ +/* +* +* 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.IO; +using System.Text; +using org.apache.qpid.transport.util; + +namespace org.apache.qpid.transport.codec +{ + /// <summary> + /// AbstractEncoder + /// </summary> + public abstract class AbstractEncoder : IEncoder + { + private static readonly Dictionary<Type, Code> ENCODINGS = new Dictionary<Type, Code>(); + private readonly Dictionary<String, byte[]> str8cache = new Dictionary<String, byte[]>(); + + static AbstractEncoder() + { + ENCODINGS.Add(typeof (Boolean), Code.BOOLEAN); + ENCODINGS.Add(typeof (String), Code.STR16); + ENCODINGS.Add(typeof (long), Code.INT64); + ENCODINGS.Add(typeof (int), Code.INT32); + ENCODINGS.Add(typeof (short), Code.INT16); + ENCODINGS.Add(typeof (Byte), Code.INT8); + ENCODINGS.Add(typeof (Dictionary<String, Object>), Code.MAP); + ENCODINGS.Add(typeof (List<Object>), Code.LIST); + ENCODINGS.Add(typeof (float), Code.FLOAT); + ENCODINGS.Add(typeof (Double), Code.DOUBLE); + ENCODINGS.Add(typeof (char), Code.CHAR); + ENCODINGS.Add(typeof (byte[]), Code.VBIN32); + ENCODINGS.Add(typeof (UUID), Code.UUID); + } + + protected abstract void DoPut(byte b); + + protected abstract void DoPut(MemoryStream src); + + + protected void Put(byte b) + { + DoPut(b); + } + + protected void Put(MemoryStream src) + { + DoPut(src); + } + + protected virtual void Put(byte[] bytes) + { + Put(new MemoryStream(bytes)); + } + + protected abstract int BeginSize8(); + protected abstract void EndSize8(int pos); + + protected abstract int BeginSize16(); + protected abstract void EndSize16(int pos); + + protected abstract int BeginSize32(); + protected abstract void EndSize32(int pos); + + public virtual void WriteUint8(short b) + { + Debug.Assert(b < 0x100); + Put((byte) b); + } + + public virtual void WriteUint16(int s) + { + Debug.Assert(s < 0x10000); + Put((byte) Functions.Lsb(s >> 8)); + Put((byte) Functions.Lsb(s)); + } + + public virtual void WriteUint32(long i) + { + Debug.Assert(i < 0x100000000L); + Put((byte) Functions.Lsb(i >> 24)); + Put((byte) Functions.Lsb(i >> 16)); + Put((byte) Functions.Lsb(i >> 8)); + Put((byte) Functions.Lsb(i)); + } + + public void WriteSequenceNo(int i) + { + WriteUint32(i); + } + + public virtual void WriteUint64(long l) + { + for (int i = 0; i < 8; i++) + { + Put((byte) Functions.Lsb(l >> (56 - i*8))); + } + } + + public abstract void WriteInt8(short b) ; + public abstract void WriteInt16(int s) ; + public abstract void WriteInt32(long i) ; + public abstract void WriteInt64(long l) ; + public abstract void WriteFloat(float f) ; + public abstract void WriteDouble(double d) ; + + public void WriteDatetime(long l) + { + WriteUint64(l); + } + + private static byte[] Encode(String s, Encoding encoding) + { + return encoding.GetBytes(s); + } + + public void WriteStr8(String s) + { + if (s == null) + { + s = ""; + } + + byte[] bytes; + if (! str8cache.ContainsKey(s)) + { + bytes = Encode(s, System.Text.Encoding.UTF8); + str8cache.Add(s, bytes); + } + else + { + bytes = str8cache[s]; + } + WriteUint8((short) bytes.Length); + Put(bytes); + } + + public void WriteStr16(String s) + { + if (s == null) + { + s = ""; + } + + byte[] bytes = Encode(s, System.Text.Encoding.UTF8); + WriteUint16(bytes.Length); + Put(bytes); + } + + public void WriteVbin8(byte[] bytes) + { + if (bytes == null) + { + bytes = new byte[0]; + } + if (bytes.Length > 255) + { + throw new Exception("array too long: " + bytes.Length); + } + WriteUint8((short) bytes.Length); + Put(bytes); + } + + public void WriteVbin16(byte[] bytes) + { + if (bytes == null) + { + bytes = new byte[0]; + } + WriteUint16(bytes.Length); + Put(bytes); + } + + public void WriteVbin32(byte[] bytes) + { + if (bytes == null) + { + bytes = new byte[0]; + } + WriteUint32(bytes.Length); + Put(bytes); + } + + public void WriteSequenceSet(RangeSet ranges) + { + if (ranges == null) + { + WriteUint16(0); + } + else + { + WriteUint16(ranges.Size()*8); + foreach (Range range in ranges) + { + WriteSequenceNo(range.Lower); + WriteSequenceNo(range.Upper); + } + } + } + + public void WriteByteRanges(RangeSet ranges) + { + throw new Exception("not implemented"); + } + + public void WriteUuid(UUID uuid) + { + long msb = 0; + long lsb = 0; + if (uuid != null) + { + msb = uuid.MostSignificantBits; + lsb = uuid.LeastSignificantBits; + } + WriteUint64(msb); + WriteUint64(lsb); + } + + public void WriteStruct(int type, Struct s) + { + if (s == null) + { + s = Struct.Create(type); + } + + int width = s.GetSizeWidth(); + int pos = -1; + if (width > 0) + { + pos = BeginSize(width); + } + + if (type > 0) + { + WriteUint16(type); + } + + s.Write(this); + + if (width > 0) + { + EndSize(width, pos); + } + } + + public void WriteStruct32(Struct s) + { + if (s == null) + { + WriteUint32(0); + } + else + { + int pos = BeginSize32(); + WriteUint16(s.GetEncodedType()); + s.Write(this); + EndSize32(pos); + } + } + + private Code Encoding(Object value) + { + if (value == null) + { + return Code.VOID; + } + + Type klass = value.GetType(); + Code type = Resolve(klass); + + if (type == Code.VOID) + { + throw new Exception + ("unable to resolve type: " + klass + ", " + value); + } + else + { + return type; + } + } + + private static Code Resolve(Type klass) + { + Code type; + if(ENCODINGS.ContainsKey(klass)) + { + return ENCODINGS[klass]; + } + + Type sup = klass.BaseType; + if (sup != null) + { + type = Resolve(sup); + + if (type != Code.VOID) + { + return type; + } + } + foreach (Type iface in klass.GetInterfaces()) + { + type = Resolve(iface); + if (type != Code.VOID) + { + return type; + } + } + return Code.VOID; + } + + public void WriteMap(Dictionary<String, Object> map) + { + int pos = BeginSize32(); + if (map != null) + { + WriteUint32(map.Count); + WriteMapEntries(map); + } + EndSize32(pos); + } + + protected void WriteMapEntries(Dictionary<String, Object> map) + { + foreach (KeyValuePair<String, Object> entry in map) + { + String key = entry.Key; + Object value = entry.Value; + Code type = Encoding(value); + WriteStr8(key); + Put((byte) type); + Write(type, value); + } + } + + public void WriteList(List<Object> list) + { + int pos = BeginSize32(); + if (list != null) + { + WriteUint32(list.Count); + WriteListEntries(list); + } + EndSize32(pos); + } + + protected void WriteListEntries(List<Object> list) + { + foreach (Object value in list) + { + Code type = Encoding(value); + Put((byte) type); + Write(type, value); + } + } + + public void WriteArray(List<Object> array) + { + int pos = BeginSize32(); + if (array != null) + { + WriteArrayEntries(array); + } + EndSize32(pos); + } + + protected void WriteArrayEntries(List<Object> array) + { + Code type; + + if (array.Count == 0) + { + return; + } + else + { + type = Encoding(array[0]); + } + Put((byte) type); + WriteUint32(array.Count); + + foreach (Object value in array) + { + Write(type, value); + } + } + + private void WriteSize(QpidType t, int size) + { + if (t.Fixed) + { + if (size != t.width) + { + throw new Exception("size does not match fixed width " + t.width + ": " + size); + } + } + else + { + WriteSize(t.width, size); + } + } + + private void WriteSize(int width, int size) + { + // XXX: should check lengths + switch (width) + { + case 1: + WriteUint8((short) size); + break; + case 2: + WriteUint16(size); + break; + case 4: + WriteUint32(size); + break; + default: + throw new Exception("illegal width: " + width); + } + } + + private int BeginSize(int width) + { + switch (width) + { + case 1: + return BeginSize8(); + case 2: + return BeginSize16(); + case 4: + return BeginSize32(); + default: + throw new Exception("illegal width: " + width); + } + } + + private void EndSize(int width, int pos) + { + switch (width) + { + case 1: + EndSize8(pos); + break; + case 2: + EndSize16(pos); + break; + case 4: + EndSize32(pos); + break; + default: + throw new Exception("illegal width: " + width); + } + } + + private void WriteBytes(QpidType t, byte[] bytes) + { + WriteSize(t, bytes.Length); + Put(bytes); + } + + private void Write(Code t, Object value) + { + switch (t) + { + case Code.BIN8: + case Code.UINT8: + WriteUint8((short) value); + break; + case Code.INT8: + Put((Byte) value); + break; + case Code.CHAR: + byte[] b = BitConverter.GetBytes((char) value); + Put(b[0]); + break; + case Code.BOOLEAN: + if ((bool) value) + { + Put(1); + } + else + { + Put(0); + } + + break; + + case Code.BIN16: + case Code.UINT16: + WriteUint16((int) value); + break; + + case Code.INT16: + WriteUint16((short) value); + break; + + case Code.BIN32: + case Code.UINT32: + WriteUint32((long) value); + break; + + case Code.CHAR_UTF32: + case Code.INT32: + WriteUint32((int) value); + break; + + case Code.FLOAT: + WriteUint32(BitConverter.DoubleToInt64Bits((float) value) >> 32); + break; + + case Code.BIN64: + case Code.UINT64: + case Code.INT64: + case Code.DATETIME: + WriteUint64((long) value); + break; + + case Code.DOUBLE: + WriteUint64( BitConverter.DoubleToInt64Bits((double) value)); + break; + + case Code.UUID: + WriteUuid((UUID) value); + break; + + case Code.STR8: + WriteStr8((string) value); + break; + + case Code.STR16: + WriteStr16((string) value); + break; + + case Code.STR8_LATIN: + case Code.STR8_UTF16: + case Code.STR16_LATIN: + case Code.STR16_UTF16: + // XXX: need to do character conversion + WriteBytes(QpidType.get((byte) t), Encode((string) value, System.Text.Encoding.Unicode)); + break; + + case Code.MAP: + WriteMap((Dictionary<String, Object>) value); + break; + case Code.LIST: + WriteList((List<Object>) value); + break; + case Code.ARRAY: + WriteList((List<Object>) value); + break; + case Code.STRUCT32: + WriteStruct32((Struct) value); + break; + + case Code.BIN40: + case Code.DEC32: + case Code.BIN72: + case Code.DEC64: + // XXX: what types are we supposed to use here? + WriteBytes(QpidType.get((byte) t), (byte[]) value); + break; + + case Code.VOID: + break; + + default: + WriteBytes(QpidType.get((byte) t), (byte[]) value); + break; + } + } + } +} |