• 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         [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 }