Files
wc3re/util.cc

201 lines
4.5 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_;
}
char const* MmapFile::data() const
{
if (!*this)
throw std::logic_error("data() called on invalid MmapFile");
return static_cast<char const*>(base_);
}
MmapFile::operator bool() const
{
return base_;
}
uint16_t readU16BE(char const* data)
{
if(!data)
throw std::logic_error("readU16BE() called with nullptr");
uint16_t ret;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
ret = ((static_cast<uint16_t>(*data)&0xff)<<8) | static_cast<uint8_t>(*(data+1));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(&ret, data, 2);
#else
#error Unknown endianess
#endif
return ret;
}
uint32_t readU24BE(char const* data)
{
if(!data)
throw std::logic_error("readU24BE() called with nullptr");
uint32_t ret = 0;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
ret = ((static_cast<uint32_t>(*data)&0xff)<<16) |
((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
static_cast<uint8_t>(*(data+2));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(static_cast<char*>(&ret)+1, data, 3);
#else
#error Unknown endianess
#endif
return ret;
}
uint32_t readU32BE(char const* data)
{
if(!data)
throw std::logic_error("readU32BE() called with nullptr");
uint32_t ret;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
ret = ((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));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(&ret, data, 4);
#else
#error Unknown endianess
#endif
return ret;
}
uint16_t readU16LE(char const* data)
{
if(!data)
throw std::logic_error("readU16LE() called with nullptr");
uint16_t ret;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, data, 2);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((static_cast<uint16_t>(*(data+1))&0xff)<<8) | static_cast<uint8_t>(*data);
#else
#error Unknown endianess
#endif
return ret;
}
uint32_t readU24LE(char const* data)
{
if(!data)
throw std::logic_error("readU24LE() called with nullptr");
uint32_t ret = 0;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, data, 3);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
static_cast<uint8_t>(*data);
#else
#error Unknown endianess
#endif
return ret;
}
uint32_t readU32LE(char const* data)
{
if(!data)
throw std::logic_error("readU32LE() called with nullptr");
uint32_t ret;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, data, 4);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((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);
#else
#error Unknown endianess
#endif
return ret;
}