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