Home | History | Annotate | Download | only in objectivec
      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     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 
    236 NSData *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 
    246 NSData *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 
    260 size_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 
    272 void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state,
    273                                  size_t oldLimit) {
    274   state->currentLimit = oldLimit;
    275 }
    276 
    277 size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) {
    278   return state->currentLimit - state->bufferPos;
    279 }
    280 
    281 BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) {
    282   return (state->bufferPos == state->bufferSize) ||
    283          (state->bufferPos == state->currentLimit);
    284 }
    285 
    286 void 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