From 10ad8b7d72664d54a126b73fb9a3b40183951c22 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Wed, 21 Sep 2022 21:13:00 +0200 Subject: [PATCH] Experimental reader prototype Need optimization in further version --- include/RDI.h | 4 +++ src/DatEntry.cpp | 9 ++++-- src/DatEntry.h | 13 +++++++-- src/RDI.cpp | 44 +++++++++++++++++++++++++++++ src/RDat.cpp | 69 ++++++++++++++++++++++++++++++++++++++++------ src/RDat.h | 5 ++++ tools/RDIdebug.cpp | 41 +++++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 12 deletions(-) diff --git a/include/RDI.h b/include/RDI.h index 053a509..4746737 100644 --- a/include/RDI.h +++ b/include/RDI.h @@ -63,6 +63,10 @@ namespace RDI { RDI_EXTERN std::string getSectionName( unsigned char id ); RDI_EXTERN unsigned int getSectionOffset( unsigned char id ); + RDI_EXTERN unsigned int getDirectoryElementCount( std::string path ); + RDI_EXTERN std::vector getDirectoryElements( std::string path ); + RDI_EXTERN bool isElementDirectory( std::string path ); + /** * @brief Clean up global resources. */ diff --git a/src/DatEntry.cpp b/src/DatEntry.cpp index dbed5da..354c21a 100644 --- a/src/DatEntry.cpp +++ b/src/DatEntry.cpp @@ -29,13 +29,14 @@ FileEntry::~FileEntry() {} DirectoryEntry::DirectoryEntry( std::string name ) { this->name = name; this->fFlags.raw = 0; - this->fFlags.sectionRootDir = 1; + this->rootDir = true; vSubFiles = new std::vector; } DirectoryEntry::DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags ) { this->name = name; this->fFlags.raw = fFlags.raw; + this->rootDir = false; vSubFiles = new std::vector; } @@ -46,7 +47,11 @@ DirectoryEntry::DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags, DatEntr AddEntry(hFileEntry); } -DirectoryEntry::~DirectoryEntry() {} +DirectoryEntry::~DirectoryEntry() { + for ( DatEntry* e : *vSubFiles ) + delete e; + delete vSubFiles; +} /*std::string DirectoryEntry::toString() { diff --git a/src/DatEntry.h b/src/DatEntry.h index 61fb1c2..119ed75 100644 --- a/src/DatEntry.h +++ b/src/DatEntry.h @@ -20,12 +20,13 @@ namespace RDI { typedef union u_file_flags { struct { + // LSB unsigned short unknown0:1; unsigned short isFile:1; unsigned short unknown1:5; unsigned short isDirectory:1; - unsigned short unknown2:7; - unsigned short sectionRootDir:1; + unsigned short unknown2:8; + // MSB }; unsigned short raw; } DAT_FILE_FLAGS; @@ -36,14 +37,18 @@ class DatEntry { public: virtual ~DatEntry() = 0; virtual bool isDirectory() = 0; + virtual bool isRootDirectory() = 0; //virtual std::string toString() = 0; virtual unsigned int getSize() = 0; + std::string getName() { return name; }; + protected: std::string name; DAT_FILE_FLAGS fFlags; }; +inline DatEntry::~DatEntry() {} class FileEntry : public DatEntry { public: @@ -54,6 +59,7 @@ public: //std::string toString(); bool isDirectory() { return false; } + bool isRootDirectory() { return false; } unsigned int getSize() { return size; } private: @@ -71,12 +77,15 @@ public: void ClearLinkedFiles(); void AddEntry( DatEntry* hFileEntry ); + std::vector getFiles() { return *vSubFiles; } //std::string toString(); bool isDirectory() { return true; } + bool isRootDirectory() { return rootDir; } unsigned int getSize() { return vSubFiles->size(); } private: + bool rootDir; std::vector *vSubFiles; }; diff --git a/src/RDI.cpp b/src/RDI.cpp index f264461..93fe10a 100644 --- a/src/RDI.cpp +++ b/src/RDI.cpp @@ -13,9 +13,11 @@ #include #include +#include #include #include "config.h" #include "RDat.h" +#include "DatEntry.h" #include "RDI.h" @@ -36,6 +38,7 @@ void RDI::CreateRDatHandler( std::string roguePath ){ //return hRDat; } + unsigned char RDI::getSectionCount() { if (hRDat == nullptr) return 0; else return hRDat->getDataSectionCount(); @@ -51,6 +54,47 @@ unsigned int RDI::getSectionOffset( unsigned char id ) { else return hRDat->getDataSectionOffset(id); } + +unsigned int RDI::getDirectoryElementCount( std::string path ) { + DirectoryEntry* result = nullptr; + + if (path.empty()) return 0; + + result = dynamic_cast(hRDat->getElement(boost::filesystem::path(path))); + + if (result == nullptr) return 0; + else return result->getSize(); +} + +std::vector RDI::getDirectoryElements( std::string path ) { + DirectoryEntry* de = nullptr; + std::vector elementsNameArray; + elementsNameArray.clear(); + + if (!path.empty()) { + de = dynamic_cast(hRDat->getElement(boost::filesystem::path(path))); + + if (de != nullptr && de->isDirectory()) { + for (DatEntry* de2 : de->getFiles()) + elementsNameArray.push_back(de2->getName()); + } + } + + return elementsNameArray; +} + +bool RDI::isElementDirectory( std::string path ) { + DatEntry* result = nullptr; + + if (path.empty()) return false; + + result = hRDat->getElement(boost::filesystem::path(path)); + + if (result == nullptr) return false; + else return (result->isDirectory() || result->isRootDirectory()); +} + + void RDI::DestroyRDatHandler(){ if (hRDat) delete hRDat; } diff --git a/src/RDat.cpp b/src/RDat.cpp index c231aef..cda6c7b 100644 --- a/src/RDat.cpp +++ b/src/RDat.cpp @@ -50,6 +50,9 @@ RDat::RDat( string fPath ) { } RDat::~RDat() { + for ( DirectoryEntry* de : *pFTRoot ) + delete de; + delete pFTRoot; free(rDatPtr); delete pDatSection; } @@ -129,15 +132,16 @@ RDI_RESULT RDat::ProcessFilesTree() { MEMFILE pFileDescriptors = nullptr; // Create new root files tree. One per data section. - pFTRoot = new std::vector(cDatSection); + pFTRoot = new std::vector; + pFTRoot->clear(); for ( i = 0; i < cDatSection; i++ ) { curDir = new DirectoryEntry(pDatSection->at(i).name); pFTRoot->push_back(curDir); // Recalculate files descriptor offset for current section. pFileDescriptors = rDatPtr + pDatSection->at(i).offset + - ((T_DAT_SECTION*)rDatPtr + pDatSection->at(i).offset)->file_headers_offset; - curEntriesCount = (((T_DAT_SECTION*)rDatPtr + pDatSection->at(i).offset)->file_headers_size) / 32; + ((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_offset; + curEntriesCount = (((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_size) / 32; // Process arborescente in recursive method. ProcessDirectoryContents(curDir, pFileDescriptors, curEntriesCount, rDatPtr + pDatSection->at(i).offset); @@ -157,22 +161,24 @@ RDI_RESULT RDat::ProcessDirectoryContents( DirectoryEntry* pCurDir, MEMFILE pDes if ( count == 0) return RDI_ERROR_PROCESS; for ( i = 0; i < count; i++ ) { - curEntryFlags.raw = ((T_FILE_HEADER*)pDesc)->flags; + curEntryFlags.raw = ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->flags; tmpStr.clear(); - tmpStr.append(((T_FILE_HEADER*)pDesc)->name); + tmpStr.append(((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->name); // Test for file or directory if (!curEntryFlags.isDirectory) { - newFile = new FileEntry(tmpStr, curEntryFlags, ((T_FILE_HEADER*)pDesc)->datas_size, pSectionStart + ((T_FILE_HEADER*)pDesc)->datas_offset); + newFile = new FileEntry(tmpStr, curEntryFlags, + ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_size, + pSectionStart + ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_offset); pCurDir->AddEntry(newFile); } else { newDir = new DirectoryEntry(tmpStr, curEntryFlags); pCurDir->AddEntry(newDir); ProcessDirectoryContents(newDir, - pDesc + i * sizeof(T_FILE_HEADER), - (((T_FILE_HEADER*)pCurDir)->dir_entries_size - sizeof(T_FILE_HEADER)) / sizeof(T_FILE_HEADER), + pDesc + (i + 1) * sizeof(T_FILE_HEADER), + (((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->dir_entries_size - sizeof(T_FILE_HEADER)) / sizeof(T_FILE_HEADER), pSectionStart); } } @@ -180,4 +186,51 @@ RDI_RESULT RDat::ProcessDirectoryContents( DirectoryEntry* pCurDir, MEMFILE pDes return RDI_OK; } +DatEntry *RDat::getElement( boost::filesystem::path virtualDirPath ) { + bool skip = false; + boost::filesystem::path newPath; + + for ( DatEntry* de : *pFTRoot ) { + if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { + if (de->getName() == virtualDirPath.filename().string()) + return de; + } else { + if (de->getName() == virtualDirPath.begin()->string()) { + for (auto& sp : virtualDirPath) { + if (skip) + newPath.append(sp); + skip = true; + } + return SearchSectionForEntry(dynamic_cast(de), newPath); + } + } + } + + return nullptr; +} + +DatEntry *RDat::SearchSectionForEntry( DirectoryEntry *curDir, boost::filesystem::path virtualDirPath ) { + bool skip = false; + boost::filesystem::path newPath; + + for ( DatEntry* e : curDir->getFiles() ) { + if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { + if (e->getName() == virtualDirPath.filename().string()) + return e; + } else { + if (e->isDirectory() && (e->getName() == virtualDirPath.begin()->string())) { + for (auto& sp : virtualDirPath) { + if (skip) + newPath.append(sp); + skip = true; + } + //TODO: add safety when trying to access inside a file + return SearchSectionForEntry(dynamic_cast(e), newPath); + } + } + } + + return nullptr; +} + } diff --git a/src/RDat.h b/src/RDat.h index f15f894..1c1d476 100644 --- a/src/RDat.h +++ b/src/RDat.h @@ -39,6 +39,8 @@ public: std::string getDataSectionName( unsigned char id ); unsigned int getDataSectionOffset( unsigned char id ); + DatEntry *getElement( boost::filesystem::path virtualDirPath ); + private: std::string workingDir = "."; @@ -59,6 +61,9 @@ private: MEMFILE pSectionStart ); + /* Tree manipulation/parse methods */ + DatEntry *SearchSectionForEntry( DirectoryEntry *curDir, boost::filesystem::path virtualDirPath); + }; } /* namespace RDI */ diff --git a/tools/RDIdebug.cpp b/tools/RDIdebug.cpp index 03bfd25..61a7e30 100644 --- a/tools/RDIdebug.cpp +++ b/tools/RDIdebug.cpp @@ -8,11 +8,17 @@ */ #include +#include +#include #include +void PrintVirtualDirectoryContents( boost::filesystem::path, std::string ); + int main( int argc, char *argv[] ) { unsigned int i; + boost::filesystem::path pathBuilder; + std::string prefix; printf("Using RDI lib v%s\n\n", RDI::getLibVersion().c_str()); //cout << "Using RDI lib v" << RDI::getLibVersion() << endl << endl; @@ -28,7 +34,42 @@ int main( int argc, char *argv[] ) { printf(" -Section %d offset: 0x%X\n", i, RDI::getSectionOffset(i)); } + //prefix.append("\t"); + prefix.append(" "); + printf("\nSections files root:\n"); + for ( i = 0; i < RDI::getSectionCount(); i++ ) { + printf("%s:\n", RDI::getSectionName(i).c_str()); // Print root trees + + pathBuilder.clear(); + pathBuilder.concat(RDI::getSectionName(i)); + + PrintVirtualDirectoryContents(pathBuilder, prefix); + } + RDI::DestroyRDatHandler(); return 0; } + +void PrintVirtualDirectoryContents( boost::filesystem::path path, std::string outPrefix ) { + auto curDirElementsName = RDI::getDirectoryElements(path.string()); + auto newPath = boost::filesystem::path(path); + auto newOutPrefix = std::string(outPrefix); + + for ( std::string eName : curDirElementsName ) { + newPath.clear(); + newPath.concat(path); + newOutPrefix.clear(); + newOutPrefix.append(outPrefix); + + newPath.append(eName); + if (RDI::isElementDirectory(newPath.string())) { + printf("%s%s:\n", outPrefix.c_str(), eName.c_str()); + //newOutPrefix.append("\t"); + newOutPrefix.append(" "); + PrintVirtualDirectoryContents(newPath, newOutPrefix); + } else { + printf("%s%s\n", newOutPrefix.c_str(), eName.c_str()); + } + } +}