• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }