summaryrefslogtreecommitdiff
path: root/csharp/src/Ice/InputStream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src/Ice/InputStream.cs')
-rw-r--r--csharp/src/Ice/InputStream.cs4029
1 files changed, 4029 insertions, 0 deletions
diff --git a/csharp/src/Ice/InputStream.cs b/csharp/src/Ice/InputStream.cs
new file mode 100644
index 00000000000..100328fcb5e
--- /dev/null
+++ b/csharp/src/Ice/InputStream.cs
@@ -0,0 +1,4029 @@
+// **********************************************************************
+//
+// 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 Ice
+{
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+#if !COMPACT && !SILVERLIGHT
+ using System.Runtime.Serialization;
+ using System.Runtime.Serialization.Formatters.Binary;
+#endif
+ using System.Threading;
+ using Protocol = IceInternal.Protocol;
+
+ /// <summary>
+ /// After a call to readPendingObjects(), delegates are called to supply the
+ /// unmarshaled objects.
+ /// </summary>
+ /// <param name="obj">The unmarshaled object.</param>
+ public delegate void ReadObjectCallback(Ice.Object obj);
+
+ /// <summary>
+ /// A ClassResolver translates a Slice type Id into a type using
+ /// an implementation-defined algorithm.
+ /// </summary>
+ /// <param name="id">A Slice type Id corresponding to a Slice value or user exception.</param>
+ public delegate System.Type ClassResolver(string id);
+
+ /// <summary>
+ /// Throws a UserException corresponding to the given Slice type Id, such as "::Module::MyException".
+ /// If the implementation does not throw an exception, the Ice run time will fall back
+ /// to using its default behavior for instantiating the user exception.
+ /// </summary>
+ /// <param name="id">A Slice type Id corresponding to a Slice user exception.</param>
+ public delegate void UserExceptionFactory(string id);
+
+ /// <summary>
+ /// Interface for input streams used to extract Slice types from a sequence of bytes.
+ /// </summary>
+ public class InputStream
+ {
+
+ /// <summary>
+ /// Constructing an InputStream without providing a communicator means the stream will
+ /// use the default encoding version. A communicator is required in order to unmarshal
+ /// proxies. You can supply a communicator later by calling initialize().
+ /// </summary>
+ public InputStream()
+ {
+ initialize(Util.currentEncoding);
+ _buf = new IceInternal.Buffer();
+ }
+
+ /// <summary>
+ /// Constructing an InputStream without providing a communicator means the stream will
+ /// use the default encoding version. A communicator is required in order to unmarshal
+ /// proxies. You can supply a communicator later by calling initialize().
+ /// </summary>
+ /// <param name="data">The byte array containing encoded Slice types.</param>
+ public InputStream(byte[] data)
+ {
+ initialize(Util.currentEncoding);
+ _buf = new IceInternal.Buffer(data);
+ }
+
+ public InputStream(IceInternal.ByteBuffer buf)
+ {
+ initialize(Util.currentEncoding);
+ _buf = new IceInternal.Buffer(buf);
+ }
+
+ public InputStream(IceInternal.Buffer buf) :
+ this(buf, false)
+ {
+ }
+
+ public InputStream(IceInternal.Buffer buf, bool adopt)
+ {
+ initialize(Util.currentEncoding);
+ _buf = new IceInternal.Buffer(buf, adopt);
+ }
+
+ /// <summary>
+ /// This constructor uses the communicator's default encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ public InputStream(Communicator communicator)
+ {
+ initialize(communicator);
+ _buf = new IceInternal.Buffer();
+ }
+
+ /// <summary>
+ /// This constructor uses the communicator's default encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ /// <param name="data">The byte array containing encoded Slice types.</param>
+ public InputStream(Communicator communicator, byte[] data)
+ {
+ initialize(communicator);
+ _buf = new IceInternal.Buffer(data);
+ }
+
+ public InputStream(Communicator communicator, IceInternal.ByteBuffer buf)
+ {
+ initialize(communicator);
+ _buf = new IceInternal.Buffer(buf);
+ }
+
+ public InputStream(Communicator communicator, IceInternal.Buffer buf) :
+ this(communicator, buf, false)
+ {
+ }
+
+ public InputStream(Communicator communicator, IceInternal.Buffer buf, bool adopt)
+ {
+ initialize(communicator);
+ _buf = new IceInternal.Buffer(buf, adopt);
+ }
+
+ /// <summary>
+ /// This constructor uses the given encoding version.
+ /// </summary>
+ /// <param name="encoding">The desired encoding version.</param>
+ public InputStream(EncodingVersion encoding)
+ {
+ initialize(encoding);
+ _buf = new IceInternal.Buffer();
+ }
+
+ /// <summary>
+ /// This constructor uses the given encoding version.
+ /// </summary>
+ /// <param name="encoding">The desired encoding version.</param>
+ /// <param name="data">The byte array containing encoded Slice types.</param>
+ public InputStream(EncodingVersion encoding, byte[] data)
+ {
+ initialize(encoding);
+ _buf = new IceInternal.Buffer(data);
+ }
+
+ public InputStream(EncodingVersion encoding, IceInternal.ByteBuffer buf)
+ {
+ initialize(encoding);
+ _buf = new IceInternal.Buffer(buf);
+ }
+
+ public InputStream(EncodingVersion encoding, IceInternal.Buffer buf) :
+ this(encoding, buf, false)
+ {
+ }
+
+ public InputStream(EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)
+ {
+ initialize(encoding);
+ _buf = new IceInternal.Buffer(buf, adopt);
+ }
+
+ /// <summary>
+ /// This constructor uses the given encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ /// <param name="encoding">The desired encoding version.</param>
+ public InputStream(Communicator communicator, EncodingVersion encoding)
+ {
+ initialize(communicator, encoding);
+ _buf = new IceInternal.Buffer();
+ }
+
+ /// <summary>
+ /// This constructor uses the given encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ /// <param name="encoding">The desired encoding version.</param>
+ /// <param name="data">The byte array containing encoded Slice types.</param>
+ public InputStream(Communicator communicator, EncodingVersion encoding, byte[] data)
+ {
+ initialize(communicator, encoding);
+ _buf = new IceInternal.Buffer(data);
+ }
+
+ public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.ByteBuffer buf)
+ {
+ initialize(communicator, encoding);
+ _buf = new IceInternal.Buffer(buf);
+ }
+
+ public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf) :
+ this(communicator, encoding, buf, false)
+ {
+ }
+
+ public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)
+ {
+ initialize(communicator, encoding);
+ _buf = new IceInternal.Buffer(buf, adopt);
+ }
+
+ public InputStream(IceInternal.Instance instance, EncodingVersion encoding)
+ {
+ initialize(instance, encoding);
+ _buf = new IceInternal.Buffer();
+ }
+
+ public InputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data)
+ {
+ initialize(instance, encoding);
+ _buf = new IceInternal.Buffer(data);
+ }
+
+ public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.ByteBuffer buf)
+ {
+ initialize(instance, encoding);
+ _buf = new IceInternal.Buffer(buf);
+ }
+
+ public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf) :
+ this(instance, encoding, buf, false)
+ {
+ }
+
+ public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)
+ {
+ initialize(instance, encoding);
+ _buf = new IceInternal.Buffer(buf, adopt);
+ }
+
+ /// <summary>
+ /// Initializes the stream to use the communicator's default encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ public void initialize(Communicator communicator)
+ {
+ Debug.Assert(communicator != null);
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
+ }
+
+ /// <summary>
+ /// Initializes the stream to use the given communicator and encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator to use when initializing the stream.</param>
+ /// <param name="encoding">The desired encoding version.</param>
+ public void initialize(Communicator communicator, EncodingVersion encoding)
+ {
+ Debug.Assert(communicator != null);
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ initialize(instance, encoding);
+ }
+
+ private void initialize(IceInternal.Instance instance, EncodingVersion encoding)
+ {
+ initialize(encoding);
+
+ instance_ = instance;
+ _traceSlicing = instance_.traceLevels().slicing > 0;
+
+ _valueFactoryManager = instance_.initializationData().valueFactoryManager;
+ _logger = instance_.initializationData().logger;
+ _classResolver = instance_.resolveClass;
+ }
+
+ private void initialize(EncodingVersion encoding)
+ {
+ instance_ = null;
+ _encoding = encoding;
+ _encapsStack = null;
+ _encapsCache = null;
+ _traceSlicing = false;
+ _closure = null;
+ _sliceObjects = true;
+ _startSeq = -1;
+ _minSeqSize = 0;
+ }
+
+ /// <summary>
+ /// Resets this stream. This method allows the stream to be reused, to avoid creating
+ /// unnecessary garbage.
+ /// </summary>
+ public void reset()
+ {
+ _buf.reset();
+ clear();
+ }
+
+ /// <summary>
+ /// Releases any data retained by encapsulations. Internally calls clear().
+ /// </summary>
+ public void clear()
+ {
+ if(_encapsStack != null)
+ {
+ Debug.Assert(_encapsStack.next == null);
+ _encapsStack.next = _encapsCache;
+ _encapsCache = _encapsStack;
+ _encapsStack = null;
+ _encapsCache.reset();
+ }
+
+ _startSeq = -1;
+ _sliceObjects = true;
+ }
+
+ /// <summary>
+ /// Sets the value factory manager to use when marshaling value instances. If the stream
+ /// was initialized with a communicator, the communicator's value factory manager will
+ /// be used by default.
+ /// </summary>
+ /// <param name="vfm">The value factory manager.</param>
+ public void setValueFactoryManager(ValueFactoryManager vfm)
+ {
+ _valueFactoryManager = vfm;
+ }
+
+ /// <summary>
+ /// Sets the logger to use when logging trace messages. If the stream
+ /// was initialized with a communicator, the communicator's logger will
+ /// be used by default.
+ /// </summary>
+ /// <param name="logger">The logger to use for logging trace messages.</param>
+ public void setLogger(Logger logger)
+ {
+ _logger = logger;
+ }
+
+ /// <summary>
+ /// Sets the compact ID resolver to use when unmarshaling value and exception
+ /// instances. If the stream was initialized with a communicator, the communicator's
+ /// resolver will be used by default.
+ /// </summary>
+ /// <param name="r">The compact ID resolver.</param>
+ public void setCompactIdResolver(CompactIdResolver r)
+ {
+ _compactIdResolver = r;
+ }
+
+ /// <summary>
+ /// Sets the class resolver, which the stream will use when attempting to unmarshal
+ /// a value or exception. If the stream was initialized with a communicator, the communicator's
+ /// resolver will be used by default.
+ /// </summary>
+ /// <param name="r">The class resolver.</param>
+ public void setClassResolver(ClassResolver r)
+ {
+ _classResolver = r;
+ }
+
+ /// <summary>
+ /// Determines the behavior of the stream when extracting Slice objects.
+ /// A Slice object is "sliced" when a factory cannot be found for a Slice type ID.
+ /// The stream's default behavior is to slice objects.
+ /// </summary>
+ /// <param name="b">If true (the default), slicing is enabled; if false,
+ /// slicing is disabled. If slicing is disabled and the stream encounters a Slice type ID
+ /// during decoding for which no value factory is installed, it raises NoValueFactoryException.
+ /// </param>
+ public void setSliceObjects(bool b)
+ {
+ _sliceObjects = b;
+ }
+
+ /// <summary>
+ /// Determines whether the stream logs messages about slicing instances of Slice values.
+ /// </summary>
+ /// <param name="b">True to enable logging, false to disable logging.</param>
+ public void setTraceSlicing(bool b)
+ {
+ _traceSlicing = b;
+ }
+
+ /// <summary>
+ /// Retrieves the closure object associated with this stream.
+ /// </summary>
+ /// <returns>The closure object.</returns>
+ public object getClosure()
+ {
+ return _closure;
+ }
+
+ /// <summary>
+ /// Associates a closure object with this stream.
+ /// </summary>
+ /// <param name="p">The new closure object.</param>
+ /// <returns>The previous closure object, or null.</returns>
+ public object setClosure(object p)
+ {
+ object prev = _closure;
+ _closure = p;
+ return prev;
+ }
+
+ public IceInternal.Instance instance()
+ {
+ return instance_;
+ }
+
+ /// <summary>
+ /// Swaps the contents of one stream with another.
+ /// </summary>
+ /// <param name="other">The other stream.</param>
+ public void swap(InputStream other)
+ {
+ Debug.Assert(instance_ == other.instance_);
+
+ IceInternal.Buffer tmpBuf = other._buf;
+ other._buf = _buf;
+ _buf = tmpBuf;
+
+ EncodingVersion tmpEncoding = other._encoding;
+ other._encoding = _encoding;
+ _encoding = tmpEncoding;
+
+ bool tmpTraceSlicing = other._traceSlicing;
+ other._traceSlicing = _traceSlicing;
+ _traceSlicing = tmpTraceSlicing;
+
+ object tmpClosure = other._closure;
+ other._closure = _closure;
+ _closure = tmpClosure;
+
+ bool tmpSliceObjects = other._sliceObjects;
+ other._sliceObjects = _sliceObjects;
+ _sliceObjects = tmpSliceObjects;
+
+ //
+ // Swap is never called for InputStreams that have encapsulations being read. However,
+ // encapsulations might still be set in case un-marshalling failed. We just
+ // reset the encapsulations if there are still some set.
+ //
+ resetEncapsulation();
+ other.resetEncapsulation();
+
+ int tmpStartSeq = other._startSeq;
+ other._startSeq = _startSeq;
+ _startSeq = tmpStartSeq;
+
+ int tmpMinSeqSize = other._minSeqSize;
+ other._minSeqSize = _minSeqSize;
+ _minSeqSize = tmpMinSeqSize;
+
+ ValueFactoryManager tmpVfm = other._valueFactoryManager;
+ other._valueFactoryManager = _valueFactoryManager;
+ _valueFactoryManager = tmpVfm;
+
+ Logger tmpLogger = other._logger;
+ other._logger = _logger;
+ _logger = tmpLogger;
+
+ CompactIdResolver tmpCompactIdResolver = other._compactIdResolver;
+ other._compactIdResolver = _compactIdResolver;
+ _compactIdResolver = tmpCompactIdResolver;
+
+ ClassResolver tmpClassResolver = other._classResolver;
+ other._classResolver = _classResolver;
+ _classResolver = tmpClassResolver;
+ }
+
+ private void resetEncapsulation()
+ {
+ _encapsStack = null;
+ }
+
+ /// <summary>
+ /// Resizes the stream to a new size.
+ /// </summary>
+ /// <param name="sz">The new size.</param>
+ public void resize(int sz)
+ {
+ _buf.resize(sz, true);
+ _buf.b.position(sz);
+ }
+
+ public IceInternal.Buffer getBuffer()
+ {
+ return _buf;
+ }
+
+ /// <summary>
+ /// Marks the start of an Ice object.
+ /// </summary>
+ public void startObject()
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ _encapsStack.decoder.startInstance(SliceType.ObjectSlice);
+ }
+
+ /// <summary>
+ /// Marks the end of an Ice object.
+ /// </summary>
+ /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param>
+ /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns>
+ public SlicedData endObject(bool preserve)
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ return _encapsStack.decoder.endInstance(preserve);
+ }
+
+ /// <summary>
+ /// Marks the start of a user exception.
+ /// </summary>
+ public void startException()
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ _encapsStack.decoder.startInstance(SliceType.ExceptionSlice);
+ }
+
+ /// <summary>
+ /// Marks the end of a user exception.
+ /// </summary>
+ /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param>
+ /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns>
+ public SlicedData endException(bool preserve)
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ return _encapsStack.decoder.endInstance(preserve);
+ }
+
+ /// <summary>
+ /// Reads the start of an encapsulation.
+ /// </summary>
+ /// <returns>The encapsulation encoding version.</returns>
+ public EncodingVersion startEncapsulation()
+ {
+ Encaps curr = _encapsCache;
+ if(curr != null)
+ {
+ curr.reset();
+ _encapsCache = _encapsCache.next;
+ }
+ else
+ {
+ curr = new Encaps();
+ }
+ curr.next = _encapsStack;
+ _encapsStack = curr;
+
+ _encapsStack.start = _buf.b.position();
+
+ //
+ // I don't use readSize() 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(), it could be 1 or 5 bytes.
+ //
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new UnmarshalOutOfBoundsException();
+ }
+ if(sz - 4 > _buf.b.remaining())
+ {
+ throw new UnmarshalOutOfBoundsException();
+ }
+ _encapsStack.sz = sz;
+
+ EncodingVersion encoding = new EncodingVersion();
+ encoding.read__(this);
+ Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
+ _encapsStack.setEncoding(encoding);
+
+ return encoding;
+ }
+
+ /// <summary>
+ /// Ends the previous encapsulation.
+ /// </summary>
+ public void endEncapsulation()
+ {
+ Debug.Assert(_encapsStack != null);
+
+ if(!_encapsStack.encoding_1_0)
+ {
+ skipOptionals();
+ if(_buf.b.position() != _encapsStack.start + _encapsStack.sz)
+ {
+ throw new EncapsulationException();
+ }
+ }
+ else if(_buf.b.position() != _encapsStack.start + _encapsStack.sz)
+ {
+ if(_buf.b.position() + 1 != _encapsStack.start + _encapsStack.sz)
+ {
+ throw new 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 UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ Encaps curr = _encapsStack;
+ _encapsStack = curr.next;
+ curr.next = _encapsCache;
+ _encapsCache = curr;
+ _encapsCache.reset();
+ }
+
+ /// <summary>
+ /// Skips an empty encapsulation.
+ /// </summary>
+ /// <returns>The encapsulation's encoding version.</returns>
+ public EncodingVersion skipEmptyEncapsulation()
+ {
+ int sz = readInt();
+ if(sz != 6)
+ {
+ throw new EncapsulationException();
+ }
+
+ EncodingVersion encoding = new EncodingVersion();
+ encoding.read__(this);
+ return encoding;
+ }
+
+ /// <summary>
+ /// Returns a blob of bytes representing an encapsulation. The encapsulation's encoding version
+ /// is returned in the argument.
+ /// </summary>
+ /// <param name="encoding">The encapsulation's encoding version.</param>
+ /// <returns>The encoded encapsulation.</returns>
+ public byte[] readEncapsulation(out EncodingVersion encoding)
+ {
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new UnmarshalOutOfBoundsException();
+ }
+
+ if(sz - 4 > _buf.b.remaining())
+ {
+ throw new UnmarshalOutOfBoundsException();
+ }
+
+ encoding = new 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 UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Determines the current encoding version.
+ /// </summary>
+ /// <returns>The encoding version.</returns>
+ public EncodingVersion getEncoding()
+ {
+ return _encapsStack != null ? _encapsStack.encoding : _encoding;
+ }
+
+ /// <summary>
+ /// Determines the size of the current encapsulation, excluding the encapsulation header.
+ /// </summary>
+ /// <returns>The size of the encapsulated data.</returns>
+ public int getEncapsulationSize()
+ {
+ Debug.Assert(_encapsStack != null);
+ return _encapsStack.sz - 6;
+ }
+
+ /// <summary>
+ /// Skips over an encapsulation.
+ /// </summary>
+ /// <returns>The encoding version of the skipped encapsulation.</returns>
+ public EncodingVersion skipEncapsulation()
+ {
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new UnmarshalOutOfBoundsException();
+ }
+ EncodingVersion encoding = new EncodingVersion();
+ encoding.read__(this);
+ try
+ {
+ _buf.b.position(_buf.b.position() + sz - 6);
+ }
+ catch(ArgumentOutOfRangeException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ return encoding;
+ }
+
+ /// <summary>
+ /// Reads the start of an object or exception slice.
+ /// </summary>
+ /// <returns>The Slice type ID for this slice.</returns>
+ public string startSlice() // Returns type ID of next slice
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ return _encapsStack.decoder.startSlice();
+ }
+
+ /// <summary>
+ /// Indicates that the end of an object or exception slice has been reached.
+ /// </summary>
+ public void endSlice()
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ _encapsStack.decoder.endSlice();
+ }
+
+ /// <summary>
+ /// Skips over an object or exception slice.
+ /// </summary>
+ public void skipSlice()
+ {
+ Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
+ _encapsStack.decoder.skipSlice();
+ }
+
+ /// <summary>
+ /// Indicates that unmarshaling is complete, except for any Slice objects. The application must call this
+ /// method only if the stream actually contains Slice objects. Calling readPendingObjects triggers the
+ /// calls the ReadObjectCallback delegates to inform the application that unmarshaling of a Slice
+ /// object is complete.
+ /// </summary>
+ public void readPendingObjects()
+ {
+ if(_encapsStack != null && _encapsStack.decoder != null)
+ {
+ _encapsStack.decoder.readPendingObjects();
+ }
+ else if(_encapsStack != null ? _encapsStack.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();
+ }
+ }
+
+ /// <summary>
+ /// Extracts a size from the stream.
+ /// </summary>
+ /// <returns>The extracted size.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Reads and validates a sequence size.
+ /// </summary>
+ /// <returns>The extracted size.</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Reads a blob of bytes from the stream. The length of the given array determines how many bytes are read.
+ /// </summary>
+ /// <param name="v">Bytes from the stream.</param>
+ public void readBlob(byte[] v)
+ {
+ try
+ {
+ _buf.b.get(v);
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Reads a blob of bytes from the stream.
+ /// </summary>
+ /// <param name="sz">The number of bytes to read.</param>
+ /// <returns>The requested bytes as a byte array.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Determine if an optional value is available for reading.
+ /// </summary>
+ /// <param name="tag">The tag associated with the value.</param>
+ /// <param name="expectedFormat">The optional format for the value.</param>
+ /// <returns>True if the value is present, false otherwise.</returns>
+ public bool readOptional(int tag, Ice.OptionalFormat expectedFormat)
+ {
+ Debug.Assert(_encapsStack != null);
+ if(_encapsStack.decoder != null)
+ {
+ return _encapsStack.decoder.readOptional(tag, expectedFormat);
+ }
+ else
+ {
+ return readOptImpl(tag, expectedFormat);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a byte value from the stream.
+ /// </summary>
+ /// <returns>The extracted byte.</returns>
+ public byte readByte()
+ {
+ try
+ {
+ return _buf.b.get();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional byte value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<byte> readByte(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F1))
+ {
+ return new Ice.Optional<byte>(readByte());
+ }
+ else
+ {
+ return new Ice.Optional<byte>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional byte value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readByte(int tag, out bool isset, out byte v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F1))
+ {
+ v = readByte();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <returns>The extracted byte sequence.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted byte sequence as a list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted byte sequence as a linked list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted byte sequence as a queue.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted byte sequence as a stack.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Extracts an optional byte sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<byte[]> readByteSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<byte[]>(readByteSeq());
+ }
+ else
+ {
+ return new Ice.Optional<byte[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional byte sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readByteSeq(int tag, out bool isset, out byte[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readByteSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a serializable object from the stream.
+ /// </summary>
+ /// <returns>The serializable object.</returns>
+ public object readSerializable()
+ {
+#if !COMPACT && !SILVERLIGHT
+ int sz = readAndCheckSeqSize(1);
+ if(sz == 0)
+ {
+ return null;
+ }
+ try
+ {
+ IceInternal.InputStreamWrapper w = new IceInternal.InputStreamWrapper(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
+ }
+
+ /// <summary>
+ /// Extracts a boolean value from the stream.
+ /// </summary>
+ /// <returns>The extracted boolean.</returns>
+ public bool readBool()
+ {
+ try
+ {
+ return _buf.b.get() == 1;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional boolean value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<bool> readBool(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F1))
+ {
+ return new Ice.Optional<bool>(readBool());
+ }
+ else
+ {
+ return new Ice.Optional<bool>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional boolean value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readBool(int tag, out bool isset, out bool v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F1))
+ {
+ v = readBool();
+ }
+ else
+ {
+ v = false;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <returns>The extracted boolean sequence.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted boolean sequence as a list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted boolean sequence as a linked list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted boolean sequence as a queue.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted boolean sequence as a stack.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Extracts an optional boolean sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<bool[]> readBoolSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<bool[]>(readBoolSeq());
+ }
+ else
+ {
+ return new Ice.Optional<bool[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional boolean sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readBoolSeq(int tag, out bool isset, out bool[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readBoolSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a short value from the stream.
+ /// </summary>
+ /// <returns>The extracted short.</returns>
+ public short readShort()
+ {
+ try
+ {
+ return _buf.b.getShort();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional short value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<short> readShort(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F2))
+ {
+ return new Ice.Optional<short>(readShort());
+ }
+ else
+ {
+ return new Ice.Optional<short>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional short value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readShort(int tag, out bool isset, out short v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F2))
+ {
+ v = readShort();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <returns>The extracted short sequence.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted short sequence as a list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted short sequence as a linked list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted short sequence as a queue.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted short sequence as a stack.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Extracts an optional short sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<short[]> readShortSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<short[]>(readShortSeq());
+ }
+ else
+ {
+ return new Ice.Optional<short[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional short sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readShortSeq(int tag, out bool isset, out short[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readShortSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts an int value from the stream.
+ /// </summary>
+ /// <returns>The extracted int.</returns>
+ public int readInt()
+ {
+ try
+ {
+ return _buf.b.getInt();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional int value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<int> readInt(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F4))
+ {
+ return new Ice.Optional<int>(readInt());
+ }
+ else
+ {
+ return new Ice.Optional<int>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional int value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readInt(int tag, out bool isset, out int v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F4))
+ {
+ v = readInt();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of int values from the stream.
+ /// </summary>
+ /// <returns>The extracted int sequence.</returns>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of int values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted int sequence as a list.</param>
+ 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());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of int values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted int sequence as a linked list.</param>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of int values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted int sequence as a queue.</param>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of int values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted int sequence as a stack.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Extracts an optional int sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<int[]> readIntSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<int[]>(readIntSeq());
+ }
+ else
+ {
+ return new Ice.Optional<int[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional int sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readIntSeq(int tag, out bool isset, out int[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readIntSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a long value from the stream.
+ /// </summary>
+ /// <returns>The extracted long.</returns>
+ public long readLong()
+ {
+ try
+ {
+ return _buf.b.getLong();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional long value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<long> readLong(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F8))
+ {
+ return new Ice.Optional<long>(readLong());
+ }
+ else
+ {
+ return new Ice.Optional<long>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional long value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readLong(int tag, out bool isset, out long v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F8))
+ {
+ v = readLong();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <returns>The extracted long sequence.</returns>
+ public long[] readLongSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(8);
+ long[] v = new long[sz];
+ _buf.b.getLongSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted long sequence as a list.</param>
+ public void readLongSeq(out List<long> 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<long>(readLongSeq());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted long sequence as a linked list.</param>
+ public void readLongSeq(out LinkedList<long> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<long>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getLong());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted long sequence as a queue.</param>
+ public void readLongSeq(out Queue<long> 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<long>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getLong());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted long sequence as a stack.</param>
+ public void readLongSeq(out Stack<long> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ long[] array = readLongSeq();
+ Array.Reverse(array);
+ l = new Stack<long>(array);
+ }
+
+ /// <summary>
+ /// Extracts an optional long sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<long[]> readLongSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<long[]>(readLongSeq());
+ }
+ else
+ {
+ return new Ice.Optional<long[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional long sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readLongSeq(int tag, out bool isset, out long[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readLongSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a float value from the stream.
+ /// </summary>
+ /// <returns>The extracted float.</returns>
+ public float readFloat()
+ {
+ try
+ {
+ return _buf.b.getFloat();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional float value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<float> readFloat(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F4))
+ {
+ return new Ice.Optional<float>(readFloat());
+ }
+ else
+ {
+ return new Ice.Optional<float>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional float value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readFloat(int tag, out bool isset, out float v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F4))
+ {
+ v = readFloat();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <returns>The extracted float sequence.</returns>
+ public float[] readFloatSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ float[] v = new float[sz];
+ _buf.b.getFloatSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted float sequence as a list.</param>
+ public void readFloatSeq(out List<float> 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<float>(readFloatSeq());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted float sequence as a linked list.</param>
+ public void readFloatSeq(out LinkedList<float> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<float>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getFloat());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted float sequence as a queue.</param>
+ public void readFloatSeq(out Queue<float> 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<float>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getFloat());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted float sequence as a stack.</param>
+ public void readFloatSeq(out Stack<float> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ float[] array = readFloatSeq();
+ Array.Reverse(array);
+ l = new Stack<float>(array);
+ }
+
+ /// <summary>
+ /// Extracts an optional float sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<float[]> readFloatSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<float[]>(readFloatSeq());
+ }
+ else
+ {
+ return new Ice.Optional<float[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional float sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readFloatSeq(int tag, out bool isset, out float[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readFloatSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a double value from the stream.
+ /// </summary>
+ /// <returns>The extracted double.</returns>
+ public double readDouble()
+ {
+ try
+ {
+ return _buf.b.getDouble();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional double value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<double> readDouble(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.F8))
+ {
+ return new Ice.Optional<double>(readDouble());
+ }
+ else
+ {
+ return new Ice.Optional<double>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional double value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readDouble(int tag, out bool isset, out double v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.F8))
+ {
+ v = readDouble();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <returns>The extracted double sequence.</returns>
+ public double[] readDoubleSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(8);
+ double[] v = new double[sz];
+ _buf.b.getDoubleSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted double sequence as a list.</param>
+ public void readDoubleSeq(out List<double> 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<double>(readDoubleSeq());
+ }
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted double sequence as a linked list.</param>
+ public void readDoubleSeq(out LinkedList<double> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<double>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getDouble());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted double sequence as a queue.</param>
+ public void readDoubleSeq(out Queue<double> 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<double>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getDouble());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <param name="l">The extracted double sequence as a stack.</param>
+ public void readDoubleSeq(out Stack<double> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ double[] array = readDoubleSeq();
+ Array.Reverse(array);
+ l = new Stack<double>(array);
+ }
+
+ /// <summary>
+ /// Extracts an optional double sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<double[]> readDoubleSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<double[]>(readDoubleSeq());
+ }
+ else
+ {
+ return new Ice.Optional<double[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional double sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readDoubleSeq(int tag, out bool isset, out double[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readDoubleSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true);
+
+ /// <summary>
+ /// Extracts a string from the stream.
+ /// </summary>
+ /// <returns>The extracted string.</returns>
+ public string readString()
+ {
+ int len = readSize();
+
+ if(len == 0)
+ {
+ return "";
+ }
+
+ //
+ // Check the buffer has enough bytes to read.
+ //
+ if(_buf.b.remaining() < len)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ try
+ {
+ //
+ // We reuse the _stringBytes array to avoid creating
+ // excessive garbage
+ //
+ if(_stringBytes == null || len > _stringBytes.Length)
+ {
+ _stringBytes = new byte[len];
+ }
+ _buf.b.get(_stringBytes, 0, len);
+ return utf8.GetString(_stringBytes, 0, len);
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ catch(System.ArgumentException ex)
+ {
+ throw new Ice.MarshalException("Invalid UTF8 string", ex);
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional string from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<string> readString(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<string>(readString());
+ }
+ else
+ {
+ return new Ice.Optional<string>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional string from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readString(int tag, out bool isset, out string v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readString();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <returns>The extracted string sequence.</returns>
+ public string[] readStringSeq()
+ {
+ int sz = readAndCheckSeqSize(1);
+ string[] v = new string[sz];
+ for(int i = 0; i < sz; i++)
+ {
+ v[i] = readString();
+ }
+ return v;
+ }
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <param name="l">The extracted string sequence as a list.</param>
+ public void readStringSeq(out List<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is slower than constructing the list
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new List<string>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Add(readString());
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <param name="l">The extracted string sequence as a linked list.</param>
+ public void readStringSeq(out LinkedList<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is slower than constructing the list
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new LinkedList<string>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(readString());
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <param name="l">The extracted string sequence as a queue.</param>
+ public void readStringSeq(out Queue<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue is slower than constructing the queue
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new Queue<string>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(readString());
+ }
+ }
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <param name="l">The extracted string sequence as a stack.</param>
+ public void readStringSeq(out Stack<string> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ string[] array = readStringSeq();
+ Array.Reverse(array);
+ l = new Stack<string>(array);
+ }
+
+ /// <summary>
+ /// Extracts an optional string sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<string[]> readStringSeq(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ return new Ice.Optional<string[]>(readStringSeq());
+ }
+ else
+ {
+ return new Ice.Optional<string[]>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional string sequence from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readStringSeq(int tag, out bool isset, out string[] v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ v = readStringSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Extracts a proxy from the stream. The stream must have been initialized with a communicator.
+ /// </summary>
+ /// <returns>The extracted proxy.</returns>
+ public Ice.ObjectPrx readProxy()
+ {
+ return instance_.proxyFactory().streamToProxy(this);
+ }
+
+ /// <summary>
+ /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <returns>The optional value.</returns>
+ public Ice.Optional<Ice.ObjectPrx> readProxy(int tag)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ return new Ice.Optional<Ice.ObjectPrx>(readProxy());
+ }
+ else
+ {
+ return new Ice.Optional<Ice.ObjectPrx>();
+ }
+ }
+
+ /// <summary>
+ /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="isset">True if the optional value is present, false otherwise.</param>
+ /// <param name="v">The optional value.</param>
+ public void readProxy(int tag, out bool isset, out Ice.ObjectPrx v)
+ {
+ if(isset = readOptional(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ v = readProxy();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ /// <summary>
+ /// Read an enumerated value.
+ /// </summary>
+ /// <param name="maxValue">The maximum enumerator value in the definition.</param>
+ /// <returns>The enumerator.</returns>
+ public int readEnum(int maxValue)
+ {
+ if(getEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ if(maxValue < 127)
+ {
+ return readByte();
+ }
+ else if(maxValue < 32767)
+ {
+ return readShort();
+ }
+ else
+ {
+ return readInt();
+ }
+ }
+ else
+ {
+ return readSize();
+ }
+ }
+
+ /// <summary>
+ /// Extracts the index of a Slice value from the stream.
+ /// </summary>
+ /// <param name="cb">The callback to notify the application when the extracted instance is available.
+ /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the
+ /// corresponding instance has been fully unmarshaled.</param>
+ public void readObject(ReadObjectCallback cb)
+ {
+ initEncaps();
+ _encapsStack.decoder.readObject(cb);
+ }
+
+ /// <summary>
+ /// Extracts the index of an optional Slice value from the stream.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="cb">The callback to notify the application when the extracted instance is available (if any).
+ /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the
+ /// corresponding instance has been fully unmarshaled.</param>
+ public void readObject(int tag, ReadObjectCallback cb)
+ {
+ if(readOptional(tag, Ice.OptionalFormat.Class))
+ {
+ readObject(cb);
+ }
+ }
+
+ /// <summary>
+ /// Extracts a user exception from the stream and throws it.
+ /// </summary>
+ public void throwException()
+ {
+ throwException(null);
+ }
+
+ /// <summary>
+ /// Extracts a user exception from the stream and throws it.
+ /// </summary>
+ /// <param name="factory">The user exception factory, or null to use the stream's default behavior.</param>
+ public void throwException(UserExceptionFactory factory)
+ {
+ initEncaps();
+ _encapsStack.decoder.throwException(factory);
+ }
+
+ /// <summary>
+ /// Skip the given number of bytes.
+ /// </summary>
+ /// <param name="size">The number of bytes to skip</param>
+ public void skip(int size)
+ {
+ if(size < 0 || size > _buf.b.remaining())
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ _buf.b.position(_buf.b.position() + size);
+ }
+
+ /// <summary>
+ /// Skip over a size value.
+ /// </summary>
+ public void skipSize()
+ {
+ byte b = readByte();
+ if(b == 255)
+ {
+ skip(4);
+ }
+ }
+
+ /// <summary>
+ /// Determines the current position in the stream.
+ /// </summary>
+ /// <returns>The current position.</returns>
+ public int pos()
+ {
+ return _buf.b.position();
+ }
+
+ /// <summary>
+ /// Sets the current position in the stream.
+ /// </summary>
+ /// <param name="n">The new position.</param>
+ public void pos(int n)
+ {
+ _buf.b.position(n);
+ }
+
+ /// <summary>
+ /// Determines the current size of the stream.
+ /// </summary>
+ /// <returns>The current size.</returns>
+ public int size()
+ {
+ return _buf.size();
+ }
+
+ /// <summary>
+ /// Determines whether the stream is empty.
+ /// </summary>
+ /// <returns>True if the internal buffer has no data, false otherwise.</returns>
+ public bool isEmpty()
+ {
+ return _buf.empty();
+ }
+
+ private bool readOptImpl(int readTag, Ice.OptionalFormat expectedFormat)
+ {
+ if(isEncoding_1_0())
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ while(true)
+ {
+ if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz)
+ {
+ return false; // End of encapsulation also indicates end of optionals.
+ }
+
+ int v = readByte();
+ if(v == Protocol.OPTIONAL_END_MARKER)
+ {
+ _buf.b.position(_buf.b.position() - 1); // Rewind.
+ return false;
+ }
+
+ Ice.OptionalFormat format = (Ice.OptionalFormat)(v & 0x07); // First 3 bits.
+ int tag = v >> 3;
+ if(tag == 30)
+ {
+ tag = readSize();
+ }
+
+ if(tag > readTag)
+ {
+ int offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind
+ _buf.b.position(_buf.b.position() - offset);
+ return false; // No optional data members with the requested tag.
+ }
+ else if(tag < readTag)
+ {
+ skipOptional(format); // Skip optional data members
+ }
+ else
+ {
+ if(format != expectedFormat)
+ {
+ throw new Ice.MarshalException("invalid optional data member `" + tag + "': unexpected format");
+ }
+ return true;
+ }
+ }
+ }
+
+ private void skipOptional(Ice.OptionalFormat format)
+ {
+ switch(format)
+ {
+ case Ice.OptionalFormat.F1:
+ {
+ skip(1);
+ break;
+ }
+ case Ice.OptionalFormat.F2:
+ {
+ skip(2);
+ break;
+ }
+ case Ice.OptionalFormat.F4:
+ {
+ skip(4);
+ break;
+ }
+ case Ice.OptionalFormat.F8:
+ {
+ skip(8);
+ break;
+ }
+ case Ice.OptionalFormat.Size:
+ {
+ skipSize();
+ break;
+ }
+ case Ice.OptionalFormat.VSize:
+ {
+ skip(readSize());
+ break;
+ }
+ case Ice.OptionalFormat.FSize:
+ {
+ skip(readInt());
+ break;
+ }
+ case Ice.OptionalFormat.Class:
+ {
+ readObject(null);
+ break;
+ }
+ }
+ }
+
+ private bool skipOptionals()
+ {
+ //
+ // Skip remaining un-read optional members.
+ //
+ while(true)
+ {
+ if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz)
+ {
+ return false; // End of encapsulation also indicates end of optionals.
+ }
+
+ int v = readByte();
+ if(v == Protocol.OPTIONAL_END_MARKER)
+ {
+ return true;
+ }
+
+ Ice.OptionalFormat format = (Ice.OptionalFormat)(v & 0x07); // Read first 3 bits.
+ if((v >> 3) == 30)
+ {
+ skipSize();
+ }
+ skipOptional(format);
+ }
+ }
+
+ private Ice.UserException createUserException(string id)
+ {
+ Ice.UserException userEx = null;
+
+ try
+ {
+ if(_classResolver != null)
+ {
+ Type c = _classResolver(id);
+ if(c != null)
+ {
+ Debug.Assert(!c.IsAbstract && !c.IsInterface);
+ userEx = (Ice.UserException)IceInternal.AssemblyUtil.createInstance(c);
+ }
+ }
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.MarshalException(ex);
+ }
+
+ return userEx;
+ }
+
+ private IceInternal.Instance instance_;
+ private IceInternal.Buffer _buf;
+ private object _closure;
+ private byte[] _stringBytes; // Reusable array for reading strings.
+
+ private enum SliceType { NoSlice, ObjectSlice, ExceptionSlice }
+
+ abstract private class EncapsDecoder
+ {
+ internal EncapsDecoder(InputStream stream, Encaps encaps, bool sliceObjects, ValueFactoryManager f,
+ ClassResolver cr)
+ {
+ _stream = stream;
+ _encaps = encaps;
+ _sliceObjects = sliceObjects;
+ _valueFactoryManager = f;
+ _classResolver = cr;
+ _typeIdIndex = 0;
+ _unmarshaledMap = new Dictionary<int, Ice.Object>();
+ }
+
+ internal abstract void readObject(ReadObjectCallback cb);
+ internal abstract void throwException(UserExceptionFactory factory);
+
+ internal abstract void startInstance(SliceType type);
+ internal abstract Ice.SlicedData endInstance(bool preserve);
+ internal abstract string startSlice();
+ internal abstract void endSlice();
+ internal abstract void skipSlice();
+
+ internal virtual bool readOptional(int tag, Ice.OptionalFormat format)
+ {
+ return false;
+ }
+
+ internal virtual void readPendingObjects()
+ {
+ }
+
+ protected string readTypeId(bool isIndex)
+ {
+ if(_typeIdMap == null)
+ {
+ _typeIdMap = new Dictionary<int, string>();
+ }
+
+ if(isIndex)
+ {
+ int index = _stream.readSize();
+ string typeId;
+ if(!_typeIdMap.TryGetValue(index, out typeId))
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ return typeId;
+ }
+ else
+ {
+ string typeId = _stream.readString();
+ _typeIdMap.Add(++_typeIdIndex, typeId);
+ return typeId;
+ }
+ }
+
+ protected Type resolveClass(string typeId)
+ {
+ Type cls = null;
+ if(_typeIdCache == null)
+ {
+ _typeIdCache = new Dictionary<string, Type>(); // Lazy initialization.
+ }
+ else
+ {
+ _typeIdCache.TryGetValue(typeId, out cls);
+ }
+
+ if(cls == typeof(EncapsDecoder)) // Marker for non-existent class.
+ {
+ cls = null;
+ }
+ else if(cls == null)
+ {
+ try
+ {
+ if(_classResolver != null)
+ {
+ cls = _classResolver(typeId);
+ _typeIdCache.Add(typeId, cls != null ? cls : typeof(EncapsDecoder));
+ }
+ }
+ catch(Exception ex)
+ {
+ throw new NoValueFactoryException("no value factory", typeId, ex);
+ }
+ }
+
+ return cls;
+ }
+
+ protected Ice.Object newInstance(string typeId)
+ {
+ //
+ // Try to find a factory registered for the specific type.
+ //
+ ValueFactory userFactory = _valueFactoryManager.find(typeId);
+ Ice.Object v = null;
+ if(userFactory != null)
+ {
+ v = userFactory(typeId);
+ }
+
+ //
+ // If that fails, invoke the default factory if one has been
+ // registered.
+ //
+ if(v == null)
+ {
+ userFactory = _valueFactoryManager.find("");
+ if(userFactory != null)
+ {
+ v = userFactory(typeId);
+ }
+ }
+
+ //
+ // Last chance: try to instantiate the class dynamically.
+ //
+ if(v == null)
+ {
+ Type cls = resolveClass(typeId);
+
+ if(cls != null)
+ {
+ try
+ {
+ Debug.Assert(!cls.IsAbstract && !cls.IsInterface);
+ v = (Ice.Object)IceInternal.AssemblyUtil.createInstance(cls);
+ }
+ catch(Exception ex)
+ {
+ throw new NoValueFactoryException("no value factory", typeId, ex);
+ }
+ }
+ }
+
+ return v;
+ }
+
+ protected void addPatchEntry(int index, ReadObjectCallback cb)
+ {
+ Debug.Assert(index > 0);
+
+ //
+ // Check if already un-marshalled the object. If that's the case,
+ // just patch the object smart pointer and we're done.
+ //
+ Ice.Object obj;
+ if(_unmarshaledMap.TryGetValue(index, out obj))
+ {
+ cb(obj);
+ return;
+ }
+
+ if(_patchMap == null)
+ {
+ _patchMap = new Dictionary<int, LinkedList<ReadObjectCallback>>();
+ }
+
+ //
+ // Add patch entry if the object isn't un-marshalled yet,
+ // the smart pointer will be patched when the instance is
+ // un-marshalled.
+ //
+ LinkedList<ReadObjectCallback> l;
+ if(!_patchMap.TryGetValue(index, out l))
+ {
+ //
+ // We have no outstanding instances to be patched for this
+ // index, so make a new entry in the patch map.
+ //
+ l = new LinkedList<ReadObjectCallback>();
+ _patchMap.Add(index, l);
+ }
+
+ //
+ // Append a patch entry for this instance.
+ //
+ l.AddLast(cb);
+ }
+
+ protected void unmarshal(int index, Ice.Object v)
+ {
+ //
+ // Add the object to the map of un-marshalled objects, this must
+ // be done before reading the objects (for circular references).
+ //
+ _unmarshaledMap.Add(index, v);
+
+ //
+ // Read the object.
+ //
+ v.read__(_stream);
+
+ if(_patchMap != null)
+ {
+ //
+ // Patch all instances now that the object is un-marshalled.
+ //
+ LinkedList<ReadObjectCallback> l;
+ if(_patchMap.TryGetValue(index, out l))
+ {
+ Debug.Assert(l.Count > 0);
+
+ //
+ // Patch all pointers that refer to the instance.
+ //
+ foreach(ReadObjectCallback cb in l)
+ {
+ cb(v);
+ }
+
+ //
+ // Clear out the patch map for that index -- there is nothing left
+ // to patch for that index for the time being.
+ //
+ _patchMap.Remove(index);
+ }
+ }
+
+ if((_patchMap == null || _patchMap.Count == 0) && _objectList == null)
+ {
+ try
+ {
+ v.ice_postUnmarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_postUnmarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+ }
+ else
+ {
+ if(_objectList == null)
+ {
+ _objectList = new List<Ice.Object>();
+ }
+ _objectList.Add(v);
+
+ if(_patchMap == null || _patchMap.Count == 0)
+ {
+ //
+ // Iterate over the object list and invoke ice_postUnmarshal on
+ // each object. We must do this after all objects have been
+ // unmarshaled in order to ensure that any object data members
+ // have been properly patched.
+ //
+ foreach(Ice.Object p in _objectList)
+ {
+ try
+ {
+ p.ice_postUnmarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_postUnmarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+ }
+ _objectList.Clear();
+ }
+ }
+ }
+
+ protected readonly InputStream _stream;
+ protected readonly Encaps _encaps;
+ protected readonly bool _sliceObjects;
+ protected ValueFactoryManager _valueFactoryManager;
+ protected ClassResolver _classResolver;
+
+ //
+ // Encapsulation attributes for object unmarshaling.
+ //
+ protected Dictionary<int, LinkedList<ReadObjectCallback> > _patchMap;
+ private Dictionary<int, Ice.Object> _unmarshaledMap;
+ private Dictionary<int, string> _typeIdMap;
+ private int _typeIdIndex;
+ private List<Ice.Object> _objectList;
+ private Dictionary<string, Type> _typeIdCache;
+ }
+
+ private sealed class EncapsDecoder10 : EncapsDecoder
+ {
+ internal EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceObjects, ValueFactoryManager f,
+ ClassResolver cr)
+ : base(stream, encaps, sliceObjects, f, cr)
+ {
+ _sliceType = SliceType.NoSlice;
+ }
+
+ internal override void readObject(ReadObjectCallback cb)
+ {
+ Debug.Assert(cb != null);
+
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ int index = _stream.readInt();
+ if(index > 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+ index = -index;
+
+ if(index == 0)
+ {
+ cb(null);
+ }
+ else
+ {
+ addPatchEntry(index, cb);
+ }
+ }
+
+ internal override void throwException(UserExceptionFactory factory)
+ {
+ Debug.Assert(_sliceType == SliceType.NoSlice);
+
+ //
+ // User exception with the 1.0 encoding start with a bool flag
+ // that indicates whether or not the exception has classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ bool usesClasses = _stream.readBool();
+
+ _sliceType = SliceType.ExceptionSlice;
+ _skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _typeId;
+ while(true)
+ {
+ Ice.UserException userEx = null;
+
+ //
+ // Use a factory if one was provided.
+ //
+ if(factory != null)
+ {
+ try
+ {
+ factory(_typeId);
+ }
+ catch(Ice.UserException ex)
+ {
+ userEx = ex;
+ }
+ }
+
+ if(userEx == null)
+ {
+ userEx = _stream.createUserException(_typeId);
+ }
+
+ //
+ // We found the exception.
+ //
+ if(userEx != null)
+ {
+ userEx.read__(_stream);
+ if(usesClasses)
+ {
+ readPendingObjects();
+ }
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ try
+ {
+ startSlice();
+ }
+ catch(Ice.UnmarshalOutOfBoundsException ex)
+ {
+ //
+ // An oversight in the 1.0 encoding means there is no marker to indicate
+ // the last slice of an exception. As a result, we just try to read the
+ // next type ID, which raises UnmarshalOutOfBoundsException when the
+ // input buffer underflows.
+ //
+ // Set the reason member to a more helpful message.
+ //
+ ex.reason = "unknown exception type `" + mostDerivedId + "'";
+ throw ex;
+ }
+ }
+ }
+
+ internal override void startInstance(SliceType sliceType)
+ {
+ Debug.Assert(_sliceType == sliceType);
+ _skipFirstSlice = true;
+ }
+
+ internal override Ice.SlicedData endInstance(bool preserve)
+ {
+ //
+ // Read the Ice::Object slice.
+ //
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ startSlice();
+ int sz = _stream.readSize(); // For compatibility with the old AFM.
+ if(sz != 0)
+ {
+ throw new Ice.MarshalException("invalid Object slice");
+ }
+ endSlice();
+ }
+
+ _sliceType = SliceType.NoSlice;
+ return null;
+ }
+
+ internal override string startSlice()
+ {
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(_skipFirstSlice)
+ {
+ _skipFirstSlice = false;
+ return _typeId;
+ }
+
+ //
+ // For objects, first read the type ID bool which indicates
+ // whether or not the type ID is encoded as a string or as an
+ // index. For exceptions, the type ID is always encoded as a
+ // string.
+ //
+ if(_sliceType == SliceType.ObjectSlice) // For exceptions, the type ID is always encoded as a string
+ {
+ bool isIndex = _stream.readBool();
+ _typeId = readTypeId(isIndex);
+ }
+ else
+ {
+ _typeId = _stream.readString();
+ }
+
+ _sliceSize = _stream.readInt();
+ if(_sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ return _typeId;
+ }
+
+ internal override void endSlice()
+ {
+ }
+
+ internal override void skipSlice()
+ {
+ if(_stream.instance().traceLevels().slicing > 0)
+ {
+ Ice.Logger logger = _stream.instance().initializationData().logger;
+ string slicingCat = _stream.instance().traceLevels().slicingCat;
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ IceInternal.TraceUtil.traceSlicing("object", _typeId, slicingCat, logger);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSlicing("exception", _typeId, slicingCat, logger);
+ }
+ }
+
+ Debug.Assert(_sliceSize >= 4);
+ _stream.skip(_sliceSize - 4);
+ }
+
+ internal override void readPendingObjects()
+ {
+ int num;
+ do
+ {
+ num = _stream.readSize();
+ for(int k = num; k > 0; --k)
+ {
+ readInstance();
+ }
+ }
+ while(num > 0);
+
+ if(_patchMap != null && _patchMap.Count > 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+ }
+
+ private void readInstance()
+ {
+ int index = _stream.readInt();
+
+ if(index <= 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+
+ _sliceType = SliceType.ObjectSlice;
+ _skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _typeId;
+ Ice.Object v = null;
+ while(true)
+ {
+ //
+ // For the 1.0 encoding, the type ID for the base Object class
+ // marks the last slice.
+ //
+ if(_typeId.Equals(Ice.ObjectImpl.ice_staticId()))
+ {
+ throw new NoValueFactoryException("", mostDerivedId);
+ }
+
+ v = newInstance(_typeId);
+
+ //
+ // We found a factory, we get out of this loop.
+ //
+ if(v != null)
+ {
+ break;
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!_sliceObjects)
+ {
+ throw new NoValueFactoryException("no value factory found and object slicing is disabled",
+ _typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object and add-it to the map of un-marshaled objects.
+ //
+ unmarshal(index, v);
+ }
+
+ // Object/exception attributes
+ private SliceType _sliceType;
+ private bool _skipFirstSlice;
+
+ // Slice attributes
+ private int _sliceSize;
+ private string _typeId;
+ }
+
+ private sealed class EncapsDecoder11 : EncapsDecoder
+ {
+ internal EncapsDecoder11(InputStream stream, Encaps encaps, bool sliceObjects, ValueFactoryManager f,
+ ClassResolver cr, CompactIdResolver r)
+ : base(stream, encaps, sliceObjects, f, cr)
+ {
+ _compactIdResolver = r;
+ _current = null;
+ _objectIdIndex = 1;
+ }
+
+ internal override void readObject(ReadObjectCallback cb)
+ {
+ int index = _stream.readSize();
+ if(index < 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+ else if(index == 0)
+ {
+ if(cb != null)
+ {
+ cb(null);
+ }
+ }
+ else if(_current != null && (_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ //
+ // When reading an object within a slice and there's an
+ // indirect object table, always read an indirect reference
+ // that points to an object from the indirect object table
+ // marshaled at the end of the Slice.
+ //
+ // Maintain a list of indirect references. Note that the
+ // indirect index starts at 1, so we decrement it by one to
+ // derive an index into the indirection table that we'll read
+ // at the end of the slice.
+ //
+ if(cb != null)
+ {
+ if(_current.indirectPatchList == null)
+ {
+ _current.indirectPatchList = new Stack<IndirectPatchEntry>();
+ }
+ IndirectPatchEntry e = new IndirectPatchEntry();
+ e.index = index - 1;
+ e.patcher = cb;
+ _current.indirectPatchList.Push(e);
+ }
+ }
+ else
+ {
+ readInstance(index, cb);
+ }
+ }
+
+ internal override void throwException(UserExceptionFactory factory)
+ {
+ Debug.Assert(_current == null);
+
+ push(SliceType.ExceptionSlice);
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _current.typeId;
+ while(true)
+ {
+ Ice.UserException userEx = null;
+
+ //
+ // Use a factory if one was provided.
+ //
+ if(factory != null)
+ {
+ try
+ {
+ factory(_current.typeId);
+ }
+ catch(Ice.UserException ex)
+ {
+ userEx = ex;
+ }
+ }
+
+ if(userEx == null)
+ {
+ userEx = _stream.createUserException(_current.typeId);
+ }
+
+ //
+ // We found the exception.
+ //
+ if(userEx != null)
+ {
+ userEx.read__(_stream);
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+
+ if((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0)
+ {
+ if(mostDerivedId.StartsWith("::", StringComparison.Ordinal))
+ {
+ throw new Ice.UnknownUserException(mostDerivedId.Substring(2));
+ }
+ else
+ {
+ throw new Ice.UnknownUserException(mostDerivedId);
+ }
+ }
+
+ startSlice();
+ }
+ }
+
+ internal override void startInstance(SliceType sliceType)
+ {
+ Debug.Assert(_current.sliceType == sliceType);
+ _current.skipFirstSlice = true;
+ }
+
+ internal override Ice.SlicedData endInstance(bool preserve)
+ {
+ Ice.SlicedData slicedData = null;
+ if(preserve)
+ {
+ slicedData = readSlicedData();
+ }
+ if(_current.slices != null)
+ {
+ _current.slices.Clear();
+ _current.indirectionTables.Clear();
+ }
+ _current = _current.previous;
+ return slicedData;
+ }
+
+ internal override string startSlice()
+ {
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(_current.skipFirstSlice)
+ {
+ _current.skipFirstSlice = false;
+ return _current.typeId;
+ }
+
+ _current.sliceFlags = _stream.readByte();
+
+ //
+ // Read the type ID, for object slices the type ID is encoded as a
+ // string or as an index, for exceptions it's always encoded as a
+ // string.
+ //
+ if(_current.sliceType == SliceType.ObjectSlice)
+ {
+ //
+ // Must be checked first!
+ //
+ if((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_COMPACT) == Protocol.FLAG_HAS_TYPE_ID_COMPACT)
+ {
+ _current.typeId = "";
+ _current.compactId = _stream.readSize();
+ }
+ else if((_current.sliceFlags &
+ (Protocol.FLAG_HAS_TYPE_ID_INDEX | Protocol.FLAG_HAS_TYPE_ID_STRING)) != 0)
+ {
+ _current.typeId = readTypeId((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_INDEX) != 0);
+ _current.compactId = -1;
+ }
+ else
+ {
+ // Only the most derived slice encodes the type ID for the compact format.
+ _current.typeId = "";
+ _current.compactId = -1;
+ }
+ }
+ else
+ {
+ _current.typeId = _stream.readString();
+ _current.compactId = -1;
+ }
+
+ //
+ // Read the slice size if necessary.
+ //
+ if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ _current.sliceSize = _stream.readInt();
+ if(_current.sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+ else
+ {
+ _current.sliceSize = 0;
+ }
+
+ return _current.typeId;
+ }
+
+ internal override void endSlice()
+ {
+ if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
+ {
+ _stream.skipOptionals();
+ }
+
+ //
+ // Read the indirection table if one is present and transform the
+ // indirect patch list into patch entries with direct references.
+ //
+ if((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ //
+ // The table is written as a sequence<size> to conserve space.
+ //
+ int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
+ for(int i = 0; i < indirectionTable.Length; ++i)
+ {
+ indirectionTable[i] = readInstance(_stream.readSize(), null);
+ }
+
+ //
+ // Sanity checks. If there are optional members, it's possible
+ // that not all object references were read if they are from
+ // unknown optional data members.
+ //
+ if(indirectionTable.Length == 0)
+ {
+ throw new Ice.MarshalException("empty indirection table");
+ }
+ if((_current.indirectPatchList == null || _current.indirectPatchList.Count == 0) &&
+ (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0)
+ {
+ throw new Ice.MarshalException("no references to indirection table");
+ }
+
+ //
+ // Convert indirect references into direct references.
+ //
+ if(_current.indirectPatchList != null)
+ {
+ foreach(IndirectPatchEntry e in _current.indirectPatchList)
+ {
+ Debug.Assert(e.index >= 0);
+ if(e.index >= indirectionTable.Length)
+ {
+ throw new Ice.MarshalException("indirection out of range");
+ }
+ addPatchEntry(indirectionTable[e.index], e.patcher);
+ }
+ _current.indirectPatchList.Clear();
+ }
+ }
+ }
+
+ internal override void skipSlice()
+ {
+ if(_stream.instance().traceLevels().slicing > 0)
+ {
+ Ice.Logger logger = _stream.instance().initializationData().logger;
+ string slicingCat = _stream.instance().traceLevels().slicingCat;
+ if(_current.sliceType == SliceType.ExceptionSlice)
+ {
+ IceInternal.TraceUtil.traceSlicing("exception", _current.typeId, slicingCat, logger);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSlicing("object", _current.typeId, slicingCat, logger);
+ }
+ }
+
+ int start = _stream.pos();
+
+ if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ Debug.Assert(_current.sliceSize >= 4);
+ _stream.skip(_current.sliceSize - 4);
+ }
+ else
+ {
+ if(_current.sliceType == SliceType.ObjectSlice)
+ {
+ throw new NoValueFactoryException("no value factory found and compact format prevents " +
+ "slicing (the sender should use the sliced format " +
+ "instead)", _current.typeId);
+ }
+ else
+ {
+ if(_current.typeId.StartsWith("::", StringComparison.Ordinal))
+ {
+ throw new Ice.UnknownUserException(_current.typeId.Substring(2));
+ }
+ else
+ {
+ throw new Ice.UnknownUserException(_current.typeId);
+ }
+ }
+ }
+
+ //
+ // Preserve this slice.
+ //
+ Ice.SliceInfo info = new Ice.SliceInfo();
+ info.typeId = _current.typeId;
+ info.compactId = _current.compactId;
+ info.hasOptionalMembers = (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0;
+ info.isLastSlice = (_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0;
+ IceInternal.ByteBuffer b = _stream.getBuffer().b;
+ int end = b.position();
+ int dataEnd = end;
+ if(info.hasOptionalMembers)
+ {
+ //
+ // Don't include the optional member end marker. It will be re-written by
+ // endSlice when the sliced data is re-written.
+ //
+ --dataEnd;
+ }
+ info.bytes = new byte[dataEnd - start];
+ b.position(start);
+ b.get(info.bytes);
+ b.position(end);
+
+ if(_current.slices == null)
+ {
+ _current.slices = new List<Ice.SliceInfo>();
+ _current.indirectionTables = new List<int[]>();
+ }
+
+ //
+ // Read the indirect object table. We read the instances or their
+ // IDs if the instance is a reference to an already un-marhsaled
+ // object.
+ //
+ // The SliceInfo object sequence is initialized only if
+ // readSlicedData is called.
+ //
+ if((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
+ for(int i = 0; i < indirectionTable.Length; ++i)
+ {
+ indirectionTable[i] = readInstance(_stream.readSize(), null);
+ }
+ _current.indirectionTables.Add(indirectionTable);
+ }
+ else
+ {
+ _current.indirectionTables.Add(null);
+ }
+
+ _current.slices.Add(info);
+ }
+
+ internal override bool readOptional(int readTag, Ice.OptionalFormat expectedFormat)
+ {
+ if(_current == null)
+ {
+ return _stream.readOptImpl(readTag, expectedFormat);
+ }
+ else if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
+ {
+ return _stream.readOptImpl(readTag, expectedFormat);
+ }
+ return false;
+ }
+
+ private int readInstance(int index, ReadObjectCallback cb)
+ {
+ Debug.Assert(index > 0);
+
+ if(index > 1)
+ {
+ if(cb != null)
+ {
+ addPatchEntry(index, cb);
+ }
+ return index;
+ }
+
+ push(SliceType.ObjectSlice);
+
+ //
+ // Get the object ID before we start reading slices. If some
+ // slices are skiped, the indirect object table are still read and
+ // might read other objects.
+ //
+ index = ++_objectIdIndex;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _current.typeId;
+ Ice.Object v = null;
+ while(true)
+ {
+ bool updateCache = false;
+
+ if(_current.compactId >= 0)
+ {
+ updateCache = true;
+
+ //
+ // Translate a compact (numeric) type ID into a class.
+ //
+ if(_compactIdCache == null)
+ {
+ _compactIdCache = new Dictionary<int, Type>(); // Lazy initialization.
+ }
+ else
+ {
+ //
+ // Check the cache to see if we've already translated the compact type ID into a class.
+ //
+ Type cls = null;
+ _compactIdCache.TryGetValue(_current.compactId, out cls);
+ if(cls != null)
+ {
+ try
+ {
+ Debug.Assert(!cls.IsAbstract && !cls.IsInterface);
+ v = (Ice.Object)IceInternal.AssemblyUtil.createInstance(cls);
+ updateCache = false;
+ }
+ catch(Exception ex)
+ {
+ throw new NoValueFactoryException("no value factory", "compact ID " +
+ _current.compactId, ex);
+ }
+ }
+ }
+
+ //
+ // If we haven't already cached a class for the compact ID, then try to translate the
+ // compact ID into a type ID.
+ //
+ if(v == null)
+ {
+ _current.typeId = "";
+ if(_compactIdResolver != null)
+ {
+ try
+ {
+ _current.typeId = _compactIdResolver(_current.compactId);
+ }
+ catch(Ice.LocalException)
+ {
+ throw;
+ }
+ catch(System.Exception ex)
+ {
+ throw new Ice.MarshalException("exception in CompactIdResolver for ID " +
+ _current.compactId, ex);
+ }
+ }
+
+ if(_current.typeId.Length == 0)
+ {
+ _current.typeId = _stream.instance().resolveCompactId(_current.compactId);
+ }
+ }
+ }
+
+ if(v == null && _current.typeId.Length > 0)
+ {
+ v = newInstance(_current.typeId);
+ }
+
+ if(v != null)
+ {
+ if(updateCache)
+ {
+ Debug.Assert(_current.compactId >= 0);
+ _compactIdCache.Add(_current.compactId, v.GetType());
+ }
+
+ //
+ // We have an instance, get out of this loop.
+ //
+ break;
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!_sliceObjects)
+ {
+ throw new NoValueFactoryException("no value factory found and object slicing is disabled",
+ _current.typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+
+ //
+ // If this is the last slice, keep the object as an opaque
+ // UnknownSlicedData object.
+ //
+ if((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0)
+ {
+ //
+ // Provide a factory with an opportunity to supply the object.
+ // We pass the "::Ice::Object" ID to indicate that this is the
+ // last chance to preserve the object.
+ //
+ v = newInstance(Ice.ObjectImpl.ice_staticId());
+ if(v == null)
+ {
+ v = new Ice.UnknownSlicedObject(mostDerivedId);
+ }
+
+ break;
+ }
+
+ startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object
+ //
+ unmarshal(index, v);
+
+ if(_current == null && _patchMap != null && _patchMap.Count > 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+
+ if(cb != null)
+ {
+ cb(v);
+ }
+ return index;
+ }
+
+ private Ice.SlicedData readSlicedData()
+ {
+ if(_current.slices == null) // No preserved slices.
+ {
+ return null;
+ }
+
+ //
+ // The _indirectionTables member holds the indirection table for each slice
+ // in _slices.
+ //
+ Debug.Assert(_current.slices.Count == _current.indirectionTables.Count);
+ for(int n = 0; n < _current.slices.Count; ++n)
+ {
+ //
+ // We use the "objects" list in SliceInfo to hold references
+ // to the target objects. Note that the objects might not have
+ // been read yet in the case of a circular reference to an
+ // enclosing object.
+ //
+ int[] table = _current.indirectionTables[n];
+ Ice.SliceInfo info = _current.slices[n];
+ info.objects = new Ice.Object[table != null ? table.Length : 0];
+ for(int j = 0; j < info.objects.Length; ++j)
+ {
+ IceInternal.ArrayPatcher<Ice.Object> patcher =
+ new IceInternal.ArrayPatcher<Ice.Object>(Ice.ObjectImpl.ice_staticId(), info.objects, j);
+ addPatchEntry(table[j], patcher.patch);
+ }
+ }
+
+ return new Ice.SlicedData(_current.slices.ToArray());
+ }
+
+ private void push(SliceType sliceType)
+ {
+ if(_current == null)
+ {
+ _current = new InstanceData(null);
+ }
+ else
+ {
+ _current = _current.next == null ? new InstanceData(_current) : _current.next;
+ }
+ _current.sliceType = sliceType;
+ _current.skipFirstSlice = false;
+ }
+
+ private sealed class IndirectPatchEntry
+ {
+ public int index;
+ public ReadObjectCallback patcher;
+ }
+
+ private sealed class InstanceData
+ {
+ internal InstanceData(InstanceData previous)
+ {
+ if(previous != null)
+ {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.next = null;
+ }
+
+ // Instance attributes
+ internal SliceType sliceType;
+ internal bool skipFirstSlice;
+ internal List<Ice.SliceInfo> slices; // Preserved slices.
+ internal List<int[]> indirectionTables;
+
+ // Slice attributes
+ internal byte sliceFlags;
+ internal int sliceSize;
+ internal string typeId;
+ internal int compactId;
+ internal Stack<IndirectPatchEntry> indirectPatchList;
+
+ internal InstanceData previous;
+ internal InstanceData next;
+ }
+
+ private CompactIdResolver _compactIdResolver;
+ private InstanceData _current;
+ private int _objectIdIndex; // The ID of the next object to un-marshal.
+ private Dictionary<int, Type> _compactIdCache;
+ }
+
+ private sealed class Encaps
+ {
+ internal void reset()
+ {
+ decoder = null;
+ }
+
+ internal void setEncoding(Ice.EncodingVersion encoding)
+ {
+ this.encoding = encoding;
+ encoding_1_0 = encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ internal int start;
+ internal int sz;
+ internal Ice.EncodingVersion encoding;
+ internal bool encoding_1_0;
+
+ internal EncapsDecoder decoder;
+
+ internal Encaps next;
+ }
+
+ //
+ // The encoding version to use when there's no encapsulation to
+ // read from. This is for example used to read message headers.
+ //
+ private Ice.EncodingVersion _encoding;
+
+ private bool isEncoding_1_0()
+ {
+ return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ private Encaps _encapsStack;
+ private Encaps _encapsCache;
+
+ private void initEncaps()
+ {
+ if(_encapsStack == null) // Lazy initialization
+ {
+ _encapsStack = _encapsCache;
+ if(_encapsStack != null)
+ {
+ _encapsCache = _encapsCache.next;
+ }
+ else
+ {
+ _encapsStack = new Encaps();
+ }
+ _encapsStack.setEncoding(_encoding);
+ _encapsStack.sz = _buf.b.limit();
+ }
+
+ if(_encapsStack.decoder == null) // Lazy initialization.
+ {
+ if(_encapsStack.encoding_1_0)
+ {
+ _encapsStack.decoder = new EncapsDecoder10(this, _encapsStack, _sliceObjects, _valueFactoryManager,
+ _classResolver);
+ }
+ else
+ {
+ _encapsStack.decoder = new EncapsDecoder11(this, _encapsStack, _sliceObjects, _valueFactoryManager,
+ _classResolver, _compactIdResolver);
+ }
+ }
+ }
+
+ private bool _sliceObjects;
+ private bool _traceSlicing;
+
+ private int _startSeq;
+ private int _minSeqSize;
+
+ private ValueFactoryManager _valueFactoryManager;
+ private Logger _logger;
+ private CompactIdResolver _compactIdResolver;
+ private ClassResolver _classResolver;
+ }
+
+ /// <summary>
+ /// Base class for extracting objects from an input stream.
+ /// </summary>
+ public abstract class ObjectReader : ObjectImpl
+ {
+ /// <summary>
+ /// Read the object's data members.
+ /// </summary>
+ /// <param name="inStream">The input stream to read from.</param>
+ public abstract void read(InputStream inStream);
+
+ public override void write__(OutputStream os)
+ {
+ Debug.Assert(false);
+ }
+
+ public override void read__(InputStream istr)
+ {
+ read(istr);
+ }
+ }
+
+}