• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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