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 33 using System; 34 using System.Buffers; 35 using System.Buffers.Binary; 36 using System.Collections.Generic; 37 using System.IO; 38 using System.Runtime.CompilerServices; 39 using System.Runtime.InteropServices; 40 using System.Security; 41 using System.Text; 42 using Google.Protobuf.Collections; 43 44 namespace Google.Protobuf 45 { 46 /// <summary> 47 /// An opaque struct that represents the current parsing state and is passed along 48 /// as the parsing proceeds. 49 /// All the public methods are intended to be invoked only by the generated code, 50 /// users should never invoke them directly. 51 /// </summary> 52 [SecuritySafeCritical] 53 public ref struct ParseContext 54 { 55 internal const int DefaultRecursionLimit = 100; 56 internal const int DefaultSizeLimit = Int32.MaxValue; 57 58 internal ReadOnlySpan<byte> buffer; 59 internal ParserInternalState state; 60 61 /// <summary> 62 /// Initialize a <see cref="ParseContext"/>, building all <see cref="ParserInternalState"/> from defaults and 63 /// the given <paramref name="buffer"/>. 64 /// </summary> 65 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext66 internal static void Initialize(ReadOnlySpan<byte> buffer, out ParseContext ctx) 67 { 68 ParserInternalState state = default; 69 state.sizeLimit = DefaultSizeLimit; 70 state.recursionLimit = DefaultRecursionLimit; 71 state.currentLimit = int.MaxValue; 72 state.bufferSize = buffer.Length; 73 74 Initialize(buffer, ref state, out ctx); 75 } 76 77 /// <summary> 78 /// Initialize a <see cref="ParseContext"/> using existing <see cref="ParserInternalState"/>, e.g. from <see cref="CodedInputStream"/>. 79 /// </summary> 80 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext81 internal static void Initialize(ReadOnlySpan<byte> buffer, ref ParserInternalState state, out ParseContext ctx) 82 { 83 ctx.buffer = buffer; 84 ctx.state = state; 85 } 86 87 /// <summary> 88 /// Creates a ParseContext instance from CodedInputStream. 89 /// WARNING: internally this copies the CodedInputStream's state, so after done with the ParseContext, 90 /// the CodedInputStream's state needs to be updated. 91 /// </summary> 92 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext93 internal static void Initialize(CodedInputStream input, out ParseContext ctx) 94 { 95 ctx.buffer = new ReadOnlySpan<byte>(input.InternalBuffer); 96 // ideally we would use a reference to the original state, but that doesn't seem possible 97 // so we just copy the struct that holds the state. We will need to later store the state back 98 // into CodedInputStream if we want to keep it usable. 99 ctx.state = input.InternalState; 100 } 101 102 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext103 internal static void Initialize(ReadOnlySequence<byte> input, out ParseContext ctx) 104 { 105 Initialize(input, DefaultRecursionLimit, out ctx); 106 } 107 108 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext109 internal static void Initialize(ReadOnlySequence<byte> input, int recursionLimit, out ParseContext ctx) 110 { 111 ctx.buffer = default; 112 ctx.state = default; 113 ctx.state.lastTag = 0; 114 ctx.state.recursionDepth = 0; 115 ctx.state.sizeLimit = DefaultSizeLimit; 116 ctx.state.recursionLimit = recursionLimit; 117 ctx.state.currentLimit = int.MaxValue; 118 SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer); 119 ctx.state.bufferPos = 0; 120 ctx.state.bufferSize = ctx.buffer.Length; 121 122 ctx.state.DiscardUnknownFields = false; 123 ctx.state.ExtensionRegistry = null; 124 } 125 126 /// <summary> 127 /// Returns the last tag read, or 0 if no tags have been read or we've read beyond 128 /// the end of the input. 129 /// </summary> 130 internal uint LastTag { get { return state.lastTag; } } 131 132 /// <summary> 133 /// Internal-only property; when set to true, unknown fields will be discarded while parsing. 134 /// </summary> 135 internal bool DiscardUnknownFields { 136 get { return state.DiscardUnknownFields; } 137 set { state.DiscardUnknownFields = value; } 138 } 139 140 /// <summary> 141 /// Internal-only property; provides extension identifiers to compatible messages while parsing. 142 /// </summary> 143 internal ExtensionRegistry ExtensionRegistry 144 { 145 get { return state.ExtensionRegistry; } 146 set { state.ExtensionRegistry = value; } 147 } 148 149 /// <summary> 150 /// Reads a field tag, returning the tag of 0 for "end of input". 151 /// </summary> 152 /// <remarks> 153 /// If this method returns 0, it doesn't necessarily mean the end of all 154 /// the data in this CodedInputReader; it may be the end of the logical input 155 /// for an embedded message, for example. 156 /// </remarks> 157 /// <returns>The next field tag, or 0 for end of input. (0 is never a valid tag.)</returns> 158 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadTagGoogle.Protobuf.ParseContext159 public uint ReadTag() 160 { 161 return ParsingPrimitives.ParseTag(ref buffer, ref state); 162 } 163 164 /// <summary> 165 /// Reads a double field from the input. 166 /// </summary> 167 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadDoubleGoogle.Protobuf.ParseContext168 public double ReadDouble() 169 { 170 return ParsingPrimitives.ParseDouble(ref buffer, ref state); 171 } 172 173 /// <summary> 174 /// Reads a float field from the input. 175 /// </summary> 176 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFloatGoogle.Protobuf.ParseContext177 public float ReadFloat() 178 { 179 return ParsingPrimitives.ParseFloat(ref buffer, ref state); 180 } 181 182 /// <summary> 183 /// Reads a uint64 field from the input. 184 /// </summary> 185 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadUInt64Google.Protobuf.ParseContext186 public ulong ReadUInt64() 187 { 188 return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 189 } 190 191 /// <summary> 192 /// Reads an int64 field from the input. 193 /// </summary> 194 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadInt64Google.Protobuf.ParseContext195 public long ReadInt64() 196 { 197 return (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 198 } 199 200 /// <summary> 201 /// Reads an int32 field from the input. 202 /// </summary> 203 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadInt32Google.Protobuf.ParseContext204 public int ReadInt32() 205 { 206 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 207 } 208 209 /// <summary> 210 /// Reads a fixed64 field from the input. 211 /// </summary> 212 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFixed64Google.Protobuf.ParseContext213 public ulong ReadFixed64() 214 { 215 return ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 216 } 217 218 /// <summary> 219 /// Reads a fixed32 field from the input. 220 /// </summary> 221 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFixed32Google.Protobuf.ParseContext222 public uint ReadFixed32() 223 { 224 return ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 225 } 226 227 /// <summary> 228 /// Reads a bool field from the input. 229 /// </summary> 230 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadBoolGoogle.Protobuf.ParseContext231 public bool ReadBool() 232 { 233 return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0; 234 } 235 /// <summary> 236 /// Reads a string field from the input. 237 /// </summary> 238 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadStringGoogle.Protobuf.ParseContext239 public string ReadString() 240 { 241 return ParsingPrimitives.ReadString(ref buffer, ref state); 242 } 243 244 /// <summary> 245 /// Reads an embedded message field value from the input. 246 /// </summary> 247 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadMessageGoogle.Protobuf.ParseContext248 public void ReadMessage(IMessage message) 249 { 250 ParsingPrimitivesMessages.ReadMessage(ref this, message); 251 } 252 253 /// <summary> 254 /// Reads an embedded group field from the input. 255 /// </summary> 256 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadGroupGoogle.Protobuf.ParseContext257 public void ReadGroup(IMessage message) 258 { 259 ParsingPrimitivesMessages.ReadGroup(ref this, message); 260 } 261 262 /// <summary> 263 /// Reads a bytes field value from the input. 264 /// </summary> 265 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadBytesGoogle.Protobuf.ParseContext266 public ByteString ReadBytes() 267 { 268 return ParsingPrimitives.ReadBytes(ref buffer, ref state); 269 } 270 /// <summary> 271 /// Reads a uint32 field value from the input. 272 /// </summary> 273 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadUInt32Google.Protobuf.ParseContext274 public uint ReadUInt32() 275 { 276 return ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 277 } 278 279 /// <summary> 280 /// Reads an enum field value from the input. 281 /// </summary> 282 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadEnumGoogle.Protobuf.ParseContext283 public int ReadEnum() 284 { 285 // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. 286 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 287 } 288 289 /// <summary> 290 /// Reads an sfixed32 field value from the input. 291 /// </summary> 292 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSFixed32Google.Protobuf.ParseContext293 public int ReadSFixed32() 294 { 295 return (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 296 } 297 298 /// <summary> 299 /// Reads an sfixed64 field value from the input. 300 /// </summary> 301 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSFixed64Google.Protobuf.ParseContext302 public long ReadSFixed64() 303 { 304 return (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 305 } 306 307 /// <summary> 308 /// Reads an sint32 field value from the input. 309 /// </summary> 310 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSInt32Google.Protobuf.ParseContext311 public int ReadSInt32() 312 { 313 return ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); 314 } 315 316 /// <summary> 317 /// Reads an sint64 field value from the input. 318 /// </summary> 319 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSInt64Google.Protobuf.ParseContext320 public long ReadSInt64() 321 { 322 return ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state)); 323 } 324 325 /// <summary> 326 /// Reads a length for length-delimited data. 327 /// </summary> 328 /// <remarks> 329 /// This is internally just reading a varint, but this method exists 330 /// to make the calling code clearer. 331 /// </remarks> 332 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadLengthGoogle.Protobuf.ParseContext333 public int ReadLength() 334 { 335 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 336 } 337 CopyStateToGoogle.Protobuf.ParseContext338 internal void CopyStateTo(CodedInputStream input) 339 { 340 input.InternalState = state; 341 } 342 LoadStateFromGoogle.Protobuf.ParseContext343 internal void LoadStateFrom(CodedInputStream input) 344 { 345 state = input.InternalState; 346 } 347 } 348 }