context: // **********************************************************************
  //
  // Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
  //
  // This copy of Ice is licensed to you under the terms described in the
  // ICE_LICENSE file included in this distribution.
  //
  // **********************************************************************
  
  namespace IceInternal
  {
  
      using System;
      using System.Collections;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.Reflection;
  #if !COMPACT && !SILVERLIGHT
      using System.Runtime.InteropServices;
      using System.Runtime.Serialization;
      using System.Runtime.Serialization.Formatters.Binary;
  #endif
      using System.Threading;
  
  #if !MANAGED && !COMPACT && !SILVERLIGHT
      internal static class NativeMethods
      {
          [DllImport("bzip2.dll")]
          internal static extern IntPtr BZ2_bzlibVersion();
  
          [DllImport("bzip2.dll")]
          internal static extern int BZ2_bzBuffToBuffCompress(byte[] dest,
                                                              ref int destLen,
                                                              byte[] source,
                                                              int sourceLen,
                                                              int blockSize100k,
                                                              int verbosity,
                                                              int workFactor);
  
          [DllImport("bzip2.dll")]
          internal static extern int BZ2_bzBuffToBuffDecompress(byte[] dest,
                                                                ref int destLen,
                                                                byte[] source,
                                                                int sourceLen,
                                                                int small,
                                                                int verbosity);
      }
  #endif
  
      public class BasicStream
      {
  
          static BasicStream()
          {
  #if MANAGED || COMPACT || SILVERLIGHT
              //
              // Protocol compression is not supported when using managed code.
              //
              _bzlibInstalled = false;
  #else
              //
              // Simple trick to find out whether bzip2 is
              // installed: Call the BZ2_bzlibVersion() function in the
              // library. If we get an exception, the library is
              // not available.
              //
              _bzlibInstalled = false;
  
              //
              // We are setting the library name here because, under Mono, we don't know the exact library name.
              // In addition, the FileName member of the BadImageFormatException is the empty string, even though
              // it should provide the name of the library.
              //
              string lib = AssemblyUtil.runtime_ == AssemblyUtil.Runtime.Mono ? "bzip2 library" : "bzip2.dll";
              try
              {
                  NativeMethods.BZ2_bzlibVersion();
                  _bzlibInstalled = true;
              }
              catch(DllNotFoundException)
              {
                  // Expected -- bzip2.dll not installed or not in PATH.
              }
              catch(EntryPointNotFoundException)
              {
                  Console.Error.WriteLine("warning: found " + lib + " but entry point BZ2_bzlibVersion is missing.");
              }
              catch(BadImageFormatException ex)
              {
                  if(ex.FileName != null && ex.FileName.Length != 0)
                  {
                      lib = ex.FileName; // Future-proof: we'll do the right thing if the FileName member is non-empty.
                  }
                  Console.Error.Write("warning: " + lib + " could not be loaded (likely due to 32/64-bit mismatch).");
                  if(IntPtr.Size == 8)
                  {
                      Console.Error.Write(" Make sure the directory containing the 64-bit " + lib + " is in your PATH.");
                  }
                  Console.Error.WriteLine();
              }
  #endif
          }
  
          public BasicStream(Instance instance, Ice.EncodingVersion encoding)
          {
              initialize(instance, encoding);
              _buf = new Buffer();
          }
  
          public BasicStream(Instance instance, Ice.EncodingVersion encoding, byte[] data)
          {
              initialize(instance, encoding);
              _buf = new Buffer(data);
          }
  
          private void initialize(Instance instance, Ice.EncodingVersion encoding)
          {
              instance_ = instance;
              _closure = null;
              _encoding = encoding;
  
              _readEncapsStack = null;
              _writeEncapsStack = null;
              _readEncapsCache = null;
              _writeEncapsCache = null;
  
              _sliceObjects = true;
  
              _startSeq = -1;
          }
  
          //
          // This function allows this object to be reused, rather than
          // reallocated.
          //
          public void reset()
          {
              _buf.reset();
              clear();
          }
  
          public void clear()
          {
              if(_readEncapsStack != null)
              {
                  Debug.Assert(_readEncapsStack.next == null);
                  _readEncapsStack.next = _readEncapsCache;
                  _readEncapsCache = _readEncapsStack;
                  _readEncapsStack = null;
                  _readEncapsCache.reset();
              }
  
              if(_writeEncapsStack != null)
              {
                  Debug.Assert(_writeEncapsStack.next == null);
                  _writeEncapsStack.next = _writeEncapsCache;
                  _writeEncapsCache = _writeEncapsStack;
                  _writeEncapsStack = null;
                  _writeEncapsCache.reset();
              }
  
              _startSeq = -1;
  
              _sliceObjects = true;
          }
  
          public Instance instance()
          {
              return instance_;
          }
  
          public object closure()
          {
              return _closure;
          }
  
          public object closure(object p)
          {
              object prev = _closure;
              _closure = p;
              return prev;
          }
  
          public void swap(BasicStream other)
          {
              Debug.Assert(instance_ == other.instance_);
  
              Buffer tmpBuf = other._buf;
              other._buf = _buf;
              _buf = tmpBuf;
  
              object tmpClosure = other._closure;
              other._closure = _closure;
              _closure = tmpClosure;
  
              //
              // Swap is never called for BasicStreams that have encapsulations being read/write. However,
              // encapsulations might still be set in case marshalling or un-marshalling failed. We just
              // reset the encapsulations if there are still some set.
              //
              resetEncaps();
              other.resetEncaps();
  
              int tmpStartSeq = other._startSeq;
              other._startSeq = _startSeq;
              _startSeq = tmpStartSeq;
  
              int tmpMinSeqSize = other._minSeqSize;
              other._minSeqSize = _minSeqSize;
              _minSeqSize = tmpMinSeqSize;
          }
  
          public void resetEncaps()
          {
              _readEncapsStack = null;
              _writeEncapsStack = null;
          }
  
          public void resize(int sz, bool reading)
          {
              _buf.resize(sz, reading);
              _buf.b.position(sz);
          }
  
          public Buffer prepareWrite()
          {
              _buf.b.limit(_buf.size());
              _buf.b.position(0);
              return _buf;
          }
  
          public Buffer getBuffer()
          {
              return _buf;
          }
  
          public void startWriteObject(Ice.SlicedData data)
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.startInstance(SliceType.ObjectSlice, data);
          }
  
          public void endWriteObject()
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.endInstance();
          }
  
          public void startReadObject()
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              _readEncapsStack.decoder.startInstance(SliceType.ObjectSlice);
          }
  
          public Ice.SlicedData endReadObject(bool preserve)
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              return _readEncapsStack.decoder.endInstance(preserve);
          }
  
          public void startWriteException(Ice.SlicedData data)
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.startInstance(SliceType.ExceptionSlice, data);
          }
  
          public void endWriteException()
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.endInstance();
          }
  
          public void startReadException()
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              _readEncapsStack.decoder.startInstance(SliceType.ExceptionSlice);
          }
  
          public Ice.SlicedData endReadException(bool preserve)
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              return _readEncapsStack.decoder.endInstance(preserve);
          }
  
          public void startWriteEncaps()
          {
              //
              // If no encoding version is specified, use the current write
              // encapsulation encoding version if there's a current write
              // encapsulation, otherwise, use the stream encoding version.
              //
  
              if(_writeEncapsStack != null)
              {
                  startWriteEncaps(_writeEncapsStack.encoding, _writeEncapsStack.format);
              }
              else
              {
                  startWriteEncaps(_encoding, Ice.FormatType.DefaultFormat);
              }
          }
  
          public void startWriteEncaps(Ice.EncodingVersion encoding, Ice.FormatType format)
          {
              Protocol.checkSupportedEncoding(encoding);
  
              WriteEncaps curr = _writeEncapsCache;
              if(curr != null)
              {
                  curr.reset();
                  _writeEncapsCache = _writeEncapsCache.next;
              }
              else
              {
                  curr = new WriteEncaps();
              }
              curr.next = _writeEncapsStack;
              _writeEncapsStack = curr;
  
              _writeEncapsStack.format = format;
              _writeEncapsStack.setEncoding(encoding);
              _writeEncapsStack.start = _buf.b.position();
  
              writeInt(0); // Placeholder for the encapsulation length.
              _writeEncapsStack.encoding.write__(this);
          }
  
          public void endWriteEncaps()
          {
              Debug.Assert(_writeEncapsStack != null);
  
              // Size includes size and version.
              int start = _writeEncapsStack.start;
              int sz = _buf.size() - start;
              _buf.b.putInt(start, sz);
  
              WriteEncaps curr = _writeEncapsStack;
              _writeEncapsStack = curr.next;
              curr.next = _writeEncapsCache;
              _writeEncapsCache = curr;
              _writeEncapsCache.reset();
          }
  
          public void endWriteEncapsChecked()
          {
              if(_writeEncapsStack == null)
              {
                  throw new Ice.EncapsulationException("not in an encapsulation");
              }
              endWriteEncaps();
          }
  
          public void writeEmptyEncaps(Ice.EncodingVersion encoding)
          {
              Protocol.checkSupportedEncoding(encoding);
              writeInt(6); // Size
              encoding.write__(this);
          }
  
          public void writeEncaps(byte[] v)
          {
              if(v.Length < 6)
              {
                  throw new Ice.EncapsulationException();
              }
              expand(v.Length);
              _buf.b.put(v);
          }
  
          public Ice.EncodingVersion getWriteEncoding()
          {
              return _writeEncapsStack != null ? _writeEncapsStack.encoding : _encoding;
          }
  
          public Ice.EncodingVersion startReadEncaps()
          {
              ReadEncaps curr = _readEncapsCache;
              if(curr != null)
              {
                  curr.reset();
                  _readEncapsCache = _readEncapsCache.next;
              }
              else
              {
                  curr = new ReadEncaps();
              }
              curr.next = _readEncapsStack;
              _readEncapsStack = curr;
  
              _readEncapsStack.start = _buf.b.position();
  
              //
              // I don't use readSize() and writeSize() for encapsulations,
              // because when creating an encapsulation, I must know in advance
              // how many bytes the size information will require in the data
              // stream. If I use an Int, it is always 4 bytes. For
              // readSize()/writeSize(), it could be 1 or 5 bytes.
              //
              int sz = readInt();
              if(sz < 6)
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
              if(sz - 4 > _buf.b.remaining())
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
              _readEncapsStack.sz = sz;
  
              Ice.EncodingVersion encoding = new Ice.EncodingVersion();
              encoding.read__(this);
              Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
              _readEncapsStack.setEncoding(encoding);
  
              return encoding;
          }
  
          public void endReadEncaps()
          {
              Debug.Assert(_readEncapsStack != null);
  
              if(!_readEncapsStack.encoding_1_0)
              {
                  skipOpts();
                  if(_buf.b.position() != _readEncapsStack.start + _readEncapsStack.sz)
                  {
                      throw new Ice.EncapsulationException();
                  }
              }
              else if(_buf.b.position() != _readEncapsStack.start + _readEncapsStack.sz)
              {
                  if(_buf.b.position() + 1 != _readEncapsStack.start + _readEncapsStack.sz)
                  {
                      throw new Ice.EncapsulationException();
                  }
  
                  //
                  // Ice version < 3.3 had a bug where user exceptions with
                  // class members could be encoded with a trailing byte
                  // when dispatched with AMD. So we tolerate an extra byte
                  // in the encapsulation.
                  //
                  try
                  {
                      _buf.b.get();
                  }
                  catch(InvalidOperationException ex)
                  {
                      throw new Ice.UnmarshalOutOfBoundsException(ex);
                  }
              }
  
              ReadEncaps curr = _readEncapsStack;
              _readEncapsStack = curr.next;
              curr.next = _readEncapsCache;
              _readEncapsCache = curr;
              _readEncapsCache.reset();
          }
  
          public Ice.EncodingVersion skipEmptyEncaps()
          {
              int sz = readInt();
              if(sz != 6)
              {
                  throw new Ice.EncapsulationException();
              }
  
              Ice.EncodingVersion encoding = new Ice.EncodingVersion();
              encoding.read__(this);
              return encoding;
          }
  
          public void endReadEncapsChecked() // Used by public stream API.
          {
              if(_readEncapsStack == null)
              {
                  throw new Ice.EncapsulationException("not in an encapsulation");
              }
              endReadEncaps();
          }
  
          public byte[] readEncaps(out Ice.EncodingVersion encoding)
          {
              int sz = readInt();
              if(sz < 6)
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
  
              if(sz - 4 > _buf.b.remaining())
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
  
              encoding = new Ice.EncodingVersion();
              encoding.read__(this);
              _buf.b.position(_buf.b.position() - 6);
  
              byte[] v = new byte[sz];
              try
              {
                  _buf.b.get(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.EncodingVersion getReadEncoding()
          {
              return _readEncapsStack != null ? _readEncapsStack.encoding : _encoding;
          }
  
          public int getReadEncapsSize()
          {
              Debug.Assert(_readEncapsStack != null);
              return _readEncapsStack.sz - 6;
          }
  
          public Ice.EncodingVersion skipEncaps()
          {
              int sz = readInt();
              if(sz < 6)
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
              Ice.EncodingVersion encoding = new Ice.EncodingVersion();
              encoding.read__(this);
              try
              {
                  _buf.b.position(_buf.b.position() + sz - 6);
              }
              catch(ArgumentOutOfRangeException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
              return encoding;
          }
  
          public void startWriteSlice(string typeId, int compactId, bool last)
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.startSlice(typeId, compactId, last);
          }
  
          public void endWriteSlice()
          {
              Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
              _writeEncapsStack.encoder.endSlice();
          }
  
          public string startReadSlice() // Returns type ID of next slice
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              return _readEncapsStack.decoder.startSlice();
          }
  
          public void endReadSlice()
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              _readEncapsStack.decoder.endSlice();
          }
  
          public void skipSlice()
          {
              Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
              _readEncapsStack.decoder.skipSlice();
          }
  
          public void readPendingObjects()
          {
              if(_readEncapsStack != null && _readEncapsStack.decoder != null)
              {
                  _readEncapsStack.decoder.readPendingObjects();
              }
              else if(_readEncapsStack != null ? _readEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0))
              {
                  //
                  // If using the 1.0 encoding and no objects were read, we
                  // still read an empty sequence of pending objects if
                  // requested (i.e.: if this is called).
                  //
                  // This is required by the 1.0 encoding, even if no objects
                  // are written we do marshal an empty sequence if marshaled
                  // data types use classes.
                  //
                  skipSize();
              }
          }
  
          public void writePendingObjects()
          {
              if(_writeEncapsStack != null && _writeEncapsStack.encoder != null)
              {
                  _writeEncapsStack.encoder.writePendingObjects();
              }
              else if(_writeEncapsStack != null ?
                      _writeEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0))
              {
                  //
                  // If using the 1.0 encoding and no objects were written, we
                  // still write an empty sequence for pending objects if
                  // requested (i.e.: if this is called).
                  //
                  // This is required by the 1.0 encoding, even if no objects
                  // are written we do marshal an empty sequence if marshaled
                  // data types use classes.
                  //
                  writeSize(0);
              }
          }
  
          public void writeSize(int v)
          {
              if(v > 254)
              {
                  expand(5);
                  _buf.b.put((byte)255);
                  _buf.b.putInt(v);
              }
              else
              {
                  expand(1);
                  _buf.b.put((byte)v);
              }
          }
  
          public int readSize()
          {
              try
              {
                  //
                  // COMPILERFIX: for some reasons _buf.get() doesn't work here on OS X with Mono;
                  //
                  //byte b = _buf.b.get();
                  byte b = readByte();
                  if(b == 255)
                  {
                      int v = _buf.b.getInt();
                      if(v < 0)
                      {
                          throw new Ice.UnmarshalOutOfBoundsException();
                      }
                      return v;
                  }
                  else
                  {
                      return b; // byte is unsigned
                  }
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public int readAndCheckSeqSize(int minSize)
          {
              int sz = readSize();
  
              if(sz == 0)
              {
                  return 0;
              }
  
              //
              // The _startSeq variable points to the start of the sequence for which
              // we expect to read at least _minSeqSize bytes from the stream.
              //
              // If not initialized or if we already read more data than _minSeqSize,
              // we reset _startSeq and _minSeqSize for this sequence (possibly a
              // top-level sequence or enclosed sequence it doesn't really matter).
              //
              // Otherwise, we are reading an enclosed sequence and we have to bump
              // _minSeqSize by the minimum size that this sequence will  require on
              // the stream.
              //
              // The goal of this check is to ensure that when we start un-marshalling
              // a new sequence, we check the minimal size of this new sequence against
              // the estimated remaining buffer size. This estimatation is based on
              // the minimum size of the enclosing sequences, it's _minSeqSize.
              //
              if(_startSeq == -1 || _buf.b.position() > (_startSeq + _minSeqSize))
              {
                  _startSeq = _buf.b.position();
                  _minSeqSize = sz * minSize;
              }
              else
              {
                  _minSeqSize += sz * minSize;
              }
  
              //
              // If there isn't enough data to read on the stream for the sequence (and
              // possibly enclosed sequences), something is wrong with the marshalled
              // data: it's claiming having more data that what is possible to read.
              //
              if(_startSeq + _minSeqSize > _buf.size())
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
  
              return sz;
          }
  
          public int startSize()
          {
              int pos = _buf.b.position();
              writeInt(0); // Placeholder for 32-bit size
              return pos;
          }
  
          public void endSize(int pos)
          {
              Debug.Assert(pos >= 0);
              rewriteInt(_buf.b.position() - pos - 4, pos);
          }
  
          public void writeBlob(byte[] v)
          {
              if(v == null)
              {
                  return;
              }
              expand(v.Length);
              _buf.b.put(v);
          }
  
          public void readBlob(byte[] v)
          {
              try
              {
                  _buf.b.get(v);
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public byte[] readBlob(int sz)
          {
              if(_buf.b.remaining() < sz)
              {
                  throw new Ice.UnmarshalOutOfBoundsException();
              }
              byte[] v = new byte[sz];
              try
              {
                  _buf.b.get(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          // Read/write type and tag for optionals
          public bool writeOpt(int tag, Ice.OptionalFormat format)
          {
              Debug.Assert(_writeEncapsStack != null);
              if(_writeEncapsStack.encoder != null)
              {
                  return _writeEncapsStack.encoder.writeOpt(tag, format);
              }
              else
              {
                  return writeOptImpl(tag, format);
              }
          }
  
          public bool readOpt(int tag, Ice.OptionalFormat expectedFormat)
          {
              Debug.Assert(_readEncapsStack != null);
              if(_readEncapsStack.decoder != null)
              {
                  return _readEncapsStack.decoder.readOpt(tag, expectedFormat);
              }
              else
              {
                  return readOptImpl(tag, expectedFormat);
              }
          }
  
          public void writeByte(byte v)
          {
              expand(1);
              _buf.b.put(v);
          }
  
          public void writeByte(int tag, Ice.Optional<byte> v)
          {
              if(v.HasValue)
              {
                  writeByte(tag, v.Value);
              }
          }
  
          public void writeByte(int tag, byte v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.F1))
              {
                  writeByte(v);
              }
          }
  
          public void rewriteByte(byte v, int dest)
          {
              _buf.b.put(dest, v);
          }
  
          public void writeByteSeq(byte[] v)
          {
              if(v == null)
              {
                  writeSize(0);
              }
              else
              {
                  writeSize(v.Length);
                  expand(v.Length);
                  _buf.b.put(v);
              }
          }
  
          public void writeByteSeq(int count, IEnumerable<byte> v)
          {
              if(count == 0)
              {
                  writeSize(0);
                  return;
              }
  
              {
                  List<byte> value = v as List<byte>;
                  if(value != null)
                  {
                      writeByteSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  LinkedList<byte> value = v as LinkedList<byte>;
                  if(value != null)
                  {
                      writeSize(count);
                      expand(count);
                      IEnumerator<byte> i = v.GetEnumerator();
                      while(i.MoveNext())
                      {
                          _buf.b.put(i.Current);
                      }
                      return;
                  }
              }
  
              {
                  Queue<byte> value = v as Queue<byte>;
                  if(value != null)
                  {
                      writeByteSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  Stack<byte> value = v as Stack<byte>;
                  if(value != null)
                  {
                      writeByteSeq(value.ToArray());
                      return;
                  }
              }
  
              writeSize(count);
              expand(count);
              foreach(byte b in v)
              {
                  _buf.b.put(b);
              }
          }
  
          public void writeByteSeq(int tag, Ice.Optional<byte[]> v)
          {
              if(v.HasValue)
              {
                  writeByteSeq(tag, v.Value);
              }
          }
  
          public void writeByteSeq<T>(int tag, int count, Ice.Optional<T> v)
              where T : IEnumerable<byte>
          {
              if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeByteSeq(count, v.Value);
              }
          }
  
          public void writeByteSeq(int tag, byte[] v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeByteSeq(v);
              }
          }
  
          public void writeByteSeq(int tag, int count, IEnumerable<byte> v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeByteSeq(count, v);
              }
          }
  
          public void writeSerializable(object o)
          {
  #if !COMPACT && !SILVERLIGHT
              if(o == null)
              {
                  writeSize(0);
                  return;
              }
              try
              {
                  StreamWrapper w = new StreamWrapper(this);
                  IFormatter f = new BinaryFormatter();
                  f.Serialize(w, o);
                  w.Close();
              }
              catch(System.Exception ex)
              {
                  throw new Ice.MarshalException("cannot serialize object:", ex);
              }
  #else
              throw new Ice.MarshalException("serialization not supported");
  #endif
          }
  
          public byte readByte()
          {
              try
              {
                  return _buf.b.get();
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.Optional<byte> readByte(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.F1))
              {
                  return new Ice.Optional<byte>(readByte());
              }
              else
              {
                  return new Ice.Optional<byte>();
              }
          }
  
          public void readByte(int tag, out bool isset, out byte v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.F1))
              {
                  v = readByte();
              }
              else
              {
                  v = 0;
              }
          }
  
          public byte[] readByteSeq()
          {
              try
              {
                  int sz = readAndCheckSeqSize(1);
                  byte[] v = new byte[sz];
                  _buf.b.get(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readByteSeq(out List<byte> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new List<byte>(readByteSeq());
          }
  
          public void readByteSeq(out LinkedList<byte> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new LinkedList<byte>(readByteSeq());
          }
  
          public void readByteSeq(out Queue<byte> l)
          {
              //
              // Reading into an array and copy-constructing the
              // queue is faster than constructing the queue
              // and adding to it one element at a time.
              //
              l = new Queue<byte>(readByteSeq());
          }
  
          public void readByteSeq(out Stack<byte> l)
          {
              //
              // Reverse the contents by copying into an array first
              // because the stack is marshaled in top-to-bottom order.
              //
              byte[] array = readByteSeq();
              Array.Reverse(array);
              l = new Stack<byte>(array);
          }
  
          public Ice.Optional<byte[]> readByteSeq(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  return new Ice.Optional<byte[]>(readByteSeq());
              }
              else
              {
                  return new Ice.Optional<byte[]>();
              }
          }
  
          public void readByteSeq(int tag, out bool isset, out byte[] v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  v = readByteSeq();
              }
              else
              {
                  v = null;
              }
          }
  
          public object readSerializable()
          {
  #if !COMPACT && !SILVERLIGHT
              int sz = readAndCheckSeqSize(1);
              if(sz == 0)
              {
                  return null;
              }
              try
              {
                  StreamWrapper w = new StreamWrapper(sz, this);
                  IFormatter f = new BinaryFormatter();
                  return f.Deserialize(w);
              }
              catch(System.Exception ex)
              {
                  throw new Ice.MarshalException("cannot deserialize object:", ex);
              }
  #else
              throw new Ice.MarshalException("serialization not supported");
  #endif
          }
  
          public void writeBool(bool v)
          {
              expand(1);
              _buf.b.put(v ? (byte)1 : (byte)0);
          }
  
          public void writeBool(int tag, Ice.Optional<bool> v)
          {
              if(v.HasValue)
              {
                  writeBool(tag, v.Value);
              }
          }
  
          public void writeBool(int tag, bool v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.F1))
              {
                  writeBool(v);
              }
          }
  
          public void rewriteBool(bool v, int dest)
          {
              _buf.b.put(dest, v ? (byte)1 : (byte)0);
          }
  
          public void writeBoolSeq(bool[] v)
          {
              if(v == null)
              {
                  writeSize(0);
              }
              else
              {
                  writeSize(v.Length);
                  expand(v.Length);
                  _buf.b.putBoolSeq(v);
              }
          }
  
          public void writeBoolSeq(int count, IEnumerable<bool> v)
          {
              if(count == 0)
              {
                  writeSize(0);
                  return;
              }
  
              {
                  List<bool> value = v as List<bool>;
                  if(value != null)
                  {
                      writeBoolSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  LinkedList<bool> value = v as LinkedList<bool>;
                  if(value != null)
                  {
                      writeSize(count);
                      expand(count);
                      IEnumerator<bool> i = v.GetEnumerator();
                      while(i.MoveNext())
                      {
                          _buf.b.putBool(i.Current);
                      }
                      return;
                  }
              }
  
              {
                  Queue<bool> value = v as Queue<bool>;
                  if(value != null)
                  {
                      writeBoolSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  Stack<bool> value = v as Stack<bool>;
                  if(value != null)
                  {
                      writeBoolSeq(value.ToArray());
                      return;
                  }
              }
  
              writeSize(count);
              expand(count);
              foreach(bool b in v)
              {
                  _buf.b.putBool(b);
              }
          }
  
          public void writeBoolSeq(int tag, Ice.Optional<bool[]> v)
          {
              if(v.HasValue)
              {
                  writeBoolSeq(tag, v.Value);
              }
          }
  
          public void writeBoolSeq<T>(int tag, int count, Ice.Optional<T> v)
              where T : IEnumerable<bool>
          {
              if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeBoolSeq(count, v.Value);
              }
          }
  
          public void writeBoolSeq(int tag, bool[] v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeBoolSeq(v);
              }
          }
  
          public void writeBoolSeq(int tag, int count, IEnumerable<bool> v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeBoolSeq(count, v);
              }
          }
  
          public bool readBool()
          {
              try
              {
                  return _buf.b.get() == 1;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.Optional<bool> readBool(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.F1))
              {
                  return new Ice.Optional<bool>(readBool());
              }
              else
              {
                  return new Ice.Optional<bool>();
              }
          }
  
          public void readBool(int tag, out bool isset, out bool v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.F1))
              {
                  v = readBool();
              }
              else
              {
                  v = false;
              }
          }
  
          public bool[] readBoolSeq()
          {
              try
              {
                  int sz = readAndCheckSeqSize(1);
                  bool[] v = new bool[sz];
                  _buf.b.getBoolSeq(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readBoolSeq(out List<bool> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new List<bool>(readBoolSeq());
          }
  
          public void readBoolSeq(out LinkedList<bool> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new LinkedList<bool>(readBoolSeq());
          }
  
          public void readBoolSeq(out Queue<bool> l)
          {
              //
              // Reading into an array and copy-constructing the
              // queue is faster than constructing the queue
              // and adding to it one element at a time.
              //
              l = new Queue<bool>(readBoolSeq());
          }
  
          public void readBoolSeq(out Stack<bool> l)
          {
              //
              // Reverse the contents by copying into an array first
              // because the stack is marshaled in top-to-bottom order.
              //
              bool[] array = readBoolSeq();
              Array.Reverse(array);
              l = new Stack<bool>(array);
          }
  
          public Ice.Optional<bool[]> readBoolSeq(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  return new Ice.Optional<bool[]>(readBoolSeq());
              }
              else
              {
                  return new Ice.Optional<bool[]>();
              }
          }
  
          public void readBoolSeq(int tag, out bool isset, out bool[] v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  v = readBoolSeq();
              }
              else
              {
                  v = null;
              }
          }
  
          public void writeShort(short v)
          {
              expand(2);
              _buf.b.putShort(v);
          }
  
          public void writeShort(int tag, Ice.Optional<short> v)
          {
              if(v.HasValue)
              {
                  writeShort(tag, v.Value);
              }
          }
  
          public void writeShort(int tag, short v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.F2))
              {
                  writeShort(v);
              }
          }
  
          public void writeShortSeq(short[] v)
          {
              if(v == null)
              {
                  writeSize(0);
              }
              else
              {
                  writeSize(v.Length);
                  expand(v.Length * 2);
                  _buf.b.putShortSeq(v);
              }
          }
  
          public void writeShortSeq(int count, IEnumerable<short> v)
          {
              if(count == 0)
              {
                  writeSize(0);
                  return;
              }
  
              {
                  List<short> value = v as List<short>;
                  if(value != null)
                  {
                      writeShortSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  LinkedList<short> value = v as LinkedList<short>;
                  if(value != null)
                  {
                      writeSize(count);
                      expand(count * 2);
                      IEnumerator<short> i = v.GetEnumerator();
                      while(i.MoveNext())
                      {
                          _buf.b.putShort(i.Current);
                      }
                      return;
                  }
              }
  
              {
                  Queue<short> value = v as Queue<short>;
                  if(value != null)
                  {
                      writeShortSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  Stack<short> value = v as Stack<short>;
                  if(value != null)
                  {
                      writeShortSeq(value.ToArray());
                      return;
                  }
              }
  
              writeSize(count);
              expand(count * 2);
              foreach(short s in v)
              {
                  _buf.b.putShort(s);
              }
          }
  
          public void writeShortSeq(int tag, Ice.Optional<short[]> v)
          {
              if(v.HasValue)
              {
                  writeShortSeq(tag, v.Value);
              }
          }
  
          public void writeShortSeq<T>(int tag, int count, Ice.Optional<T> v)
              where T : IEnumerable<short>
          {
              if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
                  writeShortSeq(count, v.Value);
              }
          }
  
          public void writeShortSeq(int tag, short[] v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || v.Length == 0 ? 1 : v.Length * 2 + (v.Length > 254 ? 5 : 1));
                  writeShortSeq(v);
              }
          }
  
          public void writeShortSeq(int tag, int count, IEnumerable<short> v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
                  writeShortSeq(count, v);
              }
          }
  
          public short readShort()
          {
              try
              {
                  return _buf.b.getShort();
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.Optional<short> readShort(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.F2))
              {
                  return new Ice.Optional<short>(readShort());
              }
              else
              {
                  return new Ice.Optional<short>();
              }
          }
  
          public void readShort(int tag, out bool isset, out short v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.F2))
              {
                  v = readShort();
              }
              else
              {
                  v = 0;
              }
          }
  
          public short[] readShortSeq()
          {
              try
              {
                  int sz = readAndCheckSeqSize(2);
                  short[] v = new short[sz];
                  _buf.b.getShortSeq(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readShortSeq(out List<short> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new List<short>(readShortSeq());
          }
  
          public void readShortSeq(out LinkedList<short> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new LinkedList<short>(readShortSeq());
          }
  
          public void readShortSeq(out Queue<short> l)
          {
              //
              // Reading into an array and copy-constructing the
              // queue is faster than constructing the queue
              // and adding to it one element at a time.
              //
              l = new Queue<short>(readShortSeq());
          }
  
          public void readShortSeq(out Stack<short> l)
          {
              //
              // Reverse the contents by copying into an array first
              // because the stack is marshaled in top-to-bottom order.
              //
              short[] array = readShortSeq();
              Array.Reverse(array);
              l = new Stack<short>(array);
          }
  
          public Ice.Optional<short[]> readShortSeq(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  skipSize();
                  return new Ice.Optional<short[]>(readShortSeq());
              }
              else
              {
                  return new Ice.Optional<short[]>();
              }
          }
  
          public void readShortSeq(int tag, out bool isset, out short[] v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  skipSize();
                  v = readShortSeq();
              }
              else
              {
                  v = null;
              }
          }
  
          public void writeInt(int v)
          {
              expand(4);
              _buf.b.putInt(v);
          }
  
          public void writeInt(int tag, Ice.Optional<int> v)
          {
              if(v.HasValue)
              {
                  writeInt(tag, v.Value);
              }
          }
  
          public void writeInt(int tag, int v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.F4))
              {
                  writeInt(v);
              }
          }
  
          public void rewriteInt(int v, int dest)
          {
              _buf.b.putInt(dest, v);
          }
  
          public void writeIntSeq(int[] v)
          {
              if(v == null)
              {
                  writeSize(0);
              }
              else
              {
                  writeSize(v.Length);
                  expand(v.Length * 4);
                  _buf.b.putIntSeq(v);
              }
          }
  
          public void writeIntSeq(int count, IEnumerable<int> v)
          {
              if(count == 0)
              {
                  writeSize(0);
                  return;
              }
  
              {
                  List<int> value = v as List<int>;
                  if(value != null)
                  {
                      writeIntSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  LinkedList<int> value = v as LinkedList<int>;
                  if(value != null)
                  {
                      writeSize(count);
                      expand(count * 4);
                      IEnumerator<int> i = v.GetEnumerator();
                      while(i.MoveNext())
                      {
                          _buf.b.putInt(i.Current);
                      }
                      return;
                  }
              }
  
              {
                  Queue<int> value = v as Queue<int>;
                  if(value != null)
                  {
                      writeIntSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  Stack<int> value = v as Stack<int>;
                  if(value != null)
                  {
                      writeIntSeq(value.ToArray());
                      return;
                  }
              }
  
              writeSize(count);
              expand(count * 4);
              foreach(int i in v)
              {
                  _buf.b.putInt(i);
              }
          }
  
          public void writeIntSeq(int tag, Ice.Optional<int[]> v)
          {
              if(v.HasValue)
              {
                  writeIntSeq(tag, v.Value);
              }
          }
  
          public void writeIntSeq<T>(int tag, int count, Ice.Optional<T> v)
              where T : IEnumerable<int>
          {
              if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
                  writeIntSeq(count, v.Value);
              }
          }
  
          public void writeIntSeq(int tag, int[] v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
                  writeIntSeq(v);
              }
          }
  
          public void writeIntSeq(int tag, int count, IEnumerable<int> v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
                  writeIntSeq(count, v);
              }
          }
  
          public int readInt()
          {
              try
              {
                  return _buf.b.getInt();
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.Optional<int> readInt(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.F4))
              {
                  return new Ice.Optional<int>(readInt());
              }
              else
              {
                  return new Ice.Optional<int>();
              }
          }
  
          public void readInt(int tag, out bool isset, out int v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.F4))
              {
                  v = readInt();
              }
              else
              {
                  v = 0;
              }
          }
  
          public int[] readIntSeq()
          {
              try
              {
                  int sz = readAndCheckSeqSize(4);
                  int[] v = new int[sz];
                  _buf.b.getIntSeq(v);
                  return v;
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readIntSeq(out List<int> l)
          {
              //
              // Reading into an array and copy-constructing the
              // list is faster than constructing the list
              // and adding to it one element at a time.
              //
              l = new List<int>(readIntSeq());
          }
  
          public void readIntSeq(out LinkedList<int> l)
          {
              try
              {
                  int sz = readAndCheckSeqSize(4);
                  l = new LinkedList<int>();
                  for(int i = 0; i < sz; ++i)
                  {
                      l.AddLast(_buf.b.getInt());
                  }
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readIntSeq(out Queue<int> l)
          {
              //
              // Reading into an array and copy-constructing the
              // queue takes the same time as constructing the queue
              // and adding to it one element at a time, so
              // we avoid the copy.
              //
              try
              {
                  int sz = readAndCheckSeqSize(4);
                  l = new Queue<int>(sz);
                  for(int i = 0; i < sz; ++i)
                  {
                      l.Enqueue(_buf.b.getInt());
                  }
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public void readIntSeq(out Stack<int> l)
          {
              //
              // Reverse the contents by copying into an array first
              // because the stack is marshaled in top-to-bottom order.
              //
              int[] array = readIntSeq();
              Array.Reverse(array);
              l = new Stack<int>(array);
          }
  
          public Ice.Optional<int[]> readIntSeq(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  skipSize();
                  return new Ice.Optional<int[]>(readIntSeq());
              }
              else
              {
                  return new Ice.Optional<int[]>();
              }
          }
  
          public void readIntSeq(int tag, out bool isset, out int[] v)
          {
              if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
              {
                  skipSize();
                  v = readIntSeq();
              }
              else
              {
                  v = null;
              }
          }
  
          public void writeLong(long v)
          {
              expand(8);
              _buf.b.putLong(v);
          }
  
          public void writeLong(int tag, Ice.Optional<long> v)
          {
              if(v.HasValue)
              {
                  writeLong(tag, v.Value);
              }
          }
  
          public void writeLong(int tag, long v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.F8))
              {
                  writeLong(v);
              }
          }
  
          public void writeLongSeq(long[] v)
          {
              if(v == null)
              {
                  writeSize(0);
              }
              else
              {
                  writeSize(v.Length);
                  expand(v.Length * 8);
                  _buf.b.putLongSeq(v);
              }
          }
  
          public void writeLongSeq(int count, IEnumerable<long> v)
          {
              if(count == 0)
              {
                  writeSize(0);
                  return;
              }
  
              {
                  List<long> value = v as List<long>;
                  if(value != null)
                  {
                      writeLongSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  LinkedList<long> value = v as LinkedList<long>;
                  if(value != null)
                  {
                      writeSize(count);
                      expand(count * 8);
                      IEnumerator<long> i = v.GetEnumerator();
                      while(i.MoveNext())
                      {
                          _buf.b.putLong(i.Current);
                      }
                      return;
                  }
              }
  
              {
                  Queue<long> value = v as Queue<long>;
                  if(value != null)
                  {
                      writeLongSeq(value.ToArray());
                      return;
                  }
              }
  
              {
                  Stack<long> value = v as Stack<long>;
                  if(value != null)
                  {
                      writeLongSeq(value.ToArray());
                      return;
                  }
              }
  
              writeSize(count);
              expand(count * 8);
              foreach(long l in v)
              {
                  _buf.b.putLong(l);
              }
          }
  
          public void writeLongSeq(int tag, Ice.Optional<long[]> v)
          {
              if(v.HasValue)
              {
                  writeLongSeq(tag, v.Value);
              }
          }
  
          public void writeLongSeq<T>(int tag, int count, Ice.Optional<T> v)
              where T : IEnumerable<long>
          {
              if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
                  writeLongSeq(count, v.Value);
              }
          }
  
          public void writeLongSeq(int tag, long[] v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
                  writeLongSeq(v);
              }
          }
  
          public void writeLongSeq(int tag, int count, IEnumerable<long> v)
          {
              if(writeOpt(tag, Ice.OptionalFormat.VSize))
              {
                  writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
                  writeLongSeq(count, v);
              }
          }
  
          public long readLong()
          {
              try
              {
                  return _buf.b.getLong();
              }
              catch(InvalidOperationException ex)
              {
                  throw new Ice.UnmarshalOutOfBoundsException(ex);
              }
          }
  
          public Ice.Optional<long> readLong(int tag)
          {
              if(readOpt(tag, Ice.OptionalFormat.F8))
              {
  
gt:                 return new Ice.Optional<long>(readLong());