Mercurial > hg > ucis.core
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3ab940a0c7a0 |
---|---|
1 using System; | |
2 using System.IO; | |
3 using System.Text; | |
4 using System.Collections.Generic; | |
5 using UCIS.Pml; | |
6 | |
7 namespace UCIS.Pml { | |
8 internal enum AmfDataType : byte { | |
9 Number = 0, | |
10 Boolean = 1, | |
11 String = 2, | |
12 UntypedObject = 3, | |
13 MovieClip = 4, | |
14 Null = 5, | |
15 Undefined = 6, | |
16 ReferencedObject = 7, | |
17 MixedArray = 8, | |
18 End = 9, | |
19 Array = 10, | |
20 Date = 11, | |
21 LongString = 12, | |
22 TypeAsObject = 13, | |
23 Recordset = 14, | |
24 Xml = 15, | |
25 TypedObject = 16 | |
26 } | |
27 public class PmlAmfWriter : IPmlWriter { | |
28 private BinaryWriter pWriter; | |
29 | |
30 public PmlAmfWriter(BinaryWriter Writer) { | |
31 pWriter = Writer; | |
32 } | |
33 public PmlAmfWriter(Stream Stream) { | |
34 pWriter = new BinaryWriter(Stream, Encoding.UTF8); | |
35 } | |
36 | |
37 public BinaryWriter BaseWriter { | |
38 get { return pWriter; } | |
39 set { pWriter = value; } | |
40 } | |
41 | |
42 public void WriteMessage(PmlElement Message) { | |
43 WriteMessageTo(Message, pWriter); | |
44 } | |
45 | |
46 public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) { | |
47 lock (Writer) { | |
48 WriteElementTo(Message, Writer); | |
49 Writer.Flush(); | |
50 } | |
51 } | |
52 | |
53 private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) { | |
54 if (Element == null) { | |
55 Writer.Write((byte)AmfDataType.Null); | |
56 return; | |
57 } | |
58 switch (Element.Type) { | |
59 case PmlType.Null: | |
60 Writer.Write((byte)AmfDataType.Null); | |
61 break; | |
62 case PmlType.Dictionary: | |
63 Writer.Write((byte)AmfDataType.UntypedObject); | |
64 //WriteDictionary(Writer, (PmlDictionary)Element); | |
65 WriteUntypedObject(Writer, (PmlDictionary)Element); | |
66 break; | |
67 case PmlType.Collection: | |
68 Writer.Write((byte)AmfDataType.Array); | |
69 WriteCollection(Writer, (PmlCollection)Element); | |
70 break; | |
71 case PmlType.Binary: | |
72 Writer.Write((byte)AmfDataType.String); | |
73 byte[] bytes = Element.ToByteArray(); | |
74 if (bytes.Length > UInt16.MaxValue) { | |
75 Writer.Write((byte)AmfDataType.String); | |
76 WriteString(Writer, bytes); | |
77 } else { | |
78 Writer.Write((byte)AmfDataType.LongString); | |
79 WriteLongString(Writer, bytes); | |
80 } | |
81 break; | |
82 case PmlType.String: | |
83 string str = Element.ToString(); | |
84 if (str.Length < UInt16.MaxValue) { | |
85 Writer.Write((byte)AmfDataType.String); | |
86 WriteString(Writer, str); | |
87 } else { | |
88 Writer.Write((byte)AmfDataType.LongString); | |
89 WriteLongString(Writer, str); | |
90 } | |
91 break; | |
92 case PmlType.Integer: | |
93 Writer.Write((byte)AmfDataType.Number); | |
94 WriteDouble(Writer, (Element as PmlInteger).ToDouble()); | |
95 break; | |
96 } | |
97 } | |
98 private static void WriteEnd(BinaryWriter w) { | |
99 WriteUInt16(w, 0); | |
100 w.Write((byte)AmfDataType.End); | |
101 } | |
102 private static void WriteUntypedObject(BinaryWriter w, PmlDictionary value) { | |
103 foreach (KeyValuePair<String, PmlElement> kvp in value) { | |
104 WriteString(w, kvp.Key); | |
105 WriteElementTo(kvp.Value, w); | |
106 } | |
107 WriteEnd(w); | |
108 } | |
109 private static void WriteDictionary(BinaryWriter w, PmlDictionary value) { | |
110 WriteUInt32(w, (UInt32)value.Count); | |
111 foreach (KeyValuePair<String, PmlElement> kvp in value) { | |
112 WriteString(w, kvp.Key); | |
113 WriteElementTo(kvp.Value, w); | |
114 } | |
115 } | |
116 private static void WriteCollection(BinaryWriter w, PmlCollection value) { | |
117 WriteUInt32(w,(UInt32)value.Count); | |
118 foreach (PmlElement o in value) { | |
119 WriteElementTo(o, w); | |
120 } | |
121 } | |
122 private static void WriteDouble(BinaryWriter w, double value) { | |
123 WriteReverse(w, BitConverter.GetBytes(value)); | |
124 } | |
125 private static void WriteUInt32(BinaryWriter w, UInt32 value) { | |
126 WriteReverse(w, BitConverter.GetBytes(value)); | |
127 } | |
128 private static void WriteUInt16(BinaryWriter w, UInt16 value) { | |
129 WriteReverse(w, BitConverter.GetBytes(value)); | |
130 } | |
131 private static void WriteString(BinaryWriter w, string value) { | |
132 WriteString(w, Encoding.UTF8.GetBytes(value)); | |
133 } | |
134 private static void WriteLongString(BinaryWriter w, string value) { | |
135 WriteLongString(w, Encoding.UTF8.GetBytes(value)); | |
136 } | |
137 private static void WriteString(BinaryWriter w, byte[] buffer) { | |
138 WriteUInt16(w, (UInt16)buffer.Length); | |
139 w.Write(buffer, 0, buffer.Length); | |
140 } | |
141 private static void WriteLongString(BinaryWriter w, byte[] buffer) { | |
142 WriteUInt32(w, (UInt32)buffer.Length); | |
143 w.Write(buffer, 0, buffer.Length); | |
144 } | |
145 private static void WriteReverse(BinaryWriter w, byte[] value) { | |
146 Array.Reverse(value); | |
147 w.Write(value); | |
148 } | |
149 } | |
150 | |
151 public class PmlAmfReader : IPmlReader { | |
152 private BinaryReader pReader; | |
153 | |
154 public PmlAmfReader(BinaryReader Reader) { | |
155 pReader = Reader; | |
156 } | |
157 public PmlAmfReader(Stream Stream) { | |
158 pReader = new BinaryReader(Stream, Encoding.UTF8); | |
159 } | |
160 | |
161 public BinaryReader BaseReader { | |
162 get { return pReader; } | |
163 set { pReader = value; } | |
164 } | |
165 | |
166 public PmlElement ReadMessage() { | |
167 return ReadMessageFrom(pReader); | |
168 } | |
169 | |
170 public static PmlElement ReadMessageFrom(BinaryReader Reader) { | |
171 PmlElement Element = null; | |
172 lock (Reader) { | |
173 Element = ReadElementFrom(Reader); | |
174 } | |
175 return Element; | |
176 } | |
177 | |
178 | |
179 private static PmlElement ReadElementFrom(BinaryReader Reader) { | |
180 AmfDataType EType = (AmfDataType)Reader.ReadByte(); | |
181 return ReadData(Reader, EType); | |
182 } | |
183 private static PmlElement ReadData(BinaryReader Reader, AmfDataType EType) { | |
184 switch (EType) { | |
185 case AmfDataType.Number: | |
186 Double d = ReadDouble(Reader); | |
187 if (d == (double)(Int64)d) { | |
188 return new PmlInteger((Int64)d); | |
189 } else if (d == (double)(UInt64)d) { | |
190 return new PmlInteger((UInt64)d); | |
191 } else { | |
192 return new PmlString(d.ToString()); | |
193 } | |
194 case AmfDataType.Boolean: | |
195 return new PmlInteger(Reader.ReadByte()); | |
196 case AmfDataType.String: | |
197 return new PmlString(ReadShortString(Reader)); | |
198 case AmfDataType.Array: | |
199 PmlCollection ElementC = new PmlCollection(); | |
200 int size = ReadInt32(Reader); | |
201 for (int i = 0; i < size; ++i) { | |
202 ElementC.Add(ReadElementFrom(Reader)); | |
203 } | |
204 return ElementC; | |
205 case AmfDataType.Date: | |
206 return new PmlString(ReadDate(Reader).ToString()); | |
207 case AmfDataType.LongString: | |
208 return new PmlString(ReadLongString(Reader)); | |
209 case AmfDataType.TypedObject: | |
210 ReadShortString(Reader); | |
211 return ReadUntypedObject(Reader); | |
212 case AmfDataType.MixedArray: | |
213 return ReadDictionary(Reader); | |
214 case AmfDataType.Null: | |
215 case AmfDataType.Undefined: | |
216 case AmfDataType.End: | |
217 return new PmlNull(); | |
218 case AmfDataType.UntypedObject: | |
219 return ReadUntypedObject(Reader); | |
220 case AmfDataType.Xml: | |
221 return new PmlString(ReadLongString(Reader)); | |
222 case AmfDataType.MovieClip: | |
223 case AmfDataType.ReferencedObject: | |
224 case AmfDataType.TypeAsObject: | |
225 case AmfDataType.Recordset: | |
226 default: | |
227 throw new NotSupportedException("The AMF type is not supported: " + EType.ToString()); | |
228 } | |
229 } | |
230 | |
231 private static PmlDictionary ReadUntypedObject(BinaryReader Reader) { | |
232 PmlDictionary ElementD = new PmlDictionary(); | |
233 string key = ReadShortString(Reader); | |
234 for (byte type = Reader.ReadByte(); type != 9; type = Reader.ReadByte()) { | |
235 ElementD.Add(key, ReadData(Reader, (AmfDataType)type)); | |
236 key = ReadShortString(Reader); | |
237 } | |
238 return ElementD; | |
239 } | |
240 private static PmlDictionary ReadDictionary(BinaryReader Reader) { | |
241 PmlDictionary ElementD = new PmlDictionary(); | |
242 int size = ReadInt32(Reader); | |
243 return ReadUntypedObject(Reader); | |
244 } | |
245 | |
246 private static DateTime ReadDate(BinaryReader r) { | |
247 double ms = ReadDouble(r); | |
248 DateTime date = (new DateTime(1970, 1, 1)).AddMilliseconds(ms); | |
249 ReadUInt16(r); //gets the timezone | |
250 return date; | |
251 } | |
252 private static double ReadDouble(BinaryReader r) { | |
253 return BitConverter.ToDouble(ReadReverse(r, 8), 0); | |
254 } | |
255 | |
256 private static int ReadInt32(BinaryReader r) { | |
257 return BitConverter.ToInt32(ReadReverse(r, 4), 0); | |
258 } | |
259 | |
260 private static ushort ReadUInt16(BinaryReader r) { | |
261 return BitConverter.ToUInt16(ReadReverse(r, 2), 0); | |
262 } | |
263 | |
264 private static byte[] ReadReverse(BinaryReader r, int size) { | |
265 byte[] buffer = r.ReadBytes(size); | |
266 Array.Reverse(buffer); | |
267 return buffer; | |
268 } | |
269 private static string ReadLongString(BinaryReader r) { | |
270 int length = ReadInt32(r); | |
271 return ReadString(r, length); | |
272 } | |
273 private static string ReadShortString(BinaryReader r) { | |
274 int length = ReadUInt16(r); | |
275 return ReadString(r, length); | |
276 } | |
277 private static string ReadString(BinaryReader r, int length) { | |
278 byte[] buffer = r.ReadBytes(length); | |
279 return Encoding.UTF8.GetString(buffer); | |
280 } | |
281 } | |
282 } |