/lib/otp.net/Otp/OtpInputStream.cs
C# | 1007 lines | 560 code | 154 blank | 293 comment | 80 complexity | f4136adf8cc35856083adb3624040349 MD5 | raw file
Possible License(s): AGPL-1.0, JSON, LGPL-2.1, BSD-3-Clause
- /*``The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved via the world wide web at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- * AB. All Rights Reserved.''
- *
- * Converted from Java to C# by Vlad Dumitrescu (vlad_Dumitrescu@hotmail.com)
- */
- namespace Otp
- {
- using System;
- /*
- * Provides a stream for decoding Erlang terms from external format.
- *
- * <p> Note that this class is not synchronized, if you need
- * synchronization you must provide it yourself.
- **/
- public class OtpInputStream:System.IO.MemoryStream
- {
- /*
- * Create a stream from a buffer containing encoded Erlang terms.
- **/
- public OtpInputStream(byte[] buf):base(buf)
- {
- }
-
- /*
- * Create a stream from a buffer containing encoded
- * Erlang terms at the given offset and length.
- **/
- public OtpInputStream(byte[] buf, int offset, int length):base(buf, offset, length)
- {
- }
-
- /*
- * Get the current position in the stream.
- *
- * @return the current position in the stream.
- **/
- public virtual int getPos()
- {
- return (int) base.Position;
- }
-
- /*
- * Set the current position in the stream.
- *
- * @param pos the position to move to in the stream. If pos
- * indicates a position beyond the end of the stream, the position
- * is move to the end of the stream instead. If pos is negative, the
- * position is moved to the beginning of the stream instead.
- *
- * @return the previous position in the stream.
- **/
- public virtual int setPos(int pos)
- {
- int oldpos = (int) base.Position;
-
- if (pos > (int) base.Length)
- pos = (int) base.Length;
- else if (pos < 0)
- pos = 0;
-
- base.Position = (System.Int64) pos;
-
- return oldpos;
- }
-
- /*
- * Read an array of bytes from the stream. The method reads at most
- * buf.length bytes from the input stream.
- *
- * @return the number of bytes read.
- *
- * @exception OtpErlangDecodeException if the next byte cannot be
- * read.
- **/
- public virtual int readN(byte[] buf)
- {
- try
- {
- return base.Read(buf, 0, buf.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- }
-
- /*
- * Look ahead one position in the stream without consuming the byte
- * found there.
- *
- * @return the next byte in the stream, as an integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int peek()
- {
- int i;
- try
- {
- i = base.ReadByte();
- base.Seek(-1, System.IO.SeekOrigin.Current);
- if (i < 0)
- i += 256;
-
- return i;
- }
- catch (System.Exception)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- }
-
- /*
- * Read a one byte integer from the stream.
- *
- * @return the byte read, as an integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int read1()
- {
- int i;
- i = base.ReadByte();
-
- if (i < 0)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
-
- return i;
- }
-
- /*
- * Read a two byte big endian integer from the stream.
- *
- * @return the bytes read, converted from big endian to an integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int read2BE()
- {
- byte[] b = new byte[2];
- try
- {
- base.Read(b, 0, b.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- return ((((int) b[0] << 8) & 0xff00) + (((int) b[1]) & 0xff));
- }
-
- /*
- * Read a four byte big endian integer from the stream.
- *
- * @return the bytes read, converted from big endian to an integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int read4BE()
- {
- byte[] b = new byte[4];
- try
- {
- base.Read(b, 0, b.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- return (int)((((int) b[0] << 24) & 0xff000000) + (((int) b[1] << 16) & 0xff0000) + (((int) b[2] << 8) & 0xff00) + (((int) b[3]) & 0xff));
- }
- /*
- * Read an eight byte big endian integer from the stream.
- *
- * @return the bytes read, converted from big endian to an integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public System.UInt64 read8BE()
- {
- byte[] b = new byte[8];
- try
- {
- base.Read(b, 0, b.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- System.UInt64 i1 = (System.UInt64)((((int)b[0] << 24) & 0xff000000) + (((int)b[1] << 16) & 0xff0000) + (((int)b[2] << 8) & 0xff00) + (((int)b[3]) & 0xff));
- System.UInt64 i2 = (i1 << 32) & 0xffffffff00000000
- + (System.UInt64)((((int)b[4] << 24) & 0xff000000) + (((int)b[5] << 16) & 0xff0000) + (((int)b[6] << 8) & 0xff00) + (((int)b[7]) & 0xff));
- return i2;
- }
- /*
- * Read a two byte little endian integer from the stream.
- *
- * @return the bytes read, converted from little endian to an
- * integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int read2LE()
- {
- byte[] b = new byte[2];
- try
- {
- base.Read(b, 0, b.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- return ((((int) b[1] << 8) & 0xff00) + (((int) b[0]) & 0xff));
- }
-
- /*
- * Read a four byte little endian integer from the stream.
- *
- * @return the bytes read, converted from little endian to an
- * integer.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual int read4LE()
- {
- byte[] b = new byte[4];
- try
- {
- base.Read(b, 0, b.Length);
- }
- catch (System.IO.IOException)
- {
- throw new Erlang.Exception("Cannot read from input stream");
- }
- return (int)((((int) b[3] << 24) & 0xff000000) + (((int) b[2] << 16) & 0xff0000) + (((int) b[1] << 8) & 0xff00) + (((int) b[0]) & 0xff));
- }
-
- /*
- * Read an Erlang atom from the stream and interpret the value as a
- * boolean.
- *
- * @return true if the atom at the current position in the stream
- * contains the value 'true' (ignoring case), false otherwise.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not an atom.
- **/
- public virtual bool read_boolean()
- {
- return System.Boolean.Parse(this.read_atom());
- }
-
- /*
- * Read an Erlang atom from the stream.
- *
- * @return a String containing the value of the atom.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not an atom.
- **/
- public virtual string read_atom()
- {
- int tag;
- int len;
- byte[] strbuf;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- if (tag != OtpExternal.atomTag)
- {
- throw new Erlang.Exception("wrong tag encountered, expected " + OtpExternal.atomTag + ", got " + tag);
- }
-
- len = this.read2BE();
-
- strbuf = new byte[len];
- this.readN(strbuf);
- int n = strbuf.Length > OtpExternal.maxAtomLength ? OtpExternal.maxAtomLength : strbuf.Length;
- return System.Text.Encoding.ASCII.GetString(strbuf, 0, n);
- }
-
- /*
- * Read an Erlang binary from the stream.
- *
- * @return a byte array containing the value of the binary.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not a binary.
- **/
- public virtual byte[] read_binary()
- {
- int tag;
- int len;
- byte[] bin;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- if (tag != OtpExternal.binTag)
- {
- throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.binTag + ", got " + tag);
- }
-
- len = this.read4BE();
-
- bin = new byte[len];
- this.readN(bin);
-
- return bin;
- }
-
- /*
- * Read an Erlang float from the stream.
- *
- * @return the float value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not a float.
- **/
- public virtual float read_float()
- {
- double d = this.read_double();
- float f = (float)d;
- if (System.Math.Abs(d - f) >= 1.0E-20)
- throw new Erlang.Exception("Value cannot be represented as float: " + d);
- return f;
- }
- /*
- * Read an Erlang float from the stream.
- *
- * @return the float value, as a double.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not a float.
- *
- **/
- public virtual double read_double()
- {
- return getFloatOrDouble();
- }
- private double getFloatOrDouble()
- {
- // parse the stream
- int tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
- byte[] strbuf;
- double parsedValue = 0.0;
- if (tag == OtpExternal.floatTag)
- {
- // get the string
- strbuf = new byte[31];
- this.readN(strbuf);
- char[] tmpChar = new char[strbuf.Length];
- strbuf.CopyTo(tmpChar, 0);
- System.String str = new System.String(tmpChar);
- //System.Diagnostics.Debug.WriteLine("getFloatOrDouble: str = " + str);
- try
- {
- // Easier than the java version.
- parsedValue = System.Double.Parse(str);
- return parsedValue;
- }
- catch
- {
- throw new Erlang.Exception("Error parsing float format: '" + str + "'");
- }
- }
- else if (tag == OtpExternal.newFloatTag)
- {
- byte[] data = new byte[8];
- this.readN(data);
- // IEEE 754 decoder
- if (BitConverter.IsLittleEndian)
- {
- Array.Reverse(data);
- }
- return BitConverter.ToDouble(data, 0);
- }
- else
- {
- throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.floatTag + ", got " + tag);
- }
- }
-
- /*
- * Read one byte from the stream.
- *
- * @return the byte read.
- *
- * @exception Erlang.DecodeException if the next byte cannot be
- * read.
- **/
- public virtual byte read_byte()
- {
- long l = this.read_long();
- byte i = (byte) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for byte: " + l);
- }
-
- return i;
- }
-
- /*
- * Read a character from the stream.
- *
- * @return the character value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not an integer that can be represented as a char.
- **/
- public virtual char read_char()
- {
- long l = this.read_long();
- char i = (char) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for byte: " + l);
- }
-
- return i;
- }
-
- /*
- * Read an unsigned integer from the stream.
- *
- * @return the integer value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as a positive integer.
- **/
- public virtual int read_uint()
- {
- long l = this.read_long();
- int i = (int) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for integer: " + l);
- }
- else if (l < 0)
- {
- throw new Erlang.Exception("Value not unsigned: " + l);
- }
-
- return i;
- }
-
- /*
- * Read an integer from the stream.
- *
- * @return the integer value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as an integer.
- **/
- public virtual int read_int()
- {
- long l = this.read_long();
- int i = (int) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for byte: " + l);
- }
-
- return i;
- }
-
- /*
- * Read an unsigned short from the stream.
- *
- * @return the short value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as a positive short.
- **/
- public virtual short read_ushort()
- {
- long l = this.read_long();
- short i = (short) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for byte: " + l);
- }
- else if (l < 0)
- {
- throw new Erlang.Exception("Value not unsigned: " + l);
- }
-
- return i;
- }
-
- /*
- * Read a short from the stream.
- *
- * @return the short value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as a short.
- **/
- public virtual short read_short()
- {
- long l = this.read_long();
- short i = (short) l;
-
- if (l != i)
- {
- throw new Erlang.Exception("Value too large for byte: " + l);
- }
-
- return i;
- }
-
- /*
- * Read an unsigned long from the stream.
- *
- * @return the long value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as a positive long.
- **/
- public virtual long read_ulong()
- {
- long l = this.read_long();
-
- if (l < 0)
- {
- throw new Erlang.Exception("Value not unsigned: " + l);
- }
-
- return l;
- }
-
- /*
- * Read a long from the stream.
- *
- * @return the long value.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream can not be represented as a long.
- **/
- public virtual long read_long()
- {
- int tag;
- int sign;
- int arity;
- long val;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- switch (tag)
- {
- case OtpExternal.smallIntTag:
- val = this.read1();
- break;
-
-
-
- case OtpExternal.intTag:
- val = this.read4BE();
- break;
-
-
-
- case OtpExternal.smallBigTag: {
- arity = this.read1();
- sign = this.read1();
- byte[] nb = new byte[arity];
- if (arity != this.readN(nb))
- {
- throw new Erlang.Exception("Cannot read from input stream. Expected smallBigTag arity " + arity);
- }
- if (arity > 8)
- throw new Erlang.Exception("Value too large for long type (arity=" + arity + ")");
- val = 0;
- for (int i = 0; i < arity; i++)
- {
- val |= (long)nb[i] << (i * 8);
- }
- val = (sign == 0 ? val : -val); // should deal with overflow
-
- break;
- }
-
-
- case OtpExternal.largeBigTag: default:
- throw new Erlang.Exception("Not valid integer tag: " + tag);
-
- }
-
- return val;
- }
-
- /*
- * Read a list header from the stream.
- *
- * @return the arity of the list.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not a list.
- **/
- public virtual int read_list_head()
- {
- int arity = 0;
- int tag = this.read1();
-
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- switch (tag)
- {
- case OtpExternal.nilTag:
- arity = 0;
- break;
-
-
-
- case OtpExternal.stringTag:
- arity = this.read2BE();
- break;
-
-
-
- case OtpExternal.listTag:
- arity = this.read4BE();
- break;
-
-
-
- default:
- throw new Erlang.Exception("Not valid list tag: " + tag);
-
- }
-
- return arity;
- }
-
- /*
- * Read a tuple header from the stream.
- *
- * @return the arity of the tuple.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not a tuple.
- **/
- public virtual int read_tuple_head()
- {
- int arity = 0;
- int tag = this.read1();
-
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- // decode the tuple header and get arity
- switch (tag)
- {
- case OtpExternal.smallTupleTag:
- arity = this.read1();
- break;
-
-
-
- case OtpExternal.largeTupleTag:
- arity = this.read4BE();
- break;
-
-
-
- default:
- throw new Erlang.Exception("Not valid tuple tag: " + tag);
-
- }
-
- return arity;
- }
-
- /*
- * Read an empty list from the stream.
- *
- * @return zero (the arity of the list).
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not an empty list.
- **/
- public virtual int read_nil()
- {
- int arity = 0;
- int tag = this.read1();
-
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- switch (tag)
- {
- case OtpExternal.nilTag:
- arity = 0;
- break;
-
-
-
- default:
- throw new Erlang.Exception("Not valid nil tag: " + tag);
-
- }
-
- return arity;
- }
-
- /*
- * Read an Erlang PID from the stream.
- *
- * @return the value of the PID.
- *
- * @exception Erlang.DecodeException if the next term in the
- * stream is not an Erlang PID.
- **/
- public virtual Erlang.Pid read_pid()
- {
- System.String node;
- int id;
- int serial;
- int creation;
- int tag;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- if (tag != OtpExternal.pidTag)
- {
- throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.pidTag + ", got " + tag);
- }
-
- node = this.read_atom();
- id = this.read4BE() & 0x7fff; // 15 bits
- serial = this.read4BE() & 0x07; // 3 bits
- creation = this.read1() & 0x03; // 2 bits
-
- return new Erlang.Pid(node, id, serial, creation);
- }
-
- /*
- * Read an Erlang port from the stream.
- *
- * @return the value of the port.
- *
- * @exception DecodeException if the next term in the
- * stream is not an Erlang port.
- **/
- public virtual Erlang.Port read_port()
- {
- System.String node;
- int id;
- int creation;
- int tag;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- if (tag != OtpExternal.portTag)
- {
- throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.portTag + ", got " + tag);
- }
-
- node = this.read_atom();
- id = this.read4BE() & 0x3ffff; // 18 bits
- creation = this.read1() & 0x03; // 2 bits
-
- return new Erlang.Port(node, id, creation);
- }
-
- /*
- * Read an Erlang reference from the stream.
- *
- * @return the value of the reference
- *
- * @exception DecodeException if the next term in the
- * stream is not an Erlang reference.
- **/
- public virtual Erlang.Ref read_ref()
- {
- System.String node;
- int id;
- int creation;
- int tag;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- switch (tag)
- {
- case OtpExternal.refTag:
- node = this.read_atom();
- id = this.read4BE() & 0x3ffff; // 18 bits
- creation = this.read1() & 0x03; // 2 bits
- return new Erlang.Ref(node, id, creation);
-
-
-
- case OtpExternal.newRefTag:
- int arity = this.read2BE();
- node = this.read_atom();
- creation = this.read1() & 0x03; // 2 bits
-
- int[] ids = new int[arity];
- for (int i = 0; i < arity; i++)
- {
- ids[i] = this.read4BE();
- }
- ids[0] &= 0x3ffff; // first id gets truncated to 18 bits
- return new Erlang.Ref(node, ids, creation);
-
-
-
- default:
- throw new Erlang.Exception("Wrong tag encountered, expected ref, got " + tag);
-
- }
- }
-
- /*
- * Read a string from the stream.
- *
- * @return the value of the string.
- *
- * @exception DecodeException if the next term in the
- * stream is not a string.
- **/
- public virtual System.String read_string()
- {
- int tag;
- int len;
- byte[] strbuf;
- char[] charbuf;
-
- tag = this.read1();
- if (tag == OtpExternal.versionTag)
- {
- tag = this.read1();
- }
-
- switch (tag)
- {
-
- case OtpExternal.stringTag:
- char[] tmpChar;
- len = this.read2BE();
- strbuf = new byte[len];
- this.readN(strbuf);
- tmpChar = new char[strbuf.Length];
- strbuf.CopyTo(tmpChar, 0);
- return new System.String(tmpChar);
- case OtpExternal.nilTag:
- return "";
- case OtpExternal.listTag:
- // List when unicode +
- len = this.read4BE();
- charbuf = new char[len];
- for (int i = 0; i < len; i++)
- charbuf[i] = this.read_char();
- this.read_nil();
- return new System.String(charbuf);
- default:
- throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.stringTag + " or " + OtpExternal.listTag + ", got " + tag);
-
- }
- }
- /*
- * Read an arbitrary Erlang term from the stream.
- *
- * @return the Erlang term.
- *
- * @exception DecodeException if the stream does not
- * contain a known Erlang type at the next position.
- **/
- public virtual Erlang.Object read_any()
- {
- // calls one of the above functions, depending on o
- int tag = this.peek();
- if (tag == OtpExternal.versionTag)
- {
- this.read1();
- tag = this.peek();
- }
- //System.Diagnostics.Debug.WriteLine("read_any: tag = " + tag);
- switch (tag)
- {
- case OtpExternal.smallIntTag: case OtpExternal.intTag: case OtpExternal.smallBigTag:
- return new Erlang.Long(this);
- case OtpExternal.atomTag:
- string s = read_atom();
- if (s == "true")
- return new Erlang.Boolean(true);
- else if (s == "false")
- return new Erlang.Boolean(false);
- else
- return new Erlang.Atom(s);
- case OtpExternal.floatTag:
- case OtpExternal.newFloatTag:
- return new Erlang.Double(this);
- case OtpExternal.refTag: case OtpExternal.newRefTag:
- return new Erlang.Ref(this);
- case OtpExternal.portTag:
- return new Erlang.Port(this);
- case OtpExternal.pidTag:
- return new Erlang.Pid(this);
- case OtpExternal.stringTag:
- return new Erlang.String(this);
- case OtpExternal.listTag: case OtpExternal.nilTag:
- return new Erlang.List(this);
- case OtpExternal.smallTupleTag: case OtpExternal.largeTupleTag:
- return new Erlang.Tuple(this);
- case OtpExternal.binTag:
- return new Erlang.Binary(this);
- case OtpExternal.largeBigTag: default:
- throw new Erlang.Exception("Uknown data type: " + tag);
-
- }
- }
- }
- }