|
@@ -37,7 +37,6 @@
|
|
using System;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO;
|
|
-using Google.Protobuf.Collections;
|
|
|
|
|
|
|
|
namespace Google.Protobuf
|
|
namespace Google.Protobuf
|
|
{
|
|
{
|
|
@@ -178,8 +177,61 @@ namespace Google.Protobuf
|
|
/// </summary>
|
|
/// </summary>
|
|
internal uint LastTag { get { return lastTag; } }
|
|
internal uint LastTag { get { return lastTag; } }
|
|
|
|
|
|
- #region Validation
|
|
|
|
|
|
+ #region Limits for recursion and length
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Set the maximum message recursion depth.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// In order to prevent malicious
|
|
|
|
+ /// messages from causing stack overflows, CodedInputStream limits
|
|
|
|
+ /// how deeply messages may be nested. The default limit is 64.
|
|
|
|
+ /// </remarks>
|
|
|
|
+ public int SetRecursionLimit(int limit)
|
|
|
|
+ {
|
|
|
|
+ if (limit < 0)
|
|
|
|
+ {
|
|
|
|
+ throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);
|
|
|
|
+ }
|
|
|
|
+ int oldLimit = recursionLimit;
|
|
|
|
+ recursionLimit = limit;
|
|
|
|
+ return oldLimit;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Set the maximum message size.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// In order to prevent malicious messages from exhausting memory or
|
|
|
|
+ /// causing integer overflows, CodedInputStream limits how large a message may be.
|
|
|
|
+ /// The default limit is 64MB. You should set this limit as small
|
|
|
|
+ /// as you can without harming your app's functionality. Note that
|
|
|
|
+ /// size limits only apply when reading from an InputStream, not
|
|
|
|
+ /// when constructed around a raw byte array (nor with ByteString.NewCodedInput).
|
|
|
|
+ /// If you want to read several messages from a single CodedInputStream, you
|
|
|
|
+ /// can call ResetSizeCounter() after each message to avoid hitting the
|
|
|
|
+ /// size limit.
|
|
|
|
+ /// </remarks>
|
|
|
|
+ public int SetSizeLimit(int limit)
|
|
|
|
+ {
|
|
|
|
+ if (limit < 0)
|
|
|
|
+ {
|
|
|
|
+ throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);
|
|
|
|
+ }
|
|
|
|
+ int oldLimit = sizeLimit;
|
|
|
|
+ sizeLimit = limit;
|
|
|
|
+ return oldLimit;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Resets the current size counter to zero (see <see cref="SetSizeLimit"/>).
|
|
|
|
+ /// </summary>
|
|
|
|
+ public void ResetSizeCounter()
|
|
|
|
+ {
|
|
|
|
+ totalBytesRetired = 0;
|
|
|
|
+ }
|
|
|
|
+ #endregion
|
|
|
|
|
|
|
|
+ #region Validation
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Verifies that the last call to ReadTag() returned the given tag value.
|
|
/// Verifies that the last call to ReadTag() returned the given tag value.
|
|
/// This is used to verify that a nested group ended with the correct
|
|
/// This is used to verify that a nested group ended with the correct
|
|
@@ -194,13 +246,12 @@ namespace Google.Protobuf
|
|
throw InvalidProtocolBufferException.InvalidEndTag();
|
|
throw InvalidProtocolBufferException.InvalidEndTag();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
#region Reading of tags etc
|
|
#region Reading of tags etc
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Attempt to peek at the next field tag.
|
|
|
|
|
|
+ /// Attempts to peek at the next field tag.
|
|
/// </summary>
|
|
/// </summary>
|
|
public bool PeekNextTag(out uint fieldTag)
|
|
public bool PeekNextTag(out uint fieldTag)
|
|
{
|
|
{
|
|
@@ -218,7 +269,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Attempt to read a field tag, returning false if we have reached the end
|
|
|
|
|
|
+ /// Attempts to read a field tag, returning false if we have reached the end
|
|
/// of the input data.
|
|
/// of the input data.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="fieldTag">The 'tag' of the field (id * 8 + wire-format)</param>
|
|
/// <param name="fieldTag">The 'tag' of the field (id * 8 + wire-format)</param>
|
|
@@ -233,14 +284,42 @@ namespace Google.Protobuf
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (IsAtEnd)
|
|
|
|
|
|
+ // Optimize for the incredibly common case of having at least two bytes left in the buffer,
|
|
|
|
+ // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
|
|
|
|
+ if (bufferPos + 2 <= bufferSize)
|
|
{
|
|
{
|
|
- fieldTag = 0;
|
|
|
|
- lastTag = fieldTag;
|
|
|
|
- return false;
|
|
|
|
|
|
+ int tmp = buffer[bufferPos++];
|
|
|
|
+ if (tmp < 128)
|
|
|
|
+ {
|
|
|
|
+ fieldTag = (uint)tmp;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ int result = tmp & 0x7f;
|
|
|
|
+ if ((tmp = buffer[bufferPos++]) < 128)
|
|
|
|
+ {
|
|
|
|
+ result |= tmp << 7;
|
|
|
|
+ fieldTag = (uint) result;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Nope, rewind and go the potentially slow route.
|
|
|
|
+ bufferPos -= 2;
|
|
|
|
+ fieldTag = ReadRawVarint32();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ if (IsAtEnd)
|
|
|
|
+ {
|
|
|
|
+ fieldTag = 0;
|
|
|
|
+ lastTag = fieldTag;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
- fieldTag = ReadRawVarint32();
|
|
|
|
|
|
+ fieldTag = ReadRawVarint32();
|
|
|
|
+ }
|
|
lastTag = fieldTag;
|
|
lastTag = fieldTag;
|
|
if (lastTag == 0)
|
|
if (lastTag == 0)
|
|
{
|
|
{
|
|
@@ -251,7 +330,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a double field from the stream.
|
|
|
|
|
|
+ /// Reads a double field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public double ReadDouble()
|
|
public double ReadDouble()
|
|
{
|
|
{
|
|
@@ -259,7 +338,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a float field from the stream.
|
|
|
|
|
|
+ /// Reads a float field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public float ReadFloat()
|
|
public float ReadFloat()
|
|
{
|
|
{
|
|
@@ -281,7 +360,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a uint64 field from the stream.
|
|
|
|
|
|
+ /// Reads a uint64 field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public ulong ReadUInt64()
|
|
public ulong ReadUInt64()
|
|
{
|
|
{
|
|
@@ -289,7 +368,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read an int64 field from the stream.
|
|
|
|
|
|
+ /// Reads an int64 field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public long ReadInt64()
|
|
public long ReadInt64()
|
|
{
|
|
{
|
|
@@ -297,7 +376,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read an int32 field from the stream.
|
|
|
|
|
|
+ /// Reads an int32 field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public int ReadInt32()
|
|
public int ReadInt32()
|
|
{
|
|
{
|
|
@@ -305,7 +384,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a fixed64 field from the stream.
|
|
|
|
|
|
+ /// Reads a fixed64 field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public ulong ReadFixed64()
|
|
public ulong ReadFixed64()
|
|
{
|
|
{
|
|
@@ -313,7 +392,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a fixed32 field from the stream.
|
|
|
|
|
|
+ /// Reads a fixed32 field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public uint ReadFixed32()
|
|
public uint ReadFixed32()
|
|
{
|
|
{
|
|
@@ -321,7 +400,7 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a bool field from the stream.
|
|
|
|
|
|
+ /// Reads a bool field from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
public bool ReadBool()
|
|
public bool ReadBool()
|
|
{
|
|
{
|
|
@@ -333,22 +412,22 @@ namespace Google.Protobuf
|
|
/// </summary>
|
|
/// </summary>
|
|
public string ReadString()
|
|
public string ReadString()
|
|
{
|
|
{
|
|
- int size = (int) ReadRawVarint32();
|
|
|
|
|
|
+ int length = ReadLength();
|
|
// No need to read any data for an empty string.
|
|
// No need to read any data for an empty string.
|
|
- if (size == 0)
|
|
|
|
|
|
+ if (length == 0)
|
|
{
|
|
{
|
|
return "";
|
|
return "";
|
|
}
|
|
}
|
|
- if (size <= bufferSize - bufferPos)
|
|
|
|
|
|
+ if (length <= bufferSize - bufferPos)
|
|
{
|
|
{
|
|
// Fast path: We already have the bytes in a contiguous buffer, so
|
|
// Fast path: We already have the bytes in a contiguous buffer, so
|
|
// just copy directly from it.
|
|
// just copy directly from it.
|
|
- String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, size);
|
|
|
|
- bufferPos += size;
|
|
|
|
|
|
+ String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
|
|
|
|
+ bufferPos += length;
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
// Slow path: Build a byte array first then copy it.
|
|
// Slow path: Build a byte array first then copy it.
|
|
- return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(size), 0, size);
|
|
|
|
|
|
+ return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -356,7 +435,7 @@ namespace Google.Protobuf
|
|
/// </summary>
|
|
/// </summary>
|
|
public void ReadMessage(IMessage builder)
|
|
public void ReadMessage(IMessage builder)
|
|
{
|
|
{
|
|
- int length = (int) ReadRawVarint32();
|
|
|
|
|
|
+ int length = ReadLength();
|
|
if (recursionDepth >= recursionLimit)
|
|
if (recursionDepth >= recursionLimit)
|
|
{
|
|
{
|
|
throw InvalidProtocolBufferException.RecursionLimitExceeded();
|
|
throw InvalidProtocolBufferException.RecursionLimitExceeded();
|
|
@@ -374,19 +453,19 @@ namespace Google.Protobuf
|
|
/// </summary>
|
|
/// </summary>
|
|
public ByteString ReadBytes()
|
|
public ByteString ReadBytes()
|
|
{
|
|
{
|
|
- int size = (int) ReadRawVarint32();
|
|
|
|
- if (size <= bufferSize - bufferPos && size > 0)
|
|
|
|
|
|
+ int length = ReadLength();
|
|
|
|
+ if (length <= bufferSize - bufferPos && length > 0)
|
|
{
|
|
{
|
|
// Fast path: We already have the bytes in a contiguous buffer, so
|
|
// Fast path: We already have the bytes in a contiguous buffer, so
|
|
// just copy directly from it.
|
|
// just copy directly from it.
|
|
- ByteString result = ByteString.CopyFrom(buffer, bufferPos, size);
|
|
|
|
- bufferPos += size;
|
|
|
|
|
|
+ ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
|
|
|
|
+ bufferPos += length;
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
// Slow path: Build a byte array and attach it to a new ByteString.
|
|
// Slow path: Build a byte array and attach it to a new ByteString.
|
|
- return ByteString.AttachBytes(ReadRawBytes(size));
|
|
|
|
|
|
+ return ByteString.AttachBytes(ReadRawBytes(length));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -441,6 +520,18 @@ namespace Google.Protobuf
|
|
return DecodeZigZag64(ReadRawVarint64());
|
|
return DecodeZigZag64(ReadRawVarint64());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Reads a length for length-delimited data.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// This is internally just reading a varint, but this method exists
|
|
|
|
+ /// to make the calling code clearer.
|
|
|
|
+ /// </remarks>
|
|
|
|
+ public int ReadLength()
|
|
|
|
+ {
|
|
|
|
+ return (int) ReadRawVarint32();
|
|
|
|
+ }
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
|
|
/// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
|
|
/// the tag is consumed and the method returns <c>true</c>; otherwise, the
|
|
/// the tag is consumed and the method returns <c>true</c>; otherwise, the
|
|
@@ -517,12 +608,12 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
|
|
|
|
|
|
+ /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
|
|
/// This method is optimised for the case where we've got lots of data in the buffer.
|
|
/// This method is optimised for the case where we've got lots of data in the buffer.
|
|
/// That means we can check the size just once, then just read directly from the buffer
|
|
/// That means we can check the size just once, then just read directly from the buffer
|
|
/// without constant rechecking of the buffer length.
|
|
/// without constant rechecking of the buffer length.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public uint ReadRawVarint32()
|
|
|
|
|
|
+ internal uint ReadRawVarint32()
|
|
{
|
|
{
|
|
if (bufferPos + 5 > bufferSize)
|
|
if (bufferPos + 5 > bufferSize)
|
|
{
|
|
{
|
|
@@ -581,13 +672,13 @@ namespace Google.Protobuf
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Reads a varint from the input one byte at a time, so that it does not
|
|
/// Reads a varint from the input one byte at a time, so that it does not
|
|
/// read any bytes after the end of the varint. If you simply wrapped the
|
|
/// read any bytes after the end of the varint. If you simply wrapped the
|
|
- /// stream in a CodedInputStream and used ReadRawVarint32(Stream)}
|
|
|
|
|
|
+ /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
|
|
/// then you would probably end up reading past the end of the varint since
|
|
/// then you would probably end up reading past the end of the varint since
|
|
/// CodedInputStream buffers its input.
|
|
/// CodedInputStream buffers its input.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|
|
- public static uint ReadRawVarint32(Stream input)
|
|
|
|
|
|
+ internal static uint ReadRawVarint32(Stream input)
|
|
{
|
|
{
|
|
int result = 0;
|
|
int result = 0;
|
|
int offset = 0;
|
|
int offset = 0;
|
|
@@ -621,9 +712,9 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a raw varint from the stream.
|
|
|
|
|
|
+ /// Reads a raw varint from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public ulong ReadRawVarint64()
|
|
|
|
|
|
+ internal ulong ReadRawVarint64()
|
|
{
|
|
{
|
|
int shift = 0;
|
|
int shift = 0;
|
|
ulong result = 0;
|
|
ulong result = 0;
|
|
@@ -641,9 +732,9 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a 32-bit little-endian integer from the stream.
|
|
|
|
|
|
+ /// Reads a 32-bit little-endian integer from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public uint ReadRawLittleEndian32()
|
|
|
|
|
|
+ internal uint ReadRawLittleEndian32()
|
|
{
|
|
{
|
|
uint b1 = ReadRawByte();
|
|
uint b1 = ReadRawByte();
|
|
uint b2 = ReadRawByte();
|
|
uint b2 = ReadRawByte();
|
|
@@ -653,9 +744,9 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a 64-bit little-endian integer from the stream.
|
|
|
|
|
|
+ /// Reads a 64-bit little-endian integer from the stream.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public ulong ReadRawLittleEndian64()
|
|
|
|
|
|
+ internal ulong ReadRawLittleEndian64()
|
|
{
|
|
{
|
|
ulong b1 = ReadRawByte();
|
|
ulong b1 = ReadRawByte();
|
|
ulong b2 = ReadRawByte();
|
|
ulong b2 = ReadRawByte();
|
|
@@ -669,8 +760,6 @@ namespace Google.Protobuf
|
|
| (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
|
|
| (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
|
|
}
|
|
}
|
|
|
|
|
|
- #endregion
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Decode a 32-bit value with ZigZag encoding.
|
|
/// Decode a 32-bit value with ZigZag encoding.
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -680,9 +769,9 @@ namespace Google.Protobuf
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
|
/// 10 bytes on the wire.)
|
|
/// 10 bytes on the wire.)
|
|
/// </remarks>
|
|
/// </remarks>
|
|
- public static int DecodeZigZag32(uint n)
|
|
|
|
|
|
+ internal static int DecodeZigZag32(uint n)
|
|
{
|
|
{
|
|
- return (int) (n >> 1) ^ -(int) (n & 1);
|
|
|
|
|
|
+ return (int)(n >> 1) ^ -(int)(n & 1);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -694,72 +783,21 @@ namespace Google.Protobuf
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
|
/// 10 bytes on the wire.)
|
|
/// 10 bytes on the wire.)
|
|
/// </remarks>
|
|
/// </remarks>
|
|
- public static long DecodeZigZag64(ulong n)
|
|
|
|
- {
|
|
|
|
- return (long) (n >> 1) ^ -(long) (n & 1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Set the maximum message recursion depth.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <remarks>
|
|
|
|
- /// In order to prevent malicious
|
|
|
|
- /// messages from causing stack overflows, CodedInputStream limits
|
|
|
|
- /// how deeply messages may be nested. The default limit is 64.
|
|
|
|
- /// </remarks>
|
|
|
|
- public int SetRecursionLimit(int limit)
|
|
|
|
- {
|
|
|
|
- if (limit < 0)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);
|
|
|
|
- }
|
|
|
|
- int oldLimit = recursionLimit;
|
|
|
|
- recursionLimit = limit;
|
|
|
|
- return oldLimit;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Set the maximum message size.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <remarks>
|
|
|
|
- /// In order to prevent malicious messages from exhausting memory or
|
|
|
|
- /// causing integer overflows, CodedInputStream limits how large a message may be.
|
|
|
|
- /// The default limit is 64MB. You should set this limit as small
|
|
|
|
- /// as you can without harming your app's functionality. Note that
|
|
|
|
- /// size limits only apply when reading from an InputStream, not
|
|
|
|
- /// when constructed around a raw byte array (nor with ByteString.NewCodedInput).
|
|
|
|
- /// If you want to read several messages from a single CodedInputStream, you
|
|
|
|
- /// can call ResetSizeCounter() after each message to avoid hitting the
|
|
|
|
- /// size limit.
|
|
|
|
- /// </remarks>
|
|
|
|
- public int SetSizeLimit(int limit)
|
|
|
|
|
|
+ internal static long DecodeZigZag64(ulong n)
|
|
{
|
|
{
|
|
- if (limit < 0)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);
|
|
|
|
- }
|
|
|
|
- int oldLimit = sizeLimit;
|
|
|
|
- sizeLimit = limit;
|
|
|
|
- return oldLimit;
|
|
|
|
|
|
+ return (long)(n >> 1) ^ -(long)(n & 1);
|
|
}
|
|
}
|
|
|
|
+ #endregion
|
|
|
|
|
|
#region Internal reading and buffer management
|
|
#region Internal reading and buffer management
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// Resets the current size counter to zero (see SetSizeLimit).
|
|
|
|
- /// </summary>
|
|
|
|
- public void ResetSizeCounter()
|
|
|
|
- {
|
|
|
|
- totalBytesRetired = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Sets currentLimit to (current position) + byteLimit. This is called
|
|
/// Sets currentLimit to (current position) + byteLimit. This is called
|
|
/// when descending into a length-delimited embedded message. The previous
|
|
/// when descending into a length-delimited embedded message. The previous
|
|
/// limit is returned.
|
|
/// limit is returned.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <returns>The old limit.</returns>
|
|
/// <returns>The old limit.</returns>
|
|
- public int PushLimit(int byteLimit)
|
|
|
|
|
|
+ internal int PushLimit(int byteLimit)
|
|
{
|
|
{
|
|
if (byteLimit < 0)
|
|
if (byteLimit < 0)
|
|
{
|
|
{
|
|
@@ -797,7 +835,7 @@ namespace Google.Protobuf
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Discards the current limit, returning the previous limit.
|
|
/// Discards the current limit, returning the previous limit.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public void PopLimit(int oldLimit)
|
|
|
|
|
|
+ internal void PopLimit(int oldLimit)
|
|
{
|
|
{
|
|
currentLimit = oldLimit;
|
|
currentLimit = oldLimit;
|
|
RecomputeBufferSizeAfterLimit();
|
|
RecomputeBufferSizeAfterLimit();
|
|
@@ -807,7 +845,7 @@ namespace Google.Protobuf
|
|
/// Returns whether or not all the data before the limit has been read.
|
|
/// Returns whether or not all the data before the limit has been read.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|
|
- public bool ReachedLimit
|
|
|
|
|
|
+ internal bool ReachedLimit
|
|
{
|
|
{
|
|
get
|
|
get
|
|
{
|
|
{
|
|
@@ -897,7 +935,7 @@ namespace Google.Protobuf
|
|
/// <exception cref="InvalidProtocolBufferException">
|
|
/// <exception cref="InvalidProtocolBufferException">
|
|
/// the end of the stream or the current limit was reached
|
|
/// the end of the stream or the current limit was reached
|
|
/// </exception>
|
|
/// </exception>
|
|
- public byte ReadRawByte()
|
|
|
|
|
|
+ internal byte ReadRawByte()
|
|
{
|
|
{
|
|
if (bufferPos == bufferSize)
|
|
if (bufferPos == bufferSize)
|
|
{
|
|
{
|
|
@@ -907,12 +945,12 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Read a fixed size of bytes from the input.
|
|
|
|
|
|
+ /// Reads a fixed size of bytes from the input.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <exception cref="InvalidProtocolBufferException">
|
|
/// <exception cref="InvalidProtocolBufferException">
|
|
/// the end of the stream or the current limit was reached
|
|
/// the end of the stream or the current limit was reached
|
|
/// </exception>
|
|
/// </exception>
|
|
- public byte[] ReadRawBytes(int size)
|
|
|
|
|
|
+ internal byte[] ReadRawBytes(int size)
|
|
{
|
|
{
|
|
if (size < 0)
|
|
if (size < 0)
|
|
{
|
|
{
|
|
@@ -921,7 +959,8 @@ namespace Google.Protobuf
|
|
|
|
|
|
if (totalBytesRetired + bufferPos + size > currentLimit)
|
|
if (totalBytesRetired + bufferPos + size > currentLimit)
|
|
{
|
|
{
|
|
- // Read to the end of the stream anyway.
|
|
|
|
|
|
+ // Read to the end of the stream (up to the current limit) anyway.
|
|
|
|
+ // TODO(jonskeet): This is the only usage of SkipRawBytes. Do we really need to do it?
|
|
SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
|
SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
|
// Then fail.
|
|
// Then fail.
|
|
throw InvalidProtocolBufferException.TruncatedMessage();
|
|
throw InvalidProtocolBufferException.TruncatedMessage();
|
|
@@ -1025,63 +1064,12 @@ namespace Google.Protobuf
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// Reads and discards a single field, given its tag value.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <returns>false if the tag is an end-group tag, in which case
|
|
|
|
- /// nothing is skipped. Otherwise, returns true.</returns>
|
|
|
|
- public bool SkipField()
|
|
|
|
- {
|
|
|
|
- uint tag = lastTag;
|
|
|
|
- switch (WireFormat.GetTagWireType(tag))
|
|
|
|
- {
|
|
|
|
- case WireFormat.WireType.Varint:
|
|
|
|
- ReadRawVarint64();
|
|
|
|
- return true;
|
|
|
|
- case WireFormat.WireType.Fixed64:
|
|
|
|
- ReadRawLittleEndian64();
|
|
|
|
- return true;
|
|
|
|
- case WireFormat.WireType.LengthDelimited:
|
|
|
|
- SkipRawBytes((int) ReadRawVarint32());
|
|
|
|
- return true;
|
|
|
|
- case WireFormat.WireType.StartGroup:
|
|
|
|
- SkipMessage();
|
|
|
|
- CheckLastTagWas(
|
|
|
|
- WireFormat.MakeTag(WireFormat.GetTagFieldNumber(tag),
|
|
|
|
- WireFormat.WireType.EndGroup));
|
|
|
|
- return true;
|
|
|
|
- case WireFormat.WireType.EndGroup:
|
|
|
|
- return false;
|
|
|
|
- case WireFormat.WireType.Fixed32:
|
|
|
|
- ReadRawLittleEndian32();
|
|
|
|
- return true;
|
|
|
|
- default:
|
|
|
|
- throw InvalidProtocolBufferException.InvalidWireType();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Reads and discards an entire message. This will read either until EOF
|
|
|
|
- /// or until an endgroup tag, whichever comes first.
|
|
|
|
- /// </summary>
|
|
|
|
- public void SkipMessage()
|
|
|
|
- {
|
|
|
|
- uint tag;
|
|
|
|
- while (ReadTag(out tag))
|
|
|
|
- {
|
|
|
|
- if (!SkipField())
|
|
|
|
- {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Reads and discards <paramref name="size"/> bytes.
|
|
/// Reads and discards <paramref name="size"/> bytes.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <exception cref="InvalidProtocolBufferException">the end of the stream
|
|
/// <exception cref="InvalidProtocolBufferException">the end of the stream
|
|
/// or the current limit was reached</exception>
|
|
/// or the current limit was reached</exception>
|
|
- public void SkipRawBytes(int size)
|
|
|
|
|
|
+ private void SkipRawBytes(int size)
|
|
{
|
|
{
|
|
if (size < 0)
|
|
if (size < 0)
|
|
{
|
|
{
|