PageRenderTime 169ms CodeModel.GetById 100ms app.highlight 37ms RepoModel.GetById 23ms app.codeStats 1ms

/lib/otp.net/Otp/OtpInputStream.cs

https://github.com/gebi/jungerl
C# | 1007 lines | 560 code | 154 blank | 293 comment | 80 complexity | f4136adf8cc35856083adb3624040349 MD5 | raw file
   1/*``The contents of this file are subject to the Erlang Public License,
   2* Version 1.1, (the "License"); you may not use this file except in
   3* compliance with the License. You should have received a copy of the
   4* Erlang Public License along with this software. If not, it can be
   5* retrieved via the world wide web at http://www.erlang.org/.
   6* 
   7* Software distributed under the License is distributed on an "AS IS"
   8* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   9* the License for the specific language governing rights and limitations
  10* under the License.
  11* 
  12* The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13* Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14* AB. All Rights Reserved.''
  15* 
  16 * Converted from Java to C# by Vlad Dumitrescu (vlad_Dumitrescu@hotmail.com)
  17*/
  18namespace Otp
  19{
  20	using System;
  21
  22	/*
  23	* Provides a stream for decoding Erlang terms from external format.
  24	*
  25	* <p> Note that this class is not synchronized, if you need
  26	* synchronization you must provide it yourself.
  27	**/
  28	public class OtpInputStream:System.IO.MemoryStream
  29	{
  30		/*
  31		* Create a stream from a buffer containing encoded Erlang terms.
  32		**/
  33		public OtpInputStream(byte[] buf):base(buf)
  34		{
  35		}
  36		
  37		/*
  38		* Create a stream from a buffer containing encoded
  39		* Erlang terms at the given offset and length.
  40		**/
  41		public OtpInputStream(byte[] buf, int offset, int length):base(buf, offset, length)
  42		{
  43		}
  44		
  45		/*
  46		* Get the current position in the stream.
  47		*
  48		* @return the current position in the stream.
  49		**/
  50		public virtual int getPos()
  51		{
  52			return (int) base.Position;
  53		}
  54		
  55		/*
  56		* Set the current position in the stream.
  57		*
  58		* @param pos the position to move to in the stream. If pos
  59		* indicates a position beyond the end of the stream, the position
  60		* is move to the end of the stream instead. If pos is negative, the
  61		* position is moved to the beginning of the stream instead.
  62		*
  63		* @return the previous position in the stream.
  64		**/
  65		public virtual int setPos(int pos)
  66		{
  67			int oldpos = (int) base.Position;
  68			
  69			if (pos > (int) base.Length)
  70				pos = (int) base.Length;
  71			else if (pos < 0)
  72				pos = 0;
  73			
  74			base.Position = (System.Int64) pos;
  75			
  76			return oldpos;
  77		}
  78		
  79		/*
  80		* Read an array of bytes from the stream. The method reads at most
  81		* buf.length bytes from the input stream.
  82		*
  83		* @return the number of bytes read.
  84		*
  85		* @exception OtpErlangDecodeException if the next byte cannot be
  86		* read.
  87		**/
  88		public virtual int readN(byte[] buf)
  89		{
  90			try
  91			{
  92				return base.Read(buf, 0, buf.Length);
  93			}
  94			catch (System.IO.IOException)
  95			{
  96				throw new Erlang.Exception("Cannot read from input stream");
  97			}
  98		}
  99		
 100		/*
 101		* Look ahead one position in the stream without consuming the byte
 102		* found there.
 103		*
 104		* @return the next byte in the stream, as an integer.
 105		*
 106		* @exception Erlang.DecodeException if the next byte cannot be
 107		* read.
 108		**/
 109		public virtual int peek()
 110		{
 111			int i;
 112			try
 113			{
 114				i = base.ReadByte();
 115				base.Seek(-1, System.IO.SeekOrigin.Current);
 116				if (i < 0)
 117					i += 256;
 118				
 119				return i;
 120			}
 121			catch (System.Exception)
 122			{
 123				throw new Erlang.Exception("Cannot read from input stream");
 124			}
 125		}
 126		
 127		/*
 128		* Read a one byte integer from the stream.
 129		*
 130		* @return the byte read, as an integer.
 131		* 
 132		* @exception Erlang.DecodeException if the next byte cannot be
 133		* read.
 134		**/
 135		public virtual int read1()
 136		{
 137			int i;
 138			i = base.ReadByte();
 139			
 140			if (i < 0)
 141			{
 142				throw new Erlang.Exception("Cannot read from input stream");
 143			}
 144			
 145			return i;
 146		}
 147		
 148		/*
 149		* Read a two byte big endian integer from the stream.
 150		*
 151		* @return the bytes read, converted from big endian to an integer.
 152		* 
 153		* @exception Erlang.DecodeException if the next byte cannot be
 154		* read.
 155		**/
 156		public virtual int read2BE()
 157		{
 158			byte[] b = new byte[2];
 159			try
 160			{
 161				base.Read(b, 0, b.Length);
 162			}
 163			catch (System.IO.IOException)
 164			{
 165				throw new Erlang.Exception("Cannot read from input stream");
 166			}
 167			return ((((int) b[0] << 8) & 0xff00) + (((int) b[1]) & 0xff));
 168		}
 169		
 170		/*
 171		* Read a four byte big endian integer from the stream.
 172		*
 173		* @return the bytes read, converted from big endian to an integer.
 174		* 
 175		* @exception Erlang.DecodeException if the next byte cannot be
 176		* read.
 177		**/
 178		public virtual int read4BE()
 179		{
 180			byte[] b = new byte[4];
 181			try
 182			{
 183				base.Read(b, 0, b.Length);
 184			}
 185			catch (System.IO.IOException)
 186			{
 187				throw new Erlang.Exception("Cannot read from input stream");
 188			}
 189			return (int)((((int) b[0] << 24) & 0xff000000) + (((int) b[1] << 16) & 0xff0000) + (((int) b[2] << 8) & 0xff00) + (((int) b[3]) & 0xff));
 190		}
 191
 192        /*
 193        * Read an eight byte big endian integer from the stream.
 194        *
 195        * @return the bytes read, converted from big endian to an integer.
 196        * 
 197        * @exception Erlang.DecodeException if the next byte cannot be
 198        * read.
 199        **/
 200        public System.UInt64 read8BE()
 201        {
 202            byte[] b = new byte[8];
 203            try
 204            {
 205                base.Read(b, 0, b.Length);
 206            }
 207            catch (System.IO.IOException)
 208            {
 209                throw new Erlang.Exception("Cannot read from input stream");
 210            }
 211            System.UInt64 i1 = (System.UInt64)((((int)b[0] << 24) & 0xff000000) + (((int)b[1] << 16) & 0xff0000) + (((int)b[2] << 8) & 0xff00) + (((int)b[3]) & 0xff));
 212            System.UInt64 i2 = (i1 << 32) & 0xffffffff00000000
 213                             + (System.UInt64)((((int)b[4] << 24) & 0xff000000) + (((int)b[5] << 16) & 0xff0000) + (((int)b[6] << 8) & 0xff00) + (((int)b[7]) & 0xff));
 214            return i2;
 215        }
 216
 217        /*
 218        * Read a two byte little endian integer from the stream.
 219        *
 220        * @return the bytes read, converted from little endian to an
 221        * integer.
 222        * 
 223        * @exception Erlang.DecodeException if the next byte cannot be
 224        * read.
 225        **/
 226		public virtual int read2LE()
 227		{
 228			byte[] b = new byte[2];
 229			try
 230			{
 231				base.Read(b, 0, b.Length);
 232			}
 233			catch (System.IO.IOException)
 234			{
 235				throw new Erlang.Exception("Cannot read from input stream");
 236			}
 237			return ((((int) b[1] << 8) & 0xff00) + (((int) b[0]) & 0xff));
 238		}
 239		
 240		/*
 241		* Read a four byte little endian integer from the stream.
 242		*
 243		* @return the bytes read, converted from little endian to an
 244		* integer.
 245		* 
 246		* @exception Erlang.DecodeException if the next byte cannot be
 247		* read.
 248		**/
 249		public virtual int read4LE()
 250		{
 251			byte[] b = new byte[4];
 252			try
 253			{
 254				base.Read(b, 0, b.Length);
 255			}
 256			catch (System.IO.IOException)
 257			{
 258				throw new Erlang.Exception("Cannot read from input stream");
 259			}
 260			return (int)((((int) b[3] << 24) & 0xff000000) + (((int) b[2] << 16) & 0xff0000) + (((int) b[1] << 8) & 0xff00) + (((int) b[0]) & 0xff));
 261		}
 262		
 263		/*
 264		* Read an Erlang atom from the stream and interpret the value as a
 265		* boolean.
 266		*
 267		* @return true if the atom at the current position in the stream
 268		* contains the value 'true' (ignoring case), false otherwise.
 269		* 
 270		* @exception Erlang.DecodeException if the next term in the
 271		* stream is not an atom.
 272		**/
 273		public virtual bool read_boolean()
 274		{
 275			return System.Boolean.Parse(this.read_atom());
 276		}
 277		
 278		/*
 279		* Read an Erlang atom from the stream.
 280		*
 281		* @return a String containing the value of the atom.
 282		* 
 283		* @exception Erlang.DecodeException if the next term in the
 284		* stream is not an atom.
 285		**/
 286		public virtual string read_atom()
 287		{
 288			int tag;
 289			int len;
 290			byte[] strbuf;
 291			
 292			tag = this.read1();
 293			if (tag == OtpExternal.versionTag)
 294			{
 295				tag = this.read1();
 296			}
 297			
 298			if (tag != OtpExternal.atomTag)
 299			{
 300				throw new Erlang.Exception("wrong tag encountered, expected " + OtpExternal.atomTag + ", got " + tag);
 301			}
 302			
 303			len = this.read2BE();
 304			
 305			strbuf = new byte[len];
 306			this.readN(strbuf);
 307            int n = strbuf.Length > OtpExternal.maxAtomLength ? OtpExternal.maxAtomLength : strbuf.Length;
 308            return System.Text.Encoding.ASCII.GetString(strbuf, 0, n);
 309		}
 310		
 311		/*
 312		* Read an Erlang binary from the stream.
 313		*
 314		* @return a byte array containing the value of the binary.
 315		* 
 316		* @exception Erlang.DecodeException if the next term in the
 317		* stream is not a binary.
 318		**/
 319		public virtual byte[] read_binary()
 320		{
 321			int tag;
 322			int len;
 323			byte[] bin;
 324			
 325			tag = this.read1();
 326			if (tag == OtpExternal.versionTag)
 327			{
 328				tag = this.read1();
 329			}
 330			
 331			if (tag != OtpExternal.binTag)
 332			{
 333				throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.binTag + ", got " + tag);
 334			}
 335			
 336			len = this.read4BE();
 337			
 338			bin = new byte[len];
 339			this.readN(bin);
 340			
 341			return bin;
 342		}
 343		
 344		/*
 345		* Read an Erlang float from the stream.
 346		*
 347		* @return the float value.
 348		* 
 349		* @exception Erlang.DecodeException if the next term in the
 350		* stream is not a float.
 351		**/
 352        public virtual float read_float()
 353        {
 354            double d = this.read_double();
 355            float f = (float)d;
 356            if (System.Math.Abs(d - f) >= 1.0E-20)
 357                throw new Erlang.Exception("Value cannot be represented as float: " + d);
 358            return f;
 359        }
 360
 361        /*
 362        * Read an Erlang float from the stream.
 363        *
 364        * @return the float value, as a double.
 365        * 
 366        * @exception Erlang.DecodeException if the next term in the
 367        * stream is not a float.
 368        *
 369        **/
 370        public virtual double read_double()
 371		{
 372			return getFloatOrDouble();
 373		}
 374
 375        private double getFloatOrDouble()
 376        {
 377
 378            // parse the stream
 379            int tag = this.read1();
 380            if (tag == OtpExternal.versionTag)
 381            {
 382                tag = this.read1();
 383            }
 384
 385            byte[] strbuf;
 386            double parsedValue = 0.0;
 387
 388            if (tag == OtpExternal.floatTag)
 389            {
 390                // get the string
 391                strbuf = new byte[31];
 392                this.readN(strbuf);
 393
 394                char[] tmpChar = new char[strbuf.Length];
 395                strbuf.CopyTo(tmpChar, 0);
 396                System.String str = new System.String(tmpChar);
 397                //System.Diagnostics.Debug.WriteLine("getFloatOrDouble: str = " + str);
 398
 399                try
 400                {
 401                    // Easier than the java version.
 402                    parsedValue = System.Double.Parse(str);
 403                    return parsedValue;
 404                }
 405                catch
 406                {
 407                    throw new Erlang.Exception("Error parsing float format: '" + str + "'");
 408                }
 409            }
 410            else if (tag == OtpExternal.newFloatTag)
 411            {
 412                byte[] data = new byte[8];
 413                this.readN(data);
 414                // IEEE 754 decoder
 415                if (BitConverter.IsLittleEndian)
 416                {
 417                    Array.Reverse(data);
 418                }
 419                return BitConverter.ToDouble(data, 0);
 420            }
 421            else
 422            {
 423                throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.floatTag + ", got " + tag);
 424            }
 425        }
 426		
 427		/*
 428		* Read one byte from the stream.
 429		*
 430		* @return the byte read.
 431		* 
 432		* @exception Erlang.DecodeException if the next byte cannot be
 433		* read.
 434		**/
 435		public virtual byte read_byte()
 436		{
 437			long l = this.read_long();
 438			byte i = (byte) l;
 439			
 440			if (l != i)
 441			{
 442				throw new Erlang.Exception("Value too large for byte: " + l);
 443			}
 444			
 445			return i;
 446		}
 447		
 448		/*
 449		* Read a character from the stream.
 450		*
 451		* @return the character value.
 452		* 
 453		* @exception Erlang.DecodeException if the next term in the
 454		* stream is not an integer that can be represented as a char.
 455		**/
 456		public virtual char read_char()
 457		{
 458			long l = this.read_long();
 459			char i = (char) l;
 460			
 461			if (l != i)
 462			{
 463				throw new Erlang.Exception("Value too large for byte: " + l);
 464			}
 465			
 466			return i;
 467		}
 468		
 469		/*
 470		* Read an unsigned integer from the stream.
 471		*
 472		* @return the integer value.
 473		* 
 474		* @exception Erlang.DecodeException if the next term in the
 475		* stream can not be represented as a positive integer.
 476		**/
 477		public virtual int read_uint()
 478		{
 479			long l = this.read_long();
 480			int i = (int) l;
 481			
 482			if (l != i)
 483			{
 484				throw new Erlang.Exception("Value too large for integer: " + l);
 485			}
 486			else if (l < 0)
 487			{
 488				throw new Erlang.Exception("Value not unsigned: " + l);
 489			}
 490			
 491			return i;
 492		}
 493		
 494		/*
 495		* Read an integer from the stream.
 496		*
 497		* @return the integer value.
 498		* 
 499		* @exception Erlang.DecodeException if the next term in the
 500		* stream can not be represented as an integer.
 501		**/
 502		public virtual int read_int()
 503		{
 504			long l = this.read_long();
 505			int i = (int) l;
 506			
 507			if (l != i)
 508			{
 509				throw new Erlang.Exception("Value too large for byte: " + l);
 510			}
 511			
 512			return i;
 513		}
 514		
 515		/*
 516		* Read an unsigned short from the stream.
 517		*
 518		* @return the short value.
 519		* 
 520		* @exception Erlang.DecodeException if the next term in the
 521		* stream can not be represented as a positive short.
 522		**/
 523		public virtual short read_ushort()
 524		{
 525			long l = this.read_long();
 526			short i = (short) l;
 527			
 528			if (l != i)
 529			{
 530				throw new Erlang.Exception("Value too large for byte: " + l);
 531			}
 532			else if (l < 0)
 533			{
 534				throw new Erlang.Exception("Value not unsigned: " + l);
 535			}
 536			
 537			return i;
 538		}
 539		
 540		/*
 541		* Read a short from the stream.
 542		*
 543		* @return the short value.
 544		* 
 545		* @exception Erlang.DecodeException if the next term in the
 546		* stream can not be represented as a short.
 547		**/
 548		public virtual short read_short()
 549		{
 550			long l = this.read_long();
 551			short i = (short) l;
 552			
 553			if (l != i)
 554			{
 555				throw new Erlang.Exception("Value too large for byte: " + l);
 556			}
 557			
 558			return i;
 559		}
 560		
 561		/*
 562		* Read an unsigned long from the stream.
 563		*
 564		* @return the long value.
 565		* 
 566		* @exception Erlang.DecodeException if the next term in the
 567		* stream can not be represented as a positive long.
 568		**/
 569		public virtual long read_ulong()
 570		{
 571			long l = this.read_long();
 572			
 573			if (l < 0)
 574			{
 575				throw new Erlang.Exception("Value not unsigned: " + l);
 576			}
 577			
 578			return l;
 579		}
 580		
 581		/*
 582		* Read a long from the stream.
 583		*
 584		* @return the long value.
 585		* 
 586		* @exception Erlang.DecodeException if the next term in the
 587		* stream can not be represented as a long.
 588		**/
 589		public virtual long read_long()
 590		{
 591			int tag;
 592			int sign;
 593			int arity;
 594			long val;
 595			
 596			tag = this.read1();
 597			if (tag == OtpExternal.versionTag)
 598			{
 599				tag = this.read1();
 600			}
 601			
 602			switch (tag)
 603			{
 604				case OtpExternal.smallIntTag: 
 605					val = this.read1();
 606					break;
 607					
 608				
 609				
 610				case OtpExternal.intTag: 
 611					val = this.read4BE();
 612					break;
 613					
 614				
 615				
 616				case OtpExternal.smallBigTag: {
 617					arity = this.read1();
 618                    sign  = this.read1();
 619
 620                    byte[] nb = new byte[arity];
 621                    if (arity != this.readN(nb))
 622                    {
 623                        throw new Erlang.Exception("Cannot read from input stream. Expected smallBigTag arity " + arity);
 624                    }
 625                    if (arity > 8)
 626                        throw new Erlang.Exception("Value too large for long type (arity=" + arity + ")");
 627
 628                    val = 0;
 629                    for (int i = 0; i < arity; i++)
 630                    {
 631                         val |= (long)nb[i] << (i * 8);
 632                    }
 633
 634					val = (sign == 0 ? val : -val); // should deal with overflow
 635					
 636					break;
 637				}
 638				
 639				
 640				case OtpExternal.largeBigTag: default: 
 641					throw new Erlang.Exception("Not valid integer tag: " + tag);
 642				
 643			}
 644			
 645			return val;
 646		}
 647		
 648		/*
 649		* Read a list header from the stream.
 650		*
 651		* @return the arity of the list.
 652		* 
 653		* @exception Erlang.DecodeException if the next term in the
 654		* stream is not a list.
 655		**/
 656		public virtual int read_list_head()
 657		{
 658			int arity = 0;
 659			int tag = this.read1();
 660			
 661			if (tag == OtpExternal.versionTag)
 662			{
 663				tag = this.read1();
 664			}
 665			
 666			switch (tag)
 667			{
 668				case OtpExternal.nilTag: 
 669					arity = 0;
 670					break;
 671					
 672				
 673				
 674				case OtpExternal.stringTag: 
 675					arity = this.read2BE();
 676					break;
 677					
 678				
 679				
 680				case OtpExternal.listTag: 
 681					arity = this.read4BE();
 682					break;
 683					
 684				
 685				
 686				default: 
 687					throw new Erlang.Exception("Not valid list tag: " + tag);
 688				
 689			}
 690			
 691			return arity;
 692		}
 693		
 694		/*
 695		* Read a tuple header from the stream.
 696		*
 697		* @return the arity of the tuple.
 698		* 
 699		* @exception Erlang.DecodeException if the next term in the
 700		* stream is not a tuple.
 701		**/
 702		public virtual int read_tuple_head()
 703		{
 704			int arity = 0;
 705			int tag = this.read1();
 706			
 707			if (tag == OtpExternal.versionTag)
 708			{
 709				tag = this.read1();
 710			}
 711			
 712			// decode the tuple header and get arity
 713			switch (tag)
 714			{
 715				case OtpExternal.smallTupleTag: 
 716					arity = this.read1();
 717					break;
 718					
 719				
 720				
 721				case OtpExternal.largeTupleTag: 
 722					arity = this.read4BE();
 723					break;
 724					
 725				
 726				
 727				default: 
 728					throw new Erlang.Exception("Not valid tuple tag: " + tag);
 729				
 730			}
 731			
 732			return arity;
 733		}
 734		
 735		/*
 736		* Read an empty list from the stream.
 737		*
 738		* @return zero (the arity of the list).
 739		* 
 740		* @exception Erlang.DecodeException if the next term in the
 741		* stream is not an empty list.
 742		**/
 743		public virtual int read_nil()
 744		{
 745			int arity = 0;
 746			int tag = this.read1();
 747			
 748			if (tag == OtpExternal.versionTag)
 749			{
 750				tag = this.read1();
 751			}
 752			
 753			switch (tag)
 754			{
 755				case OtpExternal.nilTag: 
 756					arity = 0;
 757					break;
 758					
 759				
 760				
 761				default: 
 762					throw new Erlang.Exception("Not valid nil tag: " + tag);
 763				
 764			}
 765			
 766			return arity;
 767		}
 768		
 769		/*
 770		* Read an Erlang PID from the stream.
 771		*
 772		* @return the value of the PID.
 773		* 
 774		* @exception Erlang.DecodeException if the next term in the
 775		* stream is not an Erlang PID.
 776		**/
 777		public virtual Erlang.Pid read_pid()
 778		{
 779			System.String node;
 780			int id;
 781			int serial;
 782			int creation;
 783			int tag;
 784			
 785			tag = this.read1();
 786			if (tag == OtpExternal.versionTag)
 787			{
 788				tag = this.read1();
 789			}
 790			
 791			if (tag != OtpExternal.pidTag)
 792			{
 793				throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.pidTag + ", got " + tag);
 794			}
 795			
 796			node = this.read_atom();
 797			id = this.read4BE() & 0x7fff; // 15 bits
 798			serial = this.read4BE() & 0x07; // 3 bits
 799			creation = this.read1() & 0x03; // 2 bits
 800			
 801			return new Erlang.Pid(node, id, serial, creation);
 802		}
 803		
 804		/*
 805		* Read an Erlang port from the stream.
 806		*
 807		* @return the value of the port.
 808		* 
 809		* @exception DecodeException if the next term in the
 810		* stream is not an Erlang port.
 811		**/
 812		public virtual Erlang.Port read_port()
 813		{
 814			System.String node;
 815			int id;
 816			int creation;
 817			int tag;
 818			
 819			tag = this.read1();
 820			if (tag == OtpExternal.versionTag)
 821			{
 822				tag = this.read1();
 823			}
 824			
 825			if (tag != OtpExternal.portTag)
 826			{
 827				throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.portTag + ", got " + tag);
 828			}
 829			
 830			node = this.read_atom();
 831			id = this.read4BE() & 0x3ffff; // 18 bits
 832			creation = this.read1() & 0x03; // 2 bits
 833			
 834			return new Erlang.Port(node, id, creation);
 835		}
 836		
 837		/*
 838		* Read an Erlang reference from the stream.
 839		*
 840		* @return the value of the reference
 841		* 
 842		* @exception DecodeException if the next term in the
 843		* stream is not an Erlang reference.
 844		**/
 845		public virtual Erlang.Ref read_ref()
 846		{
 847			System.String node;
 848			int id;
 849			int creation;
 850			int tag;
 851			
 852			tag = this.read1();
 853			if (tag == OtpExternal.versionTag)
 854			{
 855				tag = this.read1();
 856			}
 857			
 858			switch (tag)
 859			{
 860				case OtpExternal.refTag: 
 861					node = this.read_atom();
 862					id = this.read4BE() & 0x3ffff; // 18 bits
 863					creation = this.read1() & 0x03; // 2 bits
 864					return new Erlang.Ref(node, id, creation);
 865					
 866				
 867				
 868				case OtpExternal.newRefTag: 
 869					int arity = this.read2BE();
 870					node = this.read_atom();
 871					creation = this.read1() & 0x03; // 2 bits
 872					
 873					int[] ids = new int[arity];
 874					 for (int i = 0; i < arity; i++)
 875					{
 876						ids[i] = this.read4BE();
 877					}
 878					ids[0] &= 0x3ffff; // first id gets truncated to 18 bits
 879					return new Erlang.Ref(node, ids, creation);
 880					
 881				
 882				
 883				default: 
 884					throw new Erlang.Exception("Wrong tag encountered, expected ref, got " + tag);
 885				
 886			}
 887		}
 888		
 889		/*
 890		* Read a string from the stream.
 891		*
 892		* @return the value of the string.
 893		* 
 894		* @exception DecodeException if the next term in the
 895		* stream is not a string.
 896		**/
 897		public virtual System.String read_string()
 898		{
 899			int tag;
 900			int len;
 901			byte[] strbuf;
 902			char[] charbuf;
 903			
 904			tag = this.read1();
 905			if (tag == OtpExternal.versionTag)
 906			{
 907				tag = this.read1();
 908			}
 909			
 910			switch (tag)
 911			{
 912				
 913				case OtpExternal.stringTag: 
 914					char[] tmpChar;
 915					len = this.read2BE();
 916					strbuf = new byte[len];
 917					this.readN(strbuf);
 918					tmpChar = new char[strbuf.Length];
 919					strbuf.CopyTo(tmpChar, 0);
 920					return new System.String(tmpChar);
 921
 922				case OtpExternal.nilTag:
 923					return "";
 924
 925				case OtpExternal.listTag:
 926					// List when unicode +
 927					len = this.read4BE();
 928					charbuf = new char[len];
 929
 930					 for (int i = 0; i < len; i++)
 931						charbuf[i] = this.read_char();
 932
 933					this.read_nil();
 934					return new System.String(charbuf);
 935
 936				default:
 937					throw new Erlang.Exception("Wrong tag encountered, expected " + OtpExternal.stringTag + " or " + OtpExternal.listTag + ", got " + tag);
 938				
 939			}
 940		}
 941
 942		/*
 943		* Read an arbitrary Erlang term from the stream.
 944		*
 945		* @return the Erlang term.
 946		*
 947		* @exception DecodeException if the stream does not
 948		* contain a known Erlang type at the next position.
 949		**/
 950		public virtual Erlang.Object read_any()
 951		{
 952			// calls one of the above functions, depending on o
 953			int tag = this.peek();
 954			if (tag == OtpExternal.versionTag)
 955			{
 956				this.read1();
 957				tag = this.peek();
 958			}
 959
 960            //System.Diagnostics.Debug.WriteLine("read_any: tag = " + tag);
 961
 962			switch (tag)
 963			{
 964				case OtpExternal.smallIntTag: case OtpExternal.intTag: case OtpExternal.smallBigTag:
 965					return new Erlang.Long(this);
 966
 967				case OtpExternal.atomTag:
 968                    string s = read_atom();
 969                    if (s == "true")
 970                        return new Erlang.Boolean(true);
 971                    else if (s == "false")
 972                        return new Erlang.Boolean(false);
 973                    else
 974					    return new Erlang.Atom(s);
 975
 976				case OtpExternal.floatTag:
 977                case OtpExternal.newFloatTag:
 978                    return new Erlang.Double(this);
 979
 980				case OtpExternal.refTag: case OtpExternal.newRefTag:
 981					return new Erlang.Ref(this);
 982
 983				case OtpExternal.portTag:
 984					return new Erlang.Port(this);
 985
 986				case OtpExternal.pidTag:
 987					return new Erlang.Pid(this);
 988
 989				case OtpExternal.stringTag:
 990					return new Erlang.String(this);
 991
 992				case OtpExternal.listTag: case OtpExternal.nilTag:
 993					return new Erlang.List(this);
 994
 995				case OtpExternal.smallTupleTag: case OtpExternal.largeTupleTag:
 996					return new Erlang.Tuple(this);
 997
 998				case OtpExternal.binTag:
 999					return new Erlang.Binary(this);
1000
1001				case OtpExternal.largeBigTag: default:
1002					throw new Erlang.Exception("Uknown data type: " + tag);
1003				
1004			}
1005		}
1006	}
1007}