// // Copyright (c) ZeroC, Inc. All rights reserved. // namespace Ice { using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using Protocol = IceInternal.Protocol; /// /// 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. /// /// A Slice type Id corresponding to a Slice user exception. public delegate void UserExceptionFactory(string id); /// /// Interface for input streams used to extract Slice types from a sequence of bytes. /// public class InputStream { /// /// 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(). /// public InputStream() { initialize(Util.currentEncoding); _buf = new IceInternal.Buffer(); } /// /// 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(). /// /// The byte array containing encoded Slice types. 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); } /// /// This constructor uses the communicator's default encoding version. /// /// The communicator to use when initializing the stream. public InputStream(Communicator communicator) { initialize(communicator); _buf = new IceInternal.Buffer(); } /// /// This constructor uses the communicator's default encoding version. /// /// The communicator to use when initializing the stream. /// The byte array containing encoded Slice types. 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); } /// /// This constructor uses the given encoding version. /// /// The desired encoding version. public InputStream(EncodingVersion encoding) { initialize(encoding); _buf = new IceInternal.Buffer(); } /// /// This constructor uses the given encoding version. /// /// The desired encoding version. /// The byte array containing encoded Slice types. 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); } /// /// This constructor uses the given encoding version. /// /// The communicator to use when initializing the stream. /// The desired encoding version. public InputStream(Communicator communicator, EncodingVersion encoding) { initialize(communicator, encoding); _buf = new IceInternal.Buffer(); } /// /// This constructor uses the given encoding version. /// /// The communicator to use when initializing the stream. /// The desired encoding version. /// The byte array containing encoded Slice types. 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); } /// /// Initializes the stream to use the communicator's default encoding version. /// /// The communicator to use when initializing the stream. public void initialize(Communicator communicator) { Debug.Assert(communicator != null); IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); initialize(instance, instance.defaultsAndOverrides().defaultEncoding); } /// /// Initializes the stream to use the given communicator and encoding version. /// /// The communicator to use when initializing the stream. /// The desired encoding version. 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; _classGraphDepthMax = _instance.classGraphDepthMax(); _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; _classGraphDepthMax = 0x7fffffff; _closure = null; _sliceValues = true; _startSeq = -1; _minSeqSize = 0; } /// /// Resets this stream. This method allows the stream to be reused, to avoid creating /// unnecessary garbage. /// public void reset() { _buf.reset(); clear(); } /// /// Releases any data retained by encapsulations. Internally calls clear(). /// public void clear() { if(_encapsStack != null) { Debug.Assert(_encapsStack.next == null); _encapsStack.next = _encapsCache; _encapsCache = _encapsStack; _encapsStack = null; _encapsCache.reset(); } _startSeq = -1; _sliceValues = true; } /// /// 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. /// /// The value factory manager. public void setValueFactoryManager(ValueFactoryManager vfm) { _valueFactoryManager = vfm; } /// /// 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. /// /// The logger to use for logging trace messages. public void setLogger(Logger logger) { _logger = logger; } /// /// 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. /// /// The compact ID resolver. public void setCompactIdResolver(System.Func r) { _compactIdResolver = r; } /// /// 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. /// /// The class resolver. public void setClassResolver(System.Func r) { _classResolver = r; } /// /// Determines the behavior of the stream when extracting instances of Slice classes. /// An instance is "sliced" when a factory cannot be found for a Slice type ID. /// The stream's default behavior is to slice instances. /// /// 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. /// public void setSliceValues(bool b) { _sliceValues = b; } /// /// Determines whether the stream logs messages about slicing instances of Slice values. /// /// True to enable logging, false to disable logging. public void setTraceSlicing(bool b) { _traceSlicing = b; } /// /// Set the maximum depth allowed for graph of Slice class instances. /// /// The maximum depth. public void setClassGraphDepthMax(int classGraphDepthMax) { if(classGraphDepthMax < 1) { _classGraphDepthMax = 0x7fffffff; } else { _classGraphDepthMax = classGraphDepthMax; } } /// /// Retrieves the closure object associated with this stream. /// /// The closure object. public object getClosure() { return _closure; } /// /// Associates a closure object with this stream. /// /// The new closure object. /// The previous closure object, or null. public object setClosure(object p) { object prev = _closure; _closure = p; return prev; } public IceInternal.Instance instance() { return _instance; } /// /// Swaps the contents of one stream with another. /// /// The other stream. 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 tmpSliceValues = other._sliceValues; other._sliceValues = _sliceValues; _sliceValues = tmpSliceValues; int tmpClassGraphDepthMax = other._classGraphDepthMax; other._classGraphDepthMax = _classGraphDepthMax; _classGraphDepthMax = tmpClassGraphDepthMax; // // 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; System.Func tmpCompactIdResolver = other._compactIdResolver; other._compactIdResolver = _compactIdResolver; _compactIdResolver = tmpCompactIdResolver; System.Func tmpClassResolver = other._classResolver; other._classResolver = _classResolver; _classResolver = tmpClassResolver; } private void resetEncapsulation() { _encapsStack = null; } /// /// Resizes the stream to a new size. /// /// The new size. public void resize(int sz) { _buf.resize(sz, true); _buf.b.position(sz); } public IceInternal.Buffer getBuffer() { return _buf; } /// /// Marks the start of a class instance. /// public void startValue() { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); _encapsStack.decoder.startInstance(SliceType.ValueSlice); } /// /// Marks the end of a class instance. /// /// True if unknown slices should be preserved, false otherwise. /// A SlicedData object containing the preserved slices for unknown types. public SlicedData endValue(bool preserve) { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); return _encapsStack.decoder.endInstance(preserve); } /// /// Marks the start of a user exception. /// public void startException() { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); _encapsStack.decoder.startInstance(SliceType.ExceptionSlice); } /// /// Marks the end of a user exception. /// /// True if unknown slices should be preserved, false otherwise. /// A SlicedData object containing the preserved slices for unknown types. public SlicedData endException(bool preserve) { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); return _encapsStack.decoder.endInstance(preserve); } /// /// Reads the start of an encapsulation. /// /// The encapsulation encoding version. 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.ice_readMembers(this); Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported. _encapsStack.setEncoding(encoding); return encoding; } /// /// Ends the previous encapsulation. /// 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(); } /// /// Skips an empty encapsulation. /// /// The encapsulation's encoding version. public EncodingVersion skipEmptyEncapsulation() { int sz = readInt(); if(sz < 6) { throw new EncapsulationException(); } if(sz - 4 > _buf.b.remaining()) { throw new UnmarshalOutOfBoundsException(); } var encoding = new EncodingVersion(); encoding.ice_readMembers(this); Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported. if(encoding.Equals(Util.Encoding_1_0)) { if(sz != 6) { throw new EncapsulationException(); } } else { // Skip the optional content of the encapsulation if we are expecting an // empty encapsulation. _buf.b.position(_buf.b.position() + sz - 6); } return encoding; } /// /// Returns a blob of bytes representing an encapsulation. The encapsulation's encoding version /// is returned in the argument. /// /// The encapsulation's encoding version. /// The encoded encapsulation. 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.ice_readMembers(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); } } /// /// Determines the current encoding version. /// /// The encoding version. public EncodingVersion getEncoding() { return _encapsStack != null ? _encapsStack.encoding : _encoding; } /// /// Determines the size of the current encapsulation, excluding the encapsulation header. /// /// The size of the encapsulated data. public int getEncapsulationSize() { Debug.Assert(_encapsStack != null); return _encapsStack.sz - 6; } /// /// Skips over an encapsulation. /// /// The encoding version of the skipped encapsulation. public EncodingVersion skipEncapsulation() { int sz = readInt(); if(sz < 6) { throw new UnmarshalOutOfBoundsException(); } EncodingVersion encoding = new EncodingVersion(); encoding.ice_readMembers(this); try { _buf.b.position(_buf.b.position() + sz - 6); } catch(ArgumentOutOfRangeException ex) { throw new UnmarshalOutOfBoundsException(ex); } return encoding; } /// /// Reads the start of a class instance or exception slice. /// /// The Slice type ID for this slice. public string startSlice() // Returns type ID of next slice { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); return _encapsStack.decoder.startSlice(); } /// /// Indicates that the end of a class instance or exception slice has been reached. /// public void endSlice() { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); _encapsStack.decoder.endSlice(); } /// /// Skips over a class instance or exception slice. /// public void skipSlice() { Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); _encapsStack.decoder.skipSlice(); } /// /// Indicates that unmarshaling is complete, except for any class instances. The application must call this /// method only if the stream actually contains class instances. Calling readPendingValues triggers the /// calls to the System.Action delegates to inform the application that unmarshaling of an instance /// is complete. /// public void readPendingValues() { if(_encapsStack != null && _encapsStack.decoder != null) { _encapsStack.decoder.readPendingValues(); } else if(_encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0)) { // // If using the 1.0 encoding and no instances were read, we // still read an empty sequence of pending instances if // requested (i.e.: if this is called). // // This is required by the 1.0 encoding, even if no instances // are written we do marshal an empty sequence if marshaled // data types use classes. // skipSize(); } } /// /// Extracts a size from the stream. /// /// The extracted size. public int readSize() { try { byte b = _buf.b.get(); if(b == 255) { int v = _buf.b.getInt(); if(v < 0) { throw new UnmarshalOutOfBoundsException(); } return v; } else { return b; // byte is unsigned } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Reads and validates a sequence size. /// /// The extracted size. 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 UnmarshalOutOfBoundsException(); } return sz; } /// /// Reads a blob of bytes from the stream. The length of the given array determines how many bytes are read. /// /// Bytes from the stream. public void readBlob(byte[] v) { try { _buf.b.get(v); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Reads a blob of bytes from the stream. /// /// The number of bytes to read. /// The requested bytes as a byte array. public byte[] readBlob(int sz) { if(_buf.b.remaining() < sz) { throw new UnmarshalOutOfBoundsException(); } byte[] v = new byte[sz]; try { _buf.b.get(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Determine if an optional value is available for reading. /// /// The tag associated with the value. /// The optional format for the value. /// True if the value is present, false otherwise. public bool readOptional(int tag, OptionalFormat expectedFormat) { Debug.Assert(_encapsStack != null); if(_encapsStack.decoder != null) { return _encapsStack.decoder.readOptional(tag, expectedFormat); } else { return readOptImpl(tag, expectedFormat); } } /// /// Extracts a byte value from the stream. /// /// The extracted byte. public byte readByte() { try { return _buf.b.get(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional byte value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readByte(int tag) { if(readOptional(tag, OptionalFormat.F1)) { return new Optional(readByte()); } else { return new Optional(); } } /// /// Extracts an optional byte value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readByte(int tag, out bool isset, out byte v) { if(isset = readOptional(tag, OptionalFormat.F1)) { v = readByte(); } else { v = 0; } } /// /// Extracts a sequence of byte values from the stream. /// /// The extracted byte sequence. public byte[] readByteSeq() { try { int sz = readAndCheckSeqSize(1); byte[] v = new byte[sz]; _buf.b.get(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of byte values from the stream. /// /// The extracted byte sequence as a list. public void readByteSeq(out List 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(readByteSeq()); } /// /// Extracts a sequence of byte values from the stream. /// /// The extracted byte sequence as a linked list. public void readByteSeq(out LinkedList 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(readByteSeq()); } /// /// Extracts a sequence of byte values from the stream. /// /// The extracted byte sequence as a queue. public void readByteSeq(out Queue 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(readByteSeq()); } /// /// Extracts a sequence of byte values from the stream. /// /// The extracted byte sequence as a stack. public void readByteSeq(out Stack 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(array); } /// /// Extracts an optional byte sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readByteSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { return new Optional(readByteSeq()); } else { return new Optional(); } } /// /// Extracts an optional byte sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readByteSeq(int tag, out bool isset, out byte[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { v = readByteSeq(); } else { v = null; } } /// /// Extracts a serializable object from the stream. /// /// The serializable object. public object readSerializable() { int sz = readAndCheckSeqSize(1); if(sz == 0) { return null; } try { var f = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.All, _instance)); #pragma warning disable SYSLIB0011 // Type or member is obsolete return f.Deserialize(new IceInternal.InputStreamWrapper(sz, this)); #pragma warning restore SYSLIB0011 // Type or member is obsolete } catch(System.Exception ex) { throw new MarshalException("cannot deserialize object:", ex); } } /// /// Extracts a boolean value from the stream. /// /// The extracted boolean. public bool readBool() { try { return _buf.b.get() == 1; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional boolean value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readBool(int tag) { if(readOptional(tag, OptionalFormat.F1)) { return new Optional(readBool()); } else { return new Optional(); } } /// /// Extracts an optional boolean value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readBool(int tag, out bool isset, out bool v) { if(isset = readOptional(tag, OptionalFormat.F1)) { v = readBool(); } else { v = false; } } /// /// Extracts a sequence of boolean values from the stream. /// /// The extracted boolean sequence. public bool[] readBoolSeq() { try { int sz = readAndCheckSeqSize(1); bool[] v = new bool[sz]; _buf.b.getBoolSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of boolean values from the stream. /// /// The extracted boolean sequence as a list. public void readBoolSeq(out List 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(readBoolSeq()); } /// /// Extracts a sequence of boolean values from the stream. /// /// The extracted boolean sequence as a linked list. public void readBoolSeq(out LinkedList 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(readBoolSeq()); } /// /// Extracts a sequence of boolean values from the stream. /// /// The extracted boolean sequence as a queue. public void readBoolSeq(out Queue 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(readBoolSeq()); } /// /// Extracts a sequence of boolean values from the stream. /// /// The extracted boolean sequence as a stack. public void readBoolSeq(out Stack 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(array); } /// /// Extracts an optional boolean sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readBoolSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { return new Optional(readBoolSeq()); } else { return new Optional(); } } /// /// Extracts an optional boolean sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readBoolSeq(int tag, out bool isset, out bool[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { v = readBoolSeq(); } else { v = null; } } /// /// Extracts a short value from the stream. /// /// The extracted short. public short readShort() { try { return _buf.b.getShort(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional short value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readShort(int tag) { if(readOptional(tag, OptionalFormat.F2)) { return new Optional(readShort()); } else { return new Optional(); } } /// /// Extracts an optional short value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readShort(int tag, out bool isset, out short v) { if(isset = readOptional(tag, OptionalFormat.F2)) { v = readShort(); } else { v = 0; } } /// /// Extracts a sequence of short values from the stream. /// /// The extracted short sequence. public short[] readShortSeq() { try { int sz = readAndCheckSeqSize(2); short[] v = new short[sz]; _buf.b.getShortSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of short values from the stream. /// /// The extracted short sequence as a list. public void readShortSeq(out List 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(readShortSeq()); } /// /// Extracts a sequence of short values from the stream. /// /// The extracted short sequence as a linked list. public void readShortSeq(out LinkedList 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(readShortSeq()); } /// /// Extracts a sequence of short values from the stream. /// /// The extracted short sequence as a queue. public void readShortSeq(out Queue 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(readShortSeq()); } /// /// Extracts a sequence of short values from the stream. /// /// The extracted short sequence as a stack. public void readShortSeq(out Stack 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(array); } /// /// Extracts an optional short sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readShortSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { skipSize(); return new Optional(readShortSeq()); } else { return new Optional(); } } /// /// Extracts an optional short sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readShortSeq(int tag, out bool isset, out short[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { skipSize(); v = readShortSeq(); } else { v = null; } } /// /// Extracts an int value from the stream. /// /// The extracted int. public int readInt() { try { return _buf.b.getInt(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional int value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readInt(int tag) { if(readOptional(tag, OptionalFormat.F4)) { return new Optional(readInt()); } else { return new Optional(); } } /// /// Extracts an optional int value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readInt(int tag, out bool isset, out int v) { if(isset = readOptional(tag, OptionalFormat.F4)) { v = readInt(); } else { v = 0; } } /// /// Extracts a sequence of int values from the stream. /// /// The extracted int sequence. public int[] readIntSeq() { try { int sz = readAndCheckSeqSize(4); int[] v = new int[sz]; _buf.b.getIntSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of int values from the stream. /// /// The extracted int sequence as a list. public void readIntSeq(out List 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(readIntSeq()); } /// /// Extracts a sequence of int values from the stream. /// /// The extracted int sequence as a linked list. public void readIntSeq(out LinkedList l) { try { int sz = readAndCheckSeqSize(4); l = new LinkedList(); for(int i = 0; i < sz; ++i) { l.AddLast(_buf.b.getInt()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of int values from the stream. /// /// The extracted int sequence as a queue. public void readIntSeq(out Queue 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(sz); for(int i = 0; i < sz; ++i) { l.Enqueue(_buf.b.getInt()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of int values from the stream. /// /// The extracted int sequence as a stack. public void readIntSeq(out Stack 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(array); } /// /// Extracts an optional int sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readIntSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { skipSize(); return new Optional(readIntSeq()); } else { return new Optional(); } } /// /// Extracts an optional int sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readIntSeq(int tag, out bool isset, out int[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { skipSize(); v = readIntSeq(); } else { v = null; } } /// /// Extracts a long value from the stream. /// /// The extracted long. public long readLong() { try { return _buf.b.getLong(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional long value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readLong(int tag) { if(readOptional(tag, OptionalFormat.F8)) { return new Optional(readLong()); } else { return new Optional(); } } /// /// Extracts an optional long value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readLong(int tag, out bool isset, out long v) { if(isset = readOptional(tag, OptionalFormat.F8)) { v = readLong(); } else { v = 0; } } /// /// Extracts a sequence of long values from the stream. /// /// The extracted long sequence. public long[] readLongSeq() { try { int sz = readAndCheckSeqSize(8); long[] v = new long[sz]; _buf.b.getLongSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of long values from the stream. /// /// The extracted long sequence as a list. public void readLongSeq(out List 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(readLongSeq()); } /// /// Extracts a sequence of long values from the stream. /// /// The extracted long sequence as a linked list. public void readLongSeq(out LinkedList l) { try { int sz = readAndCheckSeqSize(4); l = new LinkedList(); for(int i = 0; i < sz; ++i) { l.AddLast(_buf.b.getLong()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of long values from the stream. /// /// The extracted long sequence as a queue. public void readLongSeq(out Queue 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(sz); for(int i = 0; i < sz; ++i) { l.Enqueue(_buf.b.getLong()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of long values from the stream. /// /// The extracted long sequence as a stack. public void readLongSeq(out Stack 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(array); } /// /// Extracts an optional long sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readLongSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { skipSize(); return new Optional(readLongSeq()); } else { return new Optional(); } } /// /// Extracts an optional long sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readLongSeq(int tag, out bool isset, out long[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { skipSize(); v = readLongSeq(); } else { v = null; } } /// /// Extracts a float value from the stream. /// /// The extracted float. public float readFloat() { try { return _buf.b.getFloat(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional float value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readFloat(int tag) { if(readOptional(tag, OptionalFormat.F4)) { return new Optional(readFloat()); } else { return new Optional(); } } /// /// Extracts an optional float value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readFloat(int tag, out bool isset, out float v) { if(isset = readOptional(tag, OptionalFormat.F4)) { v = readFloat(); } else { v = 0; } } /// /// Extracts a sequence of float values from the stream. /// /// The extracted float sequence. public float[] readFloatSeq() { try { int sz = readAndCheckSeqSize(4); float[] v = new float[sz]; _buf.b.getFloatSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of float values from the stream. /// /// The extracted float sequence as a list. public void readFloatSeq(out List 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(readFloatSeq()); } /// /// Extracts a sequence of float values from the stream. /// /// The extracted float sequence as a linked list. public void readFloatSeq(out LinkedList l) { try { int sz = readAndCheckSeqSize(4); l = new LinkedList(); for(int i = 0; i < sz; ++i) { l.AddLast(_buf.b.getFloat()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of float values from the stream. /// /// The extracted float sequence as a queue. public void readFloatSeq(out Queue 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(sz); for(int i = 0; i < sz; ++i) { l.Enqueue(_buf.b.getFloat()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of float values from the stream. /// /// The extracted float sequence as a stack. public void readFloatSeq(out Stack 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(array); } /// /// Extracts an optional float sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readFloatSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { skipSize(); return new Optional(readFloatSeq()); } else { return new Optional(); } } /// /// Extracts an optional float sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readFloatSeq(int tag, out bool isset, out float[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { skipSize(); v = readFloatSeq(); } else { v = null; } } /// /// Extracts a double value from the stream. /// /// The extracted double. public double readDouble() { try { return _buf.b.getDouble(); } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts an optional double value from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readDouble(int tag) { if(readOptional(tag, OptionalFormat.F8)) { return new Optional(readDouble()); } else { return new Optional(); } } /// /// Extracts an optional double value from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readDouble(int tag, out bool isset, out double v) { if(isset = readOptional(tag, OptionalFormat.F8)) { v = readDouble(); } else { v = 0; } } /// /// Extracts a sequence of double values from the stream. /// /// The extracted double sequence. public double[] readDoubleSeq() { try { int sz = readAndCheckSeqSize(8); double[] v = new double[sz]; _buf.b.getDoubleSeq(v); return v; } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of double values from the stream. /// /// The extracted double sequence as a list. public void readDoubleSeq(out List 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(readDoubleSeq()); } /// /// Extracts a sequence of double values from the stream. /// /// The extracted double sequence as a linked list. public void readDoubleSeq(out LinkedList l) { try { int sz = readAndCheckSeqSize(4); l = new LinkedList(); for(int i = 0; i < sz; ++i) { l.AddLast(_buf.b.getDouble()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of double values from the stream. /// /// The extracted double sequence as a queue. public void readDoubleSeq(out Queue 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(sz); for(int i = 0; i < sz; ++i) { l.Enqueue(_buf.b.getDouble()); } } catch(InvalidOperationException ex) { throw new UnmarshalOutOfBoundsException(ex); } } /// /// Extracts a sequence of double values from the stream. /// /// The extracted double sequence as a stack. public void readDoubleSeq(out Stack 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(array); } /// /// Extracts an optional double sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readDoubleSeq(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { skipSize(); return new Optional(readDoubleSeq()); } else { return new Optional(); } } /// /// Extracts an optional double sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readDoubleSeq(int tag, out bool isset, out double[] v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { skipSize(); v = readDoubleSeq(); } else { v = null; } } private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true); /// /// Extracts a string from the stream. /// /// The extracted string. 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 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 UnmarshalOutOfBoundsException(ex); } catch(ArgumentException ex) { throw new MarshalException("Invalid UTF8 string", ex); } } /// /// Extracts an optional string from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readString(int tag) { if(readOptional(tag, OptionalFormat.VSize)) { return new Optional(readString()); } else { return new Optional(); } } /// /// Extracts an optional string from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readString(int tag, out bool isset, out string v) { if(isset = readOptional(tag, OptionalFormat.VSize)) { v = readString(); } else { v = null; } } /// /// Extracts a sequence of strings from the stream. /// /// The extracted string sequence. public string[] readStringSeq() { int sz = readAndCheckSeqSize(1); string[] v = new string[sz]; for(int i = 0; i < sz; i++) { v[i] = readString(); } return v; } /// /// Extracts a sequence of strings from the stream. /// /// The extracted string sequence as a list. public void readStringSeq(out List 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(sz); for(int i = 0; i < sz; ++i) { l.Add(readString()); } } /// /// Extracts a sequence of strings from the stream. /// /// The extracted string sequence as a linked list. public void readStringSeq(out LinkedList 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(); for(int i = 0; i < sz; ++i) { l.AddLast(readString()); } } /// /// Extracts a sequence of strings from the stream. /// /// The extracted string sequence as a queue. public void readStringSeq(out Queue 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(); for(int i = 0; i < sz; ++i) { l.Enqueue(readString()); } } /// /// Extracts a sequence of strings from the stream. /// /// The extracted string sequence as a stack. public void readStringSeq(out Stack 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(array); } /// /// Extracts an optional string sequence from the stream. /// /// The numeric tag associated with the value. /// The optional value. public Optional readStringSeq(int tag) { if(readOptional(tag, OptionalFormat.FSize)) { skip(4); return new Optional(readStringSeq()); } else { return new Optional(); } } /// /// Extracts an optional string sequence from the stream. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readStringSeq(int tag, out bool isset, out string[] v) { if(isset = readOptional(tag, OptionalFormat.FSize)) { skip(4); v = readStringSeq(); } else { v = null; } } /// /// Extracts a proxy from the stream. The stream must have been initialized with a communicator. /// /// The extracted proxy. public ObjectPrx readProxy() { return _instance.proxyFactory().streamToProxy(this); } /// /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator. /// /// The numeric tag associated with the value. /// The optional value. public Optional readProxy(int tag) { if(readOptional(tag, OptionalFormat.FSize)) { skip(4); return new Optional(readProxy()); } else { return new Optional(); } } /// /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator. /// /// The numeric tag associated with the value. /// True if the optional value is present, false otherwise. /// The optional value. public void readProxy(int tag, out bool isset, out ObjectPrx v) { if(isset = readOptional(tag, OptionalFormat.FSize)) { skip(4); v = readProxy(); } else { v = null; } } /// /// Read an enumerated value. /// /// The maximum enumerator value in the definition. /// The enumerator. public int readEnum(int maxValue) { if(getEncoding().Equals(Util.Encoding_1_0)) { if(maxValue < 127) { return readByte(); } else if(maxValue < 32767) { return readShort(); } else { return readInt(); } } else { return readSize(); } } /// /// Extracts the index of a Slice value from the stream. /// /// 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. public void readValue(System.Action cb) where T : Value { readValue(v => { if(v == null || v is T) { cb((T)v); } else { IceInternal.Ex.throwUOE(typeof(T), v); } }); } /// /// Extracts the index of a Slice value from the stream. /// /// 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. public void readValue(System.Action cb) { initEncaps(); _encapsStack.decoder.readValue(cb); } /// /// Extracts the index of an optional Slice value from the stream. /// /// The numeric tag associated with the value. /// 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. public void readValue(int tag, System.Action cb) where T : Value { readValue(tag, v => { if(v == null || v is T) { cb((T)v); } else { IceInternal.Ex.throwUOE(typeof(T), v); } }); } /// /// Extracts the index of an optional Slice value from the stream. /// /// The numeric tag associated with the value. /// 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. public void readValue(int tag, System.Action cb) { if(readOptional(tag, OptionalFormat.Class)) { readValue(cb); } } /// /// Extracts a user exception from the stream and throws it. /// public void throwException() { throwException(null); } /// /// Extracts a user exception from the stream and throws it. /// /// The user exception factory, or null to use the stream's default behavior. public void throwException(UserExceptionFactory factory) { initEncaps(); _encapsStack.decoder.throwException(factory); } /// /// Skip the given number of bytes. /// /// The number of bytes to skip public void skip(int size) { if(size < 0 || size > _buf.b.remaining()) { throw new UnmarshalOutOfBoundsException(); } _buf.b.position(_buf.b.position() + size); } /// /// Skip over a size value. /// public void skipSize() { byte b = readByte(); if(b == 255) { skip(4); } } /// /// Determines the current position in the stream. /// /// The current position. public int pos() { return _buf.b.position(); } /// /// Sets the current position in the stream. /// /// The new position. public void pos(int n) { _buf.b.position(n); } /// /// Determines the current size of the stream. /// /// The current size. public int size() { return _buf.size(); } /// /// Determines whether the stream is empty. /// /// True if the internal buffer has no data, false otherwise. public bool isEmpty() { return _buf.empty(); } private bool readOptImpl(int readTag, 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; } OptionalFormat format = (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 MarshalException("invalid optional data member `" + tag + "': unexpected format"); } return true; } } } private void skipOptional(OptionalFormat format) { switch(format) { case OptionalFormat.F1: { skip(1); break; } case OptionalFormat.F2: { skip(2); break; } case OptionalFormat.F4: { skip(4); break; } case OptionalFormat.F8: { skip(8); break; } case OptionalFormat.Size: { skipSize(); break; } case OptionalFormat.VSize: { skip(readSize()); break; } case OptionalFormat.FSize: { skip(readInt()); break; } case OptionalFormat.Class: { readValue(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; } OptionalFormat format = (OptionalFormat)(v & 0x07); // Read first 3 bits. if((v >> 3) == 30) { skipSize(); } skipOptional(format); } } private UserException createUserException(string id) { UserException userEx = null; try { if(_classResolver != null) { Type c = _classResolver(id); if(c != null) { Debug.Assert(!c.IsAbstract && !c.IsInterface); userEx = (UserException)IceInternal.AssemblyUtil.createInstance(c); } } } catch(Exception ex) { throw new 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, ValueSlice, ExceptionSlice } abstract private class EncapsDecoder { protected struct PatchEntry { public PatchEntry(System.Action cb, int classGraphDepth) { this.cb = cb; this.classGraphDepth = classGraphDepth; } public System.Action cb; public int classGraphDepth; }; internal EncapsDecoder(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func cr) { _stream = stream; _encaps = encaps; _sliceValues = sliceValues; _classGraphDepthMax = classGraphDepthMax; _classGraphDepth = 0; _valueFactoryManager = f; _classResolver = cr; _typeIdIndex = 0; _unmarshaledMap = new Dictionary(); } internal abstract void readValue(System.Action cb); internal abstract void throwException(UserExceptionFactory factory); internal abstract void startInstance(SliceType type); internal abstract SlicedData endInstance(bool preserve); internal abstract string startSlice(); internal abstract void endSlice(); internal abstract void skipSlice(); internal virtual bool readOptional(int tag, OptionalFormat format) { return false; } internal virtual void readPendingValues() { } protected string readTypeId(bool isIndex) { if(_typeIdMap == null) { _typeIdMap = new Dictionary(); } if(isIndex) { int index = _stream.readSize(); string typeId; if(!_typeIdMap.TryGetValue(index, out typeId)) { throw new 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(); // 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 Value newInstance(string typeId) { // // Try to find a factory registered for the specific type. // var userFactory = _valueFactoryManager.find(typeId); Value 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 = (Value)IceInternal.AssemblyUtil.createInstance(cls); } catch(Exception ex) { throw new NoValueFactoryException("no value factory", typeId, ex); } } } return v; } protected void addPatchEntry(int index, System.Action cb) { Debug.Assert(index > 0); // // Check if we already unmarshaled the instance. If that's the case, // just call the callback and we're done. // Value obj; if(_unmarshaledMap.TryGetValue(index, out obj)) { cb(obj); return; } if(_patchMap == null) { _patchMap = new Dictionary>(); } // // Add patch entry if the instance isn't unmarshaled yet, // the callback will be called when the instance is // unmarshaled. // LinkedList 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(); _patchMap.Add(index, l); } // // Append a patch entry for this instance. // l.AddLast(new PatchEntry(cb, _classGraphDepth)); } protected void unmarshal(int index, Value v) { // // Add the instance to the map of unmarshaled instances, this must // be done before reading the instances (for circular references). // _unmarshaledMap.Add(index, v); // // Read the instance. // v.iceRead(_stream); if(_patchMap != null) { // // Patch all instances now that the instance is unmarshaled. // LinkedList l; if(_patchMap.TryGetValue(index, out l)) { Debug.Assert(l.Count > 0); // // Patch all pointers that refer to the instance. // foreach(PatchEntry entry in l) { entry.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) && _valueList == 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(_valueList == null) { _valueList = new List(); } _valueList.Add(v); if(_patchMap == null || _patchMap.Count == 0) { // // Iterate over the instance list and invoke ice_postUnmarshal on // each instance. We must do this after all instances have been // unmarshaled in order to ensure that any instance data members // have been properly patched. // foreach(var p in _valueList) { try { p.ice_postUnmarshal(); } catch(System.Exception ex) { string s = "exception raised by ice_postUnmarshal:\n" + ex; _stream.instance().initializationData().logger.warning(s); } } _valueList.Clear(); } } } protected readonly InputStream _stream; protected readonly Encaps _encaps; protected readonly bool _sliceValues; protected readonly int _classGraphDepthMax; protected int _classGraphDepth; protected ValueFactoryManager _valueFactoryManager; protected System.Func _classResolver; // // Encapsulation attributes for object unmarshaling. // protected Dictionary> _patchMap; private Dictionary _unmarshaledMap; private Dictionary _typeIdMap; private int _typeIdIndex; private List _valueList; private Dictionary _typeIdCache; } private sealed class EncapsDecoder10 : EncapsDecoder { internal EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func cr) : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) { _sliceType = SliceType.NoSlice; } internal override void readValue(System.Action 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 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 instances 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) { UserException userEx = null; // // Use a factory if one was provided. // if(factory != null) { try { factory(_typeId); } catch(UserException ex) { userEx = ex; } } if(userEx == null) { userEx = _stream.createUserException(_typeId); } // // We found the exception. // if(userEx != null) { userEx.iceRead(_stream); if(usesClasses) { readPendingValues(); } throw userEx; // Never reached. } // // Slice off what we don't understand. // skipSlice(); try { startSlice(); } catch(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; } } } internal override void startInstance(SliceType sliceType) { Debug.Assert(_sliceType == sliceType); _skipFirstSlice = true; } internal override SlicedData endInstance(bool preserve) { // // Read the Ice::Object slice. // if(_sliceType == SliceType.ValueSlice) { startSlice(); int sz = _stream.readSize(); // For compatibility with the old AFM. if(sz != 0) { throw new 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 instances, 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.ValueSlice) // 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 UnmarshalOutOfBoundsException(); } return _typeId; } internal override void endSlice() { } internal override void skipSlice() { if(_stream.instance().traceLevels().slicing > 0) { Logger logger = _stream.instance().initializationData().logger; string slicingCat = _stream.instance().traceLevels().slicingCat; if(_sliceType == SliceType.ValueSlice) { 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 readPendingValues() { 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 instance, but failed // to supply the instance. // throw new MarshalException("index for class received, but no instance"); } } private void readInstance() { int index = _stream.readInt(); if(index <= 0) { throw new MarshalException("invalid object id"); } _sliceType = SliceType.ValueSlice; _skipFirstSlice = false; // // Read the first slice header. // startSlice(); string mostDerivedId = _typeId; Value v = null; while(true) { // // For the 1.0 encoding, the type ID for the base Object class // marks the last slice. // if(_typeId.Equals(Value.ice_staticId())) { throw new NoValueFactoryException("", mostDerivedId); } v = newInstance(_typeId); // // We found a factory, we get out of this loop. // if(v != null) { break; } // // If slicing is disabled, stop unmarshaling. // if(!_sliceValues) { throw new NoValueFactoryException("no value factory found and slicing is disabled", _typeId); } // // Slice off what we don't understand. // skipSlice(); startSlice(); // Read next Slice header for next iteration. } // // Compute the biggest class graph depth of this object. To compute this, // we get the class graph depth of each ancestor from the patch map and // keep the biggest one. // _classGraphDepth = 0; LinkedList l; if(_patchMap != null && _patchMap.TryGetValue(index, out l)) { Debug.Assert(l.Count > 0); foreach(PatchEntry entry in l) { if(entry.classGraphDepth > _classGraphDepth) { _classGraphDepth = entry.classGraphDepth; } } } if(++_classGraphDepth > _classGraphDepthMax) { throw new MarshalException("maximum class graph depth reached"); } // // Unmarshal the instance and add it to the map of unmarshaled instances. // 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 sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func cr, System.Func r) : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) { _compactIdResolver = r; _current = null; _valueIdIndex = 1; } internal override void readValue(System.Action cb) { int index = _stream.readSize(); if(index < 0) { throw new 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 instance within a slice and there's an // indirect instance table, always read an indirect reference // that points to an instance from the indirect instance 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 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) { UserException userEx = null; // // Use a factory if one was provided. // if(factory != null) { try { factory(_current.typeId); } catch(UserException ex) { userEx = ex; } } if(userEx == null) { userEx = _stream.createUserException(_current.typeId); } // // We found the exception. // if(userEx != null) { userEx.iceRead(_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 UnknownUserException(mostDerivedId.Substring(2)); } else { throw new UnknownUserException(mostDerivedId); } } startSlice(); } } internal override void startInstance(SliceType sliceType) { Debug.Assert(_current.sliceType == sliceType); _current.skipFirstSlice = true; } internal override SlicedData endInstance(bool preserve) { 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 instance 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.ValueSlice) { // // 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 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 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 instance references were read if they are from // unknown optional data members. // if(indirectionTable.Length == 0) { throw new MarshalException("empty indirection table"); } if((_current.indirectPatchList == null || _current.indirectPatchList.Count == 0) && (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0) { throw new 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 MarshalException("indirection out of range"); } addPatchEntry(indirectionTable[e.index], e.patcher); } _current.indirectPatchList.Clear(); } } } internal override void skipSlice() { if(_stream.instance().traceLevels().slicing > 0) { 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.ValueSlice) { 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 UnknownUserException(_current.typeId.Substring(2)); } else { throw new UnknownUserException(_current.typeId); } } } // // Preserve this slice. // SliceInfo info = new 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(); _current.indirectionTables = new List(); } // // Read the indirect instance table. We read the instances or their // IDs if the instance is a reference to an already unmarshaled // instance. // 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, 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, System.Action cb) { Debug.Assert(index > 0); if(index > 1) { if(cb != null) { addPatchEntry(index, cb); } return index; } push(SliceType.ValueSlice); // // Get the instance ID before we start reading slices. If some // slices are skipped, the indirect instance table are still read and // might read other instances. // index = ++_valueIdIndex; // // Read the first slice header. // startSlice(); string mostDerivedId = _current.typeId; Value 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(); // 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 = (Value)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(LocalException) { throw; } catch(System.Exception ex) { throw new 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 slicing is disabled, stop unmarshaling. // if(!_sliceValues) { throw new NoValueFactoryException("no value factory found and slicing is disabled", _current.typeId); } // // Slice off what we don't understand. // skipSlice(); // // If this is the last slice, keep the instance as an opaque // UnknownSlicedValue object. // if((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0) { // // Provide a factory with an opportunity to supply the instance. // We pass the "::Ice::Object" ID to indicate that this is the // last chance to preserve the instance. // v = newInstance(Value.ice_staticId()); if(v == null) { v = new UnknownSlicedValue(mostDerivedId); } break; } startSlice(); // Read next Slice header for next iteration. } if(++_classGraphDepth > _classGraphDepthMax) { throw new MarshalException("maximum class graph depth reached"); } // // Unmarshal the instance. // unmarshal(index, v); --_classGraphDepth; if(_current == null && _patchMap != null && _patchMap.Count > 0) { // // If any entries remain in the patch map, the sender has sent an index for an instance, but failed // to supply the instance. // throw new MarshalException("index for class received, but no instance"); } if(cb != null) { cb(v); } return index; } private 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 "instances" list in SliceInfo to hold references // to the target instances. Note that the instances might not have // been read yet in the case of a circular reference to an // enclosing instance. // int[] table = _current.indirectionTables[n]; SliceInfo info = _current.slices[n]; info.instances = new Value[table != null ? table.Length : 0]; for(int j = 0; j < info.instances.Length; ++j) { var cj = j; addPatchEntry(table[j], (Ice.Value v) => info.instances[cj] = v); } } return new 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 System.Action 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 slices; // Preserved slices. internal List indirectionTables; // Slice attributes internal byte sliceFlags; internal int sliceSize; internal string typeId; internal int compactId; internal Stack indirectPatchList; internal InstanceData previous; internal InstanceData next; } private System.Func _compactIdResolver; private InstanceData _current; private int _valueIdIndex; // The ID of the next instance to unmarshal. private Dictionary _compactIdCache; } private sealed class Encaps { internal void reset() { decoder = null; } internal void setEncoding(EncodingVersion encoding) { this.encoding = encoding; encoding_1_0 = encoding.Equals(Util.Encoding_1_0); } internal int start; internal int sz; internal 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 EncodingVersion _encoding; private bool isEncoding_1_0() { return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(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, _sliceValues, _classGraphDepthMax, _valueFactoryManager, _classResolver); } else { _encapsStack.decoder = new EncapsDecoder11(this, _encapsStack, _sliceValues, _classGraphDepthMax, _valueFactoryManager, _classResolver, _compactIdResolver); } } } private bool _sliceValues; private bool _traceSlicing; private int _classGraphDepthMax; private int _startSeq; private int _minSeqSize; private ValueFactoryManager _valueFactoryManager; private Logger _logger; private System.Func _compactIdResolver; private System.Func _classResolver; } /// /// Base class for extracting class instances from an input stream. /// public abstract class ValueReader : Value { /// /// Read the instance's data members. /// /// The input stream to read from. public abstract void read(InputStream inStream); public override void iceWrite(OutputStream os) { Debug.Assert(false); } public override void iceRead(InputStream istr) { read(istr); } } }