235 lines
5.0 KiB
C++
235 lines
5.0 KiB
C++
#include <stdexcept>
|
|
#include <cstring>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "common.hh"
|
|
#include "util.hh"
|
|
|
|
MmapFile::MmapFile(std::string fileName)
|
|
: name_(std::move(fileName)), fd_(fopen(name_.c_str(), "rb")), size_(0), base_(nullptr)
|
|
{
|
|
if (!fd_)
|
|
throw POSIXException{errno, "Could not open " + name_};
|
|
|
|
struct stat statBuf;
|
|
|
|
if (fstat(fileno(fd_.get()), &statBuf) != 0)
|
|
throw POSIXException(errno, "Could not stat");
|
|
|
|
|
|
if (statBuf.st_size <= 0)
|
|
throw Exception{"File size is zero or less"};
|
|
|
|
size_ = static_cast<size_t>(statBuf.st_size);
|
|
|
|
base_ = mmap(nullptr, size_, PROT_READ, MAP_SHARED, fileno(fd_.get()), 0);
|
|
if (!base_)
|
|
throw POSIXException(errno, "mmap failed");
|
|
}
|
|
|
|
MmapFile::MmapFile(MmapFile && move):
|
|
name_(std::move(move.name_)), fd_(std::move(move.fd_)), size_(move.size_),
|
|
base_(move.base_)
|
|
{
|
|
move.base_ = nullptr;
|
|
}
|
|
|
|
MmapFile::~MmapFile()
|
|
{
|
|
if (base_) {
|
|
if (munmap(base_, size_) != 0)
|
|
fprintf(stderr, "Warning: munmap failed: %s\n", strerror(errno));
|
|
base_ = nullptr;
|
|
}
|
|
}
|
|
|
|
MmapFile& MmapFile::operator=(MmapFile && move)
|
|
{
|
|
fd_ = std::move(move.fd_);
|
|
if (base_)
|
|
if (munmap(base_, size_) != 0)
|
|
fprintf(stderr, "Warning: munmap failed: %s\n", strerror(errno));
|
|
base_ = move.base_;
|
|
move.base_ = nullptr;
|
|
size_ = move.size_;
|
|
name_ = std::move(move.name_);
|
|
|
|
return *this;
|
|
}
|
|
|
|
std::string const& MmapFile::name() const
|
|
{
|
|
if (!*this)
|
|
throw std::logic_error("name() called on invalid MmapFile");
|
|
return name_;
|
|
}
|
|
|
|
size_t MmapFile::size() const
|
|
{
|
|
if (!*this)
|
|
throw std::logic_error("size() called on invalid MmapFile");
|
|
return size_;
|
|
}
|
|
|
|
uint8_t const* MmapFile::data() const
|
|
{
|
|
if (!*this)
|
|
throw std::logic_error("data() called on invalid MmapFile");
|
|
return static_cast<uint8_t const*>(base_);
|
|
}
|
|
|
|
MmapFile::operator bool() const
|
|
{
|
|
return base_;
|
|
}
|
|
|
|
|
|
uint16_t readU16BE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU16BE() called with nullptr");
|
|
|
|
return ((static_cast<uint16_t>(*data)&0xff)<<8) |
|
|
static_cast<uint8_t>(*(data+1));
|
|
}
|
|
|
|
uint32_t readU24BE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU24BE() called with nullptr");
|
|
|
|
return ((static_cast<uint32_t>(*data)&0xff)<<16) |
|
|
((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
|
|
static_cast<uint8_t>(*(data+2));
|
|
}
|
|
|
|
uint32_t readU32BE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU32BE() called with nullptr");
|
|
|
|
return ((static_cast<uint32_t>(*data)&0xff)<<24) |
|
|
((static_cast<uint32_t>(*(data+1))&0xff)<<16) |
|
|
((static_cast<uint32_t>(*(data+2))&0xff)<<8) |
|
|
static_cast<uint8_t>(*(data+3));
|
|
}
|
|
|
|
uint16_t readU16LE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU16LE() called with nullptr");
|
|
|
|
return ((static_cast<uint16_t>(*(data+1))&0xff)<<8) |
|
|
static_cast<uint8_t>(*data);
|
|
}
|
|
|
|
uint32_t readU24LE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU24LE() called with nullptr");
|
|
|
|
return ((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
|
|
((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
|
|
static_cast<uint8_t>(*data);
|
|
}
|
|
|
|
uint32_t readU32LE(uint8_t const* data)
|
|
{
|
|
if(!data)
|
|
throw std::logic_error("readU32LE() called with nullptr");
|
|
|
|
return ((static_cast<uint32_t>(*(data+3))&0xff)<<24) |
|
|
((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
|
|
((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
|
|
static_cast<uint8_t>(*data);
|
|
}
|
|
|
|
int sextend(unsigned b, unsigned msb)
|
|
{
|
|
if (msb >= sizeof(unsigned)*8)
|
|
throw std::logic_error("sextend: msb out of range");
|
|
|
|
if (b&(1<<(msb-1))) { // msb is 1
|
|
return ~((1<<msb)-1) | (b&((1<<msb)-1));
|
|
} else { // msb is 0
|
|
return b&((1<<msb)-1);
|
|
}
|
|
}
|
|
|
|
|
|
std::string fileToString(std::string const& name) {
|
|
std::FILE *file = std::fopen(name.c_str(), "r");
|
|
if (!file) {
|
|
throw POSIXException(errno);
|
|
}
|
|
|
|
std::string ret;
|
|
char buf[512];
|
|
std::size_t p;
|
|
while((p = std::fread(buf, 1, 511, file)) > 0) {
|
|
buf[p] = '\0';
|
|
ret.append(buf);
|
|
}
|
|
if (!std::feof(file)) {
|
|
std::fclose(file);
|
|
throw POSIXException(errno);
|
|
}
|
|
|
|
std::fclose(file);
|
|
return ret;
|
|
}
|
|
|
|
BitReader::BitReader(uint8_t const* data, size_t len)
|
|
: data_(data), len_(len), pos_(0), buf_(0), bufValid_(0)
|
|
{
|
|
}
|
|
|
|
unsigned BitReader::getBits(unsigned count) {
|
|
unsigned out = buf_;
|
|
unsigned bPos = bufValid_;
|
|
|
|
if (bPos >= count) {
|
|
buf_ >>= count;
|
|
bufValid_ -= count;
|
|
return out & ((1<<count)-1);
|
|
}
|
|
|
|
while (bPos < count) {
|
|
if (pos_ >= len_)
|
|
throw Exception{"Input stream overrun"};
|
|
buf_ = data_[pos_++];
|
|
|
|
out |= buf_<<bPos;
|
|
|
|
if ((count-bPos) <= 8) {
|
|
buf_ >>= (count-bPos);
|
|
bufValid_ = 8-(count-bPos);
|
|
|
|
return out & ((1<<count)-1);
|
|
} else
|
|
bPos += 8;
|
|
}
|
|
|
|
return out & ((1<<count)-1);
|
|
}
|
|
|
|
unsigned BitReader::getBit() {
|
|
if (bufValid_) {
|
|
unsigned ret = buf_&0x1;
|
|
buf_ >>= 1;
|
|
--bufValid_;
|
|
return ret;
|
|
}
|
|
|
|
if (pos_ >= len_)
|
|
throw Exception{"Input stream overrun"};
|
|
buf_ = data_[pos_++];
|
|
bufValid_ = 7;
|
|
unsigned ret = buf_&0x1;
|
|
buf_ >>= 1;
|
|
return ret;
|
|
}
|