PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/Interlace/Erlang/TermReader.cs

https://bitbucket.org/VahidN/interlace
C# | 255 lines | 168 code | 60 blank | 27 comment | 16 complexity | 521443db41580321e3f3f177dd2c6b66 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. #endregion
  28. // Portions of this code were originally developed for Bit Plantation BitLibrary.
  29. // (Portions Copyright © 2006 Bit Plantation)
  30. using System;
  31. using System.Collections.Generic;
  32. using System.Collections;
  33. using System.Text;
  34. using System.IO;
  35. using System.Net;
  36. namespace Interlace.Erlang
  37. {
  38. public class TermReader : IDisposable
  39. {
  40. BinaryReader _reader;
  41. public TermReader(Stream stream)
  42. {
  43. _reader = new BinaryReader(stream);
  44. }
  45. public void Close()
  46. {
  47. _reader.Close();
  48. }
  49. public void Dispose()
  50. {
  51. Close();
  52. }
  53. byte ReadByte()
  54. {
  55. return _reader.ReadByte();
  56. }
  57. ushort ReadUnsignedShort()
  58. {
  59. return (ushort)IPAddress.NetworkToHostOrder((short)_reader.ReadUInt16());
  60. }
  61. uint ReadUnsignedInteger()
  62. {
  63. return (uint)IPAddress.NetworkToHostOrder((int)_reader.ReadUInt32());
  64. }
  65. public object ReadTerm()
  66. {
  67. byte magic = ReadByte();
  68. if (magic != Tags.Version)
  69. {
  70. throw new CodecException("The term does not begin with a known version magic number.");
  71. }
  72. return ReadObject();
  73. }
  74. object ReadObject()
  75. {
  76. byte tag = ReadByte();
  77. switch (tag)
  78. {
  79. case Tags.Atom:
  80. return ReadAtom();
  81. case Tags.SmallTuple:
  82. int arity = (int)ReadByte();
  83. return ReadTupleData(arity);
  84. case Tags.LargeTuple:
  85. arity = (int)ReadUnsignedInteger();
  86. return ReadTupleData(arity);
  87. case Tags.SmallInteger:
  88. return (int)ReadByte();
  89. case Tags.Integer:
  90. return (int)ReadUnsignedInteger();
  91. case Tags.Nil:
  92. return new List<object>();
  93. case Tags.String:
  94. return ReadString();
  95. case Tags.List:
  96. return ReadList();
  97. case Tags.Binary:
  98. return ReadBinary();
  99. case Tags.Float:
  100. throw new CodecException("Float terms are not supported.");
  101. case Tags.Reference:
  102. throw new CodecException("Reference terms are not supported.");
  103. case Tags.Port:
  104. throw new CodecException("Port terms are not supported.");
  105. case Tags.ProcessId:
  106. return ReadProcessId();
  107. case Tags.SmallBigNumber:
  108. throw new CodecException("Small big number terms are not supported.");
  109. case Tags.LargeBigNumber:
  110. throw new CodecException("Large big number terms are not supported.");
  111. case Tags.NewAtomCacheEntry:
  112. throw new CodecException("Cached atom terms are not supported.");
  113. case Tags.CachedAtom:
  114. throw new CodecException("Cached atom terms are not supported.");
  115. case Tags.NewReference:
  116. throw new CodecException("New reference terms are not supported.");
  117. case Tags.Function:
  118. throw new CodecException("Function terms are not supported.");
  119. case Tags.NewFunction:
  120. throw new CodecException("Function terms are not supported.");
  121. case Tags.ExportFunction:
  122. throw new CodecException("Function terms are not supported.");
  123. case Tags.BitBinary:
  124. throw new CodecException("Bit (odd length) binary terms are not supported.");
  125. default:
  126. throw new CodecException(string.Format(
  127. "Unrecognised term tag ({0}) found while decoding term.", tag));
  128. }
  129. }
  130. byte[] ReadBinary()
  131. {
  132. uint length = ReadUnsignedInteger();
  133. byte[] binaryBytes = _reader.ReadBytes((int)length);
  134. if (binaryBytes.Length != length)
  135. {
  136. throw new CodecException("End of stream while reading a binary term.");
  137. }
  138. return binaryBytes;
  139. }
  140. ErlangProcessId ReadProcessId()
  141. {
  142. Atom atom = ReadObject() as Atom;
  143. if (atom == null) throw new CodecException("A process id atom was expected, but some other term was found.");
  144. uint id = ReadUnsignedInteger();
  145. uint serial = ReadUnsignedInteger();
  146. byte creation = ReadByte();
  147. return new ErlangProcessId(atom, id, serial, creation);
  148. }
  149. List<object> ReadList()
  150. {
  151. uint length = ReadUnsignedInteger();
  152. List<object> list = new List<object>((int)length);
  153. for (int i = 0; i < length; i++)
  154. {
  155. list.Add(ReadObject());
  156. }
  157. object tail = ReadObject();
  158. if (!(tail is List<object> && (tail as List<object>).Count == 0))
  159. {
  160. throw new ErlangProtocolException("Improper lists (those with a tail that is not a NIL) are not supported.");
  161. }
  162. return list;
  163. }
  164. Atom ReadAtom()
  165. {
  166. ushort length = ReadUnsignedShort();
  167. byte[] symbolBytes = _reader.ReadBytes(length);
  168. if (symbolBytes.Length != length)
  169. {
  170. throw new CodecException("End of stream while reading an atom term.");
  171. }
  172. string symbol = Encoding.ASCII.GetString(symbolBytes);
  173. return Atom.From(symbol);
  174. }
  175. string ReadString()
  176. {
  177. ushort length = ReadUnsignedShort();
  178. byte[] stringBytes = _reader.ReadBytes(length);
  179. if (stringBytes.Length != length)
  180. {
  181. throw new CodecException("End of stream while reading a string term.");
  182. }
  183. return Encoding.ASCII.GetString(stringBytes);
  184. }
  185. Tuple ReadTupleData(int arity)
  186. {
  187. object[] elements = new object[arity];
  188. for (int i = 0; i < arity; i++)
  189. {
  190. elements[i] = ReadObject();
  191. }
  192. return new Tuple(elements);
  193. }
  194. }
  195. }