< Summary

Information
Class: Ice.InputStream<T>
Assembly: Ice
File(s): /_/csharp/src/Ice/InputStream.cs
Tag: 105_25977636357
Line coverage
86%
Covered lines: 745
Uncovered lines: 121
Coverable lines: 866
Total lines: 3009
Line coverage: 86%
Branch coverage
85%
Covered branches: 312
Total branches: 364
Branch coverage: 85.7%
Method coverage
97%
Covered methods: 146
Fully covered methods: 93
Total methods: 149
Method coverage: 97.9%
Full method coverage: 62.4%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
reset()100%11100%
clear()100%22100%
instance()100%11100%
swap(...)100%11100%
resetEncapsulation()100%11100%
resize(...)100%11100%
getBuffer()100%11100%
startValue()100%11100%
endValue()100%11100%
startException()100%11100%
endException()100%11100%
startEncapsulation()66.67%6688.89%
endEncapsulation()50%12858.82%
skipEmptyEncapsulation()62.5%9875%
readEncapsulation(...)50%4469.23%
getEncoding()100%22100%
getEncapsulationSize()100%210%
skipEncapsulation()50%2266.67%
startSlice()100%11100%
endSlice()100%11100%
skipSlice()100%11100%
readPendingValues()87.5%88100%
readSize()75%4470%
readAndCheckSeqSize(...)87.5%8890%
readBlob(...)100%210%
readBlob(...)50%2262.5%
readOptional(...)100%22100%
readByte()100%1150%
readByte(...)100%22100%
readByteSeq()100%1171.43%
readByteSeq(...)100%11100%
readByteSeq(...)100%11100%
readByteSeq(...)100%11100%
readByteSeq(...)100%11100%
readByteSeq(...)100%22100%
readBool()100%11100%
readBool(...)100%22100%
readBoolSeq()100%1171.43%
readBoolSeq(...)100%11100%
readBoolSeq(...)100%11100%
readBoolSeq(...)100%11100%
readBoolSeq(...)100%11100%
readBoolSeq(...)100%22100%
readShort()100%1150%
readShort(...)100%22100%
readShortSeq()100%1171.43%
readShortSeq(...)100%11100%
readShortSeq(...)100%11100%
readShortSeq(...)100%11100%
readShortSeq(...)100%11100%
readShortSeq(...)0%620%
readInt()100%1150%
readInt(...)100%22100%
readIntSeq()100%1171.43%
readIntSeq(...)100%11100%
readIntSeq(...)100%2275%
readIntSeq(...)100%2275%
readIntSeq(...)100%11100%
readIntSeq(...)100%22100%
readLong()100%1150%
readLong(...)100%22100%
readLongSeq()100%1171.43%
readLongSeq(...)100%11100%
readLongSeq(...)100%2275%
readLongSeq(...)100%2275%
readLongSeq(...)100%11100%
readLongSeq(...)100%22100%
readFloat()100%1150%
readFloat(...)100%22100%
readFloatSeq()100%1171.43%
readFloatSeq(...)100%11100%
readFloatSeq(...)100%2275%
readFloatSeq(...)100%2275%
readFloatSeq(...)100%11100%
readFloatSeq(...)100%22100%
readDouble()100%1150%
readDouble(...)100%22100%
readDoubleSeq()100%1171.43%
readDoubleSeq(...)100%11100%
readDoubleSeq(...)100%2275%
readDoubleSeq(...)100%2275%
readDoubleSeq(...)100%11100%
readDoubleSeq(...)100%22100%
.cctor()100%11100%
readString()87.5%11864.29%
readString(...)100%22100%
readStringSeq()100%22100%
readStringSeq(...)100%22100%
readStringSeq(...)100%22100%
readStringSeq(...)100%22100%
readStringSeq(...)100%11100%
readStringSeq(...)100%22100%
readProxy()100%22100%
readProxy(...)50%3250%
readEnum(...)100%66100%
readValue<T>(...)100%11100%
readValue(...)100%11100%
throwException()100%1166.67%
skip(...)50%4475%
skipSize()100%22100%
pos()100%11100%
pos(...)100%11100%
size()100%11100%
isEmpty()100%11100%
readOptImpl(...)80%212086.96%
skipOptional(...)100%1193.33%
skipOptionals()100%66100%
createUserException(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
readOptional(...)100%11100%
readPendingValues()100%11100%
readTypeId(...)83.33%6688.89%
newInstance(...)100%11100%
addPatchEntry(...)100%66100%
unmarshal(...)100%2020100%
.ctor(...)100%11100%
readValue(...)75%4487.5%
throwException()100%4487.5%
startInstance(...)100%11100%
endInstance()75%4487.5%
startSlice()83.33%6690.91%
endSlice()100%11100%
skipSlice()25%8437.5%
readPendingValues()87.5%8885.71%
readInstance()93.75%161695.83%
.ctor(...)100%11100%
readValue(...)90%101090.91%
throwException()75%4491.67%
startInstance(...)100%11100%
endInstance()100%44100%
startSlice()91.67%121295.45%
endSlice()70%222083.33%
skipSlice()80%222082.93%
readOptional(...)75%4480%
readInstance(...)95.45%222296.3%
readSlicedData()100%88100%
push(...)100%44100%
.ctor(...)100%11100%
.ctor(...)100%22100%
reset()100%11100%
setEncoding(...)100%11100%
isEncoding_1_0()50%22100%
initEncaps()87.5%8892.86%

File(s)

/_/csharp/src/Ice/InputStream.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3#nullable enable
 4
 5using Ice.Internal;
 6using System.Diagnostics;
 7using System.Globalization;
 8using Protocol = Ice.Internal.Protocol;
 9
 10namespace Ice;
 11
 12/// <summary>
 13/// Interface for input streams used to extract Slice types from a sequence of bytes.
 14/// </summary>
 15public sealed class InputStream
 16{
 17    /// <summary>
 18    /// Initializes a new instance of the <see cref="InputStream" /> class. This constructor uses the communicator's
 19    /// default encoding version.
 20    /// </summary>
 21    /// <param name="communicator">The communicator to use when unmarshaling classes, exceptions and proxies.</param>
 22    /// <param name="data">The byte array containing encoded Slice types.</param>
 23    public InputStream(Communicator communicator, byte[] data)
 124        : this(
 125            communicator.instance,
 126            communicator.instance.defaultsAndOverrides().defaultEncoding,
 127            new Internal.Buffer(data))
 28    {
 129    }
 30
 31    /// <summary>
 32    /// Initializes a new instance of the <see cref="InputStream" /> class.
 33    /// </summary>
 34    /// <param name="communicator">The communicator to use when unmarshaling classes, exceptions and proxies.</param>
 35    /// <param name="encoding">The desired encoding version.</param>
 36    /// <param name="data">The byte array containing encoded Slice types.</param>
 37    public InputStream(Communicator communicator, EncodingVersion encoding, byte[] data)
 138        : this(communicator.instance, encoding, new Internal.Buffer(data))
 39    {
 140    }
 41
 42    /// <summary>
 43    /// Initializes a new instance of the <see cref="InputStream" /> class with an empty buffer.
 44    /// <param name="instance">The communicator instance.</param>
 45    /// <param name="encoding">The desired encoding version.</param>
 46    /// </summary>
 47    internal InputStream(Instance instance, EncodingVersion encoding)
 148        : this(instance, encoding, new Internal.Buffer())
 49    {
 150    }
 51
 52    /// <summary>
 53    /// Initializes a new instance of the <see cref="InputStream" /> class while adopting or borrowing the underlying
 54    /// buffer.
 55    /// </summary>
 56    internal InputStream(Instance instance, EncodingVersion encoding, Internal.Buffer buf, bool adopt)
 157        : this(instance, encoding, new Internal.Buffer(buf, adopt))
 58    {
 159    }
 60
 61    /// <summary>
 62    /// Initializes a new instance of the <see cref="InputStream" /> class. All other constructors delegate to this
 63    /// constructor.
 64    /// </summary>
 165    private InputStream(Instance instance, EncodingVersion encoding, Internal.Buffer buf)
 66    {
 167        _encoding = encoding;
 168        _instance = instance;
 169        _buf = buf;
 170        _classGraphDepthMax = _instance.classGraphDepthMax();
 171    }
 72
 73    /// <summary>
 74    /// Resets this stream. This method allows the stream to be reused, to avoid creating unnecessary garbage.
 75    /// </summary>
 76    public void reset()
 77    {
 178        _buf.reset();
 179        clear();
 180    }
 81
 82    /// <summary>
 83    /// Releases any data retained by encapsulations. Internally calls clear().
 84    /// </summary>
 85    public void clear()
 86    {
 187        if (_encapsStack != null)
 88        {
 89            Debug.Assert(_encapsStack.next == null);
 190            _encapsStack.next = _encapsCache;
 191            _encapsCache = _encapsStack;
 192            _encapsStack = null;
 193            _encapsCache.reset();
 94        }
 95
 196        _startSeq = -1;
 197    }
 98
 199    internal Instance instance() => _instance;
 100
 101    /// <summary>
 102    /// Swaps the contents of one stream with another.
 103    /// </summary>
 104    /// <param name="other">The other stream.</param>
 105    public void swap(InputStream other)
 106    {
 107        Debug.Assert(_instance == other._instance);
 108
 1109        Internal.Buffer tmpBuf = other._buf;
 1110        other._buf = _buf;
 1111        _buf = tmpBuf;
 112
 1113        EncodingVersion tmpEncoding = other._encoding;
 1114        other._encoding = _encoding;
 1115        _encoding = tmpEncoding;
 116
 1117        int tmpStartSeq = other._startSeq;
 1118        other._startSeq = _startSeq;
 1119        _startSeq = tmpStartSeq;
 120
 1121        int tmpMinSeqSize = other._minSeqSize;
 1122        other._minSeqSize = _minSeqSize;
 1123        _minSeqSize = tmpMinSeqSize;
 124
 125        // Swap is never called for InputStreams that have encapsulations being read. However,
 126        // encapsulations might still be set in case un-marshaling failed. We just
 127        // reset the encapsulations if there are still some set.
 1128        resetEncapsulation();
 1129        other.resetEncapsulation();
 1130    }
 131
 1132    private void resetEncapsulation() => _encapsStack = null;
 133
 134    /// <summary>
 135    /// Resizes the stream to a new size.
 136    /// </summary>
 137    /// <param name="sz">The new size.</param>
 138    internal void resize(int sz)
 139    {
 1140        _buf.resize(sz, true);
 1141        _buf.b.position(sz);
 1142    }
 143
 1144    internal Internal.Buffer getBuffer() => _buf;
 145
 146    /// <summary>
 147    /// Marks the start of a class instance.
 148    /// </summary>
 149    public void startValue()
 150    {
 151        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1152        _encapsStack.decoder.startInstance(SliceType.ValueSlice);
 1153    }
 154
 155    /// <summary>
 156    /// Marks the end of a class instance.
 157    /// </summary>
 158    /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns>
 159    public SlicedData? endValue()
 160    {
 161        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1162        return _encapsStack.decoder.endInstance();
 163    }
 164
 165    /// <summary>
 166    /// Marks the start of a user exception.
 167    /// </summary>
 168    public void startException()
 169    {
 170        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1171        _encapsStack.decoder.startInstance(SliceType.ExceptionSlice);
 1172    }
 173
 174    /// <summary>
 175    /// Marks the end of a user exception.
 176    /// </summary>
 177    public void endException()
 178    {
 179        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1180        _encapsStack.decoder.endInstance();
 1181    }
 182
 183    /// <summary>
 184    /// Reads the start of an encapsulation.
 185    /// </summary>
 186    /// <returns>The encapsulation encoding version.</returns>
 187    public EncodingVersion startEncapsulation()
 188    {
 1189        Encaps? curr = _encapsCache;
 1190        if (curr != null)
 191        {
 1192            curr.reset();
 1193            _encapsCache = _encapsCache!.next;
 194        }
 195        else
 196        {
 1197            curr = new Encaps();
 198        }
 1199        curr.next = _encapsStack;
 1200        _encapsStack = curr;
 201
 1202        _encapsStack.start = _buf.b.position();
 203
 204        //
 205        // I don't use readSize() for encapsulations, because when creating an encapsulation,
 206        // I must know in advance how many bytes the size information will require in the data
 207        // stream. If I use an Int, it is always 4 bytes. For readSize(), it could be 1 or 5 bytes.
 208        //
 1209        int sz = readInt();
 1210        if (sz < 6)
 211        {
 0212            throw new MarshalException(endOfBufferMessage);
 213        }
 1214        if (sz - 4 > _buf.b.remaining())
 215        {
 0216            throw new MarshalException(endOfBufferMessage);
 217        }
 1218        _encapsStack.sz = sz;
 219
 1220        var encoding = new EncodingVersion(this);
 1221        Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
 1222        _encapsStack.setEncoding(encoding);
 223
 1224        return encoding;
 225    }
 226
 227    /// <summary>
 228    /// Ends the previous encapsulation.
 229    /// </summary>
 230    public void endEncapsulation()
 231    {
 232        Debug.Assert(_encapsStack != null);
 233
 1234        if (!_encapsStack.encoding_1_0)
 235        {
 1236            skipOptionals();
 1237            if (_buf.b.position() != _encapsStack.start + _encapsStack.sz)
 238            {
 0239                throw new MarshalException("Failed to unmarshal encapsulation.");
 240            }
 241        }
 1242        else if (_buf.b.position() != _encapsStack.start + _encapsStack.sz)
 243        {
 0244            if (_buf.b.position() + 1 != _encapsStack.start + _encapsStack.sz)
 245            {
 0246                throw new MarshalException("Failed to unmarshal encapsulation.");
 247            }
 248
 249            //
 250            // Ice version < 3.3 had a bug where user exceptions with
 251            // class members could be encoded with a trailing byte
 252            // when dispatched with AMD. So we tolerate an extra byte
 253            // in the encapsulation.
 254            //
 255            try
 256            {
 0257                _buf.b.get();
 0258            }
 0259            catch (InvalidOperationException ex)
 260            {
 0261                throw new MarshalException(endOfBufferMessage, ex);
 262            }
 263        }
 264
 1265        Encaps curr = _encapsStack;
 1266        _encapsStack = curr.next;
 1267        curr.next = _encapsCache;
 1268        _encapsCache = curr;
 1269        _encapsCache.reset();
 1270    }
 271
 272    /// <summary>
 273    /// Skips an empty encapsulation.
 274    /// </summary>
 275    /// <returns>The encapsulation's encoding version.</returns>
 276    public EncodingVersion skipEmptyEncapsulation()
 277    {
 1278        int sz = readInt();
 1279        if (sz < 6)
 280        {
 0281            throw new MarshalException($"{sz} is not a valid encapsulation size.");
 282        }
 1283        if (sz - 4 > _buf.b.remaining())
 284        {
 0285            throw new MarshalException(endOfBufferMessage);
 286        }
 287
 1288        var encoding = new EncodingVersion(this);
 1289        Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
 290
 1291        if (encoding.Equals(Util.Encoding_1_0))
 292        {
 1293            if (sz != 6)
 294            {
 0295                throw new MarshalException($"{sz} is not a valid encapsulation size for a 1.0 empty encapsulation.");
 296            }
 297        }
 298        else
 299        {
 300            // Skip the optional content of the encapsulation if we are expecting an
 301            // empty encapsulation.
 1302            _buf.b.position(_buf.b.position() + sz - 6);
 303        }
 1304        return encoding;
 305    }
 306
 307    /// <summary>
 308    /// Returns a blob of bytes representing an encapsulation. The encapsulation's encoding version
 309    /// is returned in the argument.
 310    /// </summary>
 311    /// <param name="encoding">The encapsulation's encoding version.</param>
 312    /// <returns>The encoded encapsulation.</returns>
 313    public byte[] readEncapsulation(out EncodingVersion encoding)
 314    {
 1315        int sz = readInt();
 1316        if (sz < 6)
 317        {
 0318            throw new MarshalException(endOfBufferMessage);
 319        }
 320
 1321        if (sz - 4 > _buf.b.remaining())
 322        {
 0323            throw new MarshalException(endOfBufferMessage);
 324        }
 325
 1326        encoding = new EncodingVersion(this);
 1327        _buf.b.position(_buf.b.position() - 6);
 328
 1329        byte[] v = new byte[sz];
 330        try
 331        {
 1332            _buf.b.get(v);
 1333            return v;
 334        }
 0335        catch (InvalidOperationException ex)
 336        {
 0337            throw new MarshalException(endOfBufferMessage, ex);
 338        }
 1339    }
 340
 341    /// <summary>
 342    /// Determines the current encoding version.
 343    /// </summary>
 344    /// <returns>The encoding version.</returns>
 1345    public EncodingVersion getEncoding() => _encapsStack != null ? _encapsStack.encoding : _encoding;
 346
 347    /// <summary>
 348    /// Determines the size of the current encapsulation, excluding the encapsulation header.
 349    /// </summary>
 350    /// <returns>The size of the encapsulated data.</returns>
 351    public int getEncapsulationSize()
 352    {
 353        Debug.Assert(_encapsStack != null);
 0354        return _encapsStack.sz - 6;
 355    }
 356
 357    /// <summary>
 358    /// Skips over an encapsulation.
 359    /// </summary>
 360    /// <returns>The encoding version of the skipped encapsulation.</returns>
 361    public EncodingVersion skipEncapsulation()
 362    {
 1363        int sz = readInt();
 1364        if (sz < 6)
 365        {
 0366            throw new MarshalException(endOfBufferMessage);
 367        }
 1368        var encoding = new EncodingVersion(this);
 369        try
 370        {
 1371            _buf.b.position(_buf.b.position() + sz - 6);
 1372        }
 0373        catch (ArgumentOutOfRangeException ex)
 374        {
 0375            throw new MarshalException(endOfBufferMessage, ex);
 376        }
 1377        return encoding;
 378    }
 379
 380    /// <summary>
 381    /// Reads the start of a class instance or exception slice.
 382    /// </summary>
 383    public void startSlice()
 384    {
 385        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1386        _encapsStack.decoder.startSlice();
 1387    }
 388
 389    /// <summary>
 390    /// Indicates that the end of a class instance or exception slice has been reached.
 391    /// </summary>
 392    public void endSlice()
 393    {
 394        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1395        _encapsStack.decoder.endSlice();
 1396    }
 397
 398    /// <summary>
 399    /// Skips over a class instance or exception slice.
 400    /// </summary>
 401    public void skipSlice()
 402    {
 403        Debug.Assert(_encapsStack != null && _encapsStack.decoder != null);
 1404        _encapsStack.decoder.skipSlice();
 1405    }
 406
 407    /// <summary>
 408    /// Indicates that unmarshaling is complete, except for any class instances. The application must call this
 409    /// method only if the stream actually contains class instances. Calling readPendingValues triggers the
 410    /// calls to the System.Action delegates to inform the application that unmarshaling of an instance
 411    /// is complete.
 412    /// </summary>
 413    public void readPendingValues()
 414    {
 1415        if (_encapsStack != null && _encapsStack.decoder != null)
 416        {
 1417            _encapsStack.decoder.readPendingValues();
 418        }
 1419        else if (_encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0))
 420        {
 421            //
 422            // If using the 1.0 encoding and no instances were read, we
 423            // still read an empty sequence of pending instances if
 424            // requested (i.e.: if this is called).
 425            //
 426            // This is required by the 1.0 encoding, even if no instances
 427            // are written we do marshal an empty sequence if marshaled
 428            // data types use classes.
 429            //
 1430            skipSize();
 431        }
 1432    }
 433
 434    /// <summary>
 435    /// Extracts a size from the stream.
 436    /// </summary>
 437    /// <returns>The extracted size.</returns>
 438    public int readSize()
 439    {
 440        try
 441        {
 1442            byte b = _buf.b.get();
 1443            if (b == 255)
 444            {
 1445                int v = _buf.b.getInt();
 1446                if (v < 0)
 447                {
 0448                    throw new MarshalException(endOfBufferMessage);
 449                }
 1450                return v;
 451            }
 452            else
 453            {
 1454                return b; // byte is unsigned
 455            }
 456        }
 0457        catch (InvalidOperationException ex)
 458        {
 0459            throw new MarshalException(endOfBufferMessage, ex);
 460        }
 1461    }
 462
 463    /// <summary>
 464    /// Reads and validates a sequence size.
 465    /// </summary>
 466    /// <param name="minSize">The minimum size required to encode a sequence element.</param>
 467    /// <returns>The extracted size.</returns>
 468    public int readAndCheckSeqSize(int minSize)
 469    {
 1470        int sz = readSize();
 471
 1472        if (sz == 0)
 473        {
 1474            return 0;
 475        }
 476
 477        //
 478        // The _startSeq variable points to the start of the sequence for which
 479        // we expect to read at least _minSeqSize bytes from the stream.
 480        //
 481        // If not initialized or if we already read more data than _minSeqSize,
 482        // we reset _startSeq and _minSeqSize for this sequence (possibly a
 483        // top-level sequence or enclosed sequence it doesn't really matter).
 484        //
 485        // Otherwise, we are reading an enclosed sequence and we have to bump
 486        // _minSeqSize by the minimum size that this sequence will require on
 487        // the stream.
 488        //
 489        // The goal of this check is to ensure that when we start un-marshaling
 490        // a new sequence, we check the minimal size of this new sequence against
 491        // the estimated remaining buffer size. This estimation is based on
 492        // the minimum size of the enclosing sequences, it's _minSeqSize.
 493        //
 1494        if (_startSeq == -1 || _buf.b.position() > (_startSeq + _minSeqSize))
 495        {
 1496            _startSeq = _buf.b.position();
 1497            _minSeqSize = sz * minSize;
 498        }
 499        else
 500        {
 1501            _minSeqSize += sz * minSize;
 502        }
 503
 504        //
 505        // If there isn't enough data to read on the stream for the sequence (and
 506        // possibly enclosed sequences), something is wrong with the marshaled
 507        // data: it's claiming having more data that what is possible to read.
 508        //
 1509        if (_startSeq + _minSeqSize > _buf.size())
 510        {
 0511            throw new MarshalException(endOfBufferMessage);
 512        }
 513
 1514        return sz;
 515    }
 516
 517    /// <summary>
 518    /// Reads a blob of bytes from the stream. The length of the given array determines how many bytes are read.
 519    /// </summary>
 520    /// <param name="v">Bytes from the stream.</param>
 521    public void readBlob(byte[] v)
 522    {
 523        try
 524        {
 0525            _buf.b.get(v);
 0526        }
 0527        catch (InvalidOperationException ex)
 528        {
 0529            throw new MarshalException(endOfBufferMessage, ex);
 530        }
 0531    }
 532
 533    /// <summary>
 534    /// Reads a blob of bytes from the stream.
 535    /// </summary>
 536    /// <param name="sz">The number of bytes to read.</param>
 537    /// <returns>The requested bytes as a byte array.</returns>
 538    public byte[] readBlob(int sz)
 539    {
 1540        if (_buf.b.remaining() < sz)
 541        {
 0542            throw new MarshalException(endOfBufferMessage);
 543        }
 1544        byte[] v = new byte[sz];
 545        try
 546        {
 1547            _buf.b.get(v);
 1548            return v;
 549        }
 0550        catch (InvalidOperationException ex)
 551        {
 0552            throw new MarshalException(endOfBufferMessage, ex);
 553        }
 1554    }
 555
 556    /// <summary>
 557    /// Determine if an optional value is available for reading.
 558    /// </summary>
 559    /// <param name="tag">The tag associated with the value.</param>
 560    /// <param name="expectedFormat">The optional format for the value.</param>
 561    /// <returns><see langword="true"/> if the value is present, <see langword="false"/> otherwise.</returns>
 562    public bool readOptional(int tag, OptionalFormat expectedFormat)
 563    {
 564        Debug.Assert(_encapsStack != null);
 1565        if (_encapsStack.decoder != null)
 566        {
 1567            return _encapsStack.decoder.readOptional(tag, expectedFormat);
 568        }
 569        else
 570        {
 1571            return readOptImpl(tag, expectedFormat);
 572        }
 573    }
 574
 575    /// <summary>
 576    /// Extracts a byte value from the stream.
 577    /// </summary>
 578    /// <returns>The extracted byte.</returns>
 579    public byte readByte()
 580    {
 581        try
 582        {
 1583            return _buf.b.get();
 584        }
 0585        catch (InvalidOperationException ex)
 586        {
 0587            throw new MarshalException(endOfBufferMessage, ex);
 588        }
 1589    }
 590
 591    /// <summary>
 592    /// Extracts an optional byte value from the stream.
 593    /// </summary>
 594    /// <param name="tag">The numeric tag associated with the value.</param>
 595    /// <returns>The optional value.</returns>
 596    public byte? readByte(int tag)
 597    {
 1598        if (readOptional(tag, OptionalFormat.F1))
 599        {
 1600            return readByte();
 601        }
 602        else
 603        {
 1604            return null;
 605        }
 606    }
 607
 608    /// <summary>
 609    /// Extracts a sequence of byte values from the stream.
 610    /// </summary>
 611    /// <returns>The extracted byte sequence.</returns>
 612    public byte[] readByteSeq()
 613    {
 614        try
 615        {
 1616            int sz = readAndCheckSeqSize(1);
 1617            byte[] v = new byte[sz];
 1618            _buf.b.get(v);
 1619            return v;
 620        }
 0621        catch (InvalidOperationException ex)
 622        {
 0623            throw new MarshalException(endOfBufferMessage, ex);
 624        }
 1625    }
 626
 627    /// <summary>
 628    /// Extracts a sequence of byte values from the stream.
 629    /// </summary>
 630    /// <param name="l">The extracted byte sequence as a list.</param>
 631    public void readByteSeq(out List<byte> l) =>
 632        //
 633        // Reading into an array and copy-constructing the
 634        // list is faster than constructing the list
 635        // and adding to it one element at a time.
 636        //
 1637        l = new List<byte>(readByteSeq());
 638
 639    /// <summary>
 640    /// Extracts a sequence of byte values from the stream.
 641    /// </summary>
 642    /// <param name="l">The extracted byte sequence as a linked list.</param>
 643    public void readByteSeq(out LinkedList<byte> l) =>
 644        //
 645        // Reading into an array and copy-constructing the
 646        // list is faster than constructing the list
 647        // and adding to it one element at a time.
 648        //
 1649        l = new LinkedList<byte>(readByteSeq());
 650
 651    /// <summary>
 652    /// Extracts a sequence of byte values from the stream.
 653    /// </summary>
 654    /// <param name="l">The extracted byte sequence as a queue.</param>
 655    public void readByteSeq(out Queue<byte> l) =>
 656        //
 657        // Reading into an array and copy-constructing the
 658        // queue is faster than constructing the queue
 659        // and adding to it one element at a time.
 660        //
 1661        l = new Queue<byte>(readByteSeq());
 662
 663    /// <summary>
 664    /// Extracts a sequence of byte values from the stream.
 665    /// </summary>
 666    /// <param name="l">The extracted byte sequence as a stack.</param>
 667    public void readByteSeq(out Stack<byte> l)
 668    {
 669        //
 670        // Reverse the contents by copying into an array first
 671        // because the stack is marshaled in top-to-bottom order.
 672        //
 1673        byte[] array = readByteSeq();
 1674        Array.Reverse(array);
 1675        l = new Stack<byte>(array);
 1676    }
 677
 678    /// <summary>
 679    /// Extracts an optional byte sequence from the stream.
 680    /// </summary>
 681    /// <param name="tag">The numeric tag associated with the value.</param>
 682    /// <returns>The optional value.</returns>
 683    public byte[]? readByteSeq(int tag)
 684    {
 1685        if (readOptional(tag, OptionalFormat.VSize))
 686        {
 1687            return readByteSeq();
 688        }
 689        else
 690        {
 1691            return null;
 692        }
 693    }
 694
 695    /// <summary>
 696    /// Extracts a boolean value from the stream.
 697    /// </summary>
 698    /// <returns>The extracted boolean.</returns>
 699    public bool readBool()
 700    {
 701        try
 702        {
 1703            return _buf.b.get() == 1;
 704        }
 1705        catch (InvalidOperationException ex)
 706        {
 1707            throw new MarshalException(endOfBufferMessage, ex);
 708        }
 1709    }
 710
 711    /// <summary>
 712    /// Extracts an optional boolean value from the stream.
 713    /// </summary>
 714    /// <param name="tag">The numeric tag associated with the value.</param>
 715    /// <returns>The optional value.</returns>
 716    public bool? readBool(int tag)
 717    {
 1718        if (readOptional(tag, OptionalFormat.F1))
 719        {
 1720            return readBool();
 721        }
 722        else
 723        {
 1724            return null;
 725        }
 726    }
 727
 728    /// <summary>
 729    /// Extracts a sequence of boolean values from the stream.
 730    /// </summary>
 731    /// <returns>The extracted boolean sequence.</returns>
 732    public bool[] readBoolSeq()
 733    {
 734        try
 735        {
 1736            int sz = readAndCheckSeqSize(1);
 1737            bool[] v = new bool[sz];
 1738            _buf.b.getBoolSeq(v);
 1739            return v;
 740        }
 0741        catch (InvalidOperationException ex)
 742        {
 0743            throw new MarshalException(endOfBufferMessage, ex);
 744        }
 1745    }
 746
 747    /// <summary>
 748    /// Extracts a sequence of boolean values from the stream.
 749    /// </summary>
 750    /// <param name="l">The extracted boolean sequence as a list.</param>
 751    public void readBoolSeq(out List<bool> l) =>
 752        //
 753        // Reading into an array and copy-constructing the
 754        // list is faster than constructing the list
 755        // and adding to it one element at a time.
 756        //
 1757        l = new List<bool>(readBoolSeq());
 758
 759    /// <summary>
 760    /// Extracts a sequence of boolean values from the stream.
 761    /// </summary>
 762    /// <param name="l">The extracted boolean sequence as a linked list.</param>
 763    public void readBoolSeq(out LinkedList<bool> l) =>
 764        //
 765        // Reading into an array and copy-constructing the
 766        // list is faster than constructing the list
 767        // and adding to it one element at a time.
 768        //
 1769        l = new LinkedList<bool>(readBoolSeq());
 770
 771    /// <summary>
 772    /// Extracts a sequence of boolean values from the stream.
 773    /// </summary>
 774    /// <param name="l">The extracted boolean sequence as a queue.</param>
 775    public void readBoolSeq(out Queue<bool> l) =>
 776        //
 777        // Reading into an array and copy-constructing the
 778        // queue is faster than constructing the queue
 779        // and adding to it one element at a time.
 780        //
 1781        l = new Queue<bool>(readBoolSeq());
 782
 783    /// <summary>
 784    /// Extracts a sequence of boolean values from the stream.
 785    /// </summary>
 786    /// <param name="l">The extracted boolean sequence as a stack.</param>
 787    public void readBoolSeq(out Stack<bool> l)
 788    {
 789        //
 790        // Reverse the contents by copying into an array first
 791        // because the stack is marshaled in top-to-bottom order.
 792        //
 1793        bool[] array = readBoolSeq();
 1794        Array.Reverse(array);
 1795        l = new Stack<bool>(array);
 1796    }
 797
 798    /// <summary>
 799    /// Extracts an optional boolean sequence from the stream.
 800    /// </summary>
 801    /// <param name="tag">The numeric tag associated with the value.</param>
 802    /// <returns>The optional value.</returns>
 803    public bool[]? readBoolSeq(int tag)
 804    {
 1805        if (readOptional(tag, OptionalFormat.VSize))
 806        {
 1807            return readBoolSeq();
 808        }
 809        else
 810        {
 1811            return null;
 812        }
 813    }
 814
 815    /// <summary>
 816    /// Extracts a short value from the stream.
 817    /// </summary>
 818    /// <returns>The extracted short.</returns>
 819    public short readShort()
 820    {
 821        try
 822        {
 1823            return _buf.b.getShort();
 824        }
 0825        catch (InvalidOperationException ex)
 826        {
 0827            throw new MarshalException(endOfBufferMessage, ex);
 828        }
 1829    }
 830
 831    /// <summary>
 832    /// Extracts an optional short value from the stream.
 833    /// </summary>
 834    /// <param name="tag">The numeric tag associated with the value.</param>
 835    /// <returns>The optional value.</returns>
 836    public short? readShort(int tag)
 837    {
 1838        if (readOptional(tag, OptionalFormat.F2))
 839        {
 1840            return readShort();
 841        }
 842        else
 843        {
 1844            return null;
 845        }
 846    }
 847
 848    /// <summary>
 849    /// Extracts a sequence of short values from the stream.
 850    /// </summary>
 851    /// <returns>The extracted short sequence.</returns>
 852    public short[] readShortSeq()
 853    {
 854        try
 855        {
 1856            int sz = readAndCheckSeqSize(2);
 1857            short[] v = new short[sz];
 1858            _buf.b.getShortSeq(v);
 1859            return v;
 860        }
 0861        catch (InvalidOperationException ex)
 862        {
 0863            throw new MarshalException(endOfBufferMessage, ex);
 864        }
 1865    }
 866
 867    /// <summary>
 868    /// Extracts a sequence of short values from the stream.
 869    /// </summary>
 870    /// <param name="l">The extracted short sequence as a list.</param>
 871    public void readShortSeq(out List<short> l) =>
 872        //
 873        // Reading into an array and copy-constructing the
 874        // list is faster than constructing the list
 875        // and adding to it one element at a time.
 876        //
 1877        l = new List<short>(readShortSeq());
 878
 879    /// <summary>
 880    /// Extracts a sequence of short values from the stream.
 881    /// </summary>
 882    /// <param name="l">The extracted short sequence as a linked list.</param>
 883    public void readShortSeq(out LinkedList<short> l) =>
 884        //
 885        // Reading into an array and copy-constructing the
 886        // list is faster than constructing the list
 887        // and adding to it one element at a time.
 888        //
 1889        l = new LinkedList<short>(readShortSeq());
 890
 891    /// <summary>
 892    /// Extracts a sequence of short values from the stream.
 893    /// </summary>
 894    /// <param name="l">The extracted short sequence as a queue.</param>
 895    public void readShortSeq(out Queue<short> l) =>
 896        //
 897        // Reading into an array and copy-constructing the
 898        // queue is faster than constructing the queue
 899        // and adding to it one element at a time.
 900        //
 1901        l = new Queue<short>(readShortSeq());
 902
 903    /// <summary>
 904    /// Extracts a sequence of short values from the stream.
 905    /// </summary>
 906    /// <param name="l">The extracted short sequence as a stack.</param>
 907    public void readShortSeq(out Stack<short> l)
 908    {
 909        //
 910        // Reverse the contents by copying into an array first
 911        // because the stack is marshaled in top-to-bottom order.
 912        //
 1913        short[] array = readShortSeq();
 1914        Array.Reverse(array);
 1915        l = new Stack<short>(array);
 1916    }
 917
 918    /// <summary>
 919    /// Extracts an optional short sequence from the stream.
 920    /// </summary>
 921    /// <param name="tag">The numeric tag associated with the value.</param>
 922    /// <returns>The optional value.</returns>
 923    public short[]? readShortSeq(int tag)
 924    {
 0925        if (readOptional(tag, OptionalFormat.VSize))
 926        {
 0927            skipSize();
 0928            return readShortSeq();
 929        }
 930        else
 931        {
 0932            return null;
 933        }
 934    }
 935
 936    /// <summary>
 937    /// Extracts an int value from the stream.
 938    /// </summary>
 939    /// <returns>The extracted int.</returns>
 940    public int readInt()
 941    {
 942        try
 943        {
 1944            return _buf.b.getInt();
 945        }
 0946        catch (InvalidOperationException ex)
 947        {
 0948            throw new MarshalException(endOfBufferMessage, ex);
 949        }
 1950    }
 951
 952    /// <summary>
 953    /// Extracts an optional int value from the stream.
 954    /// </summary>
 955    /// <param name="tag">The numeric tag associated with the value.</param>
 956    /// <returns>The optional value.</returns>
 957    public int? readInt(int tag)
 958    {
 1959        if (readOptional(tag, OptionalFormat.F4))
 960        {
 1961            return readInt();
 962        }
 963        else
 964        {
 1965            return null;
 966        }
 967    }
 968
 969    /// <summary>
 970    /// Extracts a sequence of int values from the stream.
 971    /// </summary>
 972    /// <returns>The extracted int sequence.</returns>
 973    public int[] readIntSeq()
 974    {
 975        try
 976        {
 1977            int sz = readAndCheckSeqSize(4);
 1978            int[] v = new int[sz];
 1979            _buf.b.getIntSeq(v);
 1980            return v;
 981        }
 0982        catch (InvalidOperationException ex)
 983        {
 0984            throw new MarshalException(endOfBufferMessage, ex);
 985        }
 1986    }
 987
 988    /// <summary>
 989    /// Extracts a sequence of int values from the stream.
 990    /// </summary>
 991    /// <param name="l">The extracted int sequence as a list.</param>
 992    public void readIntSeq(out List<int> l) =>
 993        //
 994        // Reading into an array and copy-constructing the
 995        // list is faster than constructing the list
 996        // and adding to it one element at a time.
 997        //
 1998        l = new List<int>(readIntSeq());
 999
 1000    /// <summary>
 1001    /// Extracts a sequence of int values from the stream.
 1002    /// </summary>
 1003    /// <param name="l">The extracted int sequence as a linked list.</param>
 1004    public void readIntSeq(out LinkedList<int> l)
 1005    {
 1006        try
 1007        {
 11008            int sz = readAndCheckSeqSize(4);
 11009            l = new LinkedList<int>();
 11010            for (int i = 0; i < sz; ++i)
 1011            {
 11012                l.AddLast(_buf.b.getInt());
 1013            }
 11014        }
 01015        catch (InvalidOperationException ex)
 1016        {
 01017            throw new MarshalException(endOfBufferMessage, ex);
 1018        }
 11019    }
 1020
 1021    /// <summary>
 1022    /// Extracts a sequence of int values from the stream.
 1023    /// </summary>
 1024    /// <param name="l">The extracted int sequence as a queue.</param>
 1025    public void readIntSeq(out Queue<int> l)
 1026    {
 1027        //
 1028        // Reading into an array and copy-constructing the
 1029        // queue takes the same time as constructing the queue
 1030        // and adding to it one element at a time, so
 1031        // we avoid the copy.
 1032        //
 1033        try
 1034        {
 11035            int sz = readAndCheckSeqSize(4);
 11036            l = new Queue<int>(sz);
 11037            for (int i = 0; i < sz; ++i)
 1038            {
 11039                l.Enqueue(_buf.b.getInt());
 1040            }
 11041        }
 01042        catch (InvalidOperationException ex)
 1043        {
 01044            throw new MarshalException(endOfBufferMessage, ex);
 1045        }
 11046    }
 1047
 1048    /// <summary>
 1049    /// Extracts a sequence of int values from the stream.
 1050    /// </summary>
 1051    /// <param name="l">The extracted int sequence as a stack.</param>
 1052    public void readIntSeq(out Stack<int> l)
 1053    {
 1054        //
 1055        // Reverse the contents by copying into an array first
 1056        // because the stack is marshaled in top-to-bottom order.
 1057        //
 11058        int[] array = readIntSeq();
 11059        Array.Reverse(array);
 11060        l = new Stack<int>(array);
 11061    }
 1062
 1063    /// <summary>
 1064    /// Extracts an optional int sequence from the stream.
 1065    /// </summary>
 1066    /// <param name="tag">The numeric tag associated with the value.</param>
 1067    /// <returns>The optional value.</returns>
 1068    public int[]? readIntSeq(int tag)
 1069    {
 11070        if (readOptional(tag, OptionalFormat.VSize))
 1071        {
 11072            skipSize();
 11073            return readIntSeq();
 1074        }
 1075        else
 1076        {
 11077            return null;
 1078        }
 1079    }
 1080
 1081    /// <summary>
 1082    /// Extracts a long value from the stream.
 1083    /// </summary>
 1084    /// <returns>The extracted long.</returns>
 1085    public long readLong()
 1086    {
 1087        try
 1088        {
 11089            return _buf.b.getLong();
 1090        }
 01091        catch (InvalidOperationException ex)
 1092        {
 01093            throw new MarshalException(endOfBufferMessage, ex);
 1094        }
 11095    }
 1096
 1097    /// <summary>
 1098    /// Extracts an optional long value from the stream.
 1099    /// </summary>
 1100    /// <param name="tag">The numeric tag associated with the value.</param>
 1101    /// <returns>The optional value.</returns>
 1102    public long? readLong(int tag)
 1103    {
 11104        if (readOptional(tag, OptionalFormat.F8))
 1105        {
 11106            return readLong();
 1107        }
 1108        else
 1109        {
 11110            return null;
 1111        }
 1112    }
 1113
 1114    /// <summary>
 1115    /// Extracts a sequence of long values from the stream.
 1116    /// </summary>
 1117    /// <returns>The extracted long sequence.</returns>
 1118    public long[] readLongSeq()
 1119    {
 1120        try
 1121        {
 11122            int sz = readAndCheckSeqSize(8);
 11123            long[] v = new long[sz];
 11124            _buf.b.getLongSeq(v);
 11125            return v;
 1126        }
 01127        catch (InvalidOperationException ex)
 1128        {
 01129            throw new MarshalException(endOfBufferMessage, ex);
 1130        }
 11131    }
 1132
 1133    /// <summary>
 1134    /// Extracts a sequence of long values from the stream.
 1135    /// </summary>
 1136    /// <param name="l">The extracted long sequence as a list.</param>
 1137    public void readLongSeq(out List<long> l) =>
 1138        //
 1139        // Reading into an array and copy-constructing the
 1140        // list is faster than constructing the list
 1141        // and adding to it one element at a time.
 1142        //
 11143        l = new List<long>(readLongSeq());
 1144
 1145    /// <summary>
 1146    /// Extracts a sequence of long values from the stream.
 1147    /// </summary>
 1148    /// <param name="l">The extracted long sequence as a linked list.</param>
 1149    public void readLongSeq(out LinkedList<long> l)
 1150    {
 1151        try
 1152        {
 11153            int sz = readAndCheckSeqSize(4);
 11154            l = new LinkedList<long>();
 11155            for (int i = 0; i < sz; ++i)
 1156            {
 11157                l.AddLast(_buf.b.getLong());
 1158            }
 11159        }
 01160        catch (InvalidOperationException ex)
 1161        {
 01162            throw new MarshalException(endOfBufferMessage, ex);
 1163        }
 11164    }
 1165
 1166    /// <summary>
 1167    /// Extracts a sequence of long values from the stream.
 1168    /// </summary>
 1169    /// <param name="l">The extracted long sequence as a queue.</param>
 1170    public void readLongSeq(out Queue<long> l)
 1171    {
 1172        //
 1173        // Reading into an array and copy-constructing the
 1174        // queue takes the same time as constructing the queue
 1175        // and adding to it one element at a time, so
 1176        // we avoid the copy.
 1177        //
 1178        try
 1179        {
 11180            int sz = readAndCheckSeqSize(4);
 11181            l = new Queue<long>(sz);
 11182            for (int i = 0; i < sz; ++i)
 1183            {
 11184                l.Enqueue(_buf.b.getLong());
 1185            }
 11186        }
 01187        catch (InvalidOperationException ex)
 1188        {
 01189            throw new MarshalException(endOfBufferMessage, ex);
 1190        }
 11191    }
 1192
 1193    /// <summary>
 1194    /// Extracts a sequence of long values from the stream.
 1195    /// </summary>
 1196    /// <param name="l">The extracted long sequence as a stack.</param>
 1197    public void readLongSeq(out Stack<long> l)
 1198    {
 1199        //
 1200        // Reverse the contents by copying into an array first
 1201        // because the stack is marshaled in top-to-bottom order.
 1202        //
 11203        long[] array = readLongSeq();
 11204        Array.Reverse(array);
 11205        l = new Stack<long>(array);
 11206    }
 1207
 1208    /// <summary>
 1209    /// Extracts an optional long sequence from the stream.
 1210    /// </summary>
 1211    /// <param name="tag">The numeric tag associated with the value.</param>
 1212    /// <returns>The optional value.</returns>
 1213    public long[]? readLongSeq(int tag)
 1214    {
 11215        if (readOptional(tag, OptionalFormat.VSize))
 1216        {
 11217            skipSize();
 11218            return readLongSeq();
 1219        }
 1220        else
 1221        {
 11222            return null;
 1223        }
 1224    }
 1225
 1226    /// <summary>
 1227    /// Extracts a float value from the stream.
 1228    /// </summary>
 1229    /// <returns>The extracted float.</returns>
 1230    public float readFloat()
 1231    {
 1232        try
 1233        {
 11234            return _buf.b.getFloat();
 1235        }
 01236        catch (InvalidOperationException ex)
 1237        {
 01238            throw new MarshalException(endOfBufferMessage, ex);
 1239        }
 11240    }
 1241
 1242    /// <summary>
 1243    /// Extracts an optional float value from the stream.
 1244    /// </summary>
 1245    /// <param name="tag">The numeric tag associated with the value.</param>
 1246    /// <returns>The optional value.</returns>
 1247    public float? readFloat(int tag)
 1248    {
 11249        if (readOptional(tag, OptionalFormat.F4))
 1250        {
 11251            return readFloat();
 1252        }
 1253        else
 1254        {
 11255            return null;
 1256        }
 1257    }
 1258
 1259    /// <summary>
 1260    /// Extracts a sequence of float values from the stream.
 1261    /// </summary>
 1262    /// <returns>The extracted float sequence.</returns>
 1263    public float[] readFloatSeq()
 1264    {
 1265        try
 1266        {
 11267            int sz = readAndCheckSeqSize(4);
 11268            float[] v = new float[sz];
 11269            _buf.b.getFloatSeq(v);
 11270            return v;
 1271        }
 01272        catch (InvalidOperationException ex)
 1273        {
 01274            throw new MarshalException(endOfBufferMessage, ex);
 1275        }
 11276    }
 1277
 1278    /// <summary>
 1279    /// Extracts a sequence of float values from the stream.
 1280    /// </summary>
 1281    /// <param name="l">The extracted float sequence as a list.</param>
 1282    public void readFloatSeq(out List<float> l) =>
 1283        //
 1284        // Reading into an array and copy-constructing the
 1285        // list is faster than constructing the list
 1286        // and adding to it one element at a time.
 1287        //
 11288        l = new List<float>(readFloatSeq());
 1289
 1290    /// <summary>
 1291    /// Extracts a sequence of float values from the stream.
 1292    /// </summary>
 1293    /// <param name="l">The extracted float sequence as a linked list.</param>
 1294    public void readFloatSeq(out LinkedList<float> l)
 1295    {
 1296        try
 1297        {
 11298            int sz = readAndCheckSeqSize(4);
 11299            l = new LinkedList<float>();
 11300            for (int i = 0; i < sz; ++i)
 1301            {
 11302                l.AddLast(_buf.b.getFloat());
 1303            }
 11304        }
 01305        catch (InvalidOperationException ex)
 1306        {
 01307            throw new MarshalException(endOfBufferMessage, ex);
 1308        }
 11309    }
 1310
 1311    /// <summary>
 1312    /// Extracts a sequence of float values from the stream.
 1313    /// </summary>
 1314    /// <param name="l">The extracted float sequence as a queue.</param>
 1315    public void readFloatSeq(out Queue<float> l)
 1316    {
 1317        //
 1318        // Reading into an array and copy-constructing the
 1319        // queue takes the same time as constructing the queue
 1320        // and adding to it one element at a time, so
 1321        // we avoid the copy.
 1322        //
 1323        try
 1324        {
 11325            int sz = readAndCheckSeqSize(4);
 11326            l = new Queue<float>(sz);
 11327            for (int i = 0; i < sz; ++i)
 1328            {
 11329                l.Enqueue(_buf.b.getFloat());
 1330            }
 11331        }
 01332        catch (InvalidOperationException ex)
 1333        {
 01334            throw new MarshalException(endOfBufferMessage, ex);
 1335        }
 11336    }
 1337
 1338    /// <summary>
 1339    /// Extracts a sequence of float values from the stream.
 1340    /// </summary>
 1341    /// <param name="l">The extracted float sequence as a stack.</param>
 1342    public void readFloatSeq(out Stack<float> l)
 1343    {
 1344        //
 1345        // Reverse the contents by copying into an array first
 1346        // because the stack is marshaled in top-to-bottom order.
 1347        //
 11348        float[] array = readFloatSeq();
 11349        Array.Reverse(array);
 11350        l = new Stack<float>(array);
 11351    }
 1352
 1353    /// <summary>
 1354    /// Extracts an optional float sequence from the stream.
 1355    /// </summary>
 1356    /// <param name="tag">The numeric tag associated with the value.</param>
 1357    /// <returns>The optional value.</returns>
 1358    public float[]? readFloatSeq(int tag)
 1359    {
 11360        if (readOptional(tag, OptionalFormat.VSize))
 1361        {
 11362            skipSize();
 11363            return readFloatSeq();
 1364        }
 1365        else
 1366        {
 11367            return null;
 1368        }
 1369    }
 1370
 1371    /// <summary>
 1372    /// Extracts a double value from the stream.
 1373    /// </summary>
 1374    /// <returns>The extracted double.</returns>
 1375    public double readDouble()
 1376    {
 1377        try
 1378        {
 11379            return _buf.b.getDouble();
 1380        }
 01381        catch (InvalidOperationException ex)
 1382        {
 01383            throw new MarshalException(endOfBufferMessage, ex);
 1384        }
 11385    }
 1386
 1387    /// <summary>
 1388    /// Extracts an optional double value from the stream.
 1389    /// </summary>
 1390    /// <param name="tag">The numeric tag associated with the value.</param>
 1391    /// <returns>The optional value.</returns>
 1392    public double? readDouble(int tag)
 1393    {
 11394        if (readOptional(tag, OptionalFormat.F8))
 1395        {
 11396            return readDouble();
 1397        }
 1398        else
 1399        {
 11400            return null;
 1401        }
 1402    }
 1403
 1404    /// <summary>
 1405    /// Extracts a sequence of double values from the stream.
 1406    /// </summary>
 1407    /// <returns>The extracted double sequence.</returns>
 1408    public double[] readDoubleSeq()
 1409    {
 1410        try
 1411        {
 11412            int sz = readAndCheckSeqSize(8);
 11413            double[] v = new double[sz];
 11414            _buf.b.getDoubleSeq(v);
 11415            return v;
 1416        }
 01417        catch (InvalidOperationException ex)
 1418        {
 01419            throw new MarshalException(endOfBufferMessage, ex);
 1420        }
 11421    }
 1422
 1423    /// <summary>
 1424    /// Extracts a sequence of double values from the stream.
 1425    /// </summary>
 1426    /// <param name="l">The extracted double sequence as a list.</param>
 1427    public void readDoubleSeq(out List<double> l) =>
 1428        //
 1429        // Reading into an array and copy-constructing the
 1430        // list is faster than constructing the list
 1431        // and adding to it one element at a time.
 1432        //
 11433        l = new List<double>(readDoubleSeq());
 1434
 1435    /// <summary>
 1436    /// Extracts a sequence of double values from the stream.
 1437    /// </summary>
 1438    /// <param name="l">The extracted double sequence as a linked list.</param>
 1439    public void readDoubleSeq(out LinkedList<double> l)
 1440    {
 1441        try
 1442        {
 11443            int sz = readAndCheckSeqSize(4);
 11444            l = new LinkedList<double>();
 11445            for (int i = 0; i < sz; ++i)
 1446            {
 11447                l.AddLast(_buf.b.getDouble());
 1448            }
 11449        }
 01450        catch (InvalidOperationException ex)
 1451        {
 01452            throw new MarshalException(endOfBufferMessage, ex);
 1453        }
 11454    }
 1455
 1456    /// <summary>
 1457    /// Extracts a sequence of double values from the stream.
 1458    /// </summary>
 1459    /// <param name="l">The extracted double sequence as a queue.</param>
 1460    public void readDoubleSeq(out Queue<double> l)
 1461    {
 1462        //
 1463        // Reading into an array and copy-constructing the
 1464        // queue takes the same time as constructing the queue
 1465        // and adding to it one element at a time, so
 1466        // we avoid the copy.
 1467        //
 1468        try
 1469        {
 11470            int sz = readAndCheckSeqSize(4);
 11471            l = new Queue<double>(sz);
 11472            for (int i = 0; i < sz; ++i)
 1473            {
 11474                l.Enqueue(_buf.b.getDouble());
 1475            }
 11476        }
 01477        catch (InvalidOperationException ex)
 1478        {
 01479            throw new MarshalException(endOfBufferMessage, ex);
 1480        }
 11481    }
 1482
 1483    /// <summary>
 1484    /// Extracts a sequence of double values from the stream.
 1485    /// </summary>
 1486    /// <param name="l">The extracted double sequence as a stack.</param>
 1487    public void readDoubleSeq(out Stack<double> l)
 1488    {
 1489        //
 1490        // Reverse the contents by copying into an array first
 1491        // because the stack is marshaled in top-to-bottom order.
 1492        //
 11493        double[] array = readDoubleSeq();
 11494        Array.Reverse(array);
 11495        l = new Stack<double>(array);
 11496    }
 1497
 1498    /// <summary>
 1499    /// Extracts an optional double sequence from the stream.
 1500    /// </summary>
 1501    /// <param name="tag">The numeric tag associated with the value.</param>
 1502    /// <returns>The optional value.</returns>
 1503    public double[]? readDoubleSeq(int tag)
 1504    {
 11505        if (readOptional(tag, OptionalFormat.VSize))
 1506        {
 11507            skipSize();
 11508            return readDoubleSeq();
 1509        }
 1510        else
 1511        {
 11512            return null;
 1513        }
 1514    }
 1515
 11516    private static readonly System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true);
 1517
 1518    /// <summary>
 1519    /// Extracts a string from the stream.
 1520    /// </summary>
 1521    /// <returns>The extracted string.</returns>
 1522    public string readString()
 1523    {
 11524        int len = readSize();
 1525
 11526        if (len == 0)
 1527        {
 11528            return "";
 1529        }
 1530
 1531        //
 1532        // Check the buffer has enough bytes to read.
 1533        //
 11534        if (_buf.b.remaining() < len)
 1535        {
 01536            throw new MarshalException(endOfBufferMessage);
 1537        }
 1538
 1539        try
 1540        {
 1541            //
 1542            // We reuse the _stringBytes array to avoid creating
 1543            // excessive garbage
 1544            //
 11545            if (_stringBytes == null || len > _stringBytes.Length)
 1546            {
 11547                _stringBytes = new byte[len];
 1548            }
 11549            _buf.b.get(_stringBytes, 0, len);
 11550            return utf8.GetString(_stringBytes, 0, len);
 1551        }
 01552        catch (InvalidOperationException ex)
 1553        {
 01554            throw new MarshalException(endOfBufferMessage, ex);
 1555        }
 01556        catch (ArgumentException ex)
 1557        {
 01558            throw new MarshalException("Invalid UTF8 string.", ex);
 1559        }
 11560    }
 1561
 1562    /// <summary>
 1563    /// Extracts an optional string from the stream.
 1564    /// </summary>
 1565    /// <param name="tag">The numeric tag associated with the value.</param>
 1566    /// <returns>The optional value.</returns>
 1567    public string? readString(int tag)
 1568    {
 11569        if (readOptional(tag, OptionalFormat.VSize))
 1570        {
 11571            return readString();
 1572        }
 1573        else
 1574        {
 11575            return null;
 1576        }
 1577    }
 1578
 1579    /// <summary>
 1580    /// Extracts a sequence of strings from the stream.
 1581    /// </summary>
 1582    /// <returns>The extracted string sequence.</returns>
 1583    public string[] readStringSeq()
 1584    {
 11585        int sz = readAndCheckSeqSize(1);
 11586        string[] v = new string[sz];
 11587        for (int i = 0; i < sz; i++)
 1588        {
 11589            v[i] = readString();
 1590        }
 11591        return v;
 1592    }
 1593
 1594    /// <summary>
 1595    /// Extracts a sequence of strings from the stream.
 1596    /// </summary>
 1597    /// <param name="l">The extracted string sequence as a list.</param>
 1598    public void readStringSeq(out List<string> l)
 1599    {
 1600        //
 1601        // Reading into an array and copy-constructing the
 1602        // list is slower than constructing the list
 1603        // and adding to it one element at a time.
 1604        //
 11605        int sz = readAndCheckSeqSize(1);
 11606        l = new List<string>(sz);
 11607        for (int i = 0; i < sz; ++i)
 1608        {
 11609            l.Add(readString());
 1610        }
 11611    }
 1612
 1613    /// <summary>
 1614    /// Extracts a sequence of strings from the stream.
 1615    /// </summary>
 1616    /// <param name="l">The extracted string sequence as a linked list.</param>
 1617    public void readStringSeq(out LinkedList<string> l)
 1618    {
 1619        //
 1620        // Reading into an array and copy-constructing the
 1621        // list is slower than constructing the list
 1622        // and adding to it one element at a time.
 1623        //
 11624        int sz = readAndCheckSeqSize(1);
 11625        l = new LinkedList<string>();
 11626        for (int i = 0; i < sz; ++i)
 1627        {
 11628            l.AddLast(readString());
 1629        }
 11630    }
 1631
 1632    /// <summary>
 1633    /// Extracts a sequence of strings from the stream.
 1634    /// </summary>
 1635    /// <param name="l">The extracted string sequence as a queue.</param>
 1636    public void readStringSeq(out Queue<string> l)
 1637    {
 1638        //
 1639        // Reading into an array and copy-constructing the
 1640        // queue is slower than constructing the queue
 1641        // and adding to it one element at a time.
 1642        //
 11643        int sz = readAndCheckSeqSize(1);
 11644        l = new Queue<string>();
 11645        for (int i = 0; i < sz; ++i)
 1646        {
 11647            l.Enqueue(readString());
 1648        }
 11649    }
 1650
 1651    /// <summary>
 1652    /// Extracts a sequence of strings from the stream.
 1653    /// </summary>
 1654    /// <param name="l">The extracted string sequence as a stack.</param>
 1655    public void readStringSeq(out Stack<string> l)
 1656    {
 1657        //
 1658        // Reverse the contents by copying into an array first
 1659        // because the stack is marshaled in top-to-bottom order.
 1660        //
 11661        string[] array = readStringSeq();
 11662        Array.Reverse(array);
 11663        l = new Stack<string>(array);
 11664    }
 1665
 1666    /// <summary>
 1667    /// Extracts an optional string sequence from the stream.
 1668    /// </summary>
 1669    /// <param name="tag">The numeric tag associated with the value.</param>
 1670    /// <returns>The optional value.</returns>
 1671    public string[]? readStringSeq(int tag)
 1672    {
 11673        if (readOptional(tag, OptionalFormat.FSize))
 1674        {
 11675            skip(4);
 11676            return readStringSeq();
 1677        }
 1678        else
 1679        {
 11680            return null;
 1681        }
 1682    }
 1683
 1684    /// <summary>
 1685    /// Extracts a proxy from the stream. The stream must have been initialized with a communicator.
 1686    /// </summary>
 1687    /// <returns>The extracted proxy.</returns>
 1688    public ObjectPrx? readProxy()
 1689    {
 11690        var ident = new Identity(this);
 11691        if (ident.name.Length == 0)
 1692        {
 11693            return null;
 1694        }
 1695        else
 1696        {
 11697            return new ObjectPrxHelper(_instance.referenceFactory().create(ident, this));
 1698        }
 1699    }
 1700
 1701    /// <summary>
 1702    /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator.
 1703    /// </summary>
 1704    /// <param name="tag">The numeric tag associated with the value.</param>
 1705    /// <returns>The optional value.</returns>
 1706    /// <remarks>This method is not used by the generated code.</remarks>
 1707    public ObjectPrx? readProxy(int tag)
 1708    {
 11709        if (readOptional(tag, OptionalFormat.FSize))
 1710        {
 01711            skip(4);
 01712            return readProxy();
 1713        }
 1714        else
 1715        {
 11716            return null;
 1717        }
 1718    }
 1719
 1720    /// <summary>
 1721    /// Read an enumerated value.
 1722    /// </summary>
 1723    /// <param name="maxValue">The maximum enumerator value in the definition.</param>
 1724    /// <returns>The enumerator.</returns>
 1725    public int readEnum(int maxValue)
 1726    {
 11727        if (getEncoding().Equals(Util.Encoding_1_0))
 1728        {
 11729            if (maxValue < 127)
 1730            {
 11731                return readByte();
 1732            }
 11733            else if (maxValue < 32767)
 1734            {
 11735                return readShort();
 1736            }
 1737            else
 1738            {
 11739                return readInt();
 1740            }
 1741        }
 1742        else
 1743        {
 11744            return readSize();
 1745        }
 1746    }
 1747
 1748    /// <summary>
 1749    /// Extracts the index of a Slice value from the stream.
 1750    /// </summary>
 1751    /// <typeparam name="T">The type of the Slice value to extract.</typeparam>
 1752    /// <param name="cb">The callback to notify the application when the extracted instance is available.
 1753    /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the
 1754    /// corresponding instance has been fully unmarshaled.</param>
 1755    public void readValue<T>(System.Action<T?> cb) where T : Value
 1756    {
 11757        initEncaps();
 11758        _encapsStack!.decoder!.readValue(v =>
 11759        {
 11760            if (v == null || v is T)
 11761            {
 11762                cb((T?)v);
 11763            }
 11764            else
 11765            {
 11766                Ice.Internal.Ex.throwUOE(typeof(T), v);
 11767            }
 01768        });
 11769    }
 1770
 1771    /// <summary>
 1772    /// Extracts the index of a Slice value from the stream.
 1773    /// </summary>
 1774    /// <param name="cb">The callback to notify the application when the extracted instance is available.
 1775    /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the
 1776    /// corresponding instance has been fully unmarshaled.</param>
 11777    public void readValue(System.Action<Value?> cb) => readValue<Value>(cb);
 1778
 1779    /// <summary>
 1780    /// Extracts a user exception from the stream and throws it.
 1781    /// </summary>
 1782    public void throwException()
 1783    {
 11784        initEncaps();
 11785        _encapsStack!.decoder!.throwException();
 01786    }
 1787
 1788    /// <summary>
 1789    /// Skip the given number of bytes.
 1790    /// </summary>
 1791    /// <param name="size">The number of bytes to skip.</param>
 1792    public void skip(int size)
 1793    {
 11794        if (size < 0 || size > _buf.b.remaining())
 1795        {
 01796            throw new MarshalException(endOfBufferMessage);
 1797        }
 11798        _buf.b.position(_buf.b.position() + size);
 11799    }
 1800
 1801    /// <summary>
 1802    /// Skip over a size value.
 1803    /// </summary>
 1804    public void skipSize()
 1805    {
 11806        byte b = readByte();
 11807        if (b == 255)
 1808        {
 11809            skip(4);
 1810        }
 11811    }
 1812
 1813    /// <summary>
 1814    /// Determines the current position in the stream.
 1815    /// </summary>
 1816    /// <returns>The current position.</returns>
 11817    public int pos() => _buf.b.position();
 1818
 1819    /// <summary>
 1820    /// Sets the current position in the stream.
 1821    /// </summary>
 1822    /// <param name="n">The new position.</param>
 11823    public void pos(int n) => _buf.b.position(n);
 1824
 1825    /// <summary>
 1826    /// Determines the current size of the stream.
 1827    /// </summary>
 1828    /// <returns>The current size.</returns>
 11829    public int size() => _buf.size();
 1830
 1831    /// <summary>
 1832    /// Determines whether the stream is empty.
 1833    /// </summary>
 1834    /// <returns><see langword="true"/> if the internal buffer has no data, <see langword="false"/> otherwise.</returns>
 11835    public bool isEmpty() => _buf.empty();
 1836
 1837    private bool readOptImpl(int readTag, OptionalFormat expectedFormat)
 1838    {
 11839        if (isEncoding_1_0())
 1840        {
 11841            return false; // Optional members aren't supported with the 1.0 encoding.
 1842        }
 1843
 1844        while (true)
 1845        {
 11846            if (_buf.b.position() >= _encapsStack!.start + _encapsStack.sz)
 1847            {
 11848                return false; // End of encapsulation also indicates end of optionals.
 1849            }
 1850
 11851            int v = readByte();
 11852            if (v == Protocol.OPTIONAL_END_MARKER)
 1853            {
 11854                _buf.b.position(_buf.b.position() - 1); // Rewind.
 11855                return false;
 1856            }
 1857
 11858            var format = (OptionalFormat)(v & 0x07); // First 3 bits.
 11859            int tag = v >> 3;
 11860            if (tag > 30)
 1861            {
 1862                // We check for '> 30' instead of '> 29' because 30 is special sentinel tag, handled by the next block.
 01863                throw new MarshalException($"Invalid tag '{tag}': tags larger than 29 must be encoded as a size.");
 1864            }
 11865            if (tag == 30)
 1866            {
 11867                tag = readSize();
 1868            }
 1869
 11870            if (tag > readTag)
 1871            {
 11872                int offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind
 11873                _buf.b.position(_buf.b.position() - offset);
 11874                return false; // No optional data members with the requested tag.
 1875            }
 11876            else if (tag < readTag)
 1877            {
 01878                skipOptional(format); // Skip optional data members
 1879            }
 1880            else
 1881            {
 11882                if (format != expectedFormat)
 1883                {
 01884                    throw new MarshalException($"Invalid optional tag '{tag}': unexpected format.");
 1885                }
 11886                return true;
 1887            }
 1888        }
 1889    }
 1890
 1891    private void skipOptional(OptionalFormat format)
 1892    {
 1893        switch (format)
 1894        {
 1895            case OptionalFormat.F1:
 1896            {
 11897                skip(1);
 11898                break;
 1899            }
 1900            case OptionalFormat.F2:
 1901            {
 11902                skip(2);
 11903                break;
 1904            }
 1905            case OptionalFormat.F4:
 1906            {
 11907                skip(4);
 11908                break;
 1909            }
 1910            case OptionalFormat.F8:
 1911            {
 11912                skip(8);
 11913                break;
 1914            }
 1915            case OptionalFormat.Size:
 1916            {
 11917                skipSize();
 11918                break;
 1919            }
 1920            case OptionalFormat.VSize:
 1921            {
 11922                skip(readSize());
 11923                break;
 1924            }
 1925            case OptionalFormat.FSize:
 1926            {
 11927                skip(readInt());
 11928                break;
 1929            }
 1930            case OptionalFormat.Class:
 1931            {
 01932                throw new MarshalException("Cannot skip an optional class.");
 1933            }
 1934        }
 1935    }
 1936
 1937    private bool skipOptionals()
 1938    {
 1939        //
 1940        // Skip remaining un-read optional members.
 1941        //
 11942        while (true)
 1943        {
 11944            if (_buf.b.position() >= _encapsStack!.start + _encapsStack.sz)
 1945            {
 11946                return false; // End of encapsulation also indicates end of optionals.
 1947            }
 1948
 11949            int v = readByte();
 11950            if (v == Protocol.OPTIONAL_END_MARKER)
 1951            {
 11952                return true;
 1953            }
 1954
 11955            var format = (OptionalFormat)(v & 0x07); // Read first 3 bits.
 11956            if ((v >> 3) == 30)
 1957            {
 11958                skipSize();
 1959            }
 11960            skipOptional(format);
 1961        }
 1962    }
 1963
 11964    private UserException? createUserException(string id) => (UserException?)_instance.sliceLoader.newInstance(id);
 1965
 1966    private readonly Instance _instance;
 1967    private Internal.Buffer _buf;
 1968    private byte[]? _stringBytes; // Reusable array for reading strings.
 1969
 1970    private enum SliceType
 1971    {
 1972        NoSlice,
 1973        ValueSlice,
 1974        ExceptionSlice
 1975    }
 1976
 1977    private abstract class EncapsDecoder
 1978    {
 1979        protected struct PatchEntry
 1980        {
 1981            public PatchEntry(System.Action<Value> cb, int classGraphDepth)
 1982            {
 11983                this.cb = cb;
 11984                this.classGraphDepth = classGraphDepth;
 11985            }
 1986
 1987            public System.Action<Value> cb;
 1988            public int classGraphDepth;
 1989        }
 1990
 11991        internal EncapsDecoder(InputStream stream, Encaps encaps, int classGraphDepthMax)
 1992        {
 11993            _stream = stream;
 11994            _encaps = encaps;
 11995            _classGraphDepthMax = classGraphDepthMax;
 11996            _classGraphDepth = 0;
 11997            _typeIdIndex = 0;
 11998            _unmarshaledMap = new Dictionary<int, Value>();
 11999        }
 2000
 2001        internal abstract void readValue(System.Action<Value?> cb);
 2002
 2003        internal abstract void throwException();
 2004
 2005        internal abstract void startInstance(SliceType type);
 2006
 2007        internal abstract SlicedData? endInstance();
 2008
 2009        internal abstract void startSlice();
 2010
 2011        internal abstract void endSlice();
 2012
 2013        internal abstract void skipSlice();
 2014
 12015        internal virtual bool readOptional(int tag, OptionalFormat format) => false;
 2016
 2017        internal virtual void readPendingValues()
 2018        {
 12019        }
 2020
 2021        protected string readTypeId(bool isIndex)
 2022        {
 12023            _typeIdMap ??= new Dictionary<int, string>();
 2024
 12025            if (isIndex)
 2026            {
 12027                int index = _stream.readSize();
 12028                if (!_typeIdMap.TryGetValue(index, out string? typeId))
 2029                {
 02030                    throw new MarshalException(endOfBufferMessage);
 2031                }
 12032                return typeId;
 2033            }
 2034            else
 2035            {
 12036                string typeId = _stream.readString();
 12037                _typeIdMap.Add(++_typeIdIndex, typeId);
 12038                return typeId;
 2039            }
 2040        }
 2041
 12042        protected Value? newInstance(string typeId) => (Value?)_stream._instance.sliceLoader.newInstance(typeId);
 2043
 2044        protected void addPatchEntry(int index, System.Action<Value> cb)
 2045        {
 2046            Debug.Assert(index > 0);
 2047
 2048            //
 2049            // Check if we already unmarshaled the instance. If that's the case,
 2050            // just call the callback and we're done.
 2051            //
 12052            if (_unmarshaledMap.TryGetValue(index, out Value? obj))
 2053            {
 12054                cb(obj);
 12055                return;
 2056            }
 2057
 12058            _patchMap ??= new Dictionary<int, LinkedList<PatchEntry>>();
 2059
 2060            //
 2061            // Add patch entry if the instance isn't unmarshaled yet,
 2062            // the callback will be called when the instance is
 2063            // unmarshaled.
 2064            //
 12065            if (!_patchMap.TryGetValue(index, out LinkedList<PatchEntry>? l))
 2066            {
 2067                //
 2068                // We have no outstanding instances to be patched for this
 2069                // index, so make a new entry in the patch map.
 2070                //
 12071                l = new LinkedList<PatchEntry>();
 12072                _patchMap.Add(index, l);
 2073            }
 2074
 2075            //
 2076            // Append a patch entry for this instance.
 2077            //
 12078            l.AddLast(new PatchEntry(cb, _classGraphDepth));
 12079        }
 2080
 2081        protected void unmarshal(int index, Value v)
 2082        {
 2083            //
 2084            // Add the instance to the map of unmarshaled instances, this must
 2085            // be done before reading the instances (for circular references).
 2086            //
 12087            _unmarshaledMap.Add(index, v);
 2088
 2089            //
 2090            // Read the instance.
 2091            //
 12092            v.iceRead(_stream);
 2093
 12094            if (_patchMap != null)
 2095            {
 2096                //
 2097                // Patch all instances now that the instance is unmarshaled.
 2098                //
 12099                if (_patchMap.TryGetValue(index, out LinkedList<PatchEntry>? l))
 2100                {
 2101                    Debug.Assert(l.Count > 0);
 2102
 2103                    //
 2104                    // Patch all pointers that refer to the instance.
 2105                    //
 12106                    foreach (PatchEntry entry in l)
 2107                    {
 12108                        entry.cb(v);
 2109                    }
 2110
 2111                    //
 2112                    // Clear out the patch map for that index -- there is nothing left
 2113                    // to patch for that index for the time being.
 2114                    //
 12115                    _patchMap.Remove(index);
 2116                }
 2117            }
 2118
 12119            if ((_patchMap == null || _patchMap.Count == 0) && _valueList == null)
 2120            {
 12121                v.ice_postUnmarshal();
 2122            }
 2123            else
 2124            {
 12125                _valueList ??= new List<Value>();
 12126                _valueList.Add(v);
 2127
 12128                if (_patchMap == null || _patchMap.Count == 0)
 2129                {
 2130                    //
 2131                    // Iterate over the instance list and invoke ice_postUnmarshal on
 2132                    // each instance. We must do this after all instances have been
 2133                    // unmarshaled in order to ensure that any instance data members
 2134                    // have been properly patched.
 2135                    //
 12136                    foreach (Value p in _valueList)
 2137                    {
 12138                        p.ice_postUnmarshal();
 2139                    }
 12140                    _valueList.Clear();
 2141                }
 2142            }
 12143        }
 2144
 2145        protected readonly InputStream _stream;
 2146        protected readonly Encaps _encaps;
 2147        protected readonly int _classGraphDepthMax;
 2148        protected int _classGraphDepth;
 2149
 2150        //
 2151        // Encapsulation attributes for object unmarshaling.
 2152        //
 2153        protected Dictionary<int, LinkedList<PatchEntry>>? _patchMap;
 2154        private readonly Dictionary<int, Value> _unmarshaledMap;
 2155        private Dictionary<int, string>? _typeIdMap;
 2156        private int _typeIdIndex;
 2157        private List<Value>? _valueList;
 2158    }
 2159
 2160    private sealed class EncapsDecoder10 : EncapsDecoder
 2161    {
 2162        internal EncapsDecoder10(InputStream stream, Encaps encaps, int classGraphDepthMax)
 12163            : base(stream, encaps, classGraphDepthMax) => _sliceType = SliceType.NoSlice;
 2164
 2165        internal override void readValue(System.Action<Value?> cb)
 2166        {
 2167            //
 2168            // Object references are encoded as a negative integer in 1.0.
 2169            //
 12170            int index = _stream.readInt();
 12171            if (index > 0)
 2172            {
 02173                throw new MarshalException("Invalid object id.");
 2174            }
 12175            index = -index;
 2176
 12177            if (index == 0)
 2178            {
 12179                cb(null);
 2180            }
 2181            else
 2182            {
 12183                addPatchEntry(index, cb);
 2184            }
 12185        }
 2186
 2187        internal override void throwException()
 2188        {
 2189            Debug.Assert(_sliceType == SliceType.NoSlice);
 2190
 2191            //
 2192            // User exception with the 1.0 encoding start with a bool flag
 2193            // that indicates whether or not the exception has classes.
 2194            //
 2195            // This allows reading the pending instances even if some part of
 2196            // the exception was sliced.
 2197            //
 12198            bool usesClasses = _stream.readBool();
 2199
 12200            _sliceType = SliceType.ExceptionSlice;
 12201            _skipFirstSlice = false;
 2202
 2203            //
 2204            // Read the first slice header.
 2205            //
 12206            startSlice();
 2207            Debug.Assert(_typeId is not null);
 12208            string mostDerivedId = _typeId;
 2209            while (true)
 2210            {
 12211                UserException? userEx = _stream.createUserException(_typeId);
 2212
 2213                //
 2214                // We found the exception.
 2215                //
 12216                if (userEx != null)
 2217                {
 12218                    userEx.iceRead(_stream);
 12219                    if (usesClasses)
 2220                    {
 12221                        readPendingValues();
 2222                    }
 12223                    throw userEx;
 2224
 2225                    // Never reached.
 2226                }
 2227
 2228                //
 2229                // Slice off what we don't understand.
 2230                //
 12231                skipSlice();
 2232                try
 2233                {
 12234                    startSlice();
 12235                }
 02236                catch (MarshalException)
 2237                {
 2238                    // An oversight in the 1.0 encoding means there is no marker to indicate
 2239                    // the last slice of an exception. As a result, we just try to read the
 2240                    // next type ID, which raises MarshalException when the input buffer underflows.
 02241                    throw new MarshalException($"Unknown exception type '{mostDerivedId}'.");
 2242                }
 2243            }
 2244        }
 2245
 2246        internal override void startInstance(SliceType sliceType)
 2247        {
 2248            Debug.Assert(_sliceType == sliceType);
 12249            _skipFirstSlice = true;
 12250        }
 2251
 2252        internal override SlicedData? endInstance()
 2253        {
 2254            //
 2255            // Read the Ice::Object slice.
 2256            //
 12257            if (_sliceType == SliceType.ValueSlice)
 2258            {
 12259                startSlice();
 12260                int sz = _stream.readSize(); // For compatibility with the old AFM.
 12261                if (sz != 0)
 2262                {
 02263                    throw new MarshalException("Invalid Object slice.");
 2264                }
 12265                endSlice();
 2266            }
 2267
 12268            _sliceType = SliceType.NoSlice;
 12269            return null;
 2270        }
 2271
 2272        internal override void startSlice()
 2273        {
 2274            //
 2275            // If first slice, don't read the header, it was already read in
 2276            // readInstance or throwException to find the factory.
 2277            //
 12278            if (_skipFirstSlice)
 2279            {
 12280                _skipFirstSlice = false;
 12281                return;
 2282            }
 2283
 2284            //
 2285            // For instances, first read the type ID bool which indicates
 2286            // whether or not the type ID is encoded as a string or as an
 2287            // index. For exceptions, the type ID is always encoded as a
 2288            // string.
 2289            //
 12290            if (_sliceType == SliceType.ValueSlice) // For exceptions, the type ID is always encoded as a string
 2291            {
 12292                bool isIndex = _stream.readBool();
 12293                _typeId = readTypeId(isIndex);
 2294            }
 2295            else
 2296            {
 12297                _typeId = _stream.readString();
 2298            }
 2299
 12300            _sliceSize = _stream.readInt();
 12301            if (_sliceSize < 4)
 2302            {
 02303                throw new MarshalException(endOfBufferMessage);
 2304            }
 12305        }
 2306
 2307        internal override void endSlice()
 2308        {
 12309        }
 2310
 2311        internal override void skipSlice()
 2312        {
 12313            if (_stream.instance().traceLevels().slicing > 0)
 2314            {
 02315                Logger logger = _stream.instance().initializationData().logger!;
 02316                string slicingCat = _stream.instance().traceLevels().slicingCat;
 02317                if (_sliceType == SliceType.ValueSlice)
 2318                {
 02319                    Ice.Internal.TraceUtil.traceSlicing("object", _typeId, slicingCat, logger);
 2320                }
 2321                else
 2322                {
 02323                    Ice.Internal.TraceUtil.traceSlicing("exception", _typeId, slicingCat, logger);
 2324                }
 2325            }
 2326
 2327            Debug.Assert(_sliceSize >= 4);
 12328            _stream.skip(_sliceSize - 4);
 12329        }
 2330
 2331        internal override void readPendingValues()
 2332        {
 2333            int num;
 2334            do
 2335            {
 12336                num = _stream.readSize();
 12337                for (int k = num; k > 0; --k)
 2338                {
 12339                    readInstance();
 2340                }
 2341            }
 12342            while (num > 0);
 2343
 12344            if (_patchMap != null && _patchMap.Count > 0)
 2345            {
 2346                //
 2347                // If any entries remain in the patch map, the sender has sent an index for an instance, but failed
 2348                // to supply the instance.
 2349                //
 02350                throw new MarshalException("Index for class received, but no instance.");
 2351            }
 12352        }
 2353
 2354        private void readInstance()
 2355        {
 12356            int index = _stream.readInt();
 2357
 12358            if (index <= 0)
 2359            {
 02360                throw new MarshalException("Invalid object id.");
 2361            }
 2362
 12363            _sliceType = SliceType.ValueSlice;
 12364            _skipFirstSlice = false;
 2365
 2366            //
 2367            // Read the first slice header.
 2368            //
 12369            startSlice();
 2370            Debug.Assert(_typeId is not null);
 12371            string mostDerivedId = _typeId;
 2372            Value? v;
 12373            while (true)
 2374            {
 2375                // For the 1.0 encoding, the type ID for the base Object class marks the last slice.
 12376                if (_typeId == Value.ice_staticId())
 2377                {
 12378                    throw new MarshalException(
 12379                        $"The Slice loader did not find a class for type ID '{mostDerivedId}'.");
 2380                }
 2381
 12382                v = newInstance(_typeId);
 2383
 2384                //
 2385                // We found a factory, we get out of this loop.
 2386                //
 12387                if (v != null)
 2388                {
 2389                    break;
 2390                }
 2391
 2392                //
 2393                // Slice off what we don't understand.
 2394                //
 12395                skipSlice();
 12396                startSlice(); // Read next Slice header for next iteration.
 2397            }
 2398
 2399            //
 2400            // Compute the biggest class graph depth of this object. To compute this,
 2401            // we get the class graph depth of each ancestor from the patch map and
 2402            // keep the biggest one.
 2403            //
 12404            _classGraphDepth = 0;
 12405            if (_patchMap != null && _patchMap.TryGetValue(index, out LinkedList<PatchEntry>? l))
 2406            {
 2407                Debug.Assert(l.Count > 0);
 12408                foreach (PatchEntry entry in l)
 2409                {
 12410                    if (entry.classGraphDepth > _classGraphDepth)
 2411                    {
 12412                        _classGraphDepth = entry.classGraphDepth;
 2413                    }
 2414                }
 2415            }
 2416
 12417            if (++_classGraphDepth > _classGraphDepthMax)
 2418            {
 12419                throw new MarshalException("Maximum class graph depth reached.");
 2420            }
 2421
 2422            //
 2423            // Unmarshal the instance and add it to the map of unmarshaled instances.
 2424            //
 12425            unmarshal(index, v);
 12426        }
 2427
 2428        // Object/exception attributes
 2429        private SliceType _sliceType;
 2430        private bool _skipFirstSlice;
 2431
 2432        // Slice attributes
 2433        private int _sliceSize;
 2434        private string? _typeId;
 2435    }
 2436
 2437    private sealed class EncapsDecoder11 : EncapsDecoder
 2438    {
 2439        internal EncapsDecoder11(InputStream stream, Encaps encaps, int classGraphDepthMax)
 12440            : base(stream, encaps, classGraphDepthMax)
 2441        {
 12442            _current = null;
 12443            _valueIdIndex = 1;
 12444        }
 2445
 2446        internal override void readValue(System.Action<Value?> cb)
 2447        {
 12448            int index = _stream.readSize();
 12449            if (index < 0)
 2450            {
 02451                throw new MarshalException("Invalid object id.");
 2452            }
 12453            else if (index == 0)
 2454            {
 12455                cb(null);
 2456            }
 12457            else if (_current != null && (_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
 2458            {
 2459                //
 2460                // When reading an instance within a slice and there's an
 2461                // indirect instance table, always read an indirect reference
 2462                // that points to an instance from the indirect instance table
 2463                // marshaled at the end of the Slice.
 2464                //
 2465                // Maintain a list of indirect references. Note that the
 2466                // indirect index starts at 1, so we decrement it by one to
 2467                // derive an index into the indirection table that we'll read
 2468                // at the end of the slice.
 2469                //
 12470                _current.indirectPatchList ??= new Stack<IndirectPatchEntry>();
 12471                var e = new IndirectPatchEntry(index - 1, cb);
 12472                _current.indirectPatchList.Push(e);
 2473            }
 2474            else
 2475            {
 12476                readInstance(index, cb);
 2477            }
 12478        }
 2479
 2480        internal override void throwException()
 2481        {
 2482            Debug.Assert(_current == null);
 2483
 12484            push(SliceType.ExceptionSlice);
 2485
 2486            //
 2487            // Read the first slice header.
 2488            //
 12489            startSlice();
 12490            string mostDerivedId = _current!.typeId!;
 12491            while (true)
 2492            {
 12493                UserException? userEx = _stream.createUserException(_current!.typeId!);
 2494
 2495                //
 2496                // We found the exception.
 2497                //
 12498                if (userEx != null)
 2499                {
 12500                    userEx.iceRead(_stream);
 12501                    throw userEx;
 2502
 2503                    // Never reached.
 2504                }
 2505
 2506                //
 2507                // Slice off what we don't understand.
 2508                //
 12509                skipSlice();
 2510
 12511                if ((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0)
 2512                {
 02513                    throw new MarshalException($"Cannot unmarshal exception with type ID '{mostDerivedId}'.");
 2514                }
 2515
 12516                startSlice();
 2517            }
 2518        }
 2519
 2520        internal override void startInstance(SliceType sliceType)
 2521        {
 2522            Debug.Assert(_current!.sliceType == sliceType);
 12523            _current.skipFirstSlice = true;
 12524        }
 2525
 2526        internal override SlicedData? endInstance()
 2527        {
 12528            SlicedData? slicedData = readSlicedData();
 12529            if (_current!.slices != null)
 2530            {
 12531                _current.slices.Clear();
 2532            }
 12533            _current.indirectionTables?.Clear();
 12534            _current = _current.previous;
 12535            return slicedData;
 2536        }
 2537
 2538        internal override void startSlice()
 2539        {
 2540            //
 2541            // If first slice, don't read the header, it was already read in
 2542            // readInstance or throwException to find the factory.
 2543            //
 12544            if (_current!.skipFirstSlice)
 2545            {
 12546                _current.skipFirstSlice = false;
 12547                return;
 2548            }
 2549
 12550            _current.sliceFlags = _stream.readByte();
 2551
 2552            //
 2553            // Read the type ID, for instance slices the type ID is encoded as a
 2554            // string or as an index, for exceptions it's always encoded as a
 2555            // string.
 2556            //
 12557            if (_current.sliceType == SliceType.ValueSlice)
 2558            {
 2559                //
 2560                // Must be checked first!
 2561                //
 12562                if ((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_COMPACT) == Protocol.FLAG_HAS_TYPE_ID_COMPACT)
 2563                {
 12564                    _current.compactId = _stream.readSize();
 12565                    _current.typeId = _current.compactId.ToString(CultureInfo.InvariantCulture);
 2566                }
 12567                else if ((_current.sliceFlags &
 12568                        (Protocol.FLAG_HAS_TYPE_ID_INDEX | Protocol.FLAG_HAS_TYPE_ID_STRING)) != 0)
 2569                {
 12570                    _current.typeId = readTypeId((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_INDEX) != 0);
 12571                    _current.compactId = -1;
 2572                }
 2573                else
 2574                {
 2575                    // Only the most derived slice encodes the type ID for the compact format.
 12576                    _current.typeId = "";
 12577                    _current.compactId = -1;
 2578                }
 2579            }
 2580            else
 2581            {
 12582                _current.typeId = _stream.readString();
 12583                _current.compactId = -1;
 2584            }
 2585
 2586            //
 2587            // Read the slice size if necessary.
 2588            //
 12589            if ((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
 2590            {
 12591                _current.sliceSize = _stream.readInt();
 12592                if (_current.sliceSize < 4)
 2593                {
 02594                    throw new MarshalException(endOfBufferMessage);
 2595                }
 2596            }
 2597            else
 2598            {
 12599                _current.sliceSize = 0;
 2600            }
 12601        }
 2602
 2603        internal override void endSlice()
 2604        {
 12605            if ((_current!.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
 2606            {
 12607                _stream.skipOptionals();
 2608            }
 2609
 2610            //
 2611            // Read the indirection table if one is present and transform the
 2612            // indirect patch list into patch entries with direct references.
 2613            //
 12614            if ((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
 2615            {
 2616                //
 2617                // The table is written as a sequence<size> to conserve space.
 2618                //
 12619                int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
 12620                for (int i = 0; i < indirectionTable.Length; ++i)
 2621                {
 12622                    indirectionTable[i] = readInstance(_stream.readSize(), null);
 2623                }
 2624
 2625                //
 2626                // Sanity checks. If there are optional members, it's possible
 2627                // that not all instance references were read if they are from
 2628                // unknown optional data members.
 2629                //
 12630                if (indirectionTable.Length == 0)
 2631                {
 02632                    throw new MarshalException("Empty indirection table.");
 2633                }
 12634                if ((_current.indirectPatchList == null || _current.indirectPatchList.Count == 0) &&
 12635                   (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0)
 2636                {
 02637                    throw new MarshalException("No references to indirection table.");
 2638                }
 2639
 2640                //
 2641                // Convert indirect references into direct references.
 2642                //
 12643                if (_current.indirectPatchList != null)
 2644                {
 12645                    foreach (IndirectPatchEntry e in _current.indirectPatchList)
 2646                    {
 2647                        Debug.Assert(e.index >= 0);
 12648                        if (e.index >= indirectionTable.Length)
 2649                        {
 02650                            throw new MarshalException("Indirection out of range.");
 2651                        }
 12652                        addPatchEntry(indirectionTable[e.index], e.patcher);
 2653                    }
 12654                    _current.indirectPatchList.Clear();
 2655                }
 2656            }
 12657        }
 2658
 2659        internal override void skipSlice()
 2660        {
 12661            if (_stream.instance().traceLevels().slicing > 0)
 2662            {
 02663                Logger logger = _stream.instance().initializationData().logger!;
 02664                string slicingCat = _stream.instance().traceLevels().slicingCat;
 02665                if (_current!.sliceType == SliceType.ExceptionSlice)
 2666                {
 02667                    Ice.Internal.TraceUtil.traceSlicing("exception", _current.typeId, slicingCat, logger);
 2668                }
 2669                else
 2670                {
 02671                    Ice.Internal.TraceUtil.traceSlicing("object", _current.typeId, slicingCat, logger);
 2672                }
 2673            }
 2674
 12675            int start = _stream.pos();
 2676
 12677            if ((_current!.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
 2678            {
 2679                Debug.Assert(_current.sliceSize >= 4);
 12680                _stream.skip(_current.sliceSize - 4);
 2681            }
 2682            else
 2683            {
 12684                if (_current.sliceType == SliceType.ValueSlice)
 2685                {
 12686                    throw new MarshalException(
 12687                        $"The Slice loader did not find a class for type ID '{_current.typeId}' and compact format preve
 2688                }
 2689                else
 2690                {
 02691                    throw new MarshalException(
 02692                        $"The Slice loader did not find a user exception class for type ID '{_current.typeId}' and compa
 2693                }
 2694            }
 2695
 2696            //
 2697            // Preserve this slice if unmarshaling a value in Slice format. Exception slices are not preserved.
 2698            //
 12699            if (_current.sliceType == SliceType.ValueSlice)
 2700            {
 12701                bool hasOptionalMembers = (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0;
 2702
 12703                Ice.Internal.ByteBuffer b = _stream.getBuffer().b;
 12704                int end = b.position();
 12705                int dataEnd = end;
 12706                if (hasOptionalMembers)
 2707                {
 2708                    //
 2709                    // Don't include the optional member end marker. It will be re-written by
 2710                    // endSlice when the sliced data is re-written.
 2711                    //
 12712                    --dataEnd;
 2713                }
 12714                byte[] bytes = new byte[dataEnd - start];
 12715                b.position(start);
 12716                b.get(bytes);
 12717                b.position(end);
 2718
 12719                var info = new SliceInfo(
 12720                    typeId: _current.typeId!,
 12721                    compactId: _current.compactId,
 12722                    bytes: bytes,
 12723                    hasOptionalMembers: hasOptionalMembers,
 12724                    isLastSlice: (_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0);
 2725
 12726                _current.slices ??= new List<SliceInfo>();
 12727                _current.slices.Add(info);
 2728            }
 2729
 2730            //
 2731            // Read the indirect instance table. We read the instances or their
 2732            // IDs if the instance is a reference to an already unmarshaled
 2733            // instance.
 2734            //
 2735
 12736            _current.indirectionTables ??= new List<int[]?>();
 2737
 12738            if ((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0)
 2739            {
 12740                int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
 12741                for (int i = 0; i < indirectionTable.Length; ++i)
 2742                {
 12743                    indirectionTable[i] = readInstance(_stream.readSize(), null);
 2744                }
 12745                _current.indirectionTables.Add(indirectionTable);
 2746            }
 2747            else
 2748            {
 12749                _current.indirectionTables.Add(null);
 2750            }
 12751        }
 2752
 2753        internal override bool readOptional(int readTag, OptionalFormat expectedFormat)
 2754        {
 12755            if (_current == null)
 2756            {
 02757                return _stream.readOptImpl(readTag, expectedFormat);
 2758            }
 12759            else if ((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
 2760            {
 12761                return _stream.readOptImpl(readTag, expectedFormat);
 2762            }
 12763            return false;
 2764        }
 2765
 2766        private int readInstance(int index, System.Action<Value>? cb)
 2767        {
 2768            Debug.Assert(index > 0);
 2769
 12770            if (index > 1)
 2771            {
 12772                if (cb != null)
 2773                {
 12774                    addPatchEntry(index, cb);
 2775                }
 12776                return index;
 2777            }
 2778
 12779            push(SliceType.ValueSlice);
 2780
 2781            //
 2782            // Get the instance ID before we start reading slices. If some
 2783            // slices are skipped, the indirect instance table are still read and
 2784            // might read other instances.
 2785            //
 12786            index = ++_valueIdIndex;
 2787
 2788            //
 2789            // Read the first slice header.
 2790            //
 12791            startSlice();
 12792            string mostDerivedId = _current!.typeId!;
 2793            Value? v;
 12794            while (true)
 2795            {
 12796                string typeId = _current.typeId!;
 2797
 12798                if (typeId.Length > 0)
 2799                {
 12800                    v = newInstance(typeId);
 12801                    if (v is not null)
 2802                    {
 2803                        break;
 2804                    }
 2805                }
 2806
 2807                //
 2808                // Slice off what we don't understand.
 2809                //
 12810                skipSlice();
 2811
 2812                //
 2813                // If this is the last slice, keep the instance as an opaque
 2814                // UnknownSlicedValue object.
 2815                //
 12816                if ((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0)
 2817                {
 2818                    //
 2819                    // Provide a factory with an opportunity to supply the instance.
 2820                    // We pass the "::Ice::Object" ID to indicate that this is the
 2821                    // last chance to preserve the instance.
 2822                    //
 12823                    v = newInstance(Value.ice_staticId());
 12824                    v ??= new UnknownSlicedValue(mostDerivedId);
 2825
 12826                    break;
 2827                }
 2828
 12829                startSlice(); // Read next Slice header for next iteration.
 2830            }
 2831
 12832            if (++_classGraphDepth > _classGraphDepthMax)
 2833            {
 12834                throw new MarshalException("Maximum class graph depth reached.");
 2835            }
 2836
 2837            //
 2838            // Unmarshal the instance.
 2839            //
 12840            unmarshal(index, v);
 2841
 12842            --_classGraphDepth;
 2843
 12844            if (_current == null && _patchMap != null && _patchMap.Count > 0)
 2845            {
 2846                //
 2847                // If any entries remain in the patch map, the sender has sent an index for an instance, but failed
 2848                // to supply the instance.
 2849                //
 02850                throw new MarshalException("Index for class received, but no instance.");
 2851            }
 2852
 12853            cb?.Invoke(v);
 12854            return index;
 2855        }
 2856
 2857        private SlicedData? readSlicedData()
 2858        {
 12859            if (_current!.slices == null) // No preserved slices.
 2860            {
 12861                return null;
 2862            }
 2863
 2864            //
 2865            // The _indirectionTables member holds the indirection table for each slice
 2866            // in _slices.
 2867            //
 2868            Debug.Assert(_current.slices.Count == _current.indirectionTables!.Count);
 12869            for (int n = 0; n < _current.slices.Count; ++n)
 2870            {
 2871                //
 2872                // We use the "instances" list in SliceInfo to hold references
 2873                // to the target instances. Note that the instances might not have
 2874                // been read yet in the case of a circular reference to an
 2875                // enclosing instance.
 2876                //
 12877                int[]? table = _current.indirectionTables[n];
 12878                SliceInfo info = _current.slices[n];
 12879                info.instances = new Value[table != null ? table.Length : 0];
 12880                for (int j = 0; j < info.instances.Length; ++j)
 2881                {
 12882                    int cj = j;
 12883                    addPatchEntry(table![j], (Ice.Value v) => info.instances[cj] = v);
 2884                }
 2885            }
 2886
 12887            return new SlicedData(_current.slices.ToArray());
 2888        }
 2889
 2890        private void push(SliceType sliceType)
 2891        {
 12892            if (_current == null)
 2893            {
 12894                _current = new InstanceData(null);
 2895            }
 2896            else
 2897            {
 12898                _current = _current.next ?? new InstanceData(_current);
 2899            }
 12900            _current.sliceType = sliceType;
 12901            _current.skipFirstSlice = false;
 12902        }
 2903
 12904        private sealed record class IndirectPatchEntry(int index, Action<Value?> patcher);
 2905
 2906        private sealed class InstanceData
 2907        {
 12908            internal InstanceData(InstanceData? previous)
 2909            {
 12910                if (previous != null)
 2911                {
 12912                    previous.next = this;
 2913                }
 12914                this.previous = previous;
 12915                this.next = null;
 12916            }
 2917
 2918            // Instance attributes
 2919            internal SliceType sliceType;
 2920            internal bool skipFirstSlice;
 2921            internal List<SliceInfo>? slices;     // Preserved slices.
 2922            internal List<int[]?>? indirectionTables;
 2923
 2924            // Slice attributes
 2925            internal byte sliceFlags;
 2926            internal int sliceSize;
 2927            internal string? typeId;
 2928            internal int compactId;
 2929            internal Stack<IndirectPatchEntry>? indirectPatchList;
 2930
 2931            internal InstanceData? previous;
 2932            internal InstanceData? next;
 2933        }
 2934
 2935        private InstanceData? _current;
 2936        private int _valueIdIndex; // The ID of the next instance to unmarshal.
 2937    }
 2938
 2939    private sealed class Encaps
 2940    {
 12941        internal void reset() => decoder = null;
 2942
 2943        internal void setEncoding(EncodingVersion encoding)
 2944        {
 12945            this.encoding = encoding;
 12946            encoding_1_0 = encoding.Equals(Util.Encoding_1_0);
 12947        }
 2948
 2949        internal int start;
 2950        internal int sz;
 2951        internal EncodingVersion encoding;
 2952        internal bool encoding_1_0;
 2953
 2954        internal EncapsDecoder? decoder;
 2955
 2956        internal Encaps? next;
 2957    }
 2958
 2959    //
 2960    // The encoding version to use when there's no encapsulation to
 2961    // read from. This is for example used to read message headers.
 2962    //
 2963    private EncodingVersion _encoding;
 2964
 2965    private bool isEncoding_1_0() =>
 12966        _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0);
 2967
 2968    private Encaps? _encapsStack;
 2969    private Encaps? _encapsCache;
 2970
 2971    private void initEncaps()
 2972    {
 12973        if (_encapsStack == null) // Lazy initialization
 2974        {
 12975            _encapsStack = _encapsCache;
 12976            if (_encapsStack != null)
 2977            {
 02978                _encapsCache = _encapsCache!.next;
 2979            }
 2980            else
 2981            {
 12982                _encapsStack = new Encaps();
 2983            }
 12984            _encapsStack.setEncoding(_encoding);
 12985            _encapsStack.sz = _buf.b.limit();
 2986        }
 2987
 12988        if (_encapsStack.decoder == null) // Lazy initialization.
 2989        {
 12990            if (_encapsStack.encoding_1_0)
 2991            {
 12992                _encapsStack.decoder =
 12993                    new EncapsDecoder10(this, _encapsStack, _classGraphDepthMax);
 2994            }
 2995            else
 2996            {
 12997                _encapsStack.decoder =
 12998                    new EncapsDecoder11(this, _encapsStack, _classGraphDepthMax);
 2999            }
 3000        }
 13001    }
 3002
 3003    private readonly int _classGraphDepthMax;
 3004
 13005    private int _startSeq = -1;
 3006    private int _minSeqSize;
 3007
 3008    private const string endOfBufferMessage = "Attempting to unmarshal past the end of the buffer.";
 3009}

Methods/Properties

.ctor(Ice.Communicator, byte[])
.ctor(Ice.Communicator, Ice.EncodingVersion, byte[])
.ctor(Ice.Internal.Instance, Ice.EncodingVersion)
.ctor(Ice.Internal.Instance, Ice.EncodingVersion, Ice.Internal.Buffer, bool)
.ctor(Ice.Internal.Instance, Ice.EncodingVersion, Ice.Internal.Buffer)
reset()
clear()
instance()
swap(Ice.InputStream)
resetEncapsulation()
resize(int)
getBuffer()
startValue()
endValue()
startException()
endException()
startEncapsulation()
endEncapsulation()
skipEmptyEncapsulation()
readEncapsulation(out Ice.EncodingVersion)
getEncoding()
getEncapsulationSize()
skipEncapsulation()
startSlice()
endSlice()
skipSlice()
readPendingValues()
readSize()
readAndCheckSeqSize(int)
readBlob(byte[])
readBlob(int)
readOptional(int, Ice.OptionalFormat)
readByte()
readByte(int)
readByteSeq()
readByteSeq(out System.Collections.Generic.List<byte>)
readByteSeq(out System.Collections.Generic.LinkedList<byte>)
readByteSeq(out System.Collections.Generic.Queue<byte>)
readByteSeq(out System.Collections.Generic.Stack<byte>)
readByteSeq(int)
readBool()
readBool(int)
readBoolSeq()
readBoolSeq(out System.Collections.Generic.List<bool>)
readBoolSeq(out System.Collections.Generic.LinkedList<bool>)
readBoolSeq(out System.Collections.Generic.Queue<bool>)
readBoolSeq(out System.Collections.Generic.Stack<bool>)
readBoolSeq(int)
readShort()
readShort(int)
readShortSeq()
readShortSeq(out System.Collections.Generic.List<short>)
readShortSeq(out System.Collections.Generic.LinkedList<short>)
readShortSeq(out System.Collections.Generic.Queue<short>)
readShortSeq(out System.Collections.Generic.Stack<short>)
readShortSeq(int)
readInt()
readInt(int)
readIntSeq()
readIntSeq(out System.Collections.Generic.List<int>)
readIntSeq(out System.Collections.Generic.LinkedList<int>)
readIntSeq(out System.Collections.Generic.Queue<int>)
readIntSeq(out System.Collections.Generic.Stack<int>)
readIntSeq(int)
readLong()
readLong(int)
readLongSeq()
readLongSeq(out System.Collections.Generic.List<long>)
readLongSeq(out System.Collections.Generic.LinkedList<long>)
readLongSeq(out System.Collections.Generic.Queue<long>)
readLongSeq(out System.Collections.Generic.Stack<long>)
readLongSeq(int)
readFloat()
readFloat(int)
readFloatSeq()
readFloatSeq(out System.Collections.Generic.List<float>)
readFloatSeq(out System.Collections.Generic.LinkedList<float>)
readFloatSeq(out System.Collections.Generic.Queue<float>)
readFloatSeq(out System.Collections.Generic.Stack<float>)
readFloatSeq(int)
readDouble()
readDouble(int)
readDoubleSeq()
readDoubleSeq(out System.Collections.Generic.List<double>)
readDoubleSeq(out System.Collections.Generic.LinkedList<double>)
readDoubleSeq(out System.Collections.Generic.Queue<double>)
readDoubleSeq(out System.Collections.Generic.Stack<double>)
readDoubleSeq(int)
.cctor()
readString()
readString(int)
readStringSeq()
readStringSeq(out System.Collections.Generic.List<string>)
readStringSeq(out System.Collections.Generic.LinkedList<string>)
readStringSeq(out System.Collections.Generic.Queue<string>)
readStringSeq(out System.Collections.Generic.Stack<string>)
readStringSeq(int)
readProxy()
readProxy(int)
readEnum(int)
readValue<T>(System.Action<T>)
readValue(System.Action<Ice.Value>)
throwException()
skip(int)
skipSize()
pos()
pos(int)
size()
isEmpty()
readOptImpl(int, Ice.OptionalFormat)
skipOptional(Ice.OptionalFormat)
skipOptionals()
createUserException(string)
.ctor(System.Action<Ice.Value>, int)
.ctor(Ice.InputStream, Ice.InputStream.Encaps, int)
readOptional(int, Ice.OptionalFormat)
readPendingValues()
readTypeId(bool)
newInstance(string)
addPatchEntry(int, System.Action<Ice.Value>)
unmarshal(int, Ice.Value)
.ctor(Ice.InputStream, Ice.InputStream.Encaps, int)
readValue(System.Action<Ice.Value>)
throwException()
startInstance(Ice.InputStream.SliceType)
endInstance()
startSlice()
endSlice()
skipSlice()
readPendingValues()
readInstance()
.ctor(Ice.InputStream, Ice.InputStream.Encaps, int)
readValue(System.Action<Ice.Value>)
throwException()
startInstance(Ice.InputStream.SliceType)
endInstance()
startSlice()
endSlice()
skipSlice()
readOptional(int, Ice.OptionalFormat)
readInstance(int, System.Action<Ice.Value>)
readSlicedData()
push(Ice.InputStream.SliceType)
.ctor(int, System.Action<Ice.Value>)
.ctor(Ice.InputStream.EncapsDecoder11.InstanceData)
reset()
setEncoding(Ice.EncodingVersion)
isEncoding_1_0()
initEncaps()