PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/source/library/Interlace/Amf/AmfReader.cs

https://bitbucket.org/VahidN/interlace
C# | 429 lines | 299 code | 105 blank | 25 comment | 39 complexity | 06ee64d3c7df35248113b67aaaf51670 MD5 | raw file
  1. #region Using Directives and Copyright Notice
  2. // Copyright (c) 2007-2010, Computer Consultancy Pty Ltd
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of the Computer Consultancy Pty Ltd nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. // ARE DISCLAIMED. IN NO EVENT SHALL COMPUTER CONSULTANCY PTY LTD BE LIABLE
  20. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  26. // DAMAGE.
  27. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Net;
  31. using System.Text;
  32. using System.Xml;
  33. #endregion
  34. namespace Interlace.Amf
  35. {
  36. public class AmfReader : IDisposable
  37. {
  38. BinaryReader _reader;
  39. AmfRegistry _registry;
  40. List<string> _stringTable;
  41. List<object> _objectTable;
  42. List<AmfTraits> _traitsTable;
  43. static readonly DateTime _amfEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  44. public AmfReader(BinaryReader reader, AmfRegistry registry)
  45. {
  46. _reader = reader;
  47. _registry = registry;
  48. _stringTable = new List<string>();
  49. _objectTable = new List<object>();
  50. _traitsTable = new List<AmfTraits>();
  51. }
  52. public static object Read(AmfRegistry registry, byte[] encodedBytes)
  53. {
  54. using (MemoryStream stream = new MemoryStream(encodedBytes))
  55. {
  56. using (AmfReader reader = new AmfReader(new BinaryReader(stream), registry))
  57. {
  58. return reader.Read();
  59. }
  60. }
  61. }
  62. void ResetTables()
  63. {
  64. _stringTable.Clear();
  65. _objectTable.Clear();
  66. _traitsTable.Clear();
  67. }
  68. double ReadNetworkDouble()
  69. {
  70. return BitConverter.Int64BitsToDouble(IPAddress.NetworkToHostOrder(_reader.ReadInt64()));
  71. }
  72. int ReadPackedInteger()
  73. {
  74. int accumulator = 0;
  75. byte first = _reader.ReadByte();
  76. accumulator = 0x7f & first;
  77. if ((first & 0x80) == 0) return accumulator;
  78. byte second = _reader.ReadByte();
  79. accumulator = (accumulator << 7) | (0x7f & second);
  80. if ((second & 0x80) == 0) return accumulator;
  81. byte third = _reader.ReadByte();
  82. accumulator = (accumulator << 7) | (0x7f & third);
  83. if ((third & 0x80) == 0) return accumulator;
  84. byte fourth = _reader.ReadByte();
  85. accumulator = (accumulator << 8) | fourth;
  86. return accumulator;
  87. }
  88. bool ReadFlaggedInteger(out int value)
  89. {
  90. int read = ReadPackedInteger();
  91. value = read >> 1;
  92. return (read & 1) == 1;
  93. }
  94. bool ReadFlaggedInteger()
  95. {
  96. int read = ReadPackedInteger();
  97. return (read & 1) == 1;
  98. }
  99. public object Read()
  100. {
  101. byte marker = _reader.ReadByte();
  102. switch (marker)
  103. {
  104. case AmfMarker.Undefined:
  105. throw new NotImplementedException();
  106. case AmfMarker.Null:
  107. return null;
  108. case AmfMarker.False:
  109. return false;
  110. case AmfMarker.True:
  111. return true;
  112. case AmfMarker.Integer:
  113. return ReadPackedInteger();
  114. case AmfMarker.Double:
  115. return ReadNetworkDouble();
  116. case AmfMarker.String:
  117. return ReadString();
  118. case AmfMarker.XmlDoc:
  119. throw new NotImplementedException();
  120. case AmfMarker.Date:
  121. return ReadDate();
  122. case AmfMarker.Array:
  123. return ReadArray();
  124. case AmfMarker.Object:
  125. return ReadObject();
  126. case AmfMarker.Xml:
  127. return ReadXml();
  128. case AmfMarker.ByteArray:
  129. return ReadByteArray();
  130. default:
  131. throw new NotImplementedException();
  132. }
  133. }
  134. string ReadString()
  135. {
  136. int argument;
  137. if (ReadFlaggedInteger(out argument))
  138. {
  139. byte[] data = _reader.ReadBytes(argument);
  140. if (data.Length < argument) throw new EndOfStreamException();
  141. string value = Encoding.UTF8.GetString(data);
  142. if (value != "") _stringTable.Add(value);
  143. return value;
  144. }
  145. else
  146. {
  147. return _stringTable[argument];
  148. }
  149. }
  150. DateTime ReadDate()
  151. {
  152. int argument;
  153. if (ReadFlaggedInteger(out argument))
  154. {
  155. double millisecondsSinceEpoch = ReadNetworkDouble();
  156. DateTime dateTime = _amfEpoch + TimeSpan.FromMilliseconds(millisecondsSinceEpoch);
  157. _objectTable.Add(dateTime);
  158. return dateTime;
  159. }
  160. else
  161. {
  162. return (DateTime)_objectTable[argument];
  163. }
  164. }
  165. Dictionary<string, object> ReadPropertyList()
  166. {
  167. Dictionary<string, object> dictionary = new Dictionary<string, object>();
  168. while (true)
  169. {
  170. string key = ReadString();
  171. if (key == "") break;
  172. object value = Read();
  173. dictionary[key] = value;
  174. }
  175. return dictionary;
  176. }
  177. AmfArray ReadArray()
  178. {
  179. int argument;
  180. if (ReadFlaggedInteger(out argument))
  181. {
  182. AmfArray array = new AmfArray();
  183. _objectTable.Add(array);
  184. Dictionary<string, object> associativeElements = ReadPropertyList();
  185. List<object> denseElements = new List<object>();
  186. for (int i = 0; i < argument; i++)
  187. {
  188. object obj = Read();
  189. denseElements.Add(obj);
  190. }
  191. foreach (KeyValuePair<string, object> pair in associativeElements)
  192. {
  193. array.AssociativeElements.Add(pair);
  194. }
  195. foreach (object element in denseElements)
  196. {
  197. array.DenseElements.Add(element);
  198. }
  199. return array;
  200. }
  201. else
  202. {
  203. return (AmfArray)_objectTable[argument];
  204. }
  205. }
  206. AmfTraits ReadObjectTraits(int argument)
  207. {
  208. bool isNonReferenceTrait = (argument & 1) == 1;
  209. int remainingArgument = argument >> 1;
  210. if (isNonReferenceTrait)
  211. {
  212. string className = ReadString();
  213. bool isExternalizable = (remainingArgument & 1) == 1;
  214. int traitArgument = remainingArgument >> 1;
  215. AmfTraits traits;
  216. if (isExternalizable)
  217. {
  218. traits = new AmfTraits(className, AmfTraitsKind.Externalizable, new string[] { });
  219. }
  220. else
  221. {
  222. bool isDynamic = (traitArgument & 1) == 1;
  223. int memberCount = traitArgument >> 1;
  224. string[] memberNames = new string[memberCount];
  225. for (int i = 0; i < memberCount; i++)
  226. {
  227. memberNames[i] = ReadString();
  228. }
  229. traits = new AmfTraits(className, isDynamic ? AmfTraitsKind.Dynamic : AmfTraitsKind.Static, memberNames);
  230. }
  231. _traitsTable.Add(traits);
  232. return traits;
  233. }
  234. else
  235. {
  236. return _traitsTable[remainingArgument];
  237. }
  238. }
  239. object ReadObject()
  240. {
  241. int argument;
  242. if (ReadFlaggedInteger(out argument))
  243. {
  244. AmfTraits traits = ReadObjectTraits(argument);
  245. if (traits.Kind == AmfTraitsKind.Externalizable)
  246. {
  247. throw new NotImplementedException();
  248. }
  249. else
  250. {
  251. IAmfClassDescriptor descriptor = _registry.GetByAlias(traits.ClassName);
  252. object newObject = descriptor.BeginDeserialization(traits);
  253. _objectTable.Add(newObject);
  254. Dictionary<string, object> staticMembers = new Dictionary<string, object>();
  255. foreach (string memberName in traits.MemberNames)
  256. {
  257. object value = Read();
  258. staticMembers[memberName] = value;
  259. }
  260. Dictionary<string, object> dynamicMembers = null;
  261. if (traits.Kind == AmfTraitsKind.Dynamic)
  262. {
  263. dynamicMembers = new Dictionary<string, object>();
  264. while (true)
  265. {
  266. string key = ReadString();
  267. if (key == "") break;
  268. object value = Read();
  269. dynamicMembers[key] = value;
  270. }
  271. }
  272. descriptor.EndDeserialization(traits, newObject, staticMembers, dynamicMembers);
  273. return newObject;
  274. }
  275. }
  276. else
  277. {
  278. return _objectTable[argument];
  279. }
  280. }
  281. XmlDocument ReadXml()
  282. {
  283. int argument;
  284. if (ReadFlaggedInteger(out argument))
  285. {
  286. byte[] data = _reader.ReadBytes(argument);
  287. if (data.Length < argument) throw new EndOfStreamException();
  288. string value = Encoding.UTF8.GetString(data);
  289. XmlDocument document = new XmlDocument();
  290. document.XmlResolver = null;
  291. document.LoadXml(value);
  292. _objectTable.Add(document);
  293. return document;
  294. }
  295. else
  296. {
  297. return (XmlDocument)_objectTable[argument];
  298. }
  299. }
  300. byte[] ReadByteArray()
  301. {
  302. int argument;
  303. if (ReadFlaggedInteger(out argument))
  304. {
  305. byte[] data = _reader.ReadBytes(argument);
  306. if (data.Length < argument) throw new EndOfStreamException();
  307. _objectTable.Add(data);
  308. return data;
  309. }
  310. else
  311. {
  312. return (byte[])_objectTable[argument];
  313. }
  314. }
  315. public void Dispose()
  316. {
  317. if (_reader != null)
  318. {
  319. _reader.Close();
  320. _reader = null;
  321. }
  322. }
  323. }
  324. }