/* * 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