/* * Copyright (C) 2018 The Android Open Source Project * * 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. */ #include "leb128.h" #include #include #include #include namespace nogrod { Leb128Decoder::Leb128Decoder(const uint8_t* buffer, size_t size) : buffer_(buffer), size_(size) {} // Returns number of bytes it took do decode the value, 0 if decode has failed. size_t Leb128Decoder::Decode(size_t offset, uint64_t* result) const { return DecodeLeb128(buffer_ + offset, size_ - offset, result); } size_t DecodeLeb128(const uint8_t* buf, uint64_t buf_size, uint64_t* result) { uint64_t value = 0; size_t shift = 0; size_t size = 0; uint8_t byte; do { if (size >= buf_size) { FATAL("leb128: ran out of bounds while reading value at offset=%zd (buf_size=%" PRId64 ")", size, buf_size); } if (shift >= CHAR_BIT * sizeof(uint64_t)) { FATAL("leb128: the value at offset %zd is too big (does not fit into uint64_t), shift=%zd", size, shift); } byte = buf[size++]; value += static_cast(byte & 0x7f) << shift; shift += 7; } while ((byte & 0x80) != 0); *result = value; return size; } size_t DecodeSleb128(const uint8_t* buf, uint64_t buf_size, int64_t* result) { uint64_t value = 0; size_t shift = 0; size_t size = 0; uint8_t byte; do { if (size >= buf_size) { FATAL("sleb128: ran out of bounds while reading value at offset=%zd (buf_size=%" PRId64 ")", size, buf_size); } if (shift >= CHAR_BIT * sizeof(uint64_t)) { FATAL("sleb128: the value at offset %zd is too big (does not fit into uint64_t), shift=%zd", size, shift); } byte = buf[size++]; value += static_cast(byte & 0x7f) << shift; shift += 7; } while ((byte & 0x80) != 0); // sign extent is not applicable if shift is out of bounds of uint64_t if (shift < (sizeof(uint64_t) * CHAR_BIT) && (byte & 0x40) != 0) { value |= -(static_cast(1) << shift); } memcpy(result, &value, sizeof(*result)); return size; } } // namespace nogrod