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

View File

@@ -2,19 +2,19 @@ CXX=g++
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++14 -flto CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++14 -flto
LDOPTS= LDOPTS=
iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc exceptions.cc
iffexplore_LIBS ::= 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 ::= treexplore_LIBS ::=
font2png_CXXSRCS ::= font2png.cc font2png_CXXSRCS ::= font2png.cc
font2png_LIBS ::= -lpng 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 ::= mvedecode_LIBS ::=
progs ::= iffexplore font2png treexplore mvedecode progs ::= iffexplore treexplore mvedecode
all: $(progs) all: $(progs)

View File

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

View File

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

View File

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

View File

@@ -1,56 +1,9 @@
#ifndef WC3RE__COMMON_HH__ #ifndef WC3RE__COMMON_HH__
#define WC3RE__COMMON_HH__ #define WC3RE__COMMON_HH__
#include <string>
#include <cstring>
#include <cstdio> #include <cstdio>
#include <cerrno>
#include <memory> #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 { struct FILEDeleter {
void operator()(FILE* file) const { void operator()(FILE* file) const {
fclose(file); fclose(file);
@@ -59,4 +12,6 @@ struct FILEDeleter {
using FILEUPtr = std::unique_ptr<FILE, FILEDeleter>; using FILEUPtr = std::unique_ptr<FILE, FILEDeleter>;
#include "exceptions.hh"
#endif #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")}; FILEUPtr file{fopen(name.c_str(), "wb")};
if (!file) if (!file)
throw POSIXException{errno, "Could not open "s + name}; throw POSIXException{errno, "Could not open " + name};
png_image pngImage; png_image pngImage;
pngImage.version = PNG_IMAGE_VERSION; 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(), if (!png_image_write_to_stdio(&pngImage, file.get(), false, img.data.data(),
img.width, nullptr)) img.width, nullptr))
throw Exception{"PNG write failed: "s + pngImage.message}; throw Exception{"PNG write failed: " + pngImage.message};
} }
Image makeFontImage(Font const& font) Image makeFontImage(Font const& font)
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
try { try {
FILEUPtr fontFile{fopen(argv[1], "rb")}; FILEUPtr fontFile{fopen(argv[1], "rb")};
if (!fontFile) { if (!fontFile) {
throw POSIXException{errno, "Could not open "s + argv[1]}; throw POSIXException{errno, "Could not open "s+ argv[1]};
} }
struct stat statBuf; struct stat statBuf;
@@ -182,7 +182,7 @@ int main(int argc, char *argv[])
} }
auto font = parseFont(fontFile.get(), statBuf.st_size); auto font = parseFont(fontFile.get(), statBuf.st_size);
saveImage(argv[1] + ".png"s, makeFontImage(font)); saveImage(argv[1] + ".png", makeFontImage(font));
} catch (POSIXException &ex) { } catch (POSIXException &ex) {
fprintf(stderr, "%s\n", ex.toString().c_str()); 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) { } catch(FormatException &ex) {
if (dumpBlobs) { if (dumpBlobs) {
std::string filename{dumpPath}; 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()); printf(" dump to %s\n", filename.c_str());
blobDump(obj, filename); blobDump(obj, filename);
} else } else

117
util.cc
View File

@@ -1,5 +1,5 @@
#include <stdexcept> #include <stdexcept>
#include <cstring>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.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) : name_(std::move(fileName)), fd_(fopen(name_.c_str(), "rb")), size_(0), base_(nullptr)
{ {
if (!fd_) if (!fd_)
throw POSIXException{errno, "Could not open "s + name_}; throw POSIXException{errno, "Could not open " + name_};
struct stat statBuf; struct stat statBuf;
@@ -85,3 +85,116 @@ MmapFile::operator bool() const
{ {
return base_; 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_; 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 #endif