From 2da49b53ae7e3beb073e38f23ce743708e743dcb Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Thu, 12 Jan 2023 20:23:45 +0100 Subject: [PATCH] Reforge library structure - 3rd pass Updated CMakeFile with MSVC options Review Erso lib interface Better tree display in RDIDebug tool Change lib interface functions naming Separate namespace for date file entries --- CMakeLists.txt | 13 ++- include/FileHandler/Generic.h | 6 +- include/FileHandler/HMT.h | 2 +- include/RDI.hpp | 24 +++--- src/DatFileEntry.cpp | 72 ++++++++++++++++ src/DatFileEntry.hpp | 101 ++++++++++++++++++++++ src/Erso.cpp | 154 ++++++++++++++++++++++++---------- src/Erso.hpp | 61 ++++++++++---- src/ErsoEntry.cpp | 68 --------------- src/ErsoEntry.hpp | 94 --------------------- src/Krennic.cpp | 20 +++-- src/KrennicHandlerGeneric.cpp | 7 +- src/KrennicHandlerHMT.cpp | 4 +- src/RDI.cpp | 94 +++++++++++++-------- tools/RDIDebug.cpp | 116 ++++++++++++++++--------- 15 files changed, 506 insertions(+), 330 deletions(-) create mode 100644 src/DatFileEntry.cpp create mode 100644 src/DatFileEntry.hpp delete mode 100644 src/ErsoEntry.cpp delete mode 100644 src/ErsoEntry.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d8497ae..4bf1e10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,13 @@ else() # Standalone project mode, should not be used for release. endif() #set(RDI_LIB_NAME RDI${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}) set(RDI_LIB_NAME RDI) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +if(NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++17 -static-libgcc -static-libstdc++") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall /std:c++17") +endif() set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") @@ -176,11 +181,11 @@ if(BUILD_TOOLS) endif() if(RDI_SHARED) - target_link_libraries(rdi-debug-tools PRIVATE rdi-lib) + target_link_libraries(rdi-debug-tools PRIVATE rdi-lib ${Boost_LIBRARIES}) target_link_libraries(erso-debug-tools PRIVATE rdi-lib) target_link_libraries(krennic-debug-tools PRIVATE rdi-lib) elseif(RDI_STATIC) - target_link_libraries(rdi-debug-tools PRIVATE rdi-libstatic) + target_link_libraries(rdi-debug-tools PRIVATE rdi-libstatic ${Boost_LIBRARIES}) target_link_libraries(erso-debug-tools PRIVATE rdi-libstatic) target_link_libraries(krennic-debug-tools PRIVATE rdi-libstatic) endif() diff --git a/include/FileHandler/Generic.h b/include/FileHandler/Generic.h index bd2f152..bb1b1b9 100644 --- a/include/FileHandler/Generic.h +++ b/include/FileHandler/Generic.h @@ -16,11 +16,13 @@ namespace RDI { -class ErsoEntryFile; +namespace DatFile { + class DatFileEntryFile; +} class GenericFile { public: - GenericFile( ErsoEntryFile& hDat ); + GenericFile( DatFile::DatFileEntryFile &hDat ); virtual ~GenericFile(); MEMFILE get() { return pMemLoc; } diff --git a/include/FileHandler/HMT.h b/include/FileHandler/HMT.h index cc0e59c..5c266a6 100644 --- a/include/FileHandler/HMT.h +++ b/include/FileHandler/HMT.h @@ -17,7 +17,7 @@ namespace RDI { class HMT : public GenericFile { public: - HMT( ErsoEntryFile& hDat ); + HMT( DatFile::DatFileEntryFile &hDat ); virtual ~HMT(); }; diff --git a/include/RDI.hpp b/include/RDI.hpp index 15d3a48..b8e7c9d 100644 --- a/include/RDI.hpp +++ b/include/RDI.hpp @@ -48,7 +48,7 @@ namespace RDI { * @brief Get the current library version. * @return String of the version. */ - RDI_EXTERN std::string getLibVersion( void ); + RDI_EXTERN std::string RDI_getLibVersion( void ); /** * @brief Allocate memory and create default structure to access datas. @@ -56,26 +56,26 @@ namespace RDI { * If file can be opened, it's mapped in memory and process files list. * @param[in] roguePath Path to DATA.DAT and DATA.HDR location. */ - RDI_EXTERN void Init( std::string roguePath ); + RDI_EXTERN void RDI_Init( std::string roguePath ); /* Erso specific methods */ - RDI_EXTERN unsigned char getSectionCount( void ); - RDI_EXTERN std::string getSectionName( unsigned char id ); - RDI_EXTERN unsigned int getSectionOffset( unsigned char id ); + RDI_EXTERN unsigned char RDI_getSectionCount( void ); + RDI_EXTERN std::string RDI_getSectionName( unsigned char id ); + RDI_EXTERN unsigned int RDI_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 ); + RDI_EXTERN unsigned int RDI_getDirectoryElementCount( std::string path ); + RDI_EXTERN std::vector RDI_getDirectoryElements( std::string path ); + RDI_EXTERN bool RDI_isElementDirectory( std::string path ); /* Krennic specific methods */ - RDI_EXTERN std::vector getLevelsName( void ); - RDI_EXTERN std::vector getModelsName( void ); - RDI_EXTERN std::vector getMusicsName( void ); + RDI_EXTERN std::vector RDI_getLevelsName( void ); + RDI_EXTERN std::vector RDI_getModelsName( void ); + RDI_EXTERN std::vector RDI_getMusicsName( void ); /** * @brief Clean up global resources. */ - RDI_EXTERN void CleanUp( void ); + RDI_EXTERN void RDI_CleanUp( void ); } #endif /* RDI_HPP_ */ diff --git a/src/DatFileEntry.cpp b/src/DatFileEntry.cpp new file mode 100644 index 0000000..9018c17 --- /dev/null +++ b/src/DatFileEntry.cpp @@ -0,0 +1,72 @@ +/** + * @file DatFileEntry.cpp + * @date 12/01/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief Data file entry descriptor objects helper class. + * + */ + +#include +#include +#include +#include "DatFileEntry.hpp" + +using std::string; +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() {} + + +DatFileEntryDirectory::DatFileEntryDirectory( string name ) { + this->name = name; + this->fFlags.raw = 0; + this->rootDir = true; + vSubFiles = new vector; +} + +DatFileEntryDirectory::DatFileEntryDirectory( string name, DAT_FILE_FLAGS fFlags ) { + this->name = name; + this->fFlags.raw = fFlags.raw; + this->rootDir = false; + vSubFiles = new vector; +} + +DatFileEntryDirectory::DatFileEntryDirectory( string name, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry ) { + this->name = name; + this->fFlags.raw = fFlags.raw; + vSubFiles = new vector; + AddEntry(hFileEntry); +} + +DatFileEntryDirectory::~DatFileEntryDirectory() { + for ( DatFileEntry* e : *vSubFiles ) + delete e; + delete vSubFiles; +} + +/*std::string DirectoryEntry::toString() { + +}*/ + +void DatFileEntryDirectory::ClearLinkedFiles() { + vSubFiles->clear(); +} + +void DatFileEntryDirectory::AddEntry( DatFileEntry* hFileEntry ) { + vSubFiles->push_back(hFileEntry); +} + +} +} diff --git a/src/DatFileEntry.hpp b/src/DatFileEntry.hpp new file mode 100644 index 0000000..dad0775 --- /dev/null +++ b/src/DatFileEntry.hpp @@ -0,0 +1,101 @@ +/** + * @file DatFileEntry.hpp + * @date 12/01/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief Data file entry descriptor objects helper class. + * + * DATA and BUNDLE file store in different location file's header and + * file's data. This helper class it's used to provide a more convenient + * access to the corresponding file inside memory (after Erso module's + * initialization). + * + */ + +#include +#include +#include + + +#ifndef ERSOENTRY_HPP_ +#define ERSOENTRY_HPP_ + + +namespace RDI { +namespace DatFile { + +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:8; + // MSB + }; + unsigned short raw; +} DAT_FILE_FLAGS; + + + +class DatFileEntry { +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; }; + +protected: + std::string name; + DAT_FILE_FLAGS fFlags; +}; + +inline DatFileEntry::~DatFileEntry() {} + +class DatFileEntryFile : public DatFileEntry { +public: + DatFileEntryFile( std::string name, 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; +}; + + +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(); + + 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 + +private: + bool rootDir; + std::vector *vSubFiles; +}; + +} +} + +#endif /* ERSOENTRY_HPP_ */ diff --git a/src/Erso.cpp b/src/Erso.cpp index dd53823..0c3c348 100644 --- a/src/Erso.cpp +++ b/src/Erso.cpp @@ -1,6 +1,6 @@ /** * @file Erso.cpp - * @date 24/09/2022 + * @date 11/01/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Rogue DATA/BUNDLE file parser and interface. @@ -14,9 +14,8 @@ #include #include #include "files_mms/data_struct.h" +#include "DatFileEntry.hpp" #include "Erso.hpp" -#include "ErsoEntry.hpp" - using std::string; using std::ios; @@ -24,45 +23,78 @@ using std::vector; using boost::filesystem::path; using boost::filesystem::file_size; +using namespace RDI::DatFile; + namespace RDI { -Erso::Erso( string fPath ) { +Erso::Erso( string fPath ) : workingDir(fPath) +{ + Process(); +} + +Erso::Erso( string fPath, RDI_RESULT* outResult ) : + workingDir(fPath) +{ + if (outResult) *outResult = Process(); + else Process(); +} + +Erso::~Erso() +{ + DisposeFile(); +} + + +string Erso::getDataSectionName( unsigned char id ) const { return pDatSection->at(id).name; } +unsigned int Erso::getDataSectionOffset( unsigned char id ) const { return pDatSection->at(id).offset; } + +/** + * Change the current working directory. + * This action will reconstruct files tree, all previous file entries became invalid. + * + * @param newPath New working directory path + * + * @return Error status. + */ +RDI_RESULT Erso::setWorkingDirectory( std::string newPath ) { RDI_RESULT errCode = RDI_OK; - this->workingDir = fPath; + DisposeFile(); + + this->workingDir = newPath; + Process(); + + return errCode; +} + + +/* ------------------------------------------------------------------------------------------------------------- */ +RDI_RESULT Erso::Process() { + RDI_RESULT errCode = RDI_OK; // Process header file and dump data file in memory. - errCode = DumpLegacyFiles(); + errCode = DataFilesDumping(); if (errCode == RDI_ERROR_FILESYSTEM) { std::cout << "Data files (DATA.DAT/DATA.HDR) not found! Interrupt." << std::endl; - return; + return errCode; } else if (errCode == RDI_ERROR_MEMORY) { std::cout << "Memory allocation or file access failed! Interrupt." << std::endl; - return; + return errCode; } // Process data file tree and filter file subtype into list. - ProcessFilesTree(); -} + CreateDataFilesTree(); -Erso::~Erso() { - for ( ErsoEntryDir* de : *pFTRoot ) - delete de; - delete pFTRoot; - free(rDatPtr); - delete pDatSection; + return errCode; } -string Erso::getDataSectionName( unsigned char id ) { return pDatSection->at(id).name; } -unsigned int Erso::getDataSectionOffset( unsigned char id ) { return pDatSection->at(id).offset; } - /** * Helper function to search for legacy DATA.DAT/HDR and dump it in memory. * * @return Error status. */ -RDI_RESULT Erso::DumpLegacyFiles() { +RDI_RESULT Erso::DataFilesDumping() { unsigned int i; path fp(workingDir); MEMFILE pTmpFile; @@ -75,7 +107,7 @@ RDI_RESULT Erso::DumpLegacyFiles() { // Open and parse data header file. //if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM; - pTmpFile = MallocFile(fp); + pTmpFile = CreateMemFile(fp); if (!pTmpFile) return RDI_ERROR_MEMORY; cDatSection = file_size(fp) / sizeof(T_HDR_ENTRY); @@ -91,7 +123,7 @@ RDI_RESULT Erso::DumpLegacyFiles() { // Dump data file and store it's pointer into class member. fp.replace_extension(".DAT"); //if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM; - rDatPtr = MallocFile(fp); + rDatPtr = CreateMemFile(fp); if (!rDatPtr) return RDI_ERROR_MEMORY; return RDI_OK; @@ -103,7 +135,7 @@ RDI_RESULT Erso::DumpLegacyFiles() { * * @return Start memory pointer of the file. */ -MEMFILE Erso::MallocFile( path filePath ) { +MEMFILE Erso::CreateMemFile( path filePath ) { const unsigned int size = file_size(filePath); std::fstream rdf; MEMFILE fPtr = NULL; @@ -123,16 +155,16 @@ MEMFILE Erso::MallocFile( path filePath ) { * * @return Error status. */ -RDI_RESULT Erso::ProcessFilesTree() { +RDI_RESULT Erso::CreateDataFilesTree() { unsigned int curEntriesCount = 0, i; - ErsoEntryDir* curDir = nullptr; + DatFileEntryDirectory* curDir = nullptr; MEMFILE pFileDescriptors = nullptr; // Create new root files tree. One per data section. - pFTRoot = new std::vector; + pFTRoot = new std::vector; pFTRoot->clear(); for ( i = 0; i < cDatSection; i++ ) { - curDir = new ErsoEntryDir(pDatSection->at(i).name); + curDir = new DatFileEntryDirectory(pDatSection->at(i).name); pFTRoot->push_back(curDir); // Recalculate files descriptor offset for current section. @@ -141,21 +173,31 @@ RDI_RESULT Erso::ProcessFilesTree() { 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); + ProcessTreeDirectoryContents(curDir, pFileDescriptors, curEntriesCount, rDatPtr + pDatSection->at(i).offset); } return RDI_OK; } -RDI_RESULT Erso::ProcessDirectoryContents( ErsoEntryDir* pCurDir, MEMFILE pDesc, const unsigned int count, MEMFILE pSectionStart ) { +/** + * Recursive function to process all sub-directory from a specific DatFileEntryDirectory root. + * + * @param pCurDir Root/current DatFileEntryDirectory from which the function begin to dig into + * @param pDesc MEMFILE pointer to the first entry of directory to be parsed + * @param count Number of elements in the pCurDir directory + * @param pSectionStart MEMFILE pointer to the beginning of parsed file + * + * @return Error status. + */ +RDI_RESULT Erso::ProcessTreeDirectoryContents( DatFileEntryDirectory* pCurDir, MEMFILE pDesc, const unsigned int count, MEMFILE pSectionStart ) { unsigned int i, newDRECnt; DAT_FILE_FLAGS curEntryFlags = {0}; - ErsoEntryFile* newFile = nullptr; - ErsoEntryDir* newDir = nullptr; + DatFileEntryFile* newFile = nullptr; + DatFileEntryDirectory* newDir = nullptr; std::string tmpStr; - if ( count == 0) return RDI_ERROR_PROCESS; + if ( count == 0 ) return RDI_ERROR_PROCESS; for ( i = 0; i < count; i++ ) { curEntryFlags.raw = ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->flags; @@ -165,17 +207,17 @@ RDI_RESULT Erso::ProcessDirectoryContents( ErsoEntryDir* pCurDir, MEMFILE pDesc, // Test for file or directory if (!curEntryFlags.isDirectory) { - newFile = new ErsoEntryFile(tmpStr, curEntryFlags, + newFile = new DatFileEntryFile(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 ErsoEntryDir(tmpStr, curEntryFlags); + newDir = new DatFileEntryDirectory(tmpStr, curEntryFlags); pCurDir->AddEntry(newDir); // Keep entries count in new directory to jump over after processing it. newDRECnt = (((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->dir_entries_size - sizeof(T_FILE_HEADER)) / sizeof(T_FILE_HEADER); - ProcessDirectoryContents(newDir, pDesc + (i + 1) * sizeof(T_FILE_HEADER), newDRECnt, pSectionStart); + ProcessTreeDirectoryContents(newDir, pDesc + (i + 1) * sizeof(T_FILE_HEADER), newDRECnt, pSectionStart); if (newDRECnt <= count) i += newDRECnt; } } @@ -183,11 +225,31 @@ RDI_RESULT Erso::ProcessDirectoryContents( ErsoEntryDir* pCurDir, MEMFILE pDesc, return RDI_OK; } -ErsoEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { +/** + * Free all allocated resources for files tree and MemFile + */ +void Erso::DisposeFile() { + for ( DatFileEntryDirectory* de : *pFTRoot ) + delete de; + delete pFTRoot; + free(rDatPtr); + delete pDatSection; +} + + +/* ------------------------------------------------------------------------------------------------------------- */ +/** + * Get DatFileEntry reference from virtual path + * + * @param virtualDirPath Path to the virtual resource + * + * @return Reference to the resource from specified input path + */ +DatFileEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { bool skip = false; boost::filesystem::path newPath; - for ( ErsoEntry* de : *pFTRoot ) { + for ( DatFileEntry* de : *pFTRoot ) { if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { if (de->getName() == virtualDirPath.filename().string()) return de; @@ -198,7 +260,7 @@ ErsoEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { newPath.append(sp); skip = true; } - return SearchSectionForEntry(dynamic_cast(de), newPath); + return SearchSectionForEntry(dynamic_cast(de), newPath); } } } @@ -206,11 +268,19 @@ ErsoEntry *Erso::getElement( boost::filesystem::path virtualDirPath ) { return nullptr; } -ErsoEntry *Erso::SearchSectionForEntry( ErsoEntryDir *curDir, boost::filesystem::path virtualDirPath ) { +/** + * Browse inside virtual path to the final object from specific root DatFileEntryDirectory. + * + * @param curDir Origin of browsing + * @param virtualDirPath Requested file path + * + * @return Reference to the file resource + */ +DatFileEntry *Erso::SearchSectionForEntry( DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath ) { bool skip = false; boost::filesystem::path newPath; - for ( ErsoEntry* e : curDir->getFiles() ) { + for ( DatFileEntry* e : curDir->getFiles() ) { if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) { if (e->getName() == virtualDirPath.filename().string()) return e; @@ -221,8 +291,8 @@ ErsoEntry *Erso::SearchSectionForEntry( ErsoEntryDir *curDir, boost::filesystem: newPath.append(sp); skip = true; } - //TODO: add safety when trying to access inside a file - return SearchSectionForEntry(dynamic_cast(e), newPath); + + return SearchSectionForEntry(dynamic_cast(e), newPath); } } } diff --git a/src/Erso.hpp b/src/Erso.hpp index d39f7cc..7c5ad21 100644 --- a/src/Erso.hpp +++ b/src/Erso.hpp @@ -1,16 +1,38 @@ /** * @file Erso.hpp - * @date 24/09/2022 + * @date 11/01/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Rogue DATA/BUNDLE file parser and interface. + * @warning This module should be initialized before every others modules call of RDI library. + * + * Erso is the first module of the RDI library, it's use research work of + * , dpethes and myself to parse legacy data files of Rogue + * game. + * Currently compatible legacy files are : + * - DATA.DAT/HDR: as primary elements package containing all levels, sound, + * textures, etc. + * - BUNDLE.000: as title menu resources like pictures, buttons and cursor + * textures, menu sounds, menu macro-scripting. + * - BUNDLE.001: not known for now. + * + * This module should be initialized before every others modules call of RDI + * library. + * + * Standard usage: + * - Create a single Erso object with the folder path of datas files as input + * argument. + * - All supported data files will be parsed and a virtual tree view will be + * created. + * - The virtual tree view can be browse using appropriate 'get' functions. * */ #include #include #include "RDI_Datatypes.h" -#include "ErsoEntry.hpp" + +#include "DatFileEntry.hpp" #ifndef ERSO_HPP_ @@ -31,20 +53,22 @@ struct dataSection { class Erso final { public: Erso( std::string fPath ); + Erso( std::string fPath, RDI_RESULT* outResult ); ~Erso(); - MEMFILE getRDat() { - return rDatPtr; - } + MEMFILE getRDat() const { return rDatPtr; } + /* Workspace management */ std::string getWorkingDirectory() { return workingDir; } - void setWorkingDirectory( std::string newPath ) { workingDir = newPath; } + RDI_RESULT setWorkingDirectory( std::string newPath ); - unsigned char getDataSectionCount() { return cDatSection; } - std::string getDataSectionName( unsigned char id ); - unsigned int getDataSectionOffset( unsigned char id ); + /* Generals informations getters */ + unsigned char getDataSectionCount() const { return cDatSection; } + std::string getDataSectionName( unsigned char id ) const; + unsigned int getDataSectionOffset( unsigned char id ) const; - ErsoEntry *getElement( boost::filesystem::path virtualDirPath ); + /* Tree manipulation/parse methods */ + DatFile::DatFileEntry *getElement( boost::filesystem::path virtualDirPath ); private: std::string workingDir = "."; @@ -53,21 +77,24 @@ private: std::vector *pDatSection = nullptr; MEMFILE rDatPtr = nullptr; - std::vector *pFTRoot = nullptr; + std::vector *pFTRoot = nullptr; + /* File processing methods */ - RDI_RESULT DumpLegacyFiles(); - MEMFILE MallocFile( boost::filesystem::path filePath ); - RDI_RESULT ProcessFilesTree(); - RDI_RESULT ProcessDirectoryContents( - ErsoEntryDir* pCurDir, + RDI_RESULT Process(); + RDI_RESULT DataFilesDumping(); + MEMFILE CreateMemFile( boost::filesystem::path filePath ); + RDI_RESULT CreateDataFilesTree(); + RDI_RESULT ProcessTreeDirectoryContents( + DatFile::DatFileEntryDirectory* pCurDir, MEMFILE pDesc, const unsigned int count, MEMFILE pSectionStart ); + void DisposeFile(); /* Tree manipulation/parse methods */ - ErsoEntry *SearchSectionForEntry( ErsoEntryDir *curDir, boost::filesystem::path virtualDirPath); + DatFile::DatFileEntry *SearchSectionForEntry( DatFile::DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath); }; diff --git a/src/ErsoEntry.cpp b/src/ErsoEntry.cpp deleted file mode 100644 index 52ff513..0000000 --- a/src/ErsoEntry.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file ErsoDatEntry.cpp - * @date 24/09/2022 - * @author JackCarterSmith - * @copyright GPL-v3.0 - * @brief Data file entry descriptor class. - * - */ - -#include "ErsoEntry.hpp" - - -namespace RDI { - -ErsoEntryFile::ErsoEntryFile( std::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; -} - -ErsoEntryFile::~ErsoEntryFile() {} - -/*std::string FileEntry::toString() { - -}*/ - - -ErsoEntryDir::ErsoEntryDir( std::string name ) { - this->name = name; - this->fFlags.raw = 0; - this->rootDir = true; - vSubFiles = new std::vector; -} - -ErsoEntryDir::ErsoEntryDir( std::string name, DAT_FILE_FLAGS fFlags ) { - this->name = name; - this->fFlags.raw = fFlags.raw; - this->rootDir = false; - vSubFiles = new std::vector; -} - -ErsoEntryDir::ErsoEntryDir( std::string name, DAT_FILE_FLAGS fFlags, ErsoEntry* hFileEntry ) { - this->name = name; - this->fFlags.raw = fFlags.raw; - vSubFiles = new std::vector; - AddEntry(hFileEntry); -} - -ErsoEntryDir::~ErsoEntryDir() { - for ( ErsoEntry* e : *vSubFiles ) - delete e; - delete vSubFiles; -} - -/*std::string DirectoryEntry::toString() { - -}*/ - -void ErsoEntryDir::ClearLinkedFiles() { - vSubFiles->clear(); -} - -void ErsoEntryDir::AddEntry( ErsoEntry* hFileEntry ) { - vSubFiles->push_back(hFileEntry); -} - -} diff --git a/src/ErsoEntry.hpp b/src/ErsoEntry.hpp deleted file mode 100644 index 5c6ac88..0000000 --- a/src/ErsoEntry.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @file ErsoEntry.hpp - * @date 24/09/2022 - * @author JackCarterSmith - * @copyright GPL-v3.0 - * @brief Data file entry descriptor class. - * - */ - -#include -#include -#include - - -#ifndef ERSOENTRY_HPP_ -#define ERSOENTRY_HPP_ - - -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:8; - // MSB - }; - unsigned short raw; -} DAT_FILE_FLAGS; - - - -class ErsoEntry { -public: - virtual ~ErsoEntry() = 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 ErsoEntry::~ErsoEntry() {} - -class ErsoEntryFile : public ErsoEntry { -public: - ErsoEntryFile( std::string name, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ); - ~ErsoEntryFile(); - - MEMFILE getDatas() { return fileMemPtr; } - - //std::string toString(); - bool isDirectory() { return false; } - bool isRootDirectory() { return false; } - unsigned int getSize() { return size; } - -private: - MEMFILE fileMemPtr; - unsigned int size; -}; - - -class ErsoEntryDir : public ErsoEntry { -public: - ErsoEntryDir( std::string name ); - ErsoEntryDir( std::string name, DAT_FILE_FLAGS fFlags ); - ErsoEntryDir( std::string name, DAT_FILE_FLAGS fFlags, ErsoEntry* hFileEntry ); - ~ErsoEntryDir(); - - void ClearLinkedFiles(); - void AddEntry( ErsoEntry* 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; -}; - -} - -#endif /* ERSODATENTRY_HPP_ */ diff --git a/src/Krennic.cpp b/src/Krennic.cpp index 5a447e2..2bd7a57 100644 --- a/src/Krennic.cpp +++ b/src/Krennic.cpp @@ -17,6 +17,8 @@ #include "Erso.hpp" #include "Krennic.hpp" +using namespace RDI::DatFile; + namespace RDI { @@ -33,12 +35,12 @@ Krennic::~Krennic() {} void Krennic::BuildLevelList( Erso* pErso ) { const static std::string legacyLvlPath = "data/level"; - ErsoEntryDir* levelDir = nullptr; + DatFileEntryDirectory* levelDir = nullptr; listLevel.clear(); - levelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyLvlPath))); + levelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyLvlPath))); if (levelDir != nullptr) { - for ( ErsoEntry* fl : levelDir->getFiles() ) { + 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()); @@ -55,13 +57,13 @@ void Krennic::BuildModelList( Erso* pErso ) { "data/pl_crafts", "data/reb_stuff", "data/imp_stuff", "data/gnrc_stuff", "data2" }; - ErsoEntryDir* curModelDir = nullptr; + DatFileEntryDirectory* curModelDir = nullptr; listModel.clear(); for ( std::string path_it : legacyModelPath ) { - curModelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(path_it))); + curModelDir = dynamic_cast(pErso->getElement(boost::filesystem::path(path_it))); if (curModelDir != nullptr) { - for ( ErsoEntry* fl : curModelDir->getFiles() ) { + for ( DatFileEntry* fl : curModelDir->getFiles() ) { if (fl->getName().find("_HOB") != std::string::npos) { listModel.push_back(path_it + "/" + fl->getName()); } @@ -76,12 +78,12 @@ void Krennic::BuildTextureList( Erso* pErso ) { void Krennic::BuildMusicList( Erso* pErso ) { const static std::string legacyMusicPath = "data/sound"; - ErsoEntryDir* musicDir = nullptr; + DatFileEntryDirectory* musicDir = nullptr; listMusic.clear(); - musicDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyMusicPath))); + musicDir = dynamic_cast(pErso->getElement(boost::filesystem::path(legacyMusicPath))); if (musicDir != nullptr) { - for ( ErsoEntry* fl : musicDir->getFiles() ) { + for ( DatFileEntry* fl : musicDir->getFiles() ) { //TODO: MusyX-Class builder if (fl->getName().find("_SNG") != std::string::npos) { diff --git a/src/KrennicHandlerGeneric.cpp b/src/KrennicHandlerGeneric.cpp index 54bf350..679bf3d 100644 --- a/src/KrennicHandlerGeneric.cpp +++ b/src/KrennicHandlerGeneric.cpp @@ -8,12 +8,15 @@ */ #include +#include "DatFileEntry.hpp" #include -#include "ErsoEntry.hpp" + +using namespace RDI::DatFile; + namespace RDI { -GenericFile::GenericFile( ErsoEntryFile& hDat ) { +GenericFile::GenericFile( DatFile::DatFileEntryFile &hDat ) { this->size = hDat.getSize(); this->fileName = hDat.getName(); this->fileExtension = ""; diff --git a/src/KrennicHandlerHMT.cpp b/src/KrennicHandlerHMT.cpp index 66baf43..95c82d7 100644 --- a/src/KrennicHandlerHMT.cpp +++ b/src/KrennicHandlerHMT.cpp @@ -10,10 +10,12 @@ #include #include +using namespace RDI::DatFile; + namespace RDI { -HMT::HMT( ErsoEntryFile& hDat ): GenericFile( hDat ) { +HMT::HMT( DatFile::DatFileEntryFile &hDat ): GenericFile( hDat ) { this->fileExtension = "hmt"; } diff --git a/src/RDI.cpp b/src/RDI.cpp index b4a4a7d..984e23e 100644 --- a/src/RDI.cpp +++ b/src/RDI.cpp @@ -17,29 +17,49 @@ #include #include "config.h" #include "Erso.hpp" -#include "ErsoEntry.hpp" +#include "DatFileEntry.hpp" #include "Krennic.hpp" #include "RDI.hpp" +using namespace RDI::DatFile; + /* * Internal modules instance */ -static RDI::Erso *hErsoModule = nullptr; -static RDI::Krennic *hKrennicModule = nullptr; +static RDI::Erso *ErsoModule = nullptr; +static RDI::Krennic *KrennicModule = nullptr; /* * Libs interface */ -std::string RDI::getLibVersion() { return PRG_VERSION; } +std::string RDI::RDI_getLibVersion() { return PRG_VERSION; } -void RDI::Init( std::string roguePath ){ - if (hErsoModule == nullptr) { - hErsoModule = new RDI::Erso(roguePath); +void RDI::RDI_Init( std::string roguePath ) { +#ifdef DEBUG + std::cout << std::endl << "Running RDI v" << RDI_getLibVersion() << std::endl; + std::cout << "> RSPModelLib v" << "N/A" << std::endl; + std::cout << "> RSPTerrainLib v" << "N/A" << std::endl; + std::cout << "> RSPTextureLib v" << "N/A" << std::endl; +#endif + + // Create new instance of Erso module + // Load and extract datas files from DATA.DAT + if (ErsoModule == nullptr) { +#ifdef DEBUG + std::cout << "[RDI][DBG] Loading Erso module..." << std::endl; +#endif + ErsoModule = new RDI::Erso(roguePath); } - if (hErsoModule != nullptr && hKrennicModule == nullptr) { - hKrennicModule = new RDI::Krennic(hErsoModule); + + // Create new instance of Krennic module + // Process datas from Erso and build new dataset to be used outside this library + if (ErsoModule != nullptr && KrennicModule == nullptr) { +#ifdef DEBUG + std::cout << "[RDI][DBG] Loading Krennic module..." << std::endl; +#endif + KrennicModule = new RDI::Krennic(ErsoModule); } } @@ -48,43 +68,43 @@ void RDI::Init( std::string roguePath ){ -unsigned char RDI::getSectionCount() { - if (hErsoModule == nullptr) return 0; - else return hErsoModule->getDataSectionCount(); +unsigned char RDI::RDI_getSectionCount() { + if (ErsoModule == nullptr) return 0; + else return ErsoModule->getDataSectionCount(); } -std::string RDI::getSectionName( unsigned char id ) { - if (hErsoModule == nullptr) return ""; - else return hErsoModule->getDataSectionName(id); +std::string RDI::RDI_getSectionName( unsigned char id ) { + if (ErsoModule == nullptr) return ""; + else return ErsoModule->getDataSectionName(id); } -unsigned int RDI::getSectionOffset( unsigned char id ) { - if (hErsoModule == nullptr) return 0; - else return hErsoModule->getDataSectionOffset(id); +unsigned int RDI::RDI_getSectionOffset( unsigned char id ) { + if (ErsoModule == nullptr) return 0; + else return ErsoModule->getDataSectionOffset(id); } -unsigned int RDI::getDirectoryElementCount( std::string path ) { - ErsoEntryDir* result = nullptr; +unsigned int RDI::RDI_getDirectoryElementCount( std::string path ) { + DatFileEntryDirectory* result = nullptr; if (path.empty()) return 0; - result = dynamic_cast(hErsoModule->getElement(boost::filesystem::path(path))); + result = dynamic_cast(ErsoModule->getElement(boost::filesystem::path(path))); if (result == nullptr) return 0; else return result->getSize(); } -std::vector RDI::getDirectoryElements( std::string path ) { - ErsoEntryDir* de = nullptr; +std::vector RDI::RDI_getDirectoryElements( std::string path ) { + DatFileEntryDirectory* de = nullptr; std::vector elementsNameArray; elementsNameArray.clear(); if (!path.empty()) { - de = dynamic_cast(hErsoModule->getElement(boost::filesystem::path(path))); + de = dynamic_cast(ErsoModule->getElement(boost::filesystem::path(path))); if (de != nullptr && de->isDirectory()) { - for (ErsoEntry* de2 : de->getFiles()) + for (DatFileEntry* de2 : de->getFiles()) elementsNameArray.push_back(de2->getName()); } } @@ -92,31 +112,31 @@ std::vector RDI::getDirectoryElements( std::string path ) { return elementsNameArray; } -bool RDI::isElementDirectory( std::string path ) { - ErsoEntry* result = nullptr; +bool RDI::RDI_isElementDirectory( std::string path ) { + DatFileEntry* result = nullptr; if (path.empty()) return false; - result = hErsoModule->getElement(boost::filesystem::path(path)); + result = ErsoModule->getElement(boost::filesystem::path(path)); if (result == nullptr) return false; else return (result->isDirectory() || result->isRootDirectory()); } -std::vector RDI::getLevelsName( void ) { - return hKrennicModule->getLevelsList(); +std::vector RDI::RDI_getLevelsName( void ) { + return KrennicModule->getLevelsList(); } -std::vector RDI::getModelsName( void ) { - return hKrennicModule->getModelsList(); +std::vector RDI::RDI_getModelsName( void ) { + return KrennicModule->getModelsList(); } -std::vector RDI::getMusicsName( void ) { - return hKrennicModule->getMusicsList(); +std::vector RDI::RDI_getMusicsName( void ) { + return KrennicModule->getMusicsList(); } -void RDI::CleanUp(){ - if (hKrennicModule) delete hKrennicModule; - if (hErsoModule) delete hErsoModule; +void RDI::RDI_CleanUp(){ + if (KrennicModule) delete KrennicModule; + if (ErsoModule) delete ErsoModule; } diff --git a/tools/RDIDebug.cpp b/tools/RDIDebug.cpp index 542f53f..b6bd02e 100644 --- a/tools/RDIDebug.cpp +++ b/tools/RDIDebug.cpp @@ -1,6 +1,6 @@ /** - * @file RDIdebug.cpp - * @date 17/09/2022 + * @file RDIDebug.cpp + * @date 12/01/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Debug app to test functions of RDI library. @@ -12,74 +12,108 @@ #include #include +#ifdef _WIN32 +#include +#endif -void PrintVirtualDirectoryContents( boost::filesystem::path, std::string ); +using namespace boost::filesystem; +using namespace std; + + +void PrintVirtualDirectoryContents( path, string, bool ); int main( int argc, char *argv[] ) { unsigned int i; - boost::filesystem::path pathBuilder; - std::string prefix; + path pathBuilder; + string prefix; + bool use_unicode = true; - printf("Using RDI lib v%s\n\n", RDI::getLibVersion().c_str()); - //cout << "Using RDI lib v" << RDI::getLibVersion() << endl << endl; +#ifdef _WIN32 + SetConsoleOutputCP(CP_UTF8); +#endif - if ( argc > 1 ) - RDI::Init(argv[1]); - else - RDI::Init("."); + cout << "Using RDI lib v" << RDI::RDI_getLibVersion() << endl << endl; - printf("> Section found: %d\n", RDI::getSectionCount()); - for ( i = 0; i < RDI::getSectionCount(); i++ ) { - printf(" -Section %d name: %s\n", i, RDI::getSectionName(i).c_str()); - printf(" -Section %d offset: 0x%X\n", i, RDI::getSectionOffset(i)); + // Initialize RDI (Erso and Krennic module) with folder provided in program + // argument, or the current directory by default + if ( argc > 2 ) { + use_unicode = atoi(argv[2]); + RDI::RDI_Init(argv[1]); + } else if (argc > 1) { + RDI::RDI_Init(argv[1]); + } else { + RDI::RDI_Init("."); } - //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 + // Print details about legacy DATA.DAT file + 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; + } + + // Print DATA.DAT tree view with unicode "style" + cout << endl << "DATA.DAT files tree view:" << endl; + for ( i = 0; i < RDI::RDI_getSectionCount(); i++ ) { + cout << RDI::RDI_getSectionName(i) << ":" << endl; pathBuilder.clear(); - pathBuilder.concat(RDI::getSectionName(i)); + pathBuilder.concat(RDI::RDI_getSectionName(i)); - PrintVirtualDirectoryContents(pathBuilder, prefix); + PrintVirtualDirectoryContents(pathBuilder, prefix, use_unicode); } - for ( std::string lname : RDI::getLevelsName() ) { - printf("Level found: %s\n", lname.c_str()); + // Print game elements Krennic module found + cout << endl << "Legacy files processing result:"; + cout << endl << "> Levels found:" << endl; + for ( std::string lname : RDI::RDI_getLevelsName() ) { + cout << " " << lname << endl; } - for ( std::string mdname : RDI::getModelsName() ) { - printf("Model found: %s\n", mdname.c_str()); + cout << endl << "> Models found:" << endl; + for ( std::string mdname : RDI::RDI_getModelsName() ) { + cout << " " << mdname << endl; } - for ( std::string mname : RDI::getMusicsName() ) { - printf("Music found: %s\n", mname.c_str()); + cout << endl << "> Musics found:" << endl; + for ( std::string mname : RDI::RDI_getMusicsName() ) { + cout << " " << mname << endl; } - RDI::CleanUp(); + // Release RDI library + RDI::RDI_CleanUp(); 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); +void PrintVirtualDirectoryContents( path p, string outPrefix, bool unicode ) { + auto curDirElementsName = RDI::RDI_getDirectoryElements(p.string()); + auto newPath = path(p); + auto newOutPrefix = string(outPrefix); - for ( std::string eName : curDirElementsName ) { + for ( string eName : curDirElementsName ) { newPath.clear(); - newPath.concat(path); + newPath.concat(p); 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); + if (RDI::RDI_isElementDirectory(newPath.string())) { + if (unicode) { + cout << outPrefix << "\u251C " << eName << endl; + newOutPrefix.append("\u2502 "); + } else { + cout << outPrefix << "\\ " << eName << endl; + newOutPrefix.append("| "); + } + PrintVirtualDirectoryContents(newPath, newOutPrefix, unicode); } else { - printf("%s%s\n", newOutPrefix.c_str(), eName.c_str()); + if (unicode) { + if (*--curDirElementsName.end() == eName) + cout << newOutPrefix << "\u2514 " << eName << endl; + else + cout << newOutPrefix << "\u251C " << eName << endl; + } else { + cout << newOutPrefix << "+ " << eName << endl; + } } } }