1#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc.  All rights reserved.
4// https://developers.google.com/protocol-buffers/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10//     * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//     * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16//     * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#endregion
32
33using Google.Protobuf.Collections;
34using System;
35using System.Collections.Generic;
36using System.IO;
37
38namespace Google.Protobuf
39{
40    /// <summary>
41    /// Reads and decodes protocol message fields.
42    /// </summary>
43    /// <remarks>
44    /// <para>
45    /// This class is generally used by generated code to read appropriate
46    /// primitives from the stream. It effectively encapsulates the lowest
47    /// levels of protocol buffer format.
48    /// </para>
49    /// <para>
50    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
51    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
52    /// </para>
53    /// </remarks>
54    public sealed class CodedInputStream : IDisposable
55    {
56        /// <summary>
57        /// Whether to leave the underlying stream open when disposing of this stream.
58        /// This is always true when there's no stream.
59        /// </summary>
60        private readonly bool leaveOpen;
61
62        /// <summary>
63        /// Buffer of data read from the stream or provided at construction time.
64        /// </summary>
65        private readonly byte[] buffer;
66
67        /// <summary>
68        /// The index of the buffer at which we need to refill from the stream (if there is one).
69        /// </summary>
70        private int bufferSize;
71
72        private int bufferSizeAfterLimit = 0;
73        /// <summary>
74        /// The position within the current buffer (i.e. the next byte to read)
75        /// </summary>
76        private int bufferPos = 0;
77
78        /// <summary>
79        /// The stream to read further input from, or null if the byte array buffer was provided
80        /// directly on construction, with no further data available.
81        /// </summary>
82        private readonly Stream input;
83
84        /// <summary>
85        /// The last tag we read. 0 indicates we've read to the end of the stream
86        /// (or haven't read anything yet).
87        /// </summary>
88        private uint lastTag = 0;
89
90        /// <summary>
91        /// The next tag, used to store the value read by PeekTag.
92        /// </summary>
93        private uint nextTag = 0;
94        private bool hasNextTag = false;
95
96        internal const int DefaultRecursionLimit = 64;
97        internal const int DefaultSizeLimit = 64 << 20; // 64MB
98        internal const int BufferSize = 4096;
99
100        /// <summary>
101        /// The total number of bytes read before the current buffer. The
102        /// total bytes read up to the current position can be computed as
103        /// totalBytesRetired + bufferPos.
104        /// </summary>
105        private int totalBytesRetired = 0;
106
107        /// <summary>
108        /// The absolute position of the end of the current message.
109        /// </summary>
110        private int currentLimit = int.MaxValue;
111
112        private int recursionDepth = 0;
113
114        private readonly int recursionLimit;
115        private readonly int sizeLimit;
116
117        #region Construction
118        // Note that the checks are performed such that we don't end up checking obviously-valid things
119        // like non-null references for arrays we've just created.
120
121        /// <summary>
122        /// Creates a new CodedInputStream reading data from the given byte array.
123        /// </summary>
124        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)
125        {
126        }
127
128        /// <summary>
129        /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
130        /// </summary>
131        public CodedInputStream(byte[] buffer, int offset, int length)
132            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)
133        {
134            if (offset < 0 || offset > buffer.Length)
135            {
136                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
137            }
138            if (length < 0 || offset + length > buffer.Length)
139            {
140                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
141            }
142        }
143
144        /// <summary>
145        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
146        /// when the returned object is disposed.
147        /// </summary>
148        /// <param name="input">The stream to read from.</param>
149        public CodedInputStream(Stream input) : this(input, false)
150        {
151        }
152
153        /// <summary>
154        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
155        /// </summary>
156        /// <param name="input">The stream to read from.</param>
157        /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
158        /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the
159        /// returned object is disposed.</param>
160        public CodedInputStream(Stream input, bool leaveOpen)
161            : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0)
162        {
163            this.leaveOpen = leaveOpen;
164        }
165
166        /// <summary>
167        /// Creates a new CodedInputStream reading data from the given
168        /// stream and buffer, using the default limits.
169        /// </summary>
170        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize)
171        {
172            this.input = input;
173            this.buffer = buffer;
174            this.bufferPos = bufferPos;
175            this.bufferSize = bufferSize;
176            this.sizeLimit = DefaultSizeLimit;
177            this.recursionLimit = DefaultRecursionLimit;
178        }
179
180        /// <summary>
181        /// Creates a new CodedInputStream reading data from the given
182        /// stream and buffer, using the specified limits.
183        /// </summary>
184        /// <remarks>
185        /// This chains to the version with the default limits instead of vice versa to avoid
186        /// having to check that the default values are valid every time.
187        /// </remarks>
188        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit)
189            : this(input, buffer, bufferPos, bufferSize)
190        {
191            if (sizeLimit <= 0)
192            {
193                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
194            }
195            if (recursionLimit <= 0)
196            {
197                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
198            }
199            this.sizeLimit = sizeLimit;
200            this.recursionLimit = recursionLimit;
201        }
202        #endregion
203
204        /// <summary>
205        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
206        /// from an input stream.
207        /// </summary>
208        /// <remarks>
209        /// This method exists separately from the constructor to reduce the number of constructor overloads.
210        /// It is likely to be used considerably less frequently than the constructors, as the default limits
211        /// are suitable for most use cases.
212        /// </remarks>
213        /// <param name="input">The input stream to read from</param>
214        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
215        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
216        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
217        /// and recursion limits.</returns>
218        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
219        {
220            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit);
221        }
222
223        /// <summary>
224        /// Returns the current position in the input stream, or the position in the input buffer
225        /// </summary>
226        public long Position
227        {
228            get
229            {
230                if (input != null)
231                {
232                    return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);
233                }
234                return bufferPos;
235            }
236        }
237
238        /// <summary>
239        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
240        /// the end of the stream.
241        /// </summary>
242        internal uint LastTag { get { return lastTag; } }
243
244        /// <summary>
245        /// Returns the size limit for this stream.
246        /// </summary>
247        /// <remarks>
248        /// This limit is applied when reading from the underlying stream, as a sanity check. It is
249        /// not applied when reading from a byte array data source without an underlying stream.
250        /// The default value is 64MB.
251        /// </remarks>
252        /// <value>
253        /// The size limit.
254        /// </value>
255        public int SizeLimit { get { return sizeLimit; } }
256
257        /// <summary>
258        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
259        /// to avoid maliciously-recursive data.
260        /// </summary>
261        /// <remarks>
262        /// The default limit is 64.
263        /// </remarks>
264        /// <value>
265        /// The recursion limit for this stream.
266        /// </value>
267        public int RecursionLimit { get { return recursionLimit; } }
268
269        /// <summary>
270        /// Disposes of this instance, potentially closing any underlying stream.
271        /// </summary>
272        /// <remarks>
273        /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which
274        /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which
275        /// was constructed to read from a byte array) has no effect.
276        /// </remarks>
277        public void Dispose()
278        {
279            if (!leaveOpen)
280            {
281                input.Dispose();
282            }
283        }
284
285        #region Validation
286        /// <summary>
287        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
288        /// we've reached the end of the stream when we expected to.
289        /// </summary>
290        /// <exception cref="InvalidProtocolBufferException">The
291        /// tag read was not the one specified</exception>
292        internal void CheckReadEndOfStreamTag()
293        {
294            if (lastTag != 0)
295            {
296                throw InvalidProtocolBufferException.MoreDataAvailable();
297            }
298        }
299        #endregion
300
301        #region Reading of tags etc
302
303        /// <summary>
304        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
305        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
306        /// same value.)
307        /// </summary>
308        public uint PeekTag()
309        {
310            if (hasNextTag)
311            {
312                return nextTag;
313            }
314
315            uint savedLast = lastTag;
316            nextTag = ReadTag();
317            hasNextTag = true;
318            lastTag = savedLast; // Undo the side effect of ReadTag
319            return nextTag;
320        }
321
322        /// <summary>
323        /// Reads a field tag, returning the tag of 0 for "end of stream".
324        /// </summary>
325        /// <remarks>
326        /// If this method returns 0, it doesn't necessarily mean the end of all
327        /// the data in this CodedInputStream; it may be the end of the logical stream
328        /// for an embedded message, for example.
329        /// </remarks>
330        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
331        public uint ReadTag()
332        {
333            if (hasNextTag)
334            {
335                lastTag = nextTag;
336                hasNextTag = false;
337                return lastTag;
338            }
339
340            // Optimize for the incredibly common case of having at least two bytes left in the buffer,
341            // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
342            if (bufferPos + 2 <= bufferSize)
343            {
344                int tmp = buffer[bufferPos++];
345                if (tmp < 128)
346                {
347                    lastTag = (uint)tmp;
348                }
349                else
350                {
351                    int result = tmp & 0x7f;
352                    if ((tmp = buffer[bufferPos++]) < 128)
353                    {
354                        result |= tmp << 7;
355                        lastTag = (uint) result;
356                    }
357                    else
358                    {
359                        // Nope, rewind and go the potentially slow route.
360                        bufferPos -= 2;
361                        lastTag = ReadRawVarint32();
362                    }
363                }
364            }
365            else
366            {
367                if (IsAtEnd)
368                {
369                    lastTag = 0;
370                    return 0; // This is the only case in which we return 0.
371                }
372
373                lastTag = ReadRawVarint32();
374            }
375            if (lastTag == 0)
376            {
377                // If we actually read zero, that's not a valid tag.
378                throw InvalidProtocolBufferException.InvalidTag();
379            }
380            return lastTag;
381        }
382
383        /// <summary>
384        /// Skips the data for the field with the tag we've just read.
385        /// This should be called directly after <see cref="ReadTag"/>, when
386        /// the caller wishes to skip an unknown field.
387        /// </summary>
388        /// <remarks>
389        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
390        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
391        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
392        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
393        /// </remarks>
394        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
395        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
396        public void SkipLastField()
397        {
398            if (lastTag == 0)
399            {
400                throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
401            }
402            switch (WireFormat.GetTagWireType(lastTag))
403            {
404                case WireFormat.WireType.StartGroup:
405                    SkipGroup(lastTag);
406                    break;
407                case WireFormat.WireType.EndGroup:
408                    throw new InvalidProtocolBufferException(
409                        "SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");
410                case WireFormat.WireType.Fixed32:
411                    ReadFixed32();
412                    break;
413                case WireFormat.WireType.Fixed64:
414                    ReadFixed64();
415                    break;
416                case WireFormat.WireType.LengthDelimited:
417                    var length = ReadLength();
418                    SkipRawBytes(length);
419                    break;
420                case WireFormat.WireType.Varint:
421                    ReadRawVarint32();
422                    break;
423            }
424        }
425
426        private void SkipGroup(uint startGroupTag)
427        {
428            // Note: Currently we expect this to be the way that groups are read. We could put the recursion
429            // depth changes into the ReadTag method instead, potentially...
430            recursionDepth++;
431            if (recursionDepth >= recursionLimit)
432            {
433                throw InvalidProtocolBufferException.RecursionLimitExceeded();
434            }
435            uint tag;
436            while (true)
437            {
438                tag = ReadTag();
439                if (tag == 0)
440                {
441                    throw InvalidProtocolBufferException.TruncatedMessage();
442                }
443                // Can't call SkipLastField for this case- that would throw.
444                if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)
445                {
446                    break;
447                }
448                // This recursion will allow us to handle nested groups.
449                SkipLastField();
450            }
451            int startField = WireFormat.GetTagFieldNumber(startGroupTag);
452            int endField = WireFormat.GetTagFieldNumber(tag);
453            if (startField != endField)
454            {
455                throw new InvalidProtocolBufferException(
456                    $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}");
457            }
458            recursionDepth--;
459        }
460
461        /// <summary>
462        /// Reads a double field from the stream.
463        /// </summary>
464        public double ReadDouble()
465        {
466            return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
467        }
468
469        /// <summary>
470        /// Reads a float field from the stream.
471        /// </summary>
472        public float ReadFloat()
473        {
474            if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
475            {
476                float ret = BitConverter.ToSingle(buffer, bufferPos);
477                bufferPos += 4;
478                return ret;
479            }
480            else
481            {
482                byte[] rawBytes = ReadRawBytes(4);
483                if (!BitConverter.IsLittleEndian)
484                {
485                    ByteArray.Reverse(rawBytes);
486                }
487                return BitConverter.ToSingle(rawBytes, 0);
488            }
489        }
490
491        /// <summary>
492        /// Reads a uint64 field from the stream.
493        /// </summary>
494        public ulong ReadUInt64()
495        {
496            return ReadRawVarint64();
497        }
498
499        /// <summary>
500        /// Reads an int64 field from the stream.
501        /// </summary>
502        public long ReadInt64()
503        {
504            return (long) ReadRawVarint64();
505        }
506
507        /// <summary>
508        /// Reads an int32 field from the stream.
509        /// </summary>
510        public int ReadInt32()
511        {
512            return (int) ReadRawVarint32();
513        }
514
515        /// <summary>
516        /// Reads a fixed64 field from the stream.
517        /// </summary>
518        public ulong ReadFixed64()
519        {
520            return ReadRawLittleEndian64();
521        }
522
523        /// <summary>
524        /// Reads a fixed32 field from the stream.
525        /// </summary>
526        public uint ReadFixed32()
527        {
528            return ReadRawLittleEndian32();
529        }
530
531        /// <summary>
532        /// Reads a bool field from the stream.
533        /// </summary>
534        public bool ReadBool()
535        {
536            return ReadRawVarint32() != 0;
537        }
538
539        /// <summary>
540        /// Reads a string field from the stream.
541        /// </summary>
542        public string ReadString()
543        {
544            int length = ReadLength();
545            // No need to read any data for an empty string.
546            if (length == 0)
547            {
548                return "";
549            }
550            if (length <= bufferSize - bufferPos)
551            {
552                // Fast path:  We already have the bytes in a contiguous buffer, so
553                //   just copy directly from it.
554                String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
555                bufferPos += length;
556                return result;
557            }
558            // Slow path: Build a byte array first then copy it.
559            return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
560        }
561
562        /// <summary>
563        /// Reads an embedded message field value from the stream.
564        /// </summary>
565        public void ReadMessage(IMessage builder)
566        {
567            int length = ReadLength();
568            if (recursionDepth >= recursionLimit)
569            {
570                throw InvalidProtocolBufferException.RecursionLimitExceeded();
571            }
572            int oldLimit = PushLimit(length);
573            ++recursionDepth;
574            builder.MergeFrom(this);
575            CheckReadEndOfStreamTag();
576            // Check that we've read exactly as much data as expected.
577            if (!ReachedLimit)
578            {
579                throw InvalidProtocolBufferException.TruncatedMessage();
580            }
581            --recursionDepth;
582            PopLimit(oldLimit);
583        }
584
585        /// <summary>
586        /// Reads a bytes field value from the stream.
587        /// </summary>
588        public ByteString ReadBytes()
589        {
590            int length = ReadLength();
591            if (length <= bufferSize - bufferPos && length > 0)
592            {
593                // Fast path:  We already have the bytes in a contiguous buffer, so
594                //   just copy directly from it.
595                ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
596                bufferPos += length;
597                return result;
598            }
599            else
600            {
601                // Slow path:  Build a byte array and attach it to a new ByteString.
602                return ByteString.AttachBytes(ReadRawBytes(length));
603            }
604        }
605
606        /// <summary>
607        /// Reads a uint32 field value from the stream.
608        /// </summary>
609        public uint ReadUInt32()
610        {
611            return ReadRawVarint32();
612        }
613
614        /// <summary>
615        /// Reads an enum field value from the stream. If the enum is valid for type T,
616        /// then the ref value is set and it returns true.  Otherwise the unknown output
617        /// value is set and this method returns false.
618        /// </summary>
619        public int ReadEnum()
620        {
621            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
622            return (int) ReadRawVarint32();
623        }
624
625        /// <summary>
626        /// Reads an sfixed32 field value from the stream.
627        /// </summary>
628        public int ReadSFixed32()
629        {
630            return (int) ReadRawLittleEndian32();
631        }
632
633        /// <summary>
634        /// Reads an sfixed64 field value from the stream.
635        /// </summary>
636        public long ReadSFixed64()
637        {
638            return (long) ReadRawLittleEndian64();
639        }
640
641        /// <summary>
642        /// Reads an sint32 field value from the stream.
643        /// </summary>
644        public int ReadSInt32()
645        {
646            return DecodeZigZag32(ReadRawVarint32());
647        }
648
649        /// <summary>
650        /// Reads an sint64 field value from the stream.
651        /// </summary>
652        public long ReadSInt64()
653        {
654            return DecodeZigZag64(ReadRawVarint64());
655        }
656
657        /// <summary>
658        /// Reads a length for length-delimited data.
659        /// </summary>
660        /// <remarks>
661        /// This is internally just reading a varint, but this method exists
662        /// to make the calling code clearer.
663        /// </remarks>
664        public int ReadLength()
665        {
666            return (int) ReadRawVarint32();
667        }
668
669        /// <summary>
670        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
671        /// the tag is consumed and the method returns <c>true</c>; otherwise, the
672        /// stream is left in the original position and the method returns <c>false</c>.
673        /// </summary>
674        public bool MaybeConsumeTag(uint tag)
675        {
676            if (PeekTag() == tag)
677            {
678                hasNextTag = false;
679                return true;
680            }
681            return false;
682        }
683
684        #endregion
685
686        #region Underlying reading primitives
687
688        /// <summary>
689        /// Same code as ReadRawVarint32, but read each byte individually, checking for
690        /// buffer overflow.
691        /// </summary>
692        private uint SlowReadRawVarint32()
693        {
694            int tmp = ReadRawByte();
695            if (tmp < 128)
696            {
697                return (uint) tmp;
698            }
699            int result = tmp & 0x7f;
700            if ((tmp = ReadRawByte()) < 128)
701            {
702                result |= tmp << 7;
703            }
704            else
705            {
706                result |= (tmp & 0x7f) << 7;
707                if ((tmp = ReadRawByte()) < 128)
708                {
709                    result |= tmp << 14;
710                }
711                else
712                {
713                    result |= (tmp & 0x7f) << 14;
714                    if ((tmp = ReadRawByte()) < 128)
715                    {
716                        result |= tmp << 21;
717                    }
718                    else
719                    {
720                        result |= (tmp & 0x7f) << 21;
721                        result |= (tmp = ReadRawByte()) << 28;
722                        if (tmp >= 128)
723                        {
724                            // Discard upper 32 bits.
725                            for (int i = 0; i < 5; i++)
726                            {
727                                if (ReadRawByte() < 128)
728                                {
729                                    return (uint) result;
730                                }
731                            }
732                            throw InvalidProtocolBufferException.MalformedVarint();
733                        }
734                    }
735                }
736            }
737            return (uint) result;
738        }
739
740        /// <summary>
741        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.
742        /// This method is optimised for the case where we've got lots of data in the buffer.
743        /// That means we can check the size just once, then just read directly from the buffer
744        /// without constant rechecking of the buffer length.
745        /// </summary>
746        internal uint ReadRawVarint32()
747        {
748            if (bufferPos + 5 > bufferSize)
749            {
750                return SlowReadRawVarint32();
751            }
752
753            int tmp = buffer[bufferPos++];
754            if (tmp < 128)
755            {
756                return (uint) tmp;
757            }
758            int result = tmp & 0x7f;
759            if ((tmp = buffer[bufferPos++]) < 128)
760            {
761                result |= tmp << 7;
762            }
763            else
764            {
765                result |= (tmp & 0x7f) << 7;
766                if ((tmp = buffer[bufferPos++]) < 128)
767                {
768                    result |= tmp << 14;
769                }
770                else
771                {
772                    result |= (tmp & 0x7f) << 14;
773                    if ((tmp = buffer[bufferPos++]) < 128)
774                    {
775                        result |= tmp << 21;
776                    }
777                    else
778                    {
779                        result |= (tmp & 0x7f) << 21;
780                        result |= (tmp = buffer[bufferPos++]) << 28;
781                        if (tmp >= 128)
782                        {
783                            // Discard upper 32 bits.
784                            // Note that this has to use ReadRawByte() as we only ensure we've
785                            // got at least 5 bytes at the start of the method. This lets us
786                            // use the fast path in more cases, and we rarely hit this section of code.
787                            for (int i = 0; i < 5; i++)
788                            {
789                                if (ReadRawByte() < 128)
790                                {
791                                    return (uint) result;
792                                }
793                            }
794                            throw InvalidProtocolBufferException.MalformedVarint();
795                        }
796                    }
797                }
798            }
799            return (uint) result;
800        }
801
802        /// <summary>
803        /// Reads a varint from the input one byte at a time, so that it does not
804        /// read any bytes after the end of the varint. If you simply wrapped the
805        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
806        /// then you would probably end up reading past the end of the varint since
807        /// CodedInputStream buffers its input.
808        /// </summary>
809        /// <param name="input"></param>
810        /// <returns></returns>
811        internal static uint ReadRawVarint32(Stream input)
812        {
813            int result = 0;
814            int offset = 0;
815            for (; offset < 32; offset += 7)
816            {
817                int b = input.ReadByte();
818                if (b == -1)
819                {
820                    throw InvalidProtocolBufferException.TruncatedMessage();
821                }
822                result |= (b & 0x7f) << offset;
823                if ((b & 0x80) == 0)
824                {
825                    return (uint) result;
826                }
827            }
828            // Keep reading up to 64 bits.
829            for (; offset < 64; offset += 7)
830            {
831                int b = input.ReadByte();
832                if (b == -1)
833                {
834                    throw InvalidProtocolBufferException.TruncatedMessage();
835                }
836                if ((b & 0x80) == 0)
837                {
838                    return (uint) result;
839                }
840            }
841            throw InvalidProtocolBufferException.MalformedVarint();
842        }
843
844        /// <summary>
845        /// Reads a raw varint from the stream.
846        /// </summary>
847        internal ulong ReadRawVarint64()
848        {
849            int shift = 0;
850            ulong result = 0;
851            while (shift < 64)
852            {
853                byte b = ReadRawByte();
854                result |= (ulong) (b & 0x7F) << shift;
855                if ((b & 0x80) == 0)
856                {
857                    return result;
858                }
859                shift += 7;
860            }
861            throw InvalidProtocolBufferException.MalformedVarint();
862        }
863
864        /// <summary>
865        /// Reads a 32-bit little-endian integer from the stream.
866        /// </summary>
867        internal uint ReadRawLittleEndian32()
868        {
869            uint b1 = ReadRawByte();
870            uint b2 = ReadRawByte();
871            uint b3 = ReadRawByte();
872            uint b4 = ReadRawByte();
873            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
874        }
875
876        /// <summary>
877        /// Reads a 64-bit little-endian integer from the stream.
878        /// </summary>
879        internal ulong ReadRawLittleEndian64()
880        {
881            ulong b1 = ReadRawByte();
882            ulong b2 = ReadRawByte();
883            ulong b3 = ReadRawByte();
884            ulong b4 = ReadRawByte();
885            ulong b5 = ReadRawByte();
886            ulong b6 = ReadRawByte();
887            ulong b7 = ReadRawByte();
888            ulong b8 = ReadRawByte();
889            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
890                   | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
891        }
892
893        /// <summary>
894        /// Decode a 32-bit value with ZigZag encoding.
895        /// </summary>
896        /// <remarks>
897        /// ZigZag encodes signed integers into values that can be efficiently
898        /// encoded with varint.  (Otherwise, negative values must be
899        /// sign-extended to 64 bits to be varint encoded, thus always taking
900        /// 10 bytes on the wire.)
901        /// </remarks>
902        internal static int DecodeZigZag32(uint n)
903        {
904            return (int)(n >> 1) ^ -(int)(n & 1);
905        }
906
907        /// <summary>
908        /// Decode a 32-bit value with ZigZag encoding.
909        /// </summary>
910        /// <remarks>
911        /// ZigZag encodes signed integers into values that can be efficiently
912        /// encoded with varint.  (Otherwise, negative values must be
913        /// sign-extended to 64 bits to be varint encoded, thus always taking
914        /// 10 bytes on the wire.)
915        /// </remarks>
916        internal static long DecodeZigZag64(ulong n)
917        {
918            return (long)(n >> 1) ^ -(long)(n & 1);
919        }
920        #endregion
921
922        #region Internal reading and buffer management
923
924        /// <summary>
925        /// Sets currentLimit to (current position) + byteLimit. This is called
926        /// when descending into a length-delimited embedded message. The previous
927        /// limit is returned.
928        /// </summary>
929        /// <returns>The old limit.</returns>
930        internal int PushLimit(int byteLimit)
931        {
932            if (byteLimit < 0)
933            {
934                throw InvalidProtocolBufferException.NegativeSize();
935            }
936            byteLimit += totalBytesRetired + bufferPos;
937            int oldLimit = currentLimit;
938            if (byteLimit > oldLimit)
939            {
940                throw InvalidProtocolBufferException.TruncatedMessage();
941            }
942            currentLimit = byteLimit;
943
944            RecomputeBufferSizeAfterLimit();
945
946            return oldLimit;
947        }
948
949        private void RecomputeBufferSizeAfterLimit()
950        {
951            bufferSize += bufferSizeAfterLimit;
952            int bufferEnd = totalBytesRetired + bufferSize;
953            if (bufferEnd > currentLimit)
954            {
955                // Limit is in current buffer.
956                bufferSizeAfterLimit = bufferEnd - currentLimit;
957                bufferSize -= bufferSizeAfterLimit;
958            }
959            else
960            {
961                bufferSizeAfterLimit = 0;
962            }
963        }
964
965        /// <summary>
966        /// Discards the current limit, returning the previous limit.
967        /// </summary>
968        internal void PopLimit(int oldLimit)
969        {
970            currentLimit = oldLimit;
971            RecomputeBufferSizeAfterLimit();
972        }
973
974        /// <summary>
975        /// Returns whether or not all the data before the limit has been read.
976        /// </summary>
977        /// <returns></returns>
978        internal bool ReachedLimit
979        {
980            get
981            {
982                if (currentLimit == int.MaxValue)
983                {
984                    return false;
985                }
986                int currentAbsolutePosition = totalBytesRetired + bufferPos;
987                return currentAbsolutePosition >= currentLimit;
988            }
989        }
990
991        /// <summary>
992        /// Returns true if the stream has reached the end of the input. This is the
993        /// case if either the end of the underlying input source has been reached or
994        /// the stream has reached a limit created using PushLimit.
995        /// </summary>
996        public bool IsAtEnd
997        {
998            get { return bufferPos == bufferSize && !RefillBuffer(false); }
999        }
1000
1001        /// <summary>
1002        /// Called when buffer is empty to read more bytes from the
1003        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
1004        /// either there will be at least one byte in the buffer when it returns
1005        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,
1006        /// RefillBuffer() returns false if no more bytes were available.
1007        /// </summary>
1008        /// <param name="mustSucceed"></param>
1009        /// <returns></returns>
1010        private bool RefillBuffer(bool mustSucceed)
1011        {
1012            if (bufferPos < bufferSize)
1013            {
1014                throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
1015            }
1016
1017            if (totalBytesRetired + bufferSize == currentLimit)
1018            {
1019                // Oops, we hit a limit.
1020                if (mustSucceed)
1021                {
1022                    throw InvalidProtocolBufferException.TruncatedMessage();
1023                }
1024                else
1025                {
1026                    return false;
1027                }
1028            }
1029
1030            totalBytesRetired += bufferSize;
1031
1032            bufferPos = 0;
1033            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
1034            if (bufferSize < 0)
1035            {
1036                throw new InvalidOperationException("Stream.Read returned a negative count");
1037            }
1038            if (bufferSize == 0)
1039            {
1040                if (mustSucceed)
1041                {
1042                    throw InvalidProtocolBufferException.TruncatedMessage();
1043                }
1044                else
1045                {
1046                    return false;
1047                }
1048            }
1049            else
1050            {
1051                RecomputeBufferSizeAfterLimit();
1052                int totalBytesRead =
1053                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;
1054                if (totalBytesRead > sizeLimit || totalBytesRead < 0)
1055                {
1056                    throw InvalidProtocolBufferException.SizeLimitExceeded();
1057                }
1058                return true;
1059            }
1060        }
1061
1062        /// <summary>
1063        /// Read one byte from the input.
1064        /// </summary>
1065        /// <exception cref="InvalidProtocolBufferException">
1066        /// the end of the stream or the current limit was reached
1067        /// </exception>
1068        internal byte ReadRawByte()
1069        {
1070            if (bufferPos == bufferSize)
1071            {
1072                RefillBuffer(true);
1073            }
1074            return buffer[bufferPos++];
1075        }
1076
1077        /// <summary>
1078        /// Reads a fixed size of bytes from the input.
1079        /// </summary>
1080        /// <exception cref="InvalidProtocolBufferException">
1081        /// the end of the stream or the current limit was reached
1082        /// </exception>
1083        internal byte[] ReadRawBytes(int size)
1084        {
1085            if (size < 0)
1086            {
1087                throw InvalidProtocolBufferException.NegativeSize();
1088            }
1089
1090            if (totalBytesRetired + bufferPos + size > currentLimit)
1091            {
1092                // Read to the end of the stream (up to the current limit) anyway.
1093                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
1094                // Then fail.
1095                throw InvalidProtocolBufferException.TruncatedMessage();
1096            }
1097
1098            if (size <= bufferSize - bufferPos)
1099            {
1100                // We have all the bytes we need already.
1101                byte[] bytes = new byte[size];
1102                ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
1103                bufferPos += size;
1104                return bytes;
1105            }
1106            else if (size < buffer.Length)
1107            {
1108                // Reading more bytes than are in the buffer, but not an excessive number
1109                // of bytes.  We can safely allocate the resulting array ahead of time.
1110
1111                // First copy what we have.
1112                byte[] bytes = new byte[size];
1113                int pos = bufferSize - bufferPos;
1114                ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
1115                bufferPos = bufferSize;
1116
1117                // We want to use RefillBuffer() and then copy from the buffer into our
1118                // byte array rather than reading directly into our byte array because
1119                // the input may be unbuffered.
1120                RefillBuffer(true);
1121
1122                while (size - pos > bufferSize)
1123                {
1124                    Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
1125                    pos += bufferSize;
1126                    bufferPos = bufferSize;
1127                    RefillBuffer(true);
1128                }
1129
1130                ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
1131                bufferPos = size - pos;
1132
1133                return bytes;
1134            }
1135            else
1136            {
1137                // The size is very large.  For security reasons, we can't allocate the
1138                // entire byte array yet.  The size comes directly from the input, so a
1139                // maliciously-crafted message could provide a bogus very large size in
1140                // order to trick the app into allocating a lot of memory.  We avoid this
1141                // by allocating and reading only a small chunk at a time, so that the
1142                // malicious message must actually *be* extremely large to cause
1143                // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
1144
1145                // Remember the buffer markers since we'll have to copy the bytes out of
1146                // it later.
1147                int originalBufferPos = bufferPos;
1148                int originalBufferSize = bufferSize;
1149
1150                // Mark the current buffer consumed.
1151                totalBytesRetired += bufferSize;
1152                bufferPos = 0;
1153                bufferSize = 0;
1154
1155                // Read all the rest of the bytes we need.
1156                int sizeLeft = size - (originalBufferSize - originalBufferPos);
1157                List<byte[]> chunks = new List<byte[]>();
1158
1159                while (sizeLeft > 0)
1160                {
1161                    byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];
1162                    int pos = 0;
1163                    while (pos < chunk.Length)
1164                    {
1165                        int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
1166                        if (n <= 0)
1167                        {
1168                            throw InvalidProtocolBufferException.TruncatedMessage();
1169                        }
1170                        totalBytesRetired += n;
1171                        pos += n;
1172                    }
1173                    sizeLeft -= chunk.Length;
1174                    chunks.Add(chunk);
1175                }
1176
1177                // OK, got everything.  Now concatenate it all into one buffer.
1178                byte[] bytes = new byte[size];
1179
1180                // Start by copying the leftover bytes from this.buffer.
1181                int newPos = originalBufferSize - originalBufferPos;
1182                ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
1183
1184                // And now all the chunks.
1185                foreach (byte[] chunk in chunks)
1186                {
1187                    Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
1188                    newPos += chunk.Length;
1189                }
1190
1191                // Done.
1192                return bytes;
1193            }
1194        }
1195
1196        /// <summary>
1197        /// Reads and discards <paramref name="size"/> bytes.
1198        /// </summary>
1199        /// <exception cref="InvalidProtocolBufferException">the end of the stream
1200        /// or the current limit was reached</exception>
1201        private void SkipRawBytes(int size)
1202        {
1203            if (size < 0)
1204            {
1205                throw InvalidProtocolBufferException.NegativeSize();
1206            }
1207
1208            if (totalBytesRetired + bufferPos + size > currentLimit)
1209            {
1210                // Read to the end of the stream anyway.
1211                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
1212                // Then fail.
1213                throw InvalidProtocolBufferException.TruncatedMessage();
1214            }
1215
1216            if (size <= bufferSize - bufferPos)
1217            {
1218                // We have all the bytes we need already.
1219                bufferPos += size;
1220            }
1221            else
1222            {
1223                // Skipping more bytes than are in the buffer.  First skip what we have.
1224                int pos = bufferSize - bufferPos;
1225
1226                // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)
1227                // totalBytesRetired += pos;
1228                totalBytesRetired += bufferSize;
1229
1230                bufferPos = 0;
1231                bufferSize = 0;
1232
1233                // Then skip directly from the InputStream for the rest.
1234                if (pos < size)
1235                {
1236                    if (input == null)
1237                    {
1238                        throw InvalidProtocolBufferException.TruncatedMessage();
1239                    }
1240                    SkipImpl(size - pos);
1241                    totalBytesRetired += size - pos;
1242                }
1243            }
1244        }
1245
1246        /// <summary>
1247        /// Abstraction of skipping to cope with streams which can't really skip.
1248        /// </summary>
1249        private void SkipImpl(int amountToSkip)
1250        {
1251            if (input.CanSeek)
1252            {
1253                long previousPosition = input.Position;
1254                input.Position += amountToSkip;
1255                if (input.Position != previousPosition + amountToSkip)
1256                {
1257                    throw InvalidProtocolBufferException.TruncatedMessage();
1258                }
1259            }
1260            else
1261            {
1262                byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];
1263                while (amountToSkip > 0)
1264                {
1265                    int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));
1266                    if (bytesRead <= 0)
1267                    {
1268                        throw InvalidProtocolBufferException.TruncatedMessage();
1269                    }
1270                    amountToSkip -= bytesRead;
1271                }
1272            }
1273        }
1274
1275        #endregion
1276    }
1277}