xref: /aosp_15_r20/external/cronet/third_party/protobuf/objectivec/GPBCodedInputStream.m (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker// Protocol Buffers - Google's data interchange format
2*6777b538SAndroid Build Coastguard Worker// Copyright 2008 Google Inc.  All rights reserved.
3*6777b538SAndroid Build Coastguard Worker// https://developers.google.com/protocol-buffers/
4*6777b538SAndroid Build Coastguard Worker//
5*6777b538SAndroid Build Coastguard Worker// Redistribution and use in source and binary forms, with or without
6*6777b538SAndroid Build Coastguard Worker// modification, are permitted provided that the following conditions are
7*6777b538SAndroid Build Coastguard Worker// met:
8*6777b538SAndroid Build Coastguard Worker//
9*6777b538SAndroid Build Coastguard Worker//     * Redistributions of source code must retain the above copyright
10*6777b538SAndroid Build Coastguard Worker// notice, this list of conditions and the following disclaimer.
11*6777b538SAndroid Build Coastguard Worker//     * Redistributions in binary form must reproduce the above
12*6777b538SAndroid Build Coastguard Worker// copyright notice, this list of conditions and the following disclaimer
13*6777b538SAndroid Build Coastguard Worker// in the documentation and/or other materials provided with the
14*6777b538SAndroid Build Coastguard Worker// distribution.
15*6777b538SAndroid Build Coastguard Worker//     * Neither the name of Google Inc. nor the names of its
16*6777b538SAndroid Build Coastguard Worker// contributors may be used to endorse or promote products derived from
17*6777b538SAndroid Build Coastguard Worker// this software without specific prior written permission.
18*6777b538SAndroid Build Coastguard Worker//
19*6777b538SAndroid Build Coastguard Worker// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*6777b538SAndroid Build Coastguard Worker// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*6777b538SAndroid Build Coastguard Worker// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*6777b538SAndroid Build Coastguard Worker// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*6777b538SAndroid Build Coastguard Worker// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*6777b538SAndroid Build Coastguard Worker// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*6777b538SAndroid Build Coastguard Worker// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*6777b538SAndroid Build Coastguard Worker// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*6777b538SAndroid Build Coastguard Worker// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*6777b538SAndroid Build Coastguard Worker// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*6777b538SAndroid Build Coastguard Worker// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker#import "GPBCodedInputStream_PackagePrivate.h"
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker#import "GPBDictionary_PackagePrivate.h"
34*6777b538SAndroid Build Coastguard Worker#import "GPBMessage_PackagePrivate.h"
35*6777b538SAndroid Build Coastguard Worker#import "GPBUnknownFieldSet_PackagePrivate.h"
36*6777b538SAndroid Build Coastguard Worker#import "GPBUtilities_PackagePrivate.h"
37*6777b538SAndroid Build Coastguard Worker#import "GPBWireFormat.h"
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard WorkerNSString *const GPBCodedInputStreamException =
40*6777b538SAndroid Build Coastguard Worker    GPBNSStringifySymbol(GPBCodedInputStreamException);
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard WorkerNSString *const GPBCodedInputStreamUnderlyingErrorKey =
43*6777b538SAndroid Build Coastguard Worker    GPBNSStringifySymbol(GPBCodedInputStreamUnderlyingErrorKey);
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard WorkerNSString *const GPBCodedInputStreamErrorDomain =
46*6777b538SAndroid Build Coastguard Worker    GPBNSStringifySymbol(GPBCodedInputStreamErrorDomain);
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker// Matching:
49*6777b538SAndroid Build Coastguard Worker// https://github.com/protocolbuffers/protobuf/blob/main/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L62
50*6777b538SAndroid Build Coastguard Worker//  private static final int DEFAULT_RECURSION_LIMIT = 100;
51*6777b538SAndroid Build Coastguard Worker// https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/io/coded_stream.cc#L86
52*6777b538SAndroid Build Coastguard Worker//  int CodedInputStream::default_recursion_limit_ = 100;
53*6777b538SAndroid Build Coastguard Workerstatic const NSUInteger kDefaultRecursionLimit = 100;
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Workerstatic void RaiseException(NSInteger code, NSString *reason) {
56*6777b538SAndroid Build Coastguard Worker  NSDictionary *errorInfo = nil;
57*6777b538SAndroid Build Coastguard Worker  if ([reason length]) {
58*6777b538SAndroid Build Coastguard Worker    errorInfo = @{ GPBErrorReasonKey: reason };
59*6777b538SAndroid Build Coastguard Worker  }
60*6777b538SAndroid Build Coastguard Worker  NSError *error = [NSError errorWithDomain:GPBCodedInputStreamErrorDomain
61*6777b538SAndroid Build Coastguard Worker                                       code:code
62*6777b538SAndroid Build Coastguard Worker                                   userInfo:errorInfo];
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker  NSDictionary *exceptionInfo =
65*6777b538SAndroid Build Coastguard Worker      @{ GPBCodedInputStreamUnderlyingErrorKey: error };
66*6777b538SAndroid Build Coastguard Worker  [[NSException exceptionWithName:GPBCodedInputStreamException
67*6777b538SAndroid Build Coastguard Worker                           reason:reason
68*6777b538SAndroid Build Coastguard Worker                         userInfo:exceptionInfo] raise];
69*6777b538SAndroid Build Coastguard Worker}
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Workerstatic void CheckRecursionLimit(GPBCodedInputStreamState *state) {
72*6777b538SAndroid Build Coastguard Worker  if (state->recursionDepth >= kDefaultRecursionLimit) {
73*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorRecursionDepthExceeded, nil);
74*6777b538SAndroid Build Coastguard Worker  }
75*6777b538SAndroid Build Coastguard Worker}
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Workerstatic void CheckSize(GPBCodedInputStreamState *state, size_t size) {
78*6777b538SAndroid Build Coastguard Worker  size_t newSize = state->bufferPos + size;
79*6777b538SAndroid Build Coastguard Worker  if (newSize > state->bufferSize) {
80*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
81*6777b538SAndroid Build Coastguard Worker  }
82*6777b538SAndroid Build Coastguard Worker  if (newSize > state->currentLimit) {
83*6777b538SAndroid Build Coastguard Worker    // Fast forward to end of currentLimit;
84*6777b538SAndroid Build Coastguard Worker    state->bufferPos = state->currentLimit;
85*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorSubsectionLimitReached, nil);
86*6777b538SAndroid Build Coastguard Worker  }
87*6777b538SAndroid Build Coastguard Worker}
88*6777b538SAndroid Build Coastguard Worker
89*6777b538SAndroid Build Coastguard Workerstatic int8_t ReadRawByte(GPBCodedInputStreamState *state) {
90*6777b538SAndroid Build Coastguard Worker  CheckSize(state, sizeof(int8_t));
91*6777b538SAndroid Build Coastguard Worker  return ((int8_t *)state->bytes)[state->bufferPos++];
92*6777b538SAndroid Build Coastguard Worker}
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Workerstatic int32_t ReadRawLittleEndian32(GPBCodedInputStreamState *state) {
95*6777b538SAndroid Build Coastguard Worker  CheckSize(state, sizeof(int32_t));
96*6777b538SAndroid Build Coastguard Worker  // Not using OSReadLittleInt32 because it has undocumented dependency
97*6777b538SAndroid Build Coastguard Worker  // on reads being aligned.
98*6777b538SAndroid Build Coastguard Worker  int32_t value;
99*6777b538SAndroid Build Coastguard Worker  memcpy(&value, state->bytes + state->bufferPos, sizeof(int32_t));
100*6777b538SAndroid Build Coastguard Worker  value = OSSwapLittleToHostInt32(value);
101*6777b538SAndroid Build Coastguard Worker  state->bufferPos += sizeof(int32_t);
102*6777b538SAndroid Build Coastguard Worker  return value;
103*6777b538SAndroid Build Coastguard Worker}
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Workerstatic int64_t ReadRawLittleEndian64(GPBCodedInputStreamState *state) {
106*6777b538SAndroid Build Coastguard Worker  CheckSize(state, sizeof(int64_t));
107*6777b538SAndroid Build Coastguard Worker  // Not using OSReadLittleInt64 because it has undocumented dependency
108*6777b538SAndroid Build Coastguard Worker  // on reads being aligned.
109*6777b538SAndroid Build Coastguard Worker  int64_t value;
110*6777b538SAndroid Build Coastguard Worker  memcpy(&value, state->bytes + state->bufferPos, sizeof(int64_t));
111*6777b538SAndroid Build Coastguard Worker  value = OSSwapLittleToHostInt64(value);
112*6777b538SAndroid Build Coastguard Worker  state->bufferPos += sizeof(int64_t);
113*6777b538SAndroid Build Coastguard Worker  return value;
114*6777b538SAndroid Build Coastguard Worker}
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Workerstatic int64_t ReadRawVarint64(GPBCodedInputStreamState *state) {
117*6777b538SAndroid Build Coastguard Worker  int32_t shift = 0;
118*6777b538SAndroid Build Coastguard Worker  int64_t result = 0;
119*6777b538SAndroid Build Coastguard Worker  while (shift < 64) {
120*6777b538SAndroid Build Coastguard Worker    int8_t b = ReadRawByte(state);
121*6777b538SAndroid Build Coastguard Worker    result |= (int64_t)((uint64_t)(b & 0x7F) << shift);
122*6777b538SAndroid Build Coastguard Worker    if ((b & 0x80) == 0) {
123*6777b538SAndroid Build Coastguard Worker      return result;
124*6777b538SAndroid Build Coastguard Worker    }
125*6777b538SAndroid Build Coastguard Worker    shift += 7;
126*6777b538SAndroid Build Coastguard Worker  }
127*6777b538SAndroid Build Coastguard Worker  RaiseException(GPBCodedInputStreamErrorInvalidVarInt, @"Invalid VarInt64");
128*6777b538SAndroid Build Coastguard Worker  return 0;
129*6777b538SAndroid Build Coastguard Worker}
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Workerstatic int32_t ReadRawVarint32(GPBCodedInputStreamState *state) {
132*6777b538SAndroid Build Coastguard Worker  return (int32_t)ReadRawVarint64(state);
133*6777b538SAndroid Build Coastguard Worker}
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Workerstatic void SkipRawData(GPBCodedInputStreamState *state, size_t size) {
136*6777b538SAndroid Build Coastguard Worker  CheckSize(state, size);
137*6777b538SAndroid Build Coastguard Worker  state->bufferPos += size;
138*6777b538SAndroid Build Coastguard Worker}
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Workerdouble GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state) {
141*6777b538SAndroid Build Coastguard Worker  int64_t value = ReadRawLittleEndian64(state);
142*6777b538SAndroid Build Coastguard Worker  return GPBConvertInt64ToDouble(value);
143*6777b538SAndroid Build Coastguard Worker}
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Workerfloat GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state) {
146*6777b538SAndroid Build Coastguard Worker  int32_t value = ReadRawLittleEndian32(state);
147*6777b538SAndroid Build Coastguard Worker  return GPBConvertInt32ToFloat(value);
148*6777b538SAndroid Build Coastguard Worker}
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Workeruint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state) {
151*6777b538SAndroid Build Coastguard Worker  uint64_t value = ReadRawVarint64(state);
152*6777b538SAndroid Build Coastguard Worker  return value;
153*6777b538SAndroid Build Coastguard Worker}
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Workeruint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state) {
156*6777b538SAndroid Build Coastguard Worker  uint32_t value = ReadRawVarint32(state);
157*6777b538SAndroid Build Coastguard Worker  return value;
158*6777b538SAndroid Build Coastguard Worker}
159*6777b538SAndroid Build Coastguard Worker
160*6777b538SAndroid Build Coastguard Workerint64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state) {
161*6777b538SAndroid Build Coastguard Worker  int64_t value = ReadRawVarint64(state);
162*6777b538SAndroid Build Coastguard Worker  return value;
163*6777b538SAndroid Build Coastguard Worker}
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Workerint32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state) {
166*6777b538SAndroid Build Coastguard Worker  int32_t value = ReadRawVarint32(state);
167*6777b538SAndroid Build Coastguard Worker  return value;
168*6777b538SAndroid Build Coastguard Worker}
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Workeruint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state) {
171*6777b538SAndroid Build Coastguard Worker  uint64_t value = ReadRawLittleEndian64(state);
172*6777b538SAndroid Build Coastguard Worker  return value;
173*6777b538SAndroid Build Coastguard Worker}
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Workeruint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state) {
176*6777b538SAndroid Build Coastguard Worker  uint32_t value = ReadRawLittleEndian32(state);
177*6777b538SAndroid Build Coastguard Worker  return value;
178*6777b538SAndroid Build Coastguard Worker}
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Workerint32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state) {
181*6777b538SAndroid Build Coastguard Worker  int32_t value = ReadRawVarint32(state);
182*6777b538SAndroid Build Coastguard Worker  return value;
183*6777b538SAndroid Build Coastguard Worker}
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Workerint32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state) {
186*6777b538SAndroid Build Coastguard Worker  int32_t value = ReadRawLittleEndian32(state);
187*6777b538SAndroid Build Coastguard Worker  return value;
188*6777b538SAndroid Build Coastguard Worker}
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Workerint64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state) {
191*6777b538SAndroid Build Coastguard Worker  int64_t value = ReadRawLittleEndian64(state);
192*6777b538SAndroid Build Coastguard Worker  return value;
193*6777b538SAndroid Build Coastguard Worker}
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Workerint32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state) {
196*6777b538SAndroid Build Coastguard Worker  int32_t value = GPBDecodeZigZag32(ReadRawVarint32(state));
197*6777b538SAndroid Build Coastguard Worker  return value;
198*6777b538SAndroid Build Coastguard Worker}
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Workerint64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state) {
201*6777b538SAndroid Build Coastguard Worker  int64_t value = GPBDecodeZigZag64(ReadRawVarint64(state));
202*6777b538SAndroid Build Coastguard Worker  return value;
203*6777b538SAndroid Build Coastguard Worker}
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard WorkerBOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state) {
206*6777b538SAndroid Build Coastguard Worker  return ReadRawVarint64(state) != 0;
207*6777b538SAndroid Build Coastguard Worker}
208*6777b538SAndroid Build Coastguard Worker
209*6777b538SAndroid Build Coastguard Workerint32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
210*6777b538SAndroid Build Coastguard Worker  if (GPBCodedInputStreamIsAtEnd(state)) {
211*6777b538SAndroid Build Coastguard Worker    state->lastTag = 0;
212*6777b538SAndroid Build Coastguard Worker    return 0;
213*6777b538SAndroid Build Coastguard Worker  }
214*6777b538SAndroid Build Coastguard Worker
215*6777b538SAndroid Build Coastguard Worker  state->lastTag = ReadRawVarint32(state);
216*6777b538SAndroid Build Coastguard Worker  // Tags have to include a valid wireformat.
217*6777b538SAndroid Build Coastguard Worker  if (!GPBWireFormatIsValidTag(state->lastTag)) {
218*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorInvalidTag,
219*6777b538SAndroid Build Coastguard Worker                   @"Invalid wireformat in tag.");
220*6777b538SAndroid Build Coastguard Worker  }
221*6777b538SAndroid Build Coastguard Worker  // Zero is not a valid field number.
222*6777b538SAndroid Build Coastguard Worker  if (GPBWireFormatGetTagFieldNumber(state->lastTag) == 0) {
223*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorInvalidTag,
224*6777b538SAndroid Build Coastguard Worker                   @"A zero field number on the wire is invalid.");
225*6777b538SAndroid Build Coastguard Worker  }
226*6777b538SAndroid Build Coastguard Worker  return state->lastTag;
227*6777b538SAndroid Build Coastguard Worker}
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard WorkerNSString *GPBCodedInputStreamReadRetainedString(
230*6777b538SAndroid Build Coastguard Worker    GPBCodedInputStreamState *state) {
231*6777b538SAndroid Build Coastguard Worker  int32_t size = ReadRawVarint32(state);
232*6777b538SAndroid Build Coastguard Worker  NSString *result;
233*6777b538SAndroid Build Coastguard Worker  if (size == 0) {
234*6777b538SAndroid Build Coastguard Worker    result = @"";
235*6777b538SAndroid Build Coastguard Worker  } else {
236*6777b538SAndroid Build Coastguard Worker    CheckSize(state, size);
237*6777b538SAndroid Build Coastguard Worker    result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
238*6777b538SAndroid Build Coastguard Worker                                      length:size
239*6777b538SAndroid Build Coastguard Worker                                    encoding:NSUTF8StringEncoding];
240*6777b538SAndroid Build Coastguard Worker    state->bufferPos += size;
241*6777b538SAndroid Build Coastguard Worker    if (!result) {
242*6777b538SAndroid Build Coastguard Worker#ifdef DEBUG
243*6777b538SAndroid Build Coastguard Worker      // https://developers.google.com/protocol-buffers/docs/proto#scalar
244*6777b538SAndroid Build Coastguard Worker      NSLog(@"UTF-8 failure, is some field type 'string' when it should be "
245*6777b538SAndroid Build Coastguard Worker            @"'bytes'?");
246*6777b538SAndroid Build Coastguard Worker#endif
247*6777b538SAndroid Build Coastguard Worker      RaiseException(GPBCodedInputStreamErrorInvalidUTF8, nil);
248*6777b538SAndroid Build Coastguard Worker    }
249*6777b538SAndroid Build Coastguard Worker  }
250*6777b538SAndroid Build Coastguard Worker  return result;
251*6777b538SAndroid Build Coastguard Worker}
252*6777b538SAndroid Build Coastguard Worker
253*6777b538SAndroid Build Coastguard WorkerNSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
254*6777b538SAndroid Build Coastguard Worker  int32_t size = ReadRawVarint32(state);
255*6777b538SAndroid Build Coastguard Worker  if (size < 0) return nil;
256*6777b538SAndroid Build Coastguard Worker  CheckSize(state, size);
257*6777b538SAndroid Build Coastguard Worker  NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos
258*6777b538SAndroid Build Coastguard Worker                                          length:size];
259*6777b538SAndroid Build Coastguard Worker  state->bufferPos += size;
260*6777b538SAndroid Build Coastguard Worker  return result;
261*6777b538SAndroid Build Coastguard Worker}
262*6777b538SAndroid Build Coastguard Worker
263*6777b538SAndroid Build Coastguard WorkerNSData *GPBCodedInputStreamReadRetainedBytesNoCopy(
264*6777b538SAndroid Build Coastguard Worker    GPBCodedInputStreamState *state) {
265*6777b538SAndroid Build Coastguard Worker  int32_t size = ReadRawVarint32(state);
266*6777b538SAndroid Build Coastguard Worker  if (size < 0) return nil;
267*6777b538SAndroid Build Coastguard Worker  CheckSize(state, size);
268*6777b538SAndroid Build Coastguard Worker  // Cast is safe because freeWhenDone is NO.
269*6777b538SAndroid Build Coastguard Worker  NSData *result = [[NSData alloc]
270*6777b538SAndroid Build Coastguard Worker      initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
271*6777b538SAndroid Build Coastguard Worker                   length:size
272*6777b538SAndroid Build Coastguard Worker             freeWhenDone:NO];
273*6777b538SAndroid Build Coastguard Worker  state->bufferPos += size;
274*6777b538SAndroid Build Coastguard Worker  return result;
275*6777b538SAndroid Build Coastguard Worker}
276*6777b538SAndroid Build Coastguard Worker
277*6777b538SAndroid Build Coastguard Workersize_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state,
278*6777b538SAndroid Build Coastguard Worker                                    size_t byteLimit) {
279*6777b538SAndroid Build Coastguard Worker  byteLimit += state->bufferPos;
280*6777b538SAndroid Build Coastguard Worker  size_t oldLimit = state->currentLimit;
281*6777b538SAndroid Build Coastguard Worker  if (byteLimit > oldLimit) {
282*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorInvalidSubsectionLimit, nil);
283*6777b538SAndroid Build Coastguard Worker  }
284*6777b538SAndroid Build Coastguard Worker  state->currentLimit = byteLimit;
285*6777b538SAndroid Build Coastguard Worker  return oldLimit;
286*6777b538SAndroid Build Coastguard Worker}
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Workervoid GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state,
289*6777b538SAndroid Build Coastguard Worker                                 size_t oldLimit) {
290*6777b538SAndroid Build Coastguard Worker  state->currentLimit = oldLimit;
291*6777b538SAndroid Build Coastguard Worker}
292*6777b538SAndroid Build Coastguard Worker
293*6777b538SAndroid Build Coastguard Workersize_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) {
294*6777b538SAndroid Build Coastguard Worker  return state->currentLimit - state->bufferPos;
295*6777b538SAndroid Build Coastguard Worker}
296*6777b538SAndroid Build Coastguard Worker
297*6777b538SAndroid Build Coastguard WorkerBOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) {
298*6777b538SAndroid Build Coastguard Worker  return (state->bufferPos == state->bufferSize) ||
299*6777b538SAndroid Build Coastguard Worker         (state->bufferPos == state->currentLimit);
300*6777b538SAndroid Build Coastguard Worker}
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Workervoid GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state,
303*6777b538SAndroid Build Coastguard Worker                                        int32_t value) {
304*6777b538SAndroid Build Coastguard Worker  if (state->lastTag != value) {
305*6777b538SAndroid Build Coastguard Worker    RaiseException(GPBCodedInputStreamErrorInvalidTag, @"Unexpected tag read");
306*6777b538SAndroid Build Coastguard Worker  }
307*6777b538SAndroid Build Coastguard Worker}
308*6777b538SAndroid Build Coastguard Worker
309*6777b538SAndroid Build Coastguard Worker@implementation GPBCodedInputStream
310*6777b538SAndroid Build Coastguard Worker
311*6777b538SAndroid Build Coastguard Worker+ (instancetype)streamWithData:(NSData *)data {
312*6777b538SAndroid Build Coastguard Worker  return [[[self alloc] initWithData:data] autorelease];
313*6777b538SAndroid Build Coastguard Worker}
314*6777b538SAndroid Build Coastguard Worker
315*6777b538SAndroid Build Coastguard Worker- (instancetype)initWithData:(NSData *)data {
316*6777b538SAndroid Build Coastguard Worker  if ((self = [super init])) {
317*6777b538SAndroid Build Coastguard Worker#ifdef DEBUG
318*6777b538SAndroid Build Coastguard Worker    NSCAssert([self class] == [GPBCodedInputStream class],
319*6777b538SAndroid Build Coastguard Worker              @"Subclassing of GPBCodedInputStream is not allowed.");
320*6777b538SAndroid Build Coastguard Worker#endif
321*6777b538SAndroid Build Coastguard Worker    buffer_ = [data retain];
322*6777b538SAndroid Build Coastguard Worker    state_.bytes = (const uint8_t *)[data bytes];
323*6777b538SAndroid Build Coastguard Worker    state_.bufferSize = [data length];
324*6777b538SAndroid Build Coastguard Worker    state_.currentLimit = state_.bufferSize;
325*6777b538SAndroid Build Coastguard Worker  }
326*6777b538SAndroid Build Coastguard Worker  return self;
327*6777b538SAndroid Build Coastguard Worker}
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard Worker- (void)dealloc {
330*6777b538SAndroid Build Coastguard Worker  [buffer_ release];
331*6777b538SAndroid Build Coastguard Worker  [super dealloc];
332*6777b538SAndroid Build Coastguard Worker}
333*6777b538SAndroid Build Coastguard Worker
334*6777b538SAndroid Build Coastguard Worker// Direct access is use for speed, to avoid even internally declaring things
335*6777b538SAndroid Build Coastguard Worker// read/write, etc. The warning is enabled in the project to ensure code calling
336*6777b538SAndroid Build Coastguard Worker// protos can turn on -Wdirect-ivar-access without issues.
337*6777b538SAndroid Build Coastguard Worker#pragma clang diagnostic push
338*6777b538SAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdirect-ivar-access"
339*6777b538SAndroid Build Coastguard Worker
340*6777b538SAndroid Build Coastguard Worker- (int32_t)readTag {
341*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadTag(&state_);
342*6777b538SAndroid Build Coastguard Worker}
343*6777b538SAndroid Build Coastguard Worker
344*6777b538SAndroid Build Coastguard Worker- (void)checkLastTagWas:(int32_t)value {
345*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamCheckLastTagWas(&state_, value);
346*6777b538SAndroid Build Coastguard Worker}
347*6777b538SAndroid Build Coastguard Worker
348*6777b538SAndroid Build Coastguard Worker- (BOOL)skipField:(int32_t)tag {
349*6777b538SAndroid Build Coastguard Worker  NSAssert(GPBWireFormatIsValidTag(tag), @"Invalid tag");
350*6777b538SAndroid Build Coastguard Worker  switch (GPBWireFormatGetTagWireType(tag)) {
351*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatVarint:
352*6777b538SAndroid Build Coastguard Worker      GPBCodedInputStreamReadInt32(&state_);
353*6777b538SAndroid Build Coastguard Worker      return YES;
354*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatFixed64:
355*6777b538SAndroid Build Coastguard Worker      SkipRawData(&state_, sizeof(int64_t));
356*6777b538SAndroid Build Coastguard Worker      return YES;
357*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatLengthDelimited:
358*6777b538SAndroid Build Coastguard Worker      SkipRawData(&state_, ReadRawVarint32(&state_));
359*6777b538SAndroid Build Coastguard Worker      return YES;
360*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatStartGroup:
361*6777b538SAndroid Build Coastguard Worker      [self skipMessage];
362*6777b538SAndroid Build Coastguard Worker      GPBCodedInputStreamCheckLastTagWas(
363*6777b538SAndroid Build Coastguard Worker          &state_, GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag),
364*6777b538SAndroid Build Coastguard Worker                                        GPBWireFormatEndGroup));
365*6777b538SAndroid Build Coastguard Worker      return YES;
366*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatEndGroup:
367*6777b538SAndroid Build Coastguard Worker      return NO;
368*6777b538SAndroid Build Coastguard Worker    case GPBWireFormatFixed32:
369*6777b538SAndroid Build Coastguard Worker      SkipRawData(&state_, sizeof(int32_t));
370*6777b538SAndroid Build Coastguard Worker      return YES;
371*6777b538SAndroid Build Coastguard Worker  }
372*6777b538SAndroid Build Coastguard Worker}
373*6777b538SAndroid Build Coastguard Worker
374*6777b538SAndroid Build Coastguard Worker- (void)skipMessage {
375*6777b538SAndroid Build Coastguard Worker  while (YES) {
376*6777b538SAndroid Build Coastguard Worker    int32_t tag = GPBCodedInputStreamReadTag(&state_);
377*6777b538SAndroid Build Coastguard Worker    if (tag == 0 || ![self skipField:tag]) {
378*6777b538SAndroid Build Coastguard Worker      return;
379*6777b538SAndroid Build Coastguard Worker    }
380*6777b538SAndroid Build Coastguard Worker  }
381*6777b538SAndroid Build Coastguard Worker}
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker- (BOOL)isAtEnd {
384*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamIsAtEnd(&state_);
385*6777b538SAndroid Build Coastguard Worker}
386*6777b538SAndroid Build Coastguard Worker
387*6777b538SAndroid Build Coastguard Worker- (size_t)position {
388*6777b538SAndroid Build Coastguard Worker  return state_.bufferPos;
389*6777b538SAndroid Build Coastguard Worker}
390*6777b538SAndroid Build Coastguard Worker
391*6777b538SAndroid Build Coastguard Worker- (size_t)pushLimit:(size_t)byteLimit {
392*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamPushLimit(&state_, byteLimit);
393*6777b538SAndroid Build Coastguard Worker}
394*6777b538SAndroid Build Coastguard Worker
395*6777b538SAndroid Build Coastguard Worker- (void)popLimit:(size_t)oldLimit {
396*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamPopLimit(&state_, oldLimit);
397*6777b538SAndroid Build Coastguard Worker}
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker- (double)readDouble {
400*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadDouble(&state_);
401*6777b538SAndroid Build Coastguard Worker}
402*6777b538SAndroid Build Coastguard Worker
403*6777b538SAndroid Build Coastguard Worker- (float)readFloat {
404*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadFloat(&state_);
405*6777b538SAndroid Build Coastguard Worker}
406*6777b538SAndroid Build Coastguard Worker
407*6777b538SAndroid Build Coastguard Worker- (uint64_t)readUInt64 {
408*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadUInt64(&state_);
409*6777b538SAndroid Build Coastguard Worker}
410*6777b538SAndroid Build Coastguard Worker
411*6777b538SAndroid Build Coastguard Worker- (int64_t)readInt64 {
412*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadInt64(&state_);
413*6777b538SAndroid Build Coastguard Worker}
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Worker- (int32_t)readInt32 {
416*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadInt32(&state_);
417*6777b538SAndroid Build Coastguard Worker}
418*6777b538SAndroid Build Coastguard Worker
419*6777b538SAndroid Build Coastguard Worker- (uint64_t)readFixed64 {
420*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadFixed64(&state_);
421*6777b538SAndroid Build Coastguard Worker}
422*6777b538SAndroid Build Coastguard Worker
423*6777b538SAndroid Build Coastguard Worker- (uint32_t)readFixed32 {
424*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadFixed32(&state_);
425*6777b538SAndroid Build Coastguard Worker}
426*6777b538SAndroid Build Coastguard Worker
427*6777b538SAndroid Build Coastguard Worker- (BOOL)readBool {
428*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadBool(&state_);
429*6777b538SAndroid Build Coastguard Worker}
430*6777b538SAndroid Build Coastguard Worker
431*6777b538SAndroid Build Coastguard Worker- (NSString *)readString {
432*6777b538SAndroid Build Coastguard Worker  return [GPBCodedInputStreamReadRetainedString(&state_) autorelease];
433*6777b538SAndroid Build Coastguard Worker}
434*6777b538SAndroid Build Coastguard Worker
435*6777b538SAndroid Build Coastguard Worker- (void)readGroup:(int32_t)fieldNumber
436*6777b538SAndroid Build Coastguard Worker              message:(GPBMessage *)message
437*6777b538SAndroid Build Coastguard Worker    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
438*6777b538SAndroid Build Coastguard Worker  CheckRecursionLimit(&state_);
439*6777b538SAndroid Build Coastguard Worker  ++state_.recursionDepth;
440*6777b538SAndroid Build Coastguard Worker  [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
441*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamCheckLastTagWas(
442*6777b538SAndroid Build Coastguard Worker      &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup));
443*6777b538SAndroid Build Coastguard Worker  --state_.recursionDepth;
444*6777b538SAndroid Build Coastguard Worker}
445*6777b538SAndroid Build Coastguard Worker
446*6777b538SAndroid Build Coastguard Worker- (void)readUnknownGroup:(int32_t)fieldNumber
447*6777b538SAndroid Build Coastguard Worker                 message:(GPBUnknownFieldSet *)message {
448*6777b538SAndroid Build Coastguard Worker  CheckRecursionLimit(&state_);
449*6777b538SAndroid Build Coastguard Worker  ++state_.recursionDepth;
450*6777b538SAndroid Build Coastguard Worker  [message mergeFromCodedInputStream:self];
451*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamCheckLastTagWas(
452*6777b538SAndroid Build Coastguard Worker      &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup));
453*6777b538SAndroid Build Coastguard Worker  --state_.recursionDepth;
454*6777b538SAndroid Build Coastguard Worker}
455*6777b538SAndroid Build Coastguard Worker
456*6777b538SAndroid Build Coastguard Worker- (void)readMessage:(GPBMessage *)message
457*6777b538SAndroid Build Coastguard Worker    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
458*6777b538SAndroid Build Coastguard Worker  CheckRecursionLimit(&state_);
459*6777b538SAndroid Build Coastguard Worker  int32_t length = ReadRawVarint32(&state_);
460*6777b538SAndroid Build Coastguard Worker  size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
461*6777b538SAndroid Build Coastguard Worker  ++state_.recursionDepth;
462*6777b538SAndroid Build Coastguard Worker  [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
463*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamCheckLastTagWas(&state_, 0);
464*6777b538SAndroid Build Coastguard Worker  --state_.recursionDepth;
465*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamPopLimit(&state_, oldLimit);
466*6777b538SAndroid Build Coastguard Worker}
467*6777b538SAndroid Build Coastguard Worker
468*6777b538SAndroid Build Coastguard Worker- (void)readMapEntry:(id)mapDictionary
469*6777b538SAndroid Build Coastguard Worker    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
470*6777b538SAndroid Build Coastguard Worker                field:(GPBFieldDescriptor *)field
471*6777b538SAndroid Build Coastguard Worker        parentMessage:(GPBMessage *)parentMessage {
472*6777b538SAndroid Build Coastguard Worker  CheckRecursionLimit(&state_);
473*6777b538SAndroid Build Coastguard Worker  int32_t length = ReadRawVarint32(&state_);
474*6777b538SAndroid Build Coastguard Worker  size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
475*6777b538SAndroid Build Coastguard Worker  ++state_.recursionDepth;
476*6777b538SAndroid Build Coastguard Worker  GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field,
477*6777b538SAndroid Build Coastguard Worker                         parentMessage);
478*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamCheckLastTagWas(&state_, 0);
479*6777b538SAndroid Build Coastguard Worker  --state_.recursionDepth;
480*6777b538SAndroid Build Coastguard Worker  GPBCodedInputStreamPopLimit(&state_, oldLimit);
481*6777b538SAndroid Build Coastguard Worker}
482*6777b538SAndroid Build Coastguard Worker
483*6777b538SAndroid Build Coastguard Worker- (NSData *)readBytes {
484*6777b538SAndroid Build Coastguard Worker  return [GPBCodedInputStreamReadRetainedBytes(&state_) autorelease];
485*6777b538SAndroid Build Coastguard Worker}
486*6777b538SAndroid Build Coastguard Worker
487*6777b538SAndroid Build Coastguard Worker- (uint32_t)readUInt32 {
488*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadUInt32(&state_);
489*6777b538SAndroid Build Coastguard Worker}
490*6777b538SAndroid Build Coastguard Worker
491*6777b538SAndroid Build Coastguard Worker- (int32_t)readEnum {
492*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadEnum(&state_);
493*6777b538SAndroid Build Coastguard Worker}
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker- (int32_t)readSFixed32 {
496*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadSFixed32(&state_);
497*6777b538SAndroid Build Coastguard Worker}
498*6777b538SAndroid Build Coastguard Worker
499*6777b538SAndroid Build Coastguard Worker- (int64_t)readSFixed64 {
500*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadSFixed64(&state_);
501*6777b538SAndroid Build Coastguard Worker}
502*6777b538SAndroid Build Coastguard Worker
503*6777b538SAndroid Build Coastguard Worker- (int32_t)readSInt32 {
504*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadSInt32(&state_);
505*6777b538SAndroid Build Coastguard Worker}
506*6777b538SAndroid Build Coastguard Worker
507*6777b538SAndroid Build Coastguard Worker- (int64_t)readSInt64 {
508*6777b538SAndroid Build Coastguard Worker  return GPBCodedInputStreamReadSInt64(&state_);
509*6777b538SAndroid Build Coastguard Worker}
510*6777b538SAndroid Build Coastguard Worker
511*6777b538SAndroid Build Coastguard Worker#pragma clang diagnostic pop
512*6777b538SAndroid Build Coastguard Worker
513*6777b538SAndroid Build Coastguard Worker@end
514