Mercurial > hg > ucis.core
diff Pml/RW/PmlAmfRW.cs @ 0:3ab940a0c7a0
Initial commit
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Tue, 11 Sep 2012 16:28:53 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pml/RW/PmlAmfRW.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,282 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using UCIS.Pml; + +namespace UCIS.Pml { + internal enum AmfDataType : byte { + Number = 0, + Boolean = 1, + String = 2, + UntypedObject = 3, + MovieClip = 4, + Null = 5, + Undefined = 6, + ReferencedObject = 7, + MixedArray = 8, + End = 9, + Array = 10, + Date = 11, + LongString = 12, + TypeAsObject = 13, + Recordset = 14, + Xml = 15, + TypedObject = 16 + } + public class PmlAmfWriter : IPmlWriter { + private BinaryWriter pWriter; + + public PmlAmfWriter(BinaryWriter Writer) { + pWriter = Writer; + } + public PmlAmfWriter(Stream Stream) { + pWriter = new BinaryWriter(Stream, Encoding.UTF8); + } + + public BinaryWriter BaseWriter { + get { return pWriter; } + set { pWriter = value; } + } + + public void WriteMessage(PmlElement Message) { + WriteMessageTo(Message, pWriter); + } + + public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) { + lock (Writer) { + WriteElementTo(Message, Writer); + Writer.Flush(); + } + } + + private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) { + if (Element == null) { + Writer.Write((byte)AmfDataType.Null); + return; + } + switch (Element.Type) { + case PmlType.Null: + Writer.Write((byte)AmfDataType.Null); + break; + case PmlType.Dictionary: + Writer.Write((byte)AmfDataType.UntypedObject); + //WriteDictionary(Writer, (PmlDictionary)Element); + WriteUntypedObject(Writer, (PmlDictionary)Element); + break; + case PmlType.Collection: + Writer.Write((byte)AmfDataType.Array); + WriteCollection(Writer, (PmlCollection)Element); + break; + case PmlType.Binary: + Writer.Write((byte)AmfDataType.String); + byte[] bytes = Element.ToByteArray(); + if (bytes.Length > UInt16.MaxValue) { + Writer.Write((byte)AmfDataType.String); + WriteString(Writer, bytes); + } else { + Writer.Write((byte)AmfDataType.LongString); + WriteLongString(Writer, bytes); + } + break; + case PmlType.String: + string str = Element.ToString(); + if (str.Length < UInt16.MaxValue) { + Writer.Write((byte)AmfDataType.String); + WriteString(Writer, str); + } else { + Writer.Write((byte)AmfDataType.LongString); + WriteLongString(Writer, str); + } + break; + case PmlType.Integer: + Writer.Write((byte)AmfDataType.Number); + WriteDouble(Writer, (Element as PmlInteger).ToDouble()); + break; + } + } + private static void WriteEnd(BinaryWriter w) { + WriteUInt16(w, 0); + w.Write((byte)AmfDataType.End); + } + private static void WriteUntypedObject(BinaryWriter w, PmlDictionary value) { + foreach (KeyValuePair<String, PmlElement> kvp in value) { + WriteString(w, kvp.Key); + WriteElementTo(kvp.Value, w); + } + WriteEnd(w); + } + private static void WriteDictionary(BinaryWriter w, PmlDictionary value) { + WriteUInt32(w, (UInt32)value.Count); + foreach (KeyValuePair<String, PmlElement> kvp in value) { + WriteString(w, kvp.Key); + WriteElementTo(kvp.Value, w); + } + } + private static void WriteCollection(BinaryWriter w, PmlCollection value) { + WriteUInt32(w,(UInt32)value.Count); + foreach (PmlElement o in value) { + WriteElementTo(o, w); + } + } + private static void WriteDouble(BinaryWriter w, double value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteUInt32(BinaryWriter w, UInt32 value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteUInt16(BinaryWriter w, UInt16 value) { + WriteReverse(w, BitConverter.GetBytes(value)); + } + private static void WriteString(BinaryWriter w, string value) { + WriteString(w, Encoding.UTF8.GetBytes(value)); + } + private static void WriteLongString(BinaryWriter w, string value) { + WriteLongString(w, Encoding.UTF8.GetBytes(value)); + } + private static void WriteString(BinaryWriter w, byte[] buffer) { + WriteUInt16(w, (UInt16)buffer.Length); + w.Write(buffer, 0, buffer.Length); + } + private static void WriteLongString(BinaryWriter w, byte[] buffer) { + WriteUInt32(w, (UInt32)buffer.Length); + w.Write(buffer, 0, buffer.Length); + } + private static void WriteReverse(BinaryWriter w, byte[] value) { + Array.Reverse(value); + w.Write(value); + } + } + + public class PmlAmfReader : IPmlReader { + private BinaryReader pReader; + + public PmlAmfReader(BinaryReader Reader) { + pReader = Reader; + } + public PmlAmfReader(Stream Stream) { + pReader = new BinaryReader(Stream, Encoding.UTF8); + } + + public BinaryReader BaseReader { + get { return pReader; } + set { pReader = value; } + } + + public PmlElement ReadMessage() { + return ReadMessageFrom(pReader); + } + + public static PmlElement ReadMessageFrom(BinaryReader Reader) { + PmlElement Element = null; + lock (Reader) { + Element = ReadElementFrom(Reader); + } + return Element; + } + + + private static PmlElement ReadElementFrom(BinaryReader Reader) { + AmfDataType EType = (AmfDataType)Reader.ReadByte(); + return ReadData(Reader, EType); + } + private static PmlElement ReadData(BinaryReader Reader, AmfDataType EType) { + switch (EType) { + case AmfDataType.Number: + Double d = ReadDouble(Reader); + if (d == (double)(Int64)d) { + return new PmlInteger((Int64)d); + } else if (d == (double)(UInt64)d) { + return new PmlInteger((UInt64)d); + } else { + return new PmlString(d.ToString()); + } + case AmfDataType.Boolean: + return new PmlInteger(Reader.ReadByte()); + case AmfDataType.String: + return new PmlString(ReadShortString(Reader)); + case AmfDataType.Array: + PmlCollection ElementC = new PmlCollection(); + int size = ReadInt32(Reader); + for (int i = 0; i < size; ++i) { + ElementC.Add(ReadElementFrom(Reader)); + } + return ElementC; + case AmfDataType.Date: + return new PmlString(ReadDate(Reader).ToString()); + case AmfDataType.LongString: + return new PmlString(ReadLongString(Reader)); + case AmfDataType.TypedObject: + ReadShortString(Reader); + return ReadUntypedObject(Reader); + case AmfDataType.MixedArray: + return ReadDictionary(Reader); + case AmfDataType.Null: + case AmfDataType.Undefined: + case AmfDataType.End: + return new PmlNull(); + case AmfDataType.UntypedObject: + return ReadUntypedObject(Reader); + case AmfDataType.Xml: + return new PmlString(ReadLongString(Reader)); + case AmfDataType.MovieClip: + case AmfDataType.ReferencedObject: + case AmfDataType.TypeAsObject: + case AmfDataType.Recordset: + default: + throw new NotSupportedException("The AMF type is not supported: " + EType.ToString()); + } + } + + private static PmlDictionary ReadUntypedObject(BinaryReader Reader) { + PmlDictionary ElementD = new PmlDictionary(); + string key = ReadShortString(Reader); + for (byte type = Reader.ReadByte(); type != 9; type = Reader.ReadByte()) { + ElementD.Add(key, ReadData(Reader, (AmfDataType)type)); + key = ReadShortString(Reader); + } + return ElementD; + } + private static PmlDictionary ReadDictionary(BinaryReader Reader) { + PmlDictionary ElementD = new PmlDictionary(); + int size = ReadInt32(Reader); + return ReadUntypedObject(Reader); + } + + private static DateTime ReadDate(BinaryReader r) { + double ms = ReadDouble(r); + DateTime date = (new DateTime(1970, 1, 1)).AddMilliseconds(ms); + ReadUInt16(r); //gets the timezone + return date; + } + private static double ReadDouble(BinaryReader r) { + return BitConverter.ToDouble(ReadReverse(r, 8), 0); + } + + private static int ReadInt32(BinaryReader r) { + return BitConverter.ToInt32(ReadReverse(r, 4), 0); + } + + private static ushort ReadUInt16(BinaryReader r) { + return BitConverter.ToUInt16(ReadReverse(r, 2), 0); + } + + private static byte[] ReadReverse(BinaryReader r, int size) { + byte[] buffer = r.ReadBytes(size); + Array.Reverse(buffer); + return buffer; + } + private static string ReadLongString(BinaryReader r) { + int length = ReadInt32(r); + return ReadString(r, length); + } + private static string ReadShortString(BinaryReader r) { + int length = ReadUInt16(r); + return ReadString(r, length); + } + private static string ReadString(BinaryReader r, int length) { + byte[] buffer = r.ReadBytes(length); + return Encoding.UTF8.GetString(buffer); + } + } +} \ No newline at end of file