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