OLD | NEW |
(Empty) | |
| 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 |
| 39 static const NSUInteger kDefaultRecursionLimit = 64; |
| 40 |
| 41 static 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 |
| 53 static int8_t ReadRawByte(GPBCodedInputStreamState *state) { |
| 54 CheckSize(state, sizeof(int8_t)); |
| 55 return ((int8_t *)state->bytes)[state->bufferPos++]; |
| 56 } |
| 57 |
| 58 static 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 |
| 65 static 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 |
| 72 static 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 |
| 107 static 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 |
| 122 static void SkipRawData(GPBCodedInputStreamState *state, size_t size) { |
| 123 CheckSize(state, size); |
| 124 state->bufferPos += size; |
| 125 } |
| 126 |
| 127 double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state) { |
| 128 int64_t value = ReadRawLittleEndian64(state); |
| 129 return GPBConvertInt64ToDouble(value); |
| 130 } |
| 131 |
| 132 float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state) { |
| 133 int32_t value = ReadRawLittleEndian32(state); |
| 134 return GPBConvertInt32ToFloat(value); |
| 135 } |
| 136 |
| 137 uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state) { |
| 138 uint64_t value = ReadRawVarint64(state); |
| 139 return value; |
| 140 } |
| 141 |
| 142 uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state) { |
| 143 uint32_t value = ReadRawVarint32(state); |
| 144 return value; |
| 145 } |
| 146 |
| 147 int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state) { |
| 148 int64_t value = ReadRawVarint64(state); |
| 149 return value; |
| 150 } |
| 151 |
| 152 int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state) { |
| 153 int32_t value = ReadRawVarint32(state); |
| 154 return value; |
| 155 } |
| 156 |
| 157 uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state) { |
| 158 uint64_t value = ReadRawLittleEndian64(state); |
| 159 return value; |
| 160 } |
| 161 |
| 162 uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state) { |
| 163 uint32_t value = ReadRawLittleEndian32(state); |
| 164 return value; |
| 165 } |
| 166 |
| 167 int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state) { |
| 168 int32_t value = ReadRawVarint32(state); |
| 169 return value; |
| 170 } |
| 171 |
| 172 int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state) { |
| 173 int32_t value = ReadRawLittleEndian32(state); |
| 174 return value; |
| 175 } |
| 176 |
| 177 int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state) { |
| 178 int64_t value = ReadRawLittleEndian64(state); |
| 179 return value; |
| 180 } |
| 181 |
| 182 int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state) { |
| 183 int32_t value = GPBDecodeZigZag32(ReadRawVarint32(state)); |
| 184 return value; |
| 185 } |
| 186 |
| 187 int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state) { |
| 188 int64_t value = GPBDecodeZigZag64(ReadRawVarint64(state)); |
| 189 return value; |
| 190 } |
| 191 |
| 192 BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state) { |
| 193 return ReadRawVarint32(state) != 0; |
| 194 } |
| 195 |
| 196 int32_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 |
| 211 NSString *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 if (!result) { |
| 223 result = @""; |
| 224 #ifdef DEBUG |
| 225 // https://developers.google.com/protocol-buffers/docs/proto#scalar |
| 226 NSLog(@"UTF8 failure, is some field type 'string' when it should be " |
| 227 @"'bytes'?"); |
| 228 #endif |
| 229 } |
| 230 state->bufferPos += size; |
| 231 } |
| 232 return result; |
| 233 } |
| 234 |
| 235 NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) { |
| 236 int32_t size = ReadRawVarint32(state); |
| 237 if (size < 0) return nil; |
| 238 CheckSize(state, size); |
| 239 NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos |
| 240 length:size]; |
| 241 state->bufferPos += size; |
| 242 return result; |
| 243 } |
| 244 |
| 245 NSData *GPBCodedInputStreamReadRetainedBytesNoCopy( |
| 246 GPBCodedInputStreamState *state) { |
| 247 int32_t size = ReadRawVarint32(state); |
| 248 if (size < 0) return nil; |
| 249 CheckSize(state, size); |
| 250 // Cast is safe because freeWhenDone is NO. |
| 251 NSData *result = [[NSData alloc] |
| 252 initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos) |
| 253 length:size |
| 254 freeWhenDone:NO]; |
| 255 state->bufferPos += size; |
| 256 return result; |
| 257 } |
| 258 |
| 259 size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state, |
| 260 size_t byteLimit) { |
| 261 byteLimit += state->bufferPos; |
| 262 size_t oldLimit = state->currentLimit; |
| 263 if (byteLimit > oldLimit) { |
| 264 [NSException raise:NSInvalidArgumentException |
| 265 format:@"byteLimit > oldLimit: %tu > %tu", byteLimit, oldLimit]; |
| 266 } |
| 267 state->currentLimit = byteLimit; |
| 268 return oldLimit; |
| 269 } |
| 270 |
| 271 void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state, |
| 272 size_t oldLimit) { |
| 273 state->currentLimit = oldLimit; |
| 274 } |
| 275 |
| 276 size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) { |
| 277 return state->currentLimit - state->bufferPos; |
| 278 } |
| 279 |
| 280 BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) { |
| 281 return (state->bufferPos == state->bufferSize) || |
| 282 (state->bufferPos == state->currentLimit); |
| 283 } |
| 284 |
| 285 void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, |
| 286 int32_t value) { |
| 287 if (state->lastTag != value) { |
| 288 [NSException raise:NSParseErrorException |
| 289 format:@"Last tag: %d should be %d", state->lastTag, value]; |
| 290 } |
| 291 } |
| 292 |
| 293 @implementation GPBCodedInputStream |
| 294 |
| 295 + (instancetype)streamWithData:(NSData *)data { |
| 296 return [[[self alloc] initWithData:data] autorelease]; |
| 297 } |
| 298 |
| 299 - (instancetype)initWithData:(NSData *)data { |
| 300 if ((self = [super init])) { |
| 301 #ifdef DEBUG |
| 302 NSCAssert([self class] == [GPBCodedInputStream class], |
| 303 @"Subclassing of GPBCodedInputStream is not allowed."); |
| 304 #endif |
| 305 buffer_ = [data retain]; |
| 306 state_.bytes = (const uint8_t *)[data bytes]; |
| 307 state_.bufferSize = [data length]; |
| 308 state_.currentLimit = state_.bufferSize; |
| 309 } |
| 310 return self; |
| 311 } |
| 312 |
| 313 - (void)dealloc { |
| 314 [buffer_ release]; |
| 315 [super dealloc]; |
| 316 } |
| 317 |
| 318 - (int32_t)readTag { |
| 319 return GPBCodedInputStreamReadTag(&state_); |
| 320 } |
| 321 |
| 322 - (void)checkLastTagWas:(int32_t)value { |
| 323 GPBCodedInputStreamCheckLastTagWas(&state_, value); |
| 324 } |
| 325 |
| 326 - (BOOL)skipField:(int32_t)tag { |
| 327 switch (GPBWireFormatGetTagWireType(tag)) { |
| 328 case GPBWireFormatVarint: |
| 329 GPBCodedInputStreamReadInt32(&state_); |
| 330 return YES; |
| 331 case GPBWireFormatFixed64: |
| 332 SkipRawData(&state_, sizeof(int64_t)); |
| 333 return YES; |
| 334 case GPBWireFormatLengthDelimited: |
| 335 SkipRawData(&state_, ReadRawVarint32(&state_)); |
| 336 return YES; |
| 337 case GPBWireFormatStartGroup: |
| 338 [self skipMessage]; |
| 339 GPBCodedInputStreamCheckLastTagWas( |
| 340 &state_, GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag), |
| 341 GPBWireFormatEndGroup)); |
| 342 return YES; |
| 343 case GPBWireFormatEndGroup: |
| 344 return NO; |
| 345 case GPBWireFormatFixed32: |
| 346 SkipRawData(&state_, sizeof(int32_t)); |
| 347 return YES; |
| 348 } |
| 349 [NSException raise:NSParseErrorException format:@"Invalid tag %d", tag]; |
| 350 return NO; |
| 351 } |
| 352 |
| 353 - (void)skipMessage { |
| 354 while (YES) { |
| 355 int32_t tag = GPBCodedInputStreamReadTag(&state_); |
| 356 if (tag == 0 || ![self skipField:tag]) { |
| 357 return; |
| 358 } |
| 359 } |
| 360 } |
| 361 |
| 362 - (double)readDouble { |
| 363 return GPBCodedInputStreamReadDouble(&state_); |
| 364 } |
| 365 |
| 366 - (float)readFloat { |
| 367 return GPBCodedInputStreamReadFloat(&state_); |
| 368 } |
| 369 |
| 370 - (uint64_t)readUInt64 { |
| 371 return GPBCodedInputStreamReadUInt64(&state_); |
| 372 } |
| 373 |
| 374 - (int64_t)readInt64 { |
| 375 return GPBCodedInputStreamReadInt64(&state_); |
| 376 } |
| 377 |
| 378 - (int32_t)readInt32 { |
| 379 return GPBCodedInputStreamReadInt32(&state_); |
| 380 } |
| 381 |
| 382 - (uint64_t)readFixed64 { |
| 383 return GPBCodedInputStreamReadFixed64(&state_); |
| 384 } |
| 385 |
| 386 - (uint32_t)readFixed32 { |
| 387 return GPBCodedInputStreamReadFixed32(&state_); |
| 388 } |
| 389 |
| 390 - (BOOL)readBool { |
| 391 return GPBCodedInputStreamReadBool(&state_); |
| 392 } |
| 393 |
| 394 - (NSString *)readString { |
| 395 return [GPBCodedInputStreamReadRetainedString(&state_) autorelease]; |
| 396 } |
| 397 |
| 398 - (void)readGroup:(int32_t)fieldNumber |
| 399 message:(GPBMessage *)message |
| 400 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { |
| 401 if (state_.recursionDepth >= kDefaultRecursionLimit) { |
| 402 [NSException raise:NSParseErrorException |
| 403 format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, |
| 404 kDefaultRecursionLimit]; |
| 405 } |
| 406 ++state_.recursionDepth; |
| 407 [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; |
| 408 GPBCodedInputStreamCheckLastTagWas( |
| 409 &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)); |
| 410 --state_.recursionDepth; |
| 411 } |
| 412 |
| 413 - (void)readUnknownGroup:(int32_t)fieldNumber |
| 414 message:(GPBUnknownFieldSet *)message { |
| 415 if (state_.recursionDepth >= kDefaultRecursionLimit) { |
| 416 [NSException raise:NSParseErrorException |
| 417 format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, |
| 418 kDefaultRecursionLimit]; |
| 419 } |
| 420 ++state_.recursionDepth; |
| 421 [message mergeFromCodedInputStream:self]; |
| 422 GPBCodedInputStreamCheckLastTagWas( |
| 423 &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)); |
| 424 --state_.recursionDepth; |
| 425 } |
| 426 |
| 427 - (void)readMessage:(GPBMessage *)message |
| 428 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { |
| 429 int32_t length = ReadRawVarint32(&state_); |
| 430 if (state_.recursionDepth >= kDefaultRecursionLimit) { |
| 431 [NSException raise:NSParseErrorException |
| 432 format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, |
| 433 kDefaultRecursionLimit]; |
| 434 } |
| 435 size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length); |
| 436 ++state_.recursionDepth; |
| 437 [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; |
| 438 GPBCodedInputStreamCheckLastTagWas(&state_, 0); |
| 439 --state_.recursionDepth; |
| 440 GPBCodedInputStreamPopLimit(&state_, oldLimit); |
| 441 } |
| 442 |
| 443 - (void)readMapEntry:(id)mapDictionary |
| 444 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry |
| 445 field:(GPBFieldDescriptor *)field |
| 446 parentMessage:(GPBMessage *)parentMessage { |
| 447 int32_t length = ReadRawVarint32(&state_); |
| 448 if (state_.recursionDepth >= kDefaultRecursionLimit) { |
| 449 [NSException raise:NSParseErrorException |
| 450 format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, |
| 451 kDefaultRecursionLimit]; |
| 452 } |
| 453 size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length); |
| 454 ++state_.recursionDepth; |
| 455 GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field, |
| 456 parentMessage); |
| 457 GPBCodedInputStreamCheckLastTagWas(&state_, 0); |
| 458 --state_.recursionDepth; |
| 459 GPBCodedInputStreamPopLimit(&state_, oldLimit); |
| 460 } |
| 461 |
| 462 - (NSData *)readBytes { |
| 463 return [GPBCodedInputStreamReadRetainedBytes(&state_) autorelease]; |
| 464 } |
| 465 |
| 466 - (uint32_t)readUInt32 { |
| 467 return GPBCodedInputStreamReadUInt32(&state_); |
| 468 } |
| 469 |
| 470 - (int32_t)readEnum { |
| 471 return GPBCodedInputStreamReadEnum(&state_); |
| 472 } |
| 473 |
| 474 - (int32_t)readSFixed32 { |
| 475 return GPBCodedInputStreamReadSFixed32(&state_); |
| 476 } |
| 477 |
| 478 - (int64_t)readSFixed64 { |
| 479 return GPBCodedInputStreamReadSFixed64(&state_); |
| 480 } |
| 481 |
| 482 - (int32_t)readSInt32 { |
| 483 return GPBCodedInputStreamReadSInt32(&state_); |
| 484 } |
| 485 |
| 486 - (int64_t)readSInt64 { |
| 487 return GPBCodedInputStreamReadSInt64(&state_); |
| 488 } |
| 489 |
| 490 @end |
OLD | NEW |