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