From c8d635c5de0c80d7e0518eb37981ad43a71124e2 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Sat, 25 Apr 2015 13:30:36 +0200 Subject: [PATCH] Seperate exceptions; Use proper endian-aware int parsing routines --- IffFile.cc | 20 +++--- Makefile | 8 +-- MveDecoder.cc | 22 ++++--- TreFile.cc | 171 +++++++++++++++++++++++++++++--------------------- TreFile.hh | 12 +--- common.hh | 49 +-------------- exceptions.cc | 47 ++++++++++++++ exceptions.hh | 36 +++++++++++ font2png.cc | 8 +-- iffexplore.cc | 2 +- util.cc | 117 +++++++++++++++++++++++++++++++++- util.hh | 10 +++ 12 files changed, 339 insertions(+), 163 deletions(-) create mode 100644 exceptions.cc create mode 100644 exceptions.hh diff --git a/IffFile.cc b/IffFile.cc index 21b5172..2943590 100644 --- a/IffFile.cc +++ b/IffFile.cc @@ -1,12 +1,13 @@ -#include +#include #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) @@ -51,18 +52,13 @@ void IffFile::printStructure(unsigned level) const std::unique_ptr IffFile::parseObject(char const* base, size_t length) -{ - // if (reinterpret_cast(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])) diff --git a/Makefile b/Makefile index 04bc257..d585f62 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/MveDecoder.cc b/MveDecoder.cc index 77638c7..ae0ae96 100644 --- a/MveDecoder.cc +++ b/MveDecoder.cc @@ -1,6 +1,8 @@ #include +#include #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(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(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(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 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 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"}; } diff --git a/TreFile.cc b/TreFile.cc index 9b27b11..6a1d0d7 100644 --- a/TreFile.cc +++ b/TreFile.cc @@ -1,94 +1,107 @@ #include #include +#include #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(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(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 table2Pos; - size_t pos = header->table2Ofs; - while((pos+5) < header->table3Ofs) { - uint8_t const* nameLen = reinterpret_cast(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(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(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(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; } diff --git a/TreFile.hh b/TreFile.hh index 9b2ee58..e1575e1 100644 --- a/TreFile.hh +++ b/TreFile.hh @@ -89,16 +89,8 @@ private: std::map table1_; std::map table2_; - - struct Table3Entry { // little endian - unsigned dataPtr:32; - unsigned length:24; - unsigned flags:8; - } __attribute__((__packed__)); - - Table3Entry const* table3_; - size_t table3Size_; - + std::vector > table3_; + char const* base_; size_t length_; }; diff --git a/common.hh b/common.hh index 3ca563f..26a58ba 100644 --- a/common.hh +++ b/common.hh @@ -1,56 +1,9 @@ #ifndef WC3RE__COMMON_HH__ #define WC3RE__COMMON_HH__ -#include -#include #include -#include #include -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; +#include "exceptions.hh" + #endif diff --git a/exceptions.cc b/exceptions.cc new file mode 100644 index 0000000..fc38969 --- /dev/null +++ b/exceptions.cc @@ -0,0 +1,47 @@ +#include +#include + +#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_); +} diff --git a/exceptions.hh b/exceptions.hh new file mode 100644 index 0000000..cfa02d4 --- /dev/null +++ b/exceptions.hh @@ -0,0 +1,36 @@ +#ifndef WC3RE_EXCEPTIONS_HH__ +#define WC3RE_EXCEPTIONS_HH__ + +#include + +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 diff --git a/font2png.cc b/font2png.cc index fc50d5c..492b4c2 100644 --- a/font2png.cc +++ b/font2png.cc @@ -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()); diff --git a/iffexplore.cc b/iffexplore.cc index 65b4e9c..ab2a9de 100644 --- a/iffexplore.cc +++ b/iffexplore.cc @@ -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 diff --git a/util.cc b/util.cc index b73c902..13cb0f3 100644 --- a/util.cc +++ b/util.cc @@ -1,5 +1,5 @@ #include - +#include #include #include #include @@ -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(*data)&0xff)<<8) | static_cast(*(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(*data)&0xff)<<16) | + ((static_cast(*(data+1))&0xff)<<8) | + static_cast(*(data+2)); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + memcpy(static_cast(&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(*data)&0xff)<<24) | + ((static_cast(*(data+1))&0xff)<<16) | + ((static_cast(*(data+2))&0xff)<<8) | + static_cast(*(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(*(data+1))&0xff)<<8) | static_cast(*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(*(data+2))&0xff)<<16) | + ((static_cast(*(data+1))&0xff)<<8) | + static_cast(*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(*(data+3))&0xff)<<24) | + ((static_cast(*(data+2))&0xff)<<16) | + ((static_cast(*(data+1))&0xff)<<8) | + static_cast(*data); +#else +#error Unknown endianess +#endif + + return ret; +} diff --git a/util.hh b/util.hh index 972b2d9..3421fa4 100644 --- a/util.hh +++ b/util.hh @@ -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