diff --git a/Makefile b/Makefile index 029d69e..dd040c8 100644 --- a/Makefile +++ b/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 diff --git a/TreFile.cc b/TreFile.cc index 9a5e68d..fb696b0 100644 --- a/TreFile.cc +++ b/TreFile.cc @@ -73,33 +73,68 @@ TreFile::~TreFile() } } +std::vector TreFile::getNames() const +{ + std::vector ret; + for (auto ent : table2_) { + ret.push_back(ent.first); + } + + return ret; +} + +std::vector TreFile::getCRCs() const +{ + std::vector 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 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; +} diff --git a/TreFile.hh b/TreFile.hh index 4a1ec3a..295a187 100644 --- a/TreFile.hh +++ b/TreFile.hh @@ -16,6 +16,9 @@ public: TreFile(TreFile const& copy) = delete; TreFile& operator=(TreFile const& copy) = delete; + + std::vector getNames() const; + std::vector 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 data_; + + File(std::vector 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 table1_; std::map table2_; std::vector > table3_; - FILE* file_; + mutable FILE* file_; off_t start_; size_t length_; }; diff --git a/treexplore.cc b/treexplore.cc index a05cbfc..cbf69ed 100644 --- a/treexplore.cc +++ b/treexplore.cc @@ -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 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; }