/* This file is part of Darling. Copyright (C) 2012 Lubos Dolezel Copyright (C) 2011 Shinichiro Hamaji Darling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Darling is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Darling. If not, see . */ #include "leb.h" #include #include uint64_t uleb128(const uint8_t*& p) { uint64_t r = 0; int s = 0; do { r |= (uint64_t)(*p & 0x7f) << s; s += 7; } while (*p++ >= 0x80); return r; } int64_t sleb128(const uint8_t*& p) { int64_t r = 0; int s = 0; for (;;) { uint8_t b = *p++; if (b < 0x80) { if (b & 0x40) r -= (0x80 - b) << s; else r |= (b & 0x3f) << s; break; } r |= (b & 0x7f) << s; s += 7; } return r; } std::vector uleb128(uint64_t v) { if (!v) return std::vector({ 0 }); std::vector rv; int bitsUsed = 0, bytesUsed; for (int i = 0; i < 64; i++) { if (v & (1ll << i)) bitsUsed = i+1; } // round it up to 7 bits bytesUsed = (bitsUsed+6) / 7; for (int i = 0; i < bytesUsed; i++) { uint8_t enc = (v >> (i*7)) & 0x7f; if (i+1 < bytesUsed) enc |= 0x80; rv.push_back(enc); } return rv; } void LEBStream::add(uint64_t v) { std::vector enc = uleb128(v); m_data.insert(m_data.end(), enc.begin(), enc.end()); } size_t LEBStream::count() const { size_t count = 0; for (size_t i = 0; i < m_data.size(); i++) { if (!(m_data[i] & 0x80)) count++; } return count; } uint64_t LEBStream::pop() { if (!bytes()) throw std::underflow_error("LEBStream::pop()"); size_t start = 0; for (size_t i = 0; i < m_data.size()-1; i++) { if (!(m_data[i] & 0x80)) start = i+1; } const uint8_t* data = &m_data[start]; uint64_t v = uleb128(data); m_data.resize(start); return v; } LEBStreamIterator LEBStream::begin() const { return LEBStreamIterator(data(), 0, bytes()); } LEBStreamIterator LEBStream::end() const { return LEBStreamIterator(data(), bytes(), bytes()); } LEBStreamIterator::LEBStreamIterator(const uint8_t* data, size_t bytes, size_t pos) : m_data(data), m_bytes(bytes), m_pos(pos) { } uint64_t LEBStreamIterator::operator*() { if (m_pos >= m_bytes) return 0; const uint8_t* data = m_data + m_pos; return uleb128(data); } LEBStreamIterator& LEBStreamIterator::operator++(int) { while (m_data[m_pos] & 0x80 && m_pos < m_bytes) m_pos++; return *this; } bool LEBStreamIterator::operator!=(const LEBStreamIterator& that) { return m_pos != that.m_pos; }