You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

142 lines
3.3 KiB

/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FIRMessagingCodedInputStream.h"
#import "FIRMessagingDefines.h"
typedef struct {
const void *bytes;
size_t bufferSize;
size_t bufferPos;
} BufferState;
static BOOL CheckSize(BufferState *state, size_t size) {
size_t newSize = state->bufferPos + size;
if (newSize > state->bufferSize) {
return NO;
}
return YES;
}
static BOOL ReadRawByte(BufferState *state, int8_t *output) {
_FIRMessagingDevAssert(output != NULL && state != NULL, @"Invalid parameters");
if (CheckSize(state, sizeof(int8_t))) {
*output = ((int8_t *)state->bytes)[state->bufferPos++];
return YES;
}
return NO;
}
static BOOL ReadRawVarInt32(BufferState *state, int32_t *output) {
_FIRMessagingDevAssert(output != NULL && state != NULL, @"Invalid parameters");
int8_t tmp = 0;
if (!ReadRawByte(state, &tmp)) {
return NO;
}
if (tmp >= 0) {
*output = tmp;
return YES;
}
int32_t result = tmp & 0x7f;
if (!ReadRawByte(state, &tmp)) {
return NO;
}
if (tmp >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
if (!ReadRawByte(state, &tmp)) {
return NO;
}
if (tmp >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if (!ReadRawByte(state, &tmp)) {
return NO;
}
if (tmp >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
if (!ReadRawByte(state, &tmp)) {
return NO;
}
result |= tmp << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; ++i) {
if (!ReadRawByte(state, &tmp)) {
return NO;
}
if (tmp >= 0) {
*output = result;
return YES;
}
}
return NO;
}
}
}
}
*output = result;
return YES;
}
@interface FIRMessagingCodedInputStream()
@property(nonatomic, readwrite, strong) NSData *buffer;
@property(nonatomic, readwrite, assign) BufferState state;
@end
@implementation FIRMessagingCodedInputStream;
- (instancetype)initWithData:(NSData *)data {
self = [super init];
if (self) {
_buffer = data;
_state.bytes = _buffer.bytes;
_state.bufferSize = _buffer.length;
}
return self;
}
- (size_t)offset {
return _state.bufferPos;
}
- (BOOL)readTag:(int8_t *)tag {
return ReadRawByte(&_state, tag);
}
- (BOOL)readLength:(int32_t *)length {
return ReadRawVarInt32(&_state, length);
}
- (NSData *)readDataWithLength:(uint32_t)length {
if (!CheckSize(&_state, length)) {
return nil;
}
const void *bytesToRead = _state.bytes + _state.bufferPos;
NSData *result = [NSData dataWithBytes:bytesToRead length:length];
_state.bufferPos += length;
return result;
}
@end