Seperate exceptions; Use proper endian-aware int parsing routines
This commit is contained in:
20
IffFile.cc
20
IffFile.cc
@@ -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)
|
||||
@@ -51,18 +52,13 @@ 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]))
|
||||
|
||||
8
Makefile
8
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)
|
||||
|
||||
|
||||
@@ -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"};
|
||||
}
|
||||
|
||||
171
TreFile.cc
171
TreFile.cc
@@ -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;
|
||||
}
|
||||
|
||||
12
TreFile.hh
12
TreFile.hh
@@ -89,16 +89,8 @@ 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_;
|
||||
};
|
||||
|
||||
49
common.hh
49
common.hh
@@ -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
47
exceptions.cc
Normal 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
36
exceptions.hh
Normal 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
|
||||
@@ -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());
|
||||
|
||||
@@ -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
117
util.cc
@@ -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
10
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
|
||||
|
||||
Reference in New Issue
Block a user