diff --git a/QtPMbrowser/pmbrowserwindow.cpp b/QtPMbrowser/pmbrowserwindow.cpp index 843b68e..04f3fde 100644 --- a/QtPMbrowser/pmbrowserwindow.cpp +++ b/QtPMbrowser/pmbrowserwindow.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -306,10 +307,46 @@ void PMbrowserWindow::loadFile(QString filename) datfile->InitFromStream(infile); } catch (const std::exception& e) { - QMessageBox::warning(this, QString("File Error"), - QString("error while processing dat file:\n") + QString(e.what())); + //QMessageBox::warning(this, QString("File Error"), + // QString("error while processing dat file:\n") + QString(e.what())); + qDebug() << e.what(); datfile = nullptr; - infile.close(); + infile.seekg(0, std::ios_base::beg); + //infile.close(); + } + if (!datfile) { + try { + // we might habe an unbundled dat file + datfile = std::make_unique(); + std::filesystem::path path(QFile::encodeName(filename).constData()); + path.replace_extension(hkLib::ExtPul); + std::ifstream pulstream(path, std::ios_base::binary | std::ios_base::in); + if (!pulstream) { + throw std::runtime_error(std::string("could not open pul file, ") + ::strerror(errno)); + } + auto pullength = std::filesystem::file_size(path); + path.replace_extension(hkLib::ExtPgf); + std::ifstream pgfstream(path, std::ios_base::binary | std::ios_base::in); + if (!pgfstream) { + throw std::runtime_error(std::string("could not open pgf file, ") + ::strerror(errno)); + } + auto pgflength = std::filesystem::file_size(path); + path.replace_extension(hkLib::ExtAmp); + std::ifstream ampstream(path, std::ios_base::binary | std::ios_base::in); + if (!ampstream) { + datfile->InitFromStream(infile, pulstream, pullength, pgfstream, pgflength, nullptr, 0); + } + else { + datfile->InitFromStream(infile, pulstream, pullength, pgfstream, pgflength, &stream, std::filesystem::file_size(path)); + } + } + catch (const std::exception& e) { + qDebug() << e.what(); + QMessageBox::warning(this, QString("File Error"), + QString("error while processing unbundled dat file:\n") + QString(e.what())); + datfile = nullptr; + infile.close(); + } } if(datfile) { populateTreeView(); diff --git a/hekatoolslib/DatFile.cpp b/hekatoolslib/DatFile.cpp index ece092a..f389f78 100644 --- a/hekatoolslib/DatFile.cpp +++ b/hekatoolslib/DatFile.cpp @@ -105,6 +105,41 @@ void DatFile::InitFromStream(std::istream& infile) if (!PgfTree.isValid())throw std::runtime_error("no valid Pgf in file"); } +void hkLib::DatFile::InitFromStream(std::istream& infile, std::istream& pulstream, std::uintmax_t pullength, std::istream& pgfstream, + std::uintmax_t pgflength, std::istream* ampstream, std::uintmax_t amplength) +{ + if (!infile) { + throw std::runtime_error("cannot access file"); + } + auto bh = std::make_unique(); + infile.read(reinterpret_cast(bh.get()), BundleHeaderSize); + if (!infile) { + throw std::runtime_error("cannot read file"); + } + + bool has_header = std::memcmp(bh->Signature, BundleSignatureInvalid, 8) == 0; + // Note: if it has a valid signature, it should not be handeled by this function + if (has_header) { + Version = bh->Version; + Time = bh->Time; + isSwapped = bool(bh->IsLittleEndian) != MachineIsLittleEndian(); + if (isSwapped) { + swapInPlace(Time); + } + } + if(!PulTree.InitFromStream(ExtPul, pulstream, 0, static_cast(pullength))){ + throw std::runtime_error("error processing pulse tree"); + } + if (!PgfTree.InitFromStream(ExtPgf, pgfstream, 0, static_cast(pgflength))) { + throw std::runtime_error("error processing pgf tree"); + } + if (ampstream && amplength) { + if (!AmpTree.InitFromStream(ExtAmp, *ampstream, 0, static_cast(amplength))) { + throw std::runtime_error("error processing amp tree"); + } + } +} + std::string DatFile::getFileDate() const { #ifndef NDEBUG diff --git a/hekatoolslib/DatFile.h b/hekatoolslib/DatFile.h index e987990..62c34cd 100644 --- a/hekatoolslib/DatFile.h +++ b/hekatoolslib/DatFile.h @@ -78,7 +78,24 @@ namespace hkLib { PgfTree{}, AmpTree{} {}; DatFile(const DatFile&) = delete; DatFile operator=(const DatFile&) = delete; - void InitFromStream(std::istream& istream); + /// + /// initialize from bundle file stream, reads header and tree data, but not raw data + /// + /// input stream of the bundle file + void InitFromStream(std::istream& infile); + /// + /// initialized from unbundles dat file, requires separate streams for each tree, and their lengths + /// + /// dat file stream + /// pul file stream + /// length of pul file + /// pgf file stream + /// length of pgf file + /// pointer to optional amp file stream, can be nullptr + /// + void InitFromStream(std::istream& infile, std::istream& pulstream, std::uintmax_t pullength, + std::istream& pgfstream, std::uintmax_t pgflength, + std::istream* ampstream, std::uintmax_t amplength); std::string getFileDate() const; // return formatted file creation date hkTree& GetPulTree() { return PulTree; }; hkTree& GetPgfTree() { return PgfTree; };