Seperate exceptions; Use proper endian-aware int parsing routines

This commit is contained in:
2015-04-25 13:30:36 +02:00
parent ae51cd24c4
commit c8d635c5de
12 changed files with 339 additions and 163 deletions

View File

@@ -1,12 +1,13 @@
#include <arpa/inet.h>
#include <cstring>
#include "IffFile.hh"
#include "util.hh"
#include "common.hh"
struct ChunkHeader {
char typeID[4];
uint32_t length; // big endian!!
} __attribute__((__packed__));
uint32_t length;
};
IffFile::IffFile(char const* base, size_t length)
: base_(base), length_(length), root_(nullptr)
@@ -52,17 +53,12 @@ void IffFile::printStructure(unsigned level) const
std::unique_ptr<IffFile::Object> IffFile::parseObject(char const* base, size_t length)
{
// if (reinterpret_cast<uintptr_t>(base)%2 != 0) {
// ++base;
// --length;
// }
if (length < sizeof(ChunkHeader))
if (length < 8)
throw FormatException{"length < header size"};
ChunkHeader header;
memcpy(&header, base, sizeof(ChunkHeader));
header.length = ntohl(header.length);
memcpy(&header.typeID, base, 4);
header.length = readU32BE(base+4);
for (unsigned i = 0;i < 4;++i)
if (!isprint(header.typeID[i]))

View File

@@ -2,19 +2,19 @@ CXX=g++
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++14 -flto
LDOPTS=
iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc
iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc exceptions.cc
iffexplore_LIBS ::=
treexplore_CXXSRCS ::= treexplore.cc TreFile.cc IffFile.cc util.cc
treexplore_CXXSRCS ::= treexplore.cc TreFile.cc IffFile.cc util.cc exceptions.cc
treexplore_LIBS ::=
font2png_CXXSRCS ::= font2png.cc
font2png_LIBS ::= -lpng
mvedecode_CXXSRCS ::= mvedecode.cc TreFile.cc IffFile.cc util.cc MveDecoder.cc
mvedecode_CXXSRCS ::= mvedecode.cc TreFile.cc IffFile.cc util.cc MveDecoder.cc exceptions.cc
mvedecode_LIBS ::=
progs ::= iffexplore font2png treexplore mvedecode
progs ::= iffexplore treexplore mvedecode
all: $(progs)

View File

@@ -1,6 +1,8 @@
#include <algorithm>
#include <cstring>
#include "common.hh"
#include "util.hh"
#include "IffFile.hh"
#include "MveDecoder.hh"
@@ -30,9 +32,9 @@ MveDecoder::MveDecoder(char const* base, size_t length)
(PC.getSize() != 12))
throw FormatException{"_PC_ chunk missing or wrong size"};
PCChunk const* PCc = reinterpret_cast<PCChunk const*>(PC.begin());
const uint32_t PC_PALTcount = readU32LE(PC.begin()+8);
#ifndef NDEBUG
printf("_PC_: %u PALTs\n", PCc->PALTcount);
printf("_PC_: %u PALTs\n", PC_PALTcount);
#endif
// Parse SOND chunk
@@ -41,8 +43,8 @@ MveDecoder::MveDecoder(char const* base, size_t length)
(SOND.getSize() != 4))
throw FormatException{"SOND chunk missing or wrong size"};
uint32_t const* SONDc = reinterpret_cast<uint32_t const*>(SOND.begin());
if (*SONDc != 3)
const uint32_t SONDc = readU32LE(SOND.begin());
if (SONDc != 3)
throw FormatException{"Unexpected SOND value"};
// Parse data
@@ -52,7 +54,7 @@ MveDecoder::MveDecoder(char const* base, size_t length)
for (;it != rootForm.childrenEnd();++it) {
if (it->getType() == "PALT") {
if (curPALT > PCc->PALTcount)
if (curPALT > PC_PALTcount)
throw FormatException{"Number of PALT chunks exceeds amount specified in _PC_"};
if (it->getSize() != 768)
throw FormatException{"Unexpected PALT size"};
@@ -62,11 +64,11 @@ MveDecoder::MveDecoder(char const* base, size_t length)
[](const char& in) -> uint8_t {return (in << 2) | ((in >> 6)&0x3);});
++curPALT;
} else if (it->getType() == "SHOT") {
uint32_t const* SHOTc = reinterpret_cast<uint32_t const*>(it->begin());
if (*SHOTc > PCc->PALTcount)
const uint32_t SHOTc = readU32LE(it->begin());
if (SHOTc > PC_PALTcount)
throw FormatException{"SHOT refers to PALT outside amount specified in _PC_"};
++curSHOT;
Shot shot{palts_.at(*SHOTc), {}, {}};
Shot shot{palts_.at(SHOTc), {}, {}};
shots_.push_back(shot);
} else if (it->getType() == "VGA ") {
if (curSHOT < 0)
@@ -239,7 +241,7 @@ std::vector<uint8_t> parsePixels_(char const* data, size_t len)
ret.push_back(*(data+pos++));
for (unsigned i = 0;i < replSize;++i)
ret.push_back(ret[replOfs+i]);
ret.push_back(ret.at(replOfs+i));
} else {
//printf("Code: Copy %.2hhx\n", b);
unsigned size = (b&0x1f)*4+4;
@@ -265,8 +267,8 @@ MveDecoder::Frame MveDecoder::parseVGA(IffFile::Object const& vga, Frame const*
throw FormatException{"VGA chunk smaller than VGA header"};
std::array<uint16_t, 4> segOfs;
memcpy(segOfs.data(), vga.begin(), 8);
for(unsigned i = 0;i < segOfs.size();++i) {
segOfs[i] = readU16LE(vga.begin()+i*2);
if (segOfs[i] >= vga.getSize())
throw FormatException{"Segment offset exceeds chunk"};
}

View File

@@ -1,94 +1,107 @@
#include <cstdio>
#include <cstdint>
#include <cstring>
#include "common.hh"
#include "util.hh"
#include "TreFile.hh"
struct TreHeader { // little endian
char magic[4]; // == "XTRE"
uint32_t unknown;
//uint32_t unknown;
uint32_t table1Ofs;
uint32_t table2Ofs;
uint32_t table3Ofs;
uint32_t dataOfs;
} __attribute__((__packed__));
};
struct Table1Entry { // little endian
uint32_t crc;
uint32_t table3Ptr;
} __attribute__((__packed__));
static const size_t headerSize = 24;
static const size_t table1EntrySize = 8;
static const size_t table3EntrySize = 8;
TreFile::TreFile(char const* base, size_t length)
: base_(base), length_(length)
{
if (length_ < sizeof(TreHeader))
if (length_ < 6*4)
throw FormatException{"Size < header size"};
TreHeader const* header = reinterpret_cast<TreHeader const*>(base);
TreHeader header;
memcpy(header.magic, base, 4);
if (memcmp(header->magic, "XTRE", 4) != 0)
if (memcmp(header.magic, "XTRE", 4) != 0)
throw FormatException{"Wrong magic, not a TRE?"};
if ((header->table1Ofs > length_) ||
(header->table2Ofs > length_) ||
(header->table3Ofs > length_) ||
(header->dataOfs > length_))
header.table1Ofs = readU32LE(base_+8);
header.table2Ofs = readU32LE(base_+12);
header.table3Ofs = readU32LE(base_+16);
header.dataOfs = readU32LE(base_+20);
if ((header.table1Ofs > length_) ||
(header.table2Ofs > length_) ||
(header.table3Ofs > length_) ||
(header.dataOfs > length_))
throw FormatException{"Table offset exceeds length"};
if ((header->table1Ofs > header->table2Ofs) ||
(header->table2Ofs > header->table3Ofs) ||
(header->table3Ofs > header->dataOfs))
if ((header.table1Ofs > header.table2Ofs) ||
(header.table2Ofs > header.table3Ofs) ||
(header.table3Ofs > header.dataOfs))
throw FormatException{"Table offsets not in ascending order"};
const size_t numTable1Entries = (header->table2Ofs-header->table1Ofs)/sizeof(Table1Entry);
table3Size_ = (header->dataOfs-header->table3Ofs)/sizeof(Table3Entry);
const size_t numTable1Entries = (header.table2Ofs-header.table1Ofs)/table1EntrySize;
const size_t numTable3Entries = (header.dataOfs-header.table3Ofs)/table3EntrySize;
#ifndef NDEBUG
printf("Table 1: start %u, length %u (%lu entries)\n",
header->table1Ofs, header->table2Ofs-header->table1Ofs,
header.table1Ofs, header.table2Ofs-header.table1Ofs,
numTable1Entries);
printf("Table 2: start %u, length %u\n",
header->table2Ofs, header->table3Ofs-header->table2Ofs);
header.table2Ofs, header.table3Ofs-header.table2Ofs);
printf("Table 3: start %u, length %u (%lu entries)\n",
header->table3Ofs, header->dataOfs-header->table3Ofs,
table3Size_);
header.table3Ofs, header.dataOfs-header.table3Ofs,
numTable3Entries);
printf("Data: start %u, length %lu\n",
header->dataOfs, length_ - header->dataOfs);
header.dataOfs, length_ - header.dataOfs);
#endif
// Check Table 3
table3_ = reinterpret_cast<Table3Entry const*>(base+header->table3Ofs);
for (size_t i = 0;i < table3Size_;++i) {
if ((table3_[i].dataPtr > length_) ||
(table3_[i].dataPtr < header->dataOfs))
// Read table 3
for (size_t i = 0;i < numTable3Entries;++i) {
char const* const entryBase = base_+header.table3Ofs+i*table3EntrySize;
const uint32_t dataPtr = readU32LE(entryBase);
const uint32_t length = readU24LE(entryBase+4);
const uint8_t flags = *(entryBase+7);
if ((dataPtr > length_) ||
(dataPtr < header.dataOfs))
throw FormatException{"Data pointer out of range"};
if ((table3_[i].dataPtr + table3_[i].length) > length_) {
fprintf(stderr, "Data length exceeds file length: %.8x %.8x\n", table3_[i].dataPtr, table3_[i].length);
if ((dataPtr + length) > length_) {
fprintf(stderr, "Data length exceeds file length: %.8x %.8x\n", dataPtr, length);
}
table3_.emplace_back(dataPtr, length, flags);
}
// Read Table 2
std::map<size_t, uint32_t> table2Pos;
size_t pos = header->table2Ofs;
while((pos+5) < header->table3Ofs) {
uint8_t const* nameLen = reinterpret_cast<uint8_t const*>(base+pos);
size_t pos = header.table2Ofs;
while((pos+5) < header.table3Ofs) {
uint8_t nameLen = *(base+pos);
if (pos+*nameLen+5 > header->table3Ofs)
throw FormatException{"Table 2 entry exceeds table "s + std::to_string(*nameLen)};
if (pos+nameLen+5 > header.table3Ofs)
throw FormatException{"Table 2 entry exceeds table " + std::to_string(nameLen)};
std::string nameStr(base+pos+1, *nameLen);
std::string nameStr(base+pos+1, nameLen);
uint32_t const* table3Ptr = reinterpret_cast<uint32_t const*>(base+pos+*nameLen+1);
const uint32_t table3Ptr = readU32LE(base+pos+nameLen+1);
if ((*table3Ptr < header->table3Ofs) ||
(*table3Ptr >= header->dataOfs)) {
if ((table3Ptr < header.table3Ofs) ||
(table3Ptr >= header.dataOfs)) {
throw FormatException{"Table3 pointer out of range"};
}
const size_t table3Index = (*table3Ptr - header->table3Ofs)/sizeof(Table3Entry);
const size_t table3Index = (table3Ptr - header.table3Ofs)/table3EntrySize;
auto ins = table2_.emplace(nameStr, table3Index);
if (!ins.second) {
@@ -99,29 +112,32 @@ TreFile::TreFile(char const* base, size_t length)
ins.first->second, table3Index);
}
// Store an position-indexed copy of Table2 to resolve Table1->Table2 ptr's
table2Pos.emplace(pos, *table3Ptr);
table2Pos.emplace(pos, table3Ptr);
pos += 1+*nameLen+4;
pos += 1+nameLen+4;
}
// Read Table 1
Table1Entry const* table1 = reinterpret_cast<Table1Entry const*>(base+header->table1Ofs);
for (size_t i = 0;i < numTable1Entries;++i) {
if ((table1[i].crc == 0x00000000) &&
(table1[i].table3Ptr == 0xffffffff))
char const* const entryBase = base+header.table1Ofs+i*table1EntrySize;
const uint32_t crc = readU32LE(entryBase);
uint32_t table3Ptr = readU32LE(entryBase+4);
if ((crc == 0x00000000) &&
(table3Ptr == 0xffffffff))
continue; // Unused entry
if ((table1[i].table3Ptr < header->table2Ofs) ||
(table1[i].table3Ptr >= header->dataOfs)) {
if ((table3Ptr < header.table2Ofs) ||
(table3Ptr >= header.dataOfs)) {
throw FormatException{"Table3 pointer out of range"};
}
uint32_t table3Ptr = table1[i].table3Ptr;
if (table3Ptr < header->table3Ofs) {
if (table3Ptr < header.table3Ofs) {
auto it = table2Pos.find(table3Ptr);
if (it == table2Pos.end()) {
fprintf(stderr, "Table1->Table2 pointer: Table 2 entry not found: crc %.8x ptr %.8x\n",
table1[i].crc, table3Ptr);
crc, table3Ptr);
continue;
}
printf("Table1->Table2 pointer resolved: Table 2 %.8x -> Table 3 %.8x\n",
@@ -129,13 +145,13 @@ TreFile::TreFile(char const* base, size_t length)
table3Ptr = it->second;
}
const size_t table3Index = (table3Ptr - header->table3Ofs)/sizeof(Table3Entry);
auto ins = table1_.emplace(static_cast<uint32_t>(table1[i].crc), table3Index);
const size_t table3Index = (table3Ptr - header.table3Ofs)/table3EntrySize;
auto ins = table1_.emplace(crc, table3Index);
if (!ins.second) {
if (ins.first->second == table3Index)
printf("Duplicate entry for CRC %.8x\n", table1[i].crc);
printf("Duplicate entry for CRC %.8x\n", crc);
else
printf("Collision for CRC %.8x: prev %lu, new %lu\n", table1[i].crc, ins.first->second, table3Index);
printf("Collision for CRC %.8x: prev %lu, new %lu\n", crc, ins.first->second, table3Index);
}
}
}
@@ -235,22 +251,22 @@ void TreFile::printStructure()
{
printf("Table 1: %lu entries\n", table1_.size());
printf("Table 2: %lu entries\n", table2_.size());
printf("Table 3: %lu entries\n", table3Size_);
printf("Table 3: %lu entries\n", table3_.size());
printf("Files by CRC:\n");
for(auto const& ent : table1_) {
printf("\t%.8x -> (ofs %.8x, len %.8x, flags %.2hhx)\n", ent.first,
table3_[ent.second].dataPtr,
table3_[ent.second].length,
table3_[ent.second].flags);
std::get<0>(table3_[ent.second]),
std::get<1>(table3_[ent.second]),
std::get<2>(table3_[ent.second]));
}
printf("Files by Name:\n");
for(auto const& ent : table2_) {
printf("\t%s -> (ofs %.8x, len %.8x, flags %.2hhx)\n", ent.first.c_str(),
table3_[ent.second].dataPtr,
table3_[ent.second].length,
table3_[ent.second].flags);
std::get<0>(table3_[ent.second]),
std::get<1>(table3_[ent.second]),
std::get<2>(table3_[ent.second]));
}
}
@@ -269,7 +285,7 @@ size_t TreFile::findCRC_(uint32_t crc) const
if (it == table1_.end()) {
char crcStr[9];
snprintf(crcStr, 9, "%.8X", crc);
throw Exception{"CRC "s + crcStr + " not found"s};
throw Exception{std::string("CRC ") + crcStr + " not found"};
}
return it->second;
@@ -277,35 +293,44 @@ size_t TreFile::findCRC_(uint32_t crc) const
void TreFile::dumpIdx_(std::string const& name, size_t table3Idx) const
{
if(table3_[table3Idx].flags&0x80)
uint32_t dataPtr, length;
uint8_t flags;
std::tie(dataPtr, length, flags) = table3_[table3Idx];
if(flags&0x80)
throw Exception{"Compressed TRE objects NYI"};
if ((dataPtr + length) > length_)
throw FormatException{"length exceeds file size"};
FILEUPtr outFile{fopen(name.c_str(), "wb")};
if (!outFile)
throw POSIXException{errno, "Could not open " + name};
if (fwrite(base_+table3_[table3Idx].dataPtr, table3_[table3Idx].length, 1, outFile.get()) != 1)
if (fwrite(base_+dataPtr, length, 1, outFile.get()) != 1)
throw POSIXException{errno, "Could not write"};
}
TreFile::Object TreFile::openIdx_(size_t table3Idx) const
{
if(table3_[table3Idx].flags&0x80)
uint32_t dataPtr, length;
uint8_t flags;
std::tie(dataPtr, length, flags) = table3_[table3Idx];
if(flags&0x80)
throw Exception{"Compressed TRE objects NYI"};
if ((table3_[table3Idx].dataPtr + table3_[table3Idx].length) > length_)
if ((dataPtr + length) > length_)
throw FormatException{"length exceeds file size"};
return Object(base_+table3_[table3Idx].dataPtr,
table3_[table3Idx].length);
return Object(base_+dataPtr,
length);
}
TreFile::Stat TreFile::statIdx_(size_t table3Idx) const
{
Stat ret;
ret.size = table3_[table3Idx].length;
ret.flags = table3_[table3Idx].flags;
std::tie(std::ignore, ret.size, ret.flags) = table3_[table3Idx];
return ret;
}

View File

@@ -89,15 +89,7 @@ private:
std::map<uint32_t, size_t> table1_;
std::map<std::string, size_t> table2_;
struct Table3Entry { // little endian
unsigned dataPtr:32;
unsigned length:24;
unsigned flags:8;
} __attribute__((__packed__));
Table3Entry const* table3_;
size_t table3Size_;
std::vector<std::tuple<uint32_t, uint32_t, uint8_t> > table3_;
char const* base_;
size_t length_;

View File

@@ -1,56 +1,9 @@
#ifndef WC3RE__COMMON_HH__
#define WC3RE__COMMON_HH__
#include <string>
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <memory>
using namespace std::string_literals;
class Exception {
public:
Exception() : msg_() {
}
Exception(std::string msg) : msg_(std::move(msg)) {
}
virtual ~Exception() {}
virtual std::string toString() const {
return "Exception: "s + msg_;
}
protected:
std::string msg_;
};
class FormatException : public Exception {
public:
FormatException(std::string msg) : Exception(std::move(msg)) {
}
std::string toString() const override {
return "FormatException: "s + msg_;
}
};
class POSIXException : public Exception {
public:
POSIXException(int err, std::string msg = ""): Exception(std::move(msg)), err_(err) {
}
int getErr() const {return err_;}
std::string toString() const override {
return "POSIXException: "s + msg_ + ": "s + std::strerror(err_);
}
private:
int err_;
};
struct FILEDeleter {
void operator()(FILE* file) const {
fclose(file);
@@ -59,4 +12,6 @@ struct FILEDeleter {
using FILEUPtr = std::unique_ptr<FILE, FILEDeleter>;
#include "exceptions.hh"
#endif

47
exceptions.cc Normal file
View File

@@ -0,0 +1,47 @@
#include <cstring>
#include <cerrno>
#include "exceptions.hh"
using namespace std::string_literals;
Exception::Exception(std::string msg)
: msg_(std::move(msg))
{
}
Exception::~Exception()
{
}
std::string Exception::toString() const
{
return "Exception: " + msg_;
}
FormatException::FormatException(std::string msg)
: Exception(std::move(msg))
{
}
std::string FormatException::toString() const
{
return "FormatException: " + msg_;
}
POSIXException::POSIXException(int err, std::string msg)
: Exception(std::move(msg)), err_(err)
{
}
int POSIXException::getErr() const
{
return err_;
}
std::string POSIXException::toString() const
{
return "POSIXException: " + msg_ + ": " + std::strerror(err_);
}

36
exceptions.hh Normal file
View File

@@ -0,0 +1,36 @@
#ifndef WC3RE_EXCEPTIONS_HH__
#define WC3RE_EXCEPTIONS_HH__
#include <string>
class Exception {
public:
Exception(std::string msg = "");
virtual ~Exception();
virtual std::string toString() const;
protected:
std::string msg_;
};
class FormatException : public Exception {
public:
FormatException(std::string msg);
std::string toString() const override;
};
class POSIXException : public Exception {
public:
POSIXException(int err, std::string msg = "");
int getErr() const;
std::string toString() const override;
private:
int err_;
};
#endif

View File

@@ -111,7 +111,7 @@ void saveImage(std::string const& name, Image const& img)
{
FILEUPtr file{fopen(name.c_str(), "wb")};
if (!file)
throw POSIXException{errno, "Could not open "s + name};
throw POSIXException{errno, "Could not open " + name};
png_image pngImage;
pngImage.version = PNG_IMAGE_VERSION;
@@ -126,7 +126,7 @@ void saveImage(std::string const& name, Image const& img)
if (!png_image_write_to_stdio(&pngImage, file.get(), false, img.data.data(),
img.width, nullptr))
throw Exception{"PNG write failed: "s + pngImage.message};
throw Exception{"PNG write failed: " + pngImage.message};
}
Image makeFontImage(Font const& font)
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
try {
FILEUPtr fontFile{fopen(argv[1], "rb")};
if (!fontFile) {
throw POSIXException{errno, "Could not open "s + argv[1]};
throw POSIXException{errno, "Could not open "s+ argv[1]};
}
struct stat statBuf;
@@ -182,7 +182,7 @@ int main(int argc, char *argv[])
}
auto font = parseFont(fontFile.get(), statBuf.st_size);
saveImage(argv[1] + ".png"s, makeFontImage(font));
saveImage(argv[1] + ".png", makeFontImage(font));
} catch (POSIXException &ex) {
fprintf(stderr, "%s\n", ex.toString().c_str());

View File

@@ -38,7 +38,7 @@ void iffDumper(IffFile::Object const& obj, bool dumpBlobs, std::string dumpPath,
} catch(FormatException &ex) {
if (dumpBlobs) {
std::string filename{dumpPath};
filename += obj.getType() + "-"s + std::to_string(blobCount++);
filename += obj.getType() + "-" + std::to_string(blobCount++);
printf(" dump to %s\n", filename.c_str());
blobDump(obj, filename);
} else

117
util.cc
View File

@@ -1,5 +1,5 @@
#include <stdexcept>
#include <cstring>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -12,7 +12,7 @@ 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 "s + name_};
throw POSIXException{errno, "Could not open " + name_};
struct stat statBuf;
@@ -85,3 +85,116 @@ 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;
}

10
util.hh
View File

@@ -29,4 +29,14 @@ private:
void *base_;
};
// Helper functions to read big endian numbers
uint16_t readU16BE(char const* data);
uint32_t readU24BE(char const* data);
uint32_t readU32BE(char const* data);
// Helper functions to read little endian numbers
uint16_t readU16LE(char const* data);
uint32_t readU24LE(char const* data);
uint32_t readU32LE(char const* data);
#endif