• 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     /// Fast parsing primitives for wrapper types
48     /// </summary>
49     [SecuritySafeCritical]
50     internal static class ParsingPrimitivesWrappers
51     {
ReadFloatWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)52         internal static float? ReadFloatWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
53         {
54             // length:1 + tag:1 + value:4 = 6 bytes
55             if (state.bufferPos + 6 <= state.bufferSize)
56             {
57                 // The entire wrapper message is already contained in `buffer`.
58                 int length = buffer[state.bufferPos];
59                 if (length == 0)
60                 {
61                     state.bufferPos++;
62                     return 0F;
63                 }
64                 // tag:1 + value:4 = length of 5 bytes
65                 // field=1, type=32-bit = tag of 13
66                 if (length != 5 || buffer[state.bufferPos + 1] != 13)
67                 {
68                     return ReadFloatWrapperSlow(ref buffer, ref state);
69                 }
70                 state.bufferPos += 2;
71                 return ParsingPrimitives.ParseFloat(ref buffer, ref state);
72             }
73             else
74             {
75                 return ReadFloatWrapperSlow(ref buffer, ref state);
76             }
77         }
78 
ReadFloatWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)79         internal static float? ReadFloatWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
80         {
81             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
82             if (length == 0)
83             {
84                 return 0F;
85             }
86             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
87             float result = 0F;
88             do
89             {
90                 // field=1, type=32-bit = tag of 13
91                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 13)
92                 {
93                     result = ParsingPrimitives.ParseFloat(ref buffer, ref state);
94                 }
95                 else
96                 {
97                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
98                 }
99             }
100             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
101             return result;
102         }
103 
ReadDoubleWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)104         internal static double? ReadDoubleWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
105         {
106             // length:1 + tag:1 + value:8 = 10 bytes
107             if (state.bufferPos + 10 <= state.bufferSize)
108             {
109                 // The entire wrapper message is already contained in `buffer`.
110                 int length = buffer[state.bufferPos];
111                 if (length == 0)
112                 {
113                     state.bufferPos++;
114                     return 0D;
115                 }
116                 // tag:1 + value:8 = length of 9 bytes
117                 // field=1, type=64-bit = tag of 9
118                 if (length != 9 || buffer[state.bufferPos + 1] != 9)
119                 {
120                     return ReadDoubleWrapperSlow(ref buffer, ref state);
121                 }
122                 state.bufferPos += 2;
123                 return ParsingPrimitives.ParseDouble(ref buffer, ref state);
124             }
125             else
126             {
127                 return ReadDoubleWrapperSlow(ref buffer, ref state);
128             }
129         }
130 
ReadDoubleWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)131         internal static double? ReadDoubleWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
132         {
133             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
134             if (length == 0)
135             {
136                 return 0D;
137             }
138             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
139             double result = 0D;
140             do
141             {
142                 // field=1, type=64-bit = tag of 9
143                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 9)
144                 {
145                     result = ParsingPrimitives.ParseDouble(ref buffer, ref state);
146                 }
147                 else
148                 {
149                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
150                 }
151             }
152             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
153             return result;
154         }
155 
ReadBoolWrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)156         internal static bool? ReadBoolWrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
157         {
158             return ReadUInt64Wrapper(ref buffer, ref state) != 0;
159         }
160 
ReadUInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)161         internal static uint? ReadUInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
162         {
163             // length:1 + tag:1 + value:5(varint32-max) = 7 bytes
164             if (state.bufferPos + 7 <= state.bufferSize)
165             {
166                 // The entire wrapper message is already contained in `buffer`.
167                 int pos0 = state.bufferPos;
168                 int length = buffer[state.bufferPos++];
169                 if (length == 0)
170                 {
171                     return 0;
172                 }
173                 // Length will always fit in a single byte.
174                 if (length >= 128)
175                 {
176                     state.bufferPos = pos0;
177                     return ReadUInt32WrapperSlow(ref buffer, ref state);
178                 }
179                 int finalBufferPos = state.bufferPos + length;
180                 // field=1, type=varint = tag of 8
181                 if (buffer[state.bufferPos++] != 8)
182                 {
183                     state.bufferPos = pos0;
184                     return ReadUInt32WrapperSlow(ref buffer, ref state);
185                 }
186                 var result = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
187                 // Verify this message only contained a single field.
188                 if (state.bufferPos != finalBufferPos)
189                 {
190                     state.bufferPos = pos0;
191                     return ReadUInt32WrapperSlow(ref buffer, ref state);
192                 }
193                 return result;
194             }
195             else
196             {
197                 return ReadUInt32WrapperSlow(ref buffer, ref state);
198             }
199         }
200 
ReadUInt32WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)201         internal static uint? ReadUInt32WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
202         {
203             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
204             if (length == 0)
205             {
206                 return 0;
207             }
208             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
209             uint result = 0;
210             do
211             {
212                 // field=1, type=varint = tag of 8
213                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 8)
214                 {
215                     result = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
216                 }
217                 else
218                 {
219                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
220                 }
221             }
222             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
223             return result;
224         }
225 
ReadInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)226         internal static int? ReadInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
227         {
228             return (int?)ReadUInt32Wrapper(ref buffer, ref state);
229         }
230 
ReadUInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)231         internal static ulong? ReadUInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
232         {
233             // field=1, type=varint = tag of 8
234             const int expectedTag = 8;
235             // length:1 + tag:1 + value:10(varint64-max) = 12 bytes
236             if (state.bufferPos + 12 <= state.bufferSize)
237             {
238                 // The entire wrapper message is already contained in `buffer`.
239                 int pos0 = state.bufferPos;
240                 int length = buffer[state.bufferPos++];
241                 if (length == 0)
242                 {
243                     return 0L;
244                 }
245                 // Length will always fit in a single byte.
246                 if (length >= 128)
247                 {
248                     state.bufferPos = pos0;
249                     return ReadUInt64WrapperSlow(ref buffer, ref state);
250                 }
251                 int finalBufferPos = state.bufferPos + length;
252                 if (buffer[state.bufferPos++] != expectedTag)
253                 {
254                     state.bufferPos = pos0;
255                     return ReadUInt64WrapperSlow(ref buffer, ref state);
256                 }
257                 var result = ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
258                 // Verify this message only contained a single field.
259                 if (state.bufferPos != finalBufferPos)
260                 {
261                     state.bufferPos = pos0;
262                     return ReadUInt64WrapperSlow(ref buffer, ref state);
263                 }
264                 return result;
265             }
266             else
267             {
268                 return ReadUInt64WrapperSlow(ref buffer, ref state);
269             }
270         }
271 
ReadUInt64WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)272         internal static ulong? ReadUInt64WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
273         {
274             // field=1, type=varint = tag of 8
275             const int expectedTag = 8;
276             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
277             if (length == 0)
278             {
279                 return 0L;
280             }
281             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
282             ulong result = 0L;
283             do
284             {
285                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == expectedTag)
286                 {
287                     result = ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
288                 }
289                 else
290                 {
291                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
292                 }
293             }
294             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
295             return result;
296         }
297 
ReadInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)298         internal static long? ReadInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
299         {
300             return (long?)ReadUInt64Wrapper(ref buffer, ref state);
301         }
302 
ReadFloatWrapperLittleEndian(ref ParseContext ctx)303         internal static float? ReadFloatWrapperLittleEndian(ref ParseContext ctx)
304         {
305             return ParsingPrimitivesWrappers.ReadFloatWrapperLittleEndian(ref ctx.buffer, ref ctx.state);
306         }
307 
ReadFloatWrapperSlow(ref ParseContext ctx)308         internal static float? ReadFloatWrapperSlow(ref ParseContext ctx)
309         {
310             return ParsingPrimitivesWrappers.ReadFloatWrapperSlow(ref ctx.buffer, ref ctx.state);
311         }
312 
ReadDoubleWrapperLittleEndian(ref ParseContext ctx)313         internal static double? ReadDoubleWrapperLittleEndian(ref ParseContext ctx)
314         {
315             return ParsingPrimitivesWrappers.ReadDoubleWrapperLittleEndian(ref ctx.buffer, ref ctx.state);
316         }
317 
ReadDoubleWrapperSlow(ref ParseContext ctx)318         internal static double? ReadDoubleWrapperSlow(ref ParseContext ctx)
319         {
320             return ParsingPrimitivesWrappers.ReadDoubleWrapperSlow(ref ctx.buffer, ref ctx.state);
321         }
322 
ReadBoolWrapper(ref ParseContext ctx)323         internal static bool? ReadBoolWrapper(ref ParseContext ctx)
324         {
325             return ParsingPrimitivesWrappers.ReadBoolWrapper(ref ctx.buffer, ref ctx.state);
326         }
327 
ReadUInt32Wrapper(ref ParseContext ctx)328         internal static uint? ReadUInt32Wrapper(ref ParseContext ctx)
329         {
330             return ParsingPrimitivesWrappers.ReadUInt32Wrapper(ref ctx.buffer, ref ctx.state);
331         }
332 
ReadInt32Wrapper(ref ParseContext ctx)333         internal static int? ReadInt32Wrapper(ref ParseContext ctx)
334         {
335             return ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx.buffer, ref ctx.state);
336         }
337 
ReadUInt64Wrapper(ref ParseContext ctx)338         internal static ulong? ReadUInt64Wrapper(ref ParseContext ctx)
339         {
340             return ParsingPrimitivesWrappers.ReadUInt64Wrapper(ref ctx.buffer, ref ctx.state);
341         }
342 
ReadUInt64WrapperSlow(ref ParseContext ctx)343         internal static ulong? ReadUInt64WrapperSlow(ref ParseContext ctx)
344         {
345             return ParsingPrimitivesWrappers.ReadUInt64WrapperSlow(ref ctx.buffer, ref ctx.state);
346         }
347 
ReadInt64Wrapper(ref ParseContext ctx)348         internal static long? ReadInt64Wrapper(ref ParseContext ctx)
349         {
350             return ParsingPrimitivesWrappers.ReadInt64Wrapper(ref ctx.buffer, ref ctx.state);
351         }
352     }
353 }