Experimental reader prototype

Need optimization in further version
This commit is contained in:
JackCarterSmith 2022-09-21 21:13:00 +02:00
parent e15934f881
commit 10ad8b7d72
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
7 changed files with 173 additions and 12 deletions

View File

@ -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<std::string> getDirectoryElements( std::string path );
RDI_EXTERN bool isElementDirectory( std::string path );
/**
* @brief Clean up global resources.
*/

View File

@ -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<DatEntry*>;
}
DirectoryEntry::DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags ) {
this->name = name;
this->fFlags.raw = fFlags.raw;
this->rootDir = false;
vSubFiles = new std::vector<DatEntry*>;
}
@ -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() {

View File

@ -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<DatEntry*> 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<DatEntry*> *vSubFiles;
};

View File

@ -13,9 +13,11 @@
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#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<DirectoryEntry *>(hRDat->getElement(boost::filesystem::path(path)));
if (result == nullptr) return 0;
else return result->getSize();
}
std::vector<std::string> RDI::getDirectoryElements( std::string path ) {
DirectoryEntry* de = nullptr;
std::vector<std::string> elementsNameArray;
elementsNameArray.clear();
if (!path.empty()) {
de = dynamic_cast<DirectoryEntry *>(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;
}

View File

@ -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<DirectoryEntry*>(cDatSection);
pFTRoot = new std::vector<DirectoryEntry*>;
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<DirectoryEntry *>(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<DirectoryEntry *>(e), newPath);
}
}
}
return nullptr;
}
}

View File

@ -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 */

View File

@ -8,11 +8,17 @@
*/
#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <RDI.h>
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());
}
}
}