treexplore: Add nested IFF parsing
Use IffFile to add an option to treexplore to show the structure of contained IFF files
This commit is contained in:
2
Makefile
2
Makefile
@@ -5,7 +5,7 @@ LDOPTS=
|
||||
IFFEXPLORE_CXXSRCS=iffexplore.cc IffFile.cc
|
||||
IFFEXPLORE_OBJS=$(addprefix objs/,$(IFFEXPLORE_CXXSRCS:.cc=.o))
|
||||
|
||||
TREEXPLORE_CXXSRCS=treexplore.cc TreFile.cc
|
||||
TREEXPLORE_CXXSRCS=treexplore.cc TreFile.cc IffFile.cc
|
||||
TREEXPLORE_OBJS=$(addprefix objs/,$(TREEXPLORE_CXXSRCS:.cc=.o))
|
||||
|
||||
FONT2PNG_CXXSRCS=font2png.cc
|
||||
|
||||
102
TreFile.cc
102
TreFile.cc
@@ -73,33 +73,68 @@ TreFile::~TreFile()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> TreFile::getNames() const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
for (auto ent : table2_) {
|
||||
ret.push_back(ent.first);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> TreFile::getCRCs() const
|
||||
{
|
||||
std::vector<uint32_t> ret;
|
||||
for (auto ent : table1_) {
|
||||
ret.push_back(ent.first);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TreFile::File TreFile::openName(std::string const& name) const
|
||||
{
|
||||
return openIdx_(findName_(name));
|
||||
}
|
||||
|
||||
TreFile::File TreFile::openCRC(uint32_t crc) const
|
||||
{
|
||||
return openIdx_(findCRC_(crc));
|
||||
}
|
||||
|
||||
TreFile::Stat TreFile::statName(std::string const& name) const
|
||||
{
|
||||
return statIdx_(findName_(name));
|
||||
}
|
||||
|
||||
TreFile::Stat TreFile::statCRC(uint32_t crc) const
|
||||
{
|
||||
return statIdx_(findCRC_(crc));
|
||||
}
|
||||
|
||||
void TreFile::dumpName(std::string path, std::string const& name)
|
||||
{
|
||||
auto it = table2_.find(name);
|
||||
if (it == table2_.end())
|
||||
throw Exception{name + " not found"};
|
||||
auto idx = findName_(name);
|
||||
|
||||
if (path.back() != '/')
|
||||
path.push_back('/');
|
||||
path.append(name);
|
||||
|
||||
dumpIdx_(path, it->second);
|
||||
dumpIdx_(path, idx);
|
||||
}
|
||||
|
||||
void TreFile::dumpCRC(std::string path, uint32_t crc)
|
||||
{
|
||||
auto idx = findCRC_(crc);
|
||||
char crcStr[9];
|
||||
snprintf(crcStr, 9, "%.8X", crc);
|
||||
|
||||
auto it = table1_.find(crc);
|
||||
if (it == table1_.end())
|
||||
throw Exception{"CRC "s + crcStr + " not found"s};
|
||||
|
||||
if (path.back() != '/')
|
||||
path.push_back('/');
|
||||
path.append(crcStr);
|
||||
|
||||
dumpIdx_(path, it->second);
|
||||
dumpIdx_(path, idx);
|
||||
}
|
||||
|
||||
void TreFile::dumpAll(std::string path)
|
||||
@@ -302,6 +337,27 @@ void TreFile::construct_()
|
||||
}
|
||||
}
|
||||
|
||||
size_t TreFile::findName_(std::string const& name) const
|
||||
{
|
||||
auto it = table2_.find(name);
|
||||
if (it == table2_.end())
|
||||
throw Exception{name + " not found"};
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
size_t TreFile::findCRC_(uint32_t crc) const
|
||||
{
|
||||
auto it = table1_.find(crc);
|
||||
if (it == table1_.end()) {
|
||||
char crcStr[9];
|
||||
snprintf(crcStr, 9, "%.8X", crc);
|
||||
throw Exception{"CRC "s + crcStr + " not found"s};
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void TreFile::dumpIdx_(std::string const& name, size_t table3Idx)
|
||||
{
|
||||
uint32_t ofs, len;
|
||||
@@ -327,3 +383,31 @@ void TreFile::dumpIdx_(std::string const& name, size_t table3Idx)
|
||||
if (fwrite(buf.data(), len, 1, outFile.get()) != 1)
|
||||
throw POSIXException{errno, "Could not write"};
|
||||
}
|
||||
|
||||
TreFile::File TreFile::openIdx_(size_t table3Idx) const
|
||||
{
|
||||
uint32_t ofs, len;
|
||||
uint8_t flags;
|
||||
std::tie(ofs, len, flags) = table3_[table3Idx];
|
||||
|
||||
if(flags&0x80)
|
||||
throw Exception{"Compressed TRE objects NYI"};
|
||||
|
||||
std::vector<char> buf(len);
|
||||
|
||||
if (fseeko(file_, start_+ofs, SEEK_SET) != 0)
|
||||
throw POSIXException{errno, "Could not seek"};
|
||||
|
||||
if (fread(buf.data(), len, 1, file_) != 1)
|
||||
throw POSIXException{errno, "Could not read data"};
|
||||
|
||||
return File{buf};
|
||||
}
|
||||
|
||||
TreFile::Stat TreFile::statIdx_(size_t table3Idx) const
|
||||
{
|
||||
Stat ret;
|
||||
std::tie(std::ignore, ret.size, ret.flags) = table3_[table3Idx];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
41
TreFile.hh
41
TreFile.hh
@@ -16,6 +16,9 @@ public:
|
||||
|
||||
TreFile(TreFile const& copy) = delete;
|
||||
TreFile& operator=(TreFile const& copy) = delete;
|
||||
|
||||
std::vector<std::string> getNames() const;
|
||||
std::vector<uint32_t> getCRCs() const;
|
||||
|
||||
void dumpName(std::string path, std::string const& name);
|
||||
void dumpCRC(std::string path, uint32_t crc);
|
||||
@@ -23,15 +26,51 @@ public:
|
||||
|
||||
void printStructure();
|
||||
|
||||
class File {
|
||||
public:
|
||||
char const* data() const {
|
||||
return data_.data();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<char> data_;
|
||||
|
||||
File(std::vector<char> data)
|
||||
: data_(std::move(data)) {
|
||||
}
|
||||
|
||||
friend class TreFile;
|
||||
};
|
||||
|
||||
File openName(std::string const& name) const;
|
||||
File openCRC(uint32_t crc) const;
|
||||
|
||||
struct Stat {
|
||||
uint32_t size;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
Stat statName(std::string const& name) const;
|
||||
Stat statCRC(uint32_t crc) const;
|
||||
|
||||
private:
|
||||
void construct_();
|
||||
|
||||
size_t findName_(std::string const& name) const;
|
||||
size_t findCRC_(uint32_t crc) const;
|
||||
|
||||
void dumpIdx_(std::string const& name, size_t table3Idx);
|
||||
File openIdx_(size_t table3Idx) const;
|
||||
Stat statIdx_(size_t table3Idx) const;
|
||||
|
||||
std::map<uint32_t, size_t> table1_;
|
||||
std::map<std::string, size_t> table2_;
|
||||
std::vector<std::tuple<uint32_t, uint32_t, uint8_t> > table3_;
|
||||
FILE* file_;
|
||||
mutable FILE* file_;
|
||||
off_t start_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
@@ -12,23 +12,25 @@
|
||||
|
||||
#include "common.hh"
|
||||
#include "TreFile.hh"
|
||||
#include "IffFile.hh"
|
||||
|
||||
void usage(char *argv0) {
|
||||
fprintf(stderr, "Usage: %s [-sh] [-d dest] tre-file [filenames/crcs...]\n", argv0);
|
||||
fprintf(stderr, "\t-s\tPrint the tre-file's structure\n");
|
||||
fprintf(stderr, "\t-d dest\tDump files to dest/\n");
|
||||
fprintf(stderr, "\t\tif dilenames/crcs are supplied, dump those object, else dump all\n");
|
||||
fprintf(stderr, "\t-i\tAttempt to print iff-file's structures\n");
|
||||
fprintf(stderr, "\t-h\tPrint this help\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool printStructure = false, dumpFiles = false;
|
||||
bool printStructure = false, dumpFiles = false, dumpIff = false;
|
||||
std::string dumpPath, treFile;
|
||||
std::vector<std::string> fileSpecs;
|
||||
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "hsd:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hsd:i")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
@@ -36,6 +38,9 @@ int main(int argc, char *argv[]) {
|
||||
case 's':
|
||||
printStructure = true;
|
||||
break;
|
||||
case 'i':
|
||||
dumpIff = true;
|
||||
break;
|
||||
case 'd':
|
||||
dumpPath = optarg;
|
||||
dumpFiles = true;
|
||||
@@ -62,6 +67,36 @@ int main(int argc, char *argv[]) {
|
||||
if (printStructure)
|
||||
file.printStructure();
|
||||
|
||||
if (dumpIff) {
|
||||
for(auto name : file.getNames()) {
|
||||
auto s = file.statName(name);
|
||||
if (s.flags&0x80)
|
||||
continue;
|
||||
auto f = file.openName(name);
|
||||
try {
|
||||
IffFile iff{f.data(), f.size()};
|
||||
printf("%s:\n", name.c_str());
|
||||
iff.printStructure(1);
|
||||
} catch(FormatException &ex) {
|
||||
printf("%s: Not an IFF\n", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for(auto crc : file.getCRCs()) {
|
||||
auto s = file.statCRC(crc);
|
||||
if (s.flags&0x80)
|
||||
continue;
|
||||
auto f = file.openCRC(crc);
|
||||
try {
|
||||
IffFile iff{f.data(), f.size()};
|
||||
printf("%.8x:\n", crc);
|
||||
iff.printStructure(1);
|
||||
} catch(FormatException &ex) {
|
||||
printf("%.8x: Not an IFF\n", crc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpFiles) {
|
||||
if (fileSpecs.empty())
|
||||
file.dumpAll(dumpPath);
|
||||
@@ -83,7 +118,7 @@ int main(int argc, char *argv[]) {
|
||||
} catch (POSIXException &ex) {
|
||||
fprintf(stderr, "%s\n", ex.toString().c_str());
|
||||
return 2;
|
||||
} catch (FormatException &ex) {
|
||||
} catch (Exception &ex) {
|
||||
fprintf(stderr, "%s\n", ex.toString().c_str());
|
||||
return 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user