diff --git a/include/RDI.hpp b/include/RDI.hpp index b8e7c9d..28e02bd 100644 --- a/include/RDI.hpp +++ b/include/RDI.hpp @@ -70,6 +70,7 @@ namespace RDI { /* Krennic specific methods */ RDI_EXTERN std::vector RDI_getLevelsName( void ); RDI_EXTERN std::vector RDI_getModelsName( void ); + RDI_EXTERN std::vector RDI_getTexturesName( void ); RDI_EXTERN std::vector RDI_getMusicsName( void ); /** diff --git a/src/DatFileEntry.cpp b/src/DatFileEntry.cpp index 9018c17..e979532 100644 --- a/src/DatFileEntry.cpp +++ b/src/DatFileEntry.cpp @@ -19,33 +19,24 @@ using std::vector; namespace RDI { namespace DatFile { -DatFileEntryFile::DatFileEntryFile( string name, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ) { - this->name = name; - this->size = size; - this->fFlags.raw = fFlags.raw; - this->fileMemPtr = fPtr; -} +DatFileEntryFile::DatFileEntryFile( string name, string path, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ) + : DatFileEntry::DatFileEntry(name, path, fFlags), size(size), fileMemPtr(fPtr) {} DatFileEntryFile::~DatFileEntryFile() {} -DatFileEntryDirectory::DatFileEntryDirectory( string name ) { - this->name = name; - this->fFlags.raw = 0; - this->rootDir = true; +DatFileEntryDirectory::DatFileEntryDirectory( string name, string path ) + : DatFileEntry::DatFileEntry(name, path), rootDir(true) { vSubFiles = new vector; } -DatFileEntryDirectory::DatFileEntryDirectory( string name, DAT_FILE_FLAGS fFlags ) { - this->name = name; - this->fFlags.raw = fFlags.raw; - this->rootDir = false; +DatFileEntryDirectory::DatFileEntryDirectory( string name, string path, DAT_FILE_FLAGS fFlags ) + : DatFileEntry::DatFileEntry(name, path, fFlags), rootDir(false) { vSubFiles = new vector; } -DatFileEntryDirectory::DatFileEntryDirectory( string name, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry ) { - this->name = name; - this->fFlags.raw = fFlags.raw; +DatFileEntryDirectory::DatFileEntryDirectory( string name, string path, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry ) + : DatFileEntry::DatFileEntry(name, path, fFlags), rootDir(false) { vSubFiles = new vector; AddEntry(hFileEntry); } @@ -56,10 +47,6 @@ DatFileEntryDirectory::~DatFileEntryDirectory() { delete vSubFiles; } -/*std::string DirectoryEntry::toString() { - -}*/ - void DatFileEntryDirectory::ClearLinkedFiles() { vSubFiles->clear(); } diff --git a/src/DatFileEntry.hpp b/src/DatFileEntry.hpp index dad0775..f6f8447 100644 --- a/src/DatFileEntry.hpp +++ b/src/DatFileEntry.hpp @@ -44,13 +44,20 @@ public: virtual ~DatFileEntry() = 0; virtual bool isDirectory() = 0; virtual bool isRootDirectory() = 0; - //virtual std::string toString() = 0; virtual unsigned int getSize() = 0; - std::string getName() { return name; }; + std::string getName() { return name; } + std::string getPath() { return virtualAbsPath; } protected: + DatFileEntry( std::string name, std::string path ) : name(name), virtualAbsPath(path) { + this->fFlags.raw = 0; + } + DatFileEntry( std::string name, std::string path, DAT_FILE_FLAGS fFlags ) + : name(name), virtualAbsPath(path), fFlags(fFlags) {} + std::string name; + std::string virtualAbsPath; DAT_FILE_FLAGS fFlags; }; @@ -58,34 +65,32 @@ inline DatFileEntry::~DatFileEntry() {} class DatFileEntryFile : public DatFileEntry { public: - DatFileEntryFile( std::string name, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ); + DatFileEntryFile( std::string name, std::string path, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ); ~DatFileEntryFile(); MEMFILE getDatas() { return fileMemPtr; } - //std::string toString(); bool isDirectory() { return false; } bool isRootDirectory() { return false; } unsigned int getSize() { return size; } // In bytes private: - MEMFILE fileMemPtr; unsigned int size; + MEMFILE fileMemPtr; }; class DatFileEntryDirectory : public DatFileEntry { public: - DatFileEntryDirectory( std::string name ); - DatFileEntryDirectory( std::string name, DAT_FILE_FLAGS fFlags ); - DatFileEntryDirectory( std::string name, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry ); + DatFileEntryDirectory( std::string name, std::string path ); + DatFileEntryDirectory( std::string name, std::string path, DAT_FILE_FLAGS fFlags ); + DatFileEntryDirectory( std::string name, std::string path, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry ); ~DatFileEntryDirectory(); void ClearLinkedFiles(); void AddEntry( DatFileEntry* hFileEntry ); std::vector getFiles() { return *vSubFiles; } - //std::string toString(); bool isDirectory() { return true; } bool isRootDirectory() { return rootDir; } unsigned int getSize() { return vSubFiles->size(); } // In number of elements diff --git a/src/Erso.cpp b/src/Erso.cpp index 0c3c348..9b59ea3 100644 --- a/src/Erso.cpp +++ b/src/Erso.cpp @@ -164,7 +164,7 @@ RDI_RESULT Erso::CreateDataFilesTree() { pFTRoot = new std::vector; pFTRoot->clear(); for ( i = 0; i < cDatSection; i++ ) { - curDir = new DatFileEntryDirectory(pDatSection->at(i).name); + curDir = new DatFileEntryDirectory(pDatSection->at(i).name, pDatSection->at(i).name); pFTRoot->push_back(curDir); // Recalculate files descriptor offset for current section. @@ -207,12 +207,12 @@ RDI_RESULT Erso::ProcessTreeDirectoryContents( DatFileEntryDirectory* pCurDir, M // Test for file or directory if (!curEntryFlags.isDirectory) { - newFile = new DatFileEntryFile(tmpStr, curEntryFlags, + newFile = new DatFileEntryFile(tmpStr, pCurDir->getPath() + "/" + 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 DatFileEntryDirectory(tmpStr, curEntryFlags); + newDir = new DatFileEntryDirectory(tmpStr, pCurDir->getPath() + "/" + tmpStr, curEntryFlags); pCurDir->AddEntry(newDir); // Keep entries count in new directory to jump over after processing it. @@ -245,9 +245,9 @@ void Erso::DisposeFile() { * * @return Reference to the resource from specified input path */ -DatFileEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { +DatFileEntry *Erso::getElement( path virtualDirPath ) { bool skip = false; - boost::filesystem::path newPath; + path newPath; for ( DatFileEntry* de : *pFTRoot ) { if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { @@ -260,7 +260,7 @@ DatFileEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { newPath.append(sp); skip = true; } - return SearchSectionForEntry(dynamic_cast(de), newPath); + return SearchEntryPath(dynamic_cast(de), newPath); } } } @@ -268,6 +268,32 @@ DatFileEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { return nullptr; } +/** + * Get a list of files corresponding to the specified pattern. + * + * @param virtualDirPath Origin of browsing + * @param pattern Search filename pattern + * @param recursive Do the search inside subfolders + * + * @return List of references to the files corresponding to pattern + */ +vector Erso::getElements( path virtualDirPath, string pattern, bool recursive ) { + vector result; + DatFileEntryDirectory* curDir = dynamic_cast(getElement(virtualDirPath)); + + if (recursive) { + auto recursFileList = SearchEntriesPattern(curDir, pattern); + result.insert(result.end(), recursFileList.begin(), recursFileList.end()); + } else { + for ( DatFileEntry* e : curDir->getFiles() ) { + if (e->getName().find(pattern) != string::npos) //TODO: Replace using RegEx search + result.push_back(e); + } + } + + return result; +} + /** * Browse inside virtual path to the final object from specific root DatFileEntryDirectory. * @@ -276,9 +302,9 @@ DatFileEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { * * @return Reference to the file resource */ -DatFileEntry *Erso::SearchSectionForEntry( DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath ) { +DatFileEntry* Erso::SearchEntryPath( DatFileEntryDirectory* curDir, path virtualDirPath ) { bool skip = false; - boost::filesystem::path newPath; + path newPath; for ( DatFileEntry* e : curDir->getFiles() ) { if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { @@ -292,7 +318,7 @@ DatFileEntry *Erso::SearchSectionForEntry( DatFileEntryDirectory *curDir, boost: skip = true; } - return SearchSectionForEntry(dynamic_cast(e), newPath); + return SearchEntryPath(dynamic_cast(e), newPath); } } } @@ -300,4 +326,29 @@ DatFileEntry *Erso::SearchSectionForEntry( DatFileEntryDirectory *curDir, boost: return nullptr; } +/** + * Browse inside virtual path to find specific pattern and add it reference to the list in input. + * + * @param upDir Origin of browsing + * @param pattern Search filename pattern + * + * @return Vector list of DatFileEntry + */ +vector Erso::SearchEntriesPattern( DatFileEntryDirectory* upDir, string pattern ) { + vector subDatEntries; + + for ( DatFileEntry* e : upDir->getFiles() ) + if (e->getName().find(pattern) != string::npos) //TODO: Replace using RegEx search + subDatEntries.push_back(e); + + for ( DatFileEntry* e : upDir->getFiles() ) { + if (e->isDirectory()) { + auto recursFileList = SearchEntriesPattern(dynamic_cast(e), pattern); + subDatEntries.insert(subDatEntries.end(), recursFileList.begin(), recursFileList.end()); + } + } + + return subDatEntries; +} + } diff --git a/src/Erso.hpp b/src/Erso.hpp index 7c5ad21..b49943c 100644 --- a/src/Erso.hpp +++ b/src/Erso.hpp @@ -68,7 +68,8 @@ public: unsigned int getDataSectionOffset( unsigned char id ) const; /* Tree manipulation/parse methods */ - DatFile::DatFileEntry *getElement( boost::filesystem::path virtualDirPath ); + DatFile::DatFileEntry* getElement( boost::filesystem::path virtualDirPath ); + std::vector getElements( boost::filesystem::path virtualDirPath, std::string pattern, bool recursive ); private: std::string workingDir = "."; @@ -94,7 +95,8 @@ private: void DisposeFile(); /* Tree manipulation/parse methods */ - DatFile::DatFileEntry *SearchSectionForEntry( DatFile::DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath); + DatFile::DatFileEntry* SearchEntryPath( DatFile::DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath); + std::vector SearchEntriesPattern(DatFile::DatFileEntryDirectory *upDir, std::string pattern); }; diff --git a/src/Krennic.cpp b/src/Krennic.cpp index 2bd7a57..d5533ad 100644 --- a/src/Krennic.cpp +++ b/src/Krennic.cpp @@ -17,11 +17,28 @@ #include "Erso.hpp" #include "Krennic.hpp" +using std::string; +using std::vector; + using namespace RDI::DatFile; namespace RDI { +struct PathDescriptor { + PathDescriptor(string p, bool r) noexcept + : path(p), isRecursive(r) {} + + PathDescriptor(const PathDescriptor&) = default; + PathDescriptor& operator=(const PathDescriptor&) = default; + + PathDescriptor(PathDescriptor&&) = default; + PathDescriptor& operator=(PathDescriptor&&) = default; + + string path; + bool isRecursive; +}; + Krennic::Krennic( Erso* pErso ) { BuildLevelList(pErso); BuildModelList(pErso); @@ -34,61 +51,73 @@ Krennic::~Krennic() {} void Krennic::BuildLevelList( Erso* pErso ) { - const static std::string legacyLvlPath = "data/level"; - DatFileEntryDirectory* levelDir = nullptr; + const static vector legacyLvlPath = { + PathDescriptor("data/level", true) + }; listLevel.clear(); - levelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyLvlPath))); - if (levelDir != nullptr) { - for ( DatFileEntry* fl : levelDir->getFiles() ) { - if (fl->isDirectory()) { - if (pErso->getElement(boost::filesystem::path(legacyLvlPath).append(fl->getName()).append("dat")) != nullptr) { - listLevel.push_back(legacyLvlPath + "/" + fl->getName()); - } - } + for (PathDescriptor legacyLvlSubpath : legacyLvlPath) { + for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyLvlSubpath.path), "dat", legacyLvlSubpath.isRecursive)) { + //TODO: level-class builder + listLevel.push_back(file->getPath()); } } - - //TODO: LvlClass builder } void Krennic::BuildModelList( Erso* pErso ) { - const static std::vector legacyModelPath = { - "data/pl_crafts", "data/reb_stuff", "data/imp_stuff", - "data/gnrc_stuff", "data2" - }; - DatFileEntryDirectory* curModelDir = nullptr; + const static vector legacyModelPath = { + PathDescriptor("data", false), + PathDescriptor("data/pl_crafts", false), + PathDescriptor("data/reb_stuff", false), + PathDescriptor("data/imp_stuff", false), + PathDescriptor("data/gnrc_stuff", false), + PathDescriptor("data/level", true), + PathDescriptor("data/frontend", true), + PathDescriptor("data/dbg", false), + PathDescriptor("data2", false) + }; listModel.clear(); - for ( std::string path_it : legacyModelPath ) { - curModelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(path_it))); - if (curModelDir != nullptr) { - for ( DatFileEntry* fl : curModelDir->getFiles() ) { - if (fl->getName().find("_HOB") != std::string::npos) { - listModel.push_back(path_it + "/" + fl->getName()); - } - } + for (PathDescriptor legacyModelSubpath : legacyModelPath) { + for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath.path), "_HOB", legacyModelSubpath.isRecursive)) { + //TODO: model-class builder + listModel.push_back(file->getPath()); } } } void Krennic::BuildTextureList( Erso* pErso ) { + const static vector legacyTexturePath = { + PathDescriptor("data", false), + PathDescriptor("data/pl_crafts", false), + PathDescriptor("data/reb_stuff", false), + PathDescriptor("data/imp_stuff", false), + PathDescriptor("data/gnrc_stuff", false), + PathDescriptor("data/level", true), + PathDescriptor("data/frontend", true), + PathDescriptor("data/dbg", false), + PathDescriptor("data2", false) + }; + listTexture.clear(); + for (PathDescriptor legacyTextureSubpath : legacyTexturePath) { + for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyTextureSubpath.path), "_HMT", legacyTextureSubpath.isRecursive)) { + //TODO: texture-class builder + listTexture.push_back(file->getPath()); + } + } } void Krennic::BuildMusicList( Erso* pErso ) { - const static std::string legacyMusicPath = "data/sound"; - DatFileEntryDirectory* musicDir = nullptr; + const static vector legacyLvlPath = { + PathDescriptor("data/sound", false) + }; listMusic.clear(); - musicDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyMusicPath))); - if (musicDir != nullptr) { - for ( DatFileEntry* fl : musicDir->getFiles() ) { + for (PathDescriptor legacyMusicSubpath : legacyLvlPath) { + for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyMusicSubpath.path), "_SNG", legacyMusicSubpath.isRecursive)) { //TODO: MusyX-Class builder - - if (fl->getName().find("_SNG") != std::string::npos) { - listMusic.push_back(legacyMusicPath + "/" + fl->getName()); - } + listMusic.push_back(file->getPath()); } } } diff --git a/src/Krennic.hpp b/src/Krennic.hpp index ee74fb8..8b45d3d 100644 --- a/src/Krennic.hpp +++ b/src/Krennic.hpp @@ -46,11 +46,11 @@ public: * @return File type class handler. */ ///@{ - void* getLevel( std::string name ); - void* getModel( std::string name ); - HMT *getTexture( std::string name ); - void* getMusic( std::string name ); - void* getSample( std::string name ); + void* getLevel( std::string name ); + void* getModel( std::string name ); + HMT* getTexture( std::string name ); + void* getMusic( std::string name ); + void* getSample( std::string name ); ///@} /** diff --git a/src/RDI.cpp b/src/RDI.cpp index 984e23e..5940992 100644 --- a/src/RDI.cpp +++ b/src/RDI.cpp @@ -132,6 +132,10 @@ std::vector RDI::RDI_getModelsName( void ) { return KrennicModule->getModelsList(); } +std::vector RDI::RDI_getTexturesName( void ) { + return KrennicModule->getTexturesList(); +} + std::vector RDI::RDI_getMusicsName( void ) { return KrennicModule->getMusicsList(); } diff --git a/tools/RDIDebug.cpp b/tools/RDIDebug.cpp index b6bd02e..621c743 100644 --- a/tools/RDIDebug.cpp +++ b/tools/RDIDebug.cpp @@ -49,7 +49,7 @@ int main( int argc, char *argv[] ) { cout << "> Section found: " << RDI::RDI_getSectionCount() << endl; for ( i = 0; i < RDI::RDI_getSectionCount(); i++ ) { cout << " -Section " << i << " name: " << RDI::RDI_getSectionName(i) << endl; - cout << " -Section " << i << " offset: 0x" << hex << uppercase << RDI::RDI_getSectionOffset(i) << endl; + cout << " -Section " << i << " offset: 0x" << hex << uppercase << RDI::RDI_getSectionOffset(i) << dec << endl; } // Print DATA.DAT tree view with unicode "style" @@ -65,15 +65,19 @@ int main( int argc, char *argv[] ) { // Print game elements Krennic module found cout << endl << "Legacy files processing result:"; - cout << endl << "> Levels found:" << endl; + cout << endl << "> Levels found: " << RDI::RDI_getLevelsName().size() << endl; for ( std::string lname : RDI::RDI_getLevelsName() ) { cout << " " << lname << endl; } - cout << endl << "> Models found:" << endl; + cout << endl << "> Models found: " << RDI::RDI_getModelsName().size() << endl; for ( std::string mdname : RDI::RDI_getModelsName() ) { cout << " " << mdname << endl; } - cout << endl << "> Musics found:" << endl; + cout << endl << "> Textures found: " << RDI::RDI_getTexturesName().size() << endl; + for ( std::string txname : RDI::RDI_getTexturesName() ) { + cout << " " << txname << endl; + } + cout << endl << "> Musics found: " << RDI::RDI_getMusicsName().size() << endl; for ( std::string mname : RDI::RDI_getMusicsName() ) { cout << " " << mname << endl; }