#include #include #include #include #include #include #include "common.hh" #include "util.hh" #include "IffFile.hh" void blobDump(IffFile::Object const& obj, std::string const& filename) { FILEUPtr file{fopen(filename.c_str(), "wb")}; if (!file) throw POSIXException{errno, "Could not open file: " + filename}; if (fwrite(obj.begin(), obj.getSize(), 1, file.get()) != 1) throw POSIXException{errno, "Could not write"}; } void iffDumper(IffFile::Object const& obj, bool dumpBlobs, std::string dumpPath, unsigned& blobCount, unsigned level = 0) { for (unsigned i = 0;i < level;++i) putchar('\t'); printf("%s Length %lu (0x%.lx)", obj.getType().c_str(), obj.getSize(), obj.getSize()); if (obj.isForm()) { auto& form = dynamic_cast(obj); printf(", Subtype %s\n", form.getSubtype().c_str()); for(auto it = form.childrenBegin();it != form.childrenEnd();++it) iffDumper(*it, dumpBlobs, dumpPath, blobCount, level+1); } else { try { printf(" = \"%s\"\n", static_cast(obj).c_str()); } catch(FormatException &ex) { if (dumpBlobs) { std::string filename{dumpPath}; filename += obj.getType() + "-" + std::to_string(blobCount++); printf(" dump to %s\n", filename.c_str()); blobDump(obj, filename); } else printf("\n"); } } } void usage(char *argv0) { fprintf(stderr, "Usage: %s [-sh] [-d dest] iff-file\n", argv0); fprintf(stderr, "\t-s\tPrint the iff-file's structure\n"); fprintf(stderr, "\t-d dest\tDump BLOBs as files to dest/\n"); fprintf(stderr, "\t-h\tPrint this help\n"); } int main(int argc, char *argv[]) { bool printStructure = false, dumpBlobs = false; std::string dumpPath, iffFile; { int opt; while ((opt = getopt(argc, argv, "hsd:")) != -1) { switch (opt) { case 'h': usage(argv[0]); return 0; case 's': printStructure = true; break; case 'd': dumpPath = optarg; dumpBlobs = true; break; default: usage(argv[0]); return 1; } } if (optind >= argc) { usage(argv[0]); return 1; } iffFile = argv[optind]; } try { MmapFile mmap{iffFile}; IffFile iff{mmap.data(), mmap.size()}; if (printStructure) { unsigned blobCount = 0, subdoc = 0; for (auto& root : iff) { printf("Subdocument %u:\n", subdoc++); iffDumper(root, dumpBlobs, dumpPath, blobCount); } } } catch (POSIXException &ex) { fflush(stdout); fprintf(stderr, "%s\n", ex.toString().c_str()); return 2; } catch (FormatException &ex) { fflush(stdout); fprintf(stderr, "%s\n", ex.toString().c_str()); return 3; } return 0; }