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