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 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext62 internal static void Initialize(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, out ParseContext ctx) 63 { 64 ctx.buffer = buffer; 65 ctx.state = state; 66 } 67 68 /// <summary> 69 /// Creates a ParseContext instance from CodedInputStream. 70 /// WARNING: internally this copies the CodedInputStream's state, so after done with the ParseContext, 71 /// the CodedInputStream's state needs to be updated. 72 /// </summary> 73 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext74 internal static void Initialize(CodedInputStream input, out ParseContext ctx) 75 { 76 ctx.buffer = new ReadOnlySpan<byte>(input.InternalBuffer); 77 // ideally we would use a reference to the original state, but that doesn't seem possible 78 // so we just copy the struct that holds the state. We will need to later store the state back 79 // into CodedInputStream if we want to keep it usable. 80 ctx.state = input.InternalState; 81 } 82 83 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext84 internal static void Initialize(ReadOnlySequence<byte> input, out ParseContext ctx) 85 { 86 Initialize(input, DefaultRecursionLimit, out ctx); 87 } 88 89 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.ParseContext90 internal static void Initialize(ReadOnlySequence<byte> input, int recursionLimit, out ParseContext ctx) 91 { 92 ctx.buffer = default; 93 ctx.state = default; 94 ctx.state.lastTag = 0; 95 ctx.state.recursionDepth = 0; 96 ctx.state.sizeLimit = DefaultSizeLimit; 97 ctx.state.recursionLimit = recursionLimit; 98 ctx.state.currentLimit = int.MaxValue; 99 SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer); 100 ctx.state.bufferPos = 0; 101 ctx.state.bufferSize = ctx.buffer.Length; 102 103 ctx.state.DiscardUnknownFields = false; 104 ctx.state.ExtensionRegistry = null; 105 } 106 107 /// <summary> 108 /// Returns the last tag read, or 0 if no tags have been read or we've read beyond 109 /// the end of the input. 110 /// </summary> 111 internal uint LastTag { get { return state.lastTag; } } 112 113 /// <summary> 114 /// Internal-only property; when set to true, unknown fields will be discarded while parsing. 115 /// </summary> 116 internal bool DiscardUnknownFields { 117 get { return state.DiscardUnknownFields; } 118 set { state.DiscardUnknownFields = value; } 119 } 120 121 /// <summary> 122 /// Internal-only property; provides extension identifiers to compatible messages while parsing. 123 /// </summary> 124 internal ExtensionRegistry ExtensionRegistry 125 { 126 get { return state.ExtensionRegistry; } 127 set { state.ExtensionRegistry = value; } 128 } 129 130 /// <summary> 131 /// Reads a field tag, returning the tag of 0 for "end of input". 132 /// </summary> 133 /// <remarks> 134 /// If this method returns 0, it doesn't necessarily mean the end of all 135 /// the data in this CodedInputReader; it may be the end of the logical input 136 /// for an embedded message, for example. 137 /// </remarks> 138 /// <returns>The next field tag, or 0 for end of input. (0 is never a valid tag.)</returns> 139 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadTagGoogle.Protobuf.ParseContext140 public uint ReadTag() 141 { 142 return ParsingPrimitives.ParseTag(ref buffer, ref state); 143 } 144 145 /// <summary> 146 /// Reads a double field from the input. 147 /// </summary> 148 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadDoubleGoogle.Protobuf.ParseContext149 public double ReadDouble() 150 { 151 return ParsingPrimitives.ParseDouble(ref buffer, ref state); 152 } 153 154 /// <summary> 155 /// Reads a float field from the input. 156 /// </summary> 157 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFloatGoogle.Protobuf.ParseContext158 public float ReadFloat() 159 { 160 return ParsingPrimitives.ParseFloat(ref buffer, ref state); 161 } 162 163 /// <summary> 164 /// Reads a uint64 field from the input. 165 /// </summary> 166 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadUInt64Google.Protobuf.ParseContext167 public ulong ReadUInt64() 168 { 169 return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 170 } 171 172 /// <summary> 173 /// Reads an int64 field from the input. 174 /// </summary> 175 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadInt64Google.Protobuf.ParseContext176 public long ReadInt64() 177 { 178 return (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 179 } 180 181 /// <summary> 182 /// Reads an int32 field from the input. 183 /// </summary> 184 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadInt32Google.Protobuf.ParseContext185 public int ReadInt32() 186 { 187 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 188 } 189 190 /// <summary> 191 /// Reads a fixed64 field from the input. 192 /// </summary> 193 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFixed64Google.Protobuf.ParseContext194 public ulong ReadFixed64() 195 { 196 return ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 197 } 198 199 /// <summary> 200 /// Reads a fixed32 field from the input. 201 /// </summary> 202 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadFixed32Google.Protobuf.ParseContext203 public uint ReadFixed32() 204 { 205 return ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 206 } 207 208 /// <summary> 209 /// Reads a bool field from the input. 210 /// </summary> 211 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadBoolGoogle.Protobuf.ParseContext212 public bool ReadBool() 213 { 214 return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0; 215 } 216 /// <summary> 217 /// Reads a string field from the input. 218 /// </summary> 219 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadStringGoogle.Protobuf.ParseContext220 public string ReadString() 221 { 222 return ParsingPrimitives.ReadString(ref buffer, ref state); 223 } 224 225 /// <summary> 226 /// Reads an embedded message field value from the input. 227 /// </summary> 228 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadMessageGoogle.Protobuf.ParseContext229 public void ReadMessage(IMessage message) 230 { 231 ParsingPrimitivesMessages.ReadMessage(ref this, message); 232 } 233 234 /// <summary> 235 /// Reads an embedded group field from the input. 236 /// </summary> 237 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadGroupGoogle.Protobuf.ParseContext238 public void ReadGroup(IMessage message) 239 { 240 ParsingPrimitivesMessages.ReadGroup(ref this, message); 241 } 242 243 /// <summary> 244 /// Reads a bytes field value from the input. 245 /// </summary> 246 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadBytesGoogle.Protobuf.ParseContext247 public ByteString ReadBytes() 248 { 249 return ParsingPrimitives.ReadBytes(ref buffer, ref state); 250 } 251 /// <summary> 252 /// Reads a uint32 field value from the input. 253 /// </summary> 254 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadUInt32Google.Protobuf.ParseContext255 public uint ReadUInt32() 256 { 257 return ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 258 } 259 260 /// <summary> 261 /// Reads an enum field value from the input. 262 /// </summary> 263 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadEnumGoogle.Protobuf.ParseContext264 public int ReadEnum() 265 { 266 // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. 267 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 268 } 269 270 /// <summary> 271 /// Reads an sfixed32 field value from the input. 272 /// </summary> 273 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSFixed32Google.Protobuf.ParseContext274 public int ReadSFixed32() 275 { 276 return (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 277 } 278 279 /// <summary> 280 /// Reads an sfixed64 field value from the input. 281 /// </summary> 282 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSFixed64Google.Protobuf.ParseContext283 public long ReadSFixed64() 284 { 285 return (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 286 } 287 288 /// <summary> 289 /// Reads an sint32 field value from the input. 290 /// </summary> 291 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSInt32Google.Protobuf.ParseContext292 public int ReadSInt32() 293 { 294 return ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); 295 } 296 297 /// <summary> 298 /// Reads an sint64 field value from the input. 299 /// </summary> 300 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadSInt64Google.Protobuf.ParseContext301 public long ReadSInt64() 302 { 303 return ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state)); 304 } 305 306 /// <summary> 307 /// Reads a length for length-delimited data. 308 /// </summary> 309 /// <remarks> 310 /// This is internally just reading a varint, but this method exists 311 /// to make the calling code clearer. 312 /// </remarks> 313 [MethodImpl(MethodImplOptions.AggressiveInlining)] ReadLengthGoogle.Protobuf.ParseContext314 public int ReadLength() 315 { 316 return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 317 } 318 CopyStateToGoogle.Protobuf.ParseContext319 internal void CopyStateTo(CodedInputStream input) 320 { 321 input.InternalState = state; 322 } 323 LoadStateFromGoogle.Protobuf.ParseContext324 internal void LoadStateFrom(CodedInputStream input) 325 { 326 state = input.InternalState; 327 } 328 } 329 }