├── .gitignore ├── README.md ├── Rex.sln ├── Rex.vcxproj ├── Rex.vcxproj.filters ├── Rex.vcxproj.user ├── interface ├── cli.cpp └── cli.h ├── main.cpp └── mgs ├── archive ├── dar │ ├── dar.cpp │ └── dar.h └── stage │ ├── stage.cpp │ └── stage.h ├── common ├── ext_table.h ├── fileutil.h └── util.h └── config └── cnf ├── cnf.cpp └── cnf.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | Debug/ 3 | Release/ 4 | X64/ 5 | mgs/3rdparty/zlib/zconf.h 6 | mgs/3rdparty/zlib/zlib.h 7 | mgs/3rdparty/zlib/zlib.lib 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Rex 3 | 4 | 5 | Rex is a free open source tool designed to be used with the game Metal Gear Solid on the original Playstation. It allows the user to extract Dir and Dar archive files packaged with the game 6 | 7 | ### To Do 8 | - Add multithreaded extract 9 | - Add error handling 10 | - Create GUI variant 11 | - Clean up the code 12 | 13 | ## Usage 14 | 15 | Currently only a CLI version of the application exists. The program is primitive and just takes the filename as the only required argument. An optional output directory can also be added. It is also possible to just drag the file you wish to extract on the executable. 16 | 17 | ``` 18 | Rex.exe "path\to\stage.dir" 19 | ``` 20 | The above instruction will extract all files from stage.dir to the current directory. 21 | 22 | ``` 23 | Rex.exe "path\to\res_mdl0.dar" 24 | ``` 25 | The same can be used for Qar, Dar or Slot files. 26 | 27 | ``` 28 | Rex.exe "path\to\stg_tex1.dar" "path\to\output" 29 | ``` 30 | An optional output path can be added at the end, if it is not included then it will extract to the directory of the file being extracted. 31 | 32 | ## License 33 | [MIT](LICENSE.md) 34 | This project falls under the MIT license. -------------------------------------------------------------------------------- /Rex.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30907.101 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Rex", "Rex.vcxproj", "{77E3F2BF-D6A0-4E75-AF00-32318AE9F776}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Debug|x64.ActiveCfg = Debug|x64 17 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Debug|x64.Build.0 = Debug|x64 18 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Debug|x86.ActiveCfg = Debug|Win32 19 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Debug|x86.Build.0 = Debug|Win32 20 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Release|x64.ActiveCfg = Release|x64 21 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Release|x64.Build.0 = Release|x64 22 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Release|x86.ActiveCfg = Release|Win32 23 | {77E3F2BF-D6A0-4E75-AF00-32318AE9F776}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F4E5F536-F811-4C8E-A1AA-776CECF68C1E} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Rex.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {77e3f2bf-d6a0-4e75-af00-32318ae9f776} 25 | Rex 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | stdcpp17 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | stdcpp17 107 | 108 | 109 | Console 110 | true 111 | true 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | stdcpp17 122 | 123 | 124 | Console 125 | true 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | stdcpp17 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /Rex.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Rex.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | 7 | STAGE.DIR 8 | WindowsLocalDebugger 9 | 10 | -------------------------------------------------------------------------------- /interface/cli.cpp: -------------------------------------------------------------------------------- 1 | #include "cli.h" 2 | 3 | CLI::CLI(int argc, char** argv) { 4 | this->argc = argc; 5 | this->argv = argv; 6 | } 7 | 8 | CLI::~CLI() { 9 | 10 | } 11 | 12 | bool isDar(std::string& filepath) { 13 | return getExtension(filepath) == ".dar"; 14 | } 15 | 16 | bool isStage(std::string& filepath) { 17 | if (getExtension(filepath) == ".DIR" || getExtension(filepath) == ".dir") { 18 | std::string filename = getExtensionlessName(filepath); 19 | if (filenameContainsString(filepath, "STAGE") || filenameContainsString(filepath, "stage")) 20 | return true; 21 | } 22 | 23 | return false; 24 | } 25 | 26 | void CLI::processCommands() { 27 | while (currentArg < 2 && isCommand(argv[currentArg])) { 28 | setCommand(argv[currentArg]); 29 | currentArg++; 30 | } 31 | } 32 | 33 | void CLI::setCommand(char* arg) { 34 | 35 | printf("command not recognised\n"); 36 | } 37 | 38 | void CLI::processArgs() { 39 | processFile(); 40 | } 41 | 42 | void CLI::processFile() { 43 | std::string input = argv[currentArg]; 44 | std::string output = ""; 45 | currentArg++; 46 | 47 | 48 | if (currentArg == argc - 1) output = argv[currentArg]; 49 | 50 | if (isDar(input)) { 51 | Dar dar = Dar(input); 52 | dar.extractAll(output); 53 | 54 | exit(); return; 55 | } 56 | 57 | if (isStage(input)) { 58 | Stage stage = Stage(input); 59 | stage.open(); 60 | stage.extractAll(output); 61 | 62 | exit(); return; 63 | } 64 | 65 | } 66 | 67 | bool CLI::checkInput() { 68 | if (argc > 1 && argc <= 3) return true; 69 | printUsage(); 70 | return false; 71 | } 72 | 73 | void CLI::run(std::string programName, std::string version) { 74 | printf("Running %s v%s: Visit https://github.com/Jayveer/Rex for updates:\n", programName.c_str(), version.c_str()); 75 | if (!checkInput()) return; 76 | processArgs(); 77 | } 78 | 79 | bool CLI::isCommand(char* arg) { 80 | return arg[0] == 0x2D; 81 | } 82 | 83 | void CLI::printUsage() { 84 | printf(this->USAGE_MESSAGE); 85 | } 86 | 87 | void CLI::exit() { 88 | printf(this->EXIT_MESSAGE); 89 | } -------------------------------------------------------------------------------- /interface/cli.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../mgs/archive/dar/dar.h" 3 | #include "../mgs/archive/stage/stage.h" 4 | 5 | class CLI { 6 | public: 7 | CLI(int argc, char** argv); 8 | ~CLI(); 9 | 10 | void run(std::string programName, std::string version); 11 | void exit(); 12 | private: 13 | int argc; 14 | char** argv; 15 | int currentArg = 1; 16 | 17 | void printUsage(); 18 | bool checkInput(); 19 | void processArgs(); 20 | void processFile(); 21 | void processCommands(); 22 | bool isCommand(char* arg); 23 | void setCommand(char* arg); 24 | 25 | const char* EXIT_MESSAGE = "Exiting\n"; 26 | const char* USAGE_MESSAGE = "Usage:\t Rex.exe [OUTPUTDIRECTORY] \n"; 27 | }; -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "interface/cli.h" 2 | 3 | int main(int argc, char** argv) { 4 | CLI cli = CLI(argc, argv); 5 | cli.run("Rex", "1.0"); 6 | } -------------------------------------------------------------------------------- /mgs/archive/dar/dar.cpp: -------------------------------------------------------------------------------- 1 | #include "dar.h" 2 | 3 | Dar::Dar(std::string filename) { 4 | std::ifstream fs; 5 | this->dataSize = std::filesystem::file_size(filename); 6 | 7 | fs.open(filename, std::ios::binary); 8 | uint8_t* p = new uint8_t[dataSize]; 9 | fs.read((char*)p, dataSize); 10 | this->darData = p; 11 | fs.close(); 12 | } 13 | 14 | Dar::~Dar() { 15 | delete[] darData; 16 | } 17 | 18 | void Dar::extractAll(std::string& output) { 19 | int ptr = 0; 20 | 21 | updateDir("dar", output); 22 | 23 | while (ptr < dataSize) { 24 | DarEntry* entry = (DarEntry*)&darData[ptr]; 25 | std::string filename = intToHexString(entry->strcode) + "." + getExtForID(entry->extension); 26 | writeDataToFile(&darData[ptr + 8], entry->size, filename, output); 27 | ptr += (entry->size) + 8; 28 | } 29 | 30 | resetDir(output); 31 | } 32 | 33 | uint8_t* Dar::findFile(uint16_t id, uint16_t ext, int& size) { 34 | int ptr = 0; 35 | 36 | while (ptr < dataSize) { 37 | DarEntry* entry = (DarEntry*)&darData[ptr]; 38 | 39 | if (entry->strcode == id && entry->extension == ext) { 40 | size = entry->size; 41 | uint8_t* file = new uint8_t[size]; 42 | memcpy(file, &darData[ptr + 8], size); 43 | return file; 44 | } 45 | 46 | ptr += (entry->size) + 8; 47 | } 48 | 49 | return NULL; 50 | } -------------------------------------------------------------------------------- /mgs/archive/dar/dar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "../../common/util.h" 5 | #include "../../common/fileutil.h" 6 | #include "../../common/ext_table.h" 7 | 8 | struct DarEntry { 9 | uint16_t strcode; 10 | uint16_t extension; 11 | uint32_t size; 12 | uint8_t data[]; 13 | }; 14 | 15 | class Dar { 16 | public: 17 | Dar(std::string filename); 18 | ~Dar(); 19 | 20 | void extractAll(std::string& output); 21 | uint8_t* findFile(uint16_t id, uint16_t ext, int& size); 22 | private: 23 | uint8_t* darData; 24 | int dataSize; 25 | }; -------------------------------------------------------------------------------- /mgs/archive/stage/stage.cpp: -------------------------------------------------------------------------------- 1 | #include "stage.h" 2 | 3 | Stage::Stage(std::string filename) { 4 | this->filename = filename; 5 | } 6 | 7 | Stage::Stage(std::string filename, uint32_t sector) { 8 | this->sector = sector; 9 | this->filename = filename; 10 | } 11 | 12 | Stage::~Stage() {} 13 | 14 | int64_t Stage::getNextPageOffset(uint16_t pageID) { 15 | int numStages = tableSize / 12; 16 | return (pageID == numStages - 1) ? getFileSize(filename) : table[pageID + 1].offset * sector; 17 | } 18 | 19 | void Stage::open() { 20 | std::ifstream stageDir; 21 | stageDir.open(filename, std::ios::binary); 22 | stageDir.read((char*)&this->tableSize, 4); 23 | 24 | int numStages = tableSize / 12; 25 | 26 | table.resize(numStages); 27 | stageDir.read((char*)&this->table[0], tableSize); 28 | } 29 | 30 | void Stage::extractFiles(int64_t size, int64_t offset, std::string& output) { 31 | std::ifstream fileDat; 32 | fileDat.open(filename, std::ios::binary); 33 | fileDat.seekg(offset); 34 | 35 | uint8_t* pageData = new uint8_t[size]; 36 | fileDat.read((char*)pageData, size); 37 | fileDat.close(); 38 | 39 | DataConfig cnf = DataConfig(pageData, size); 40 | cnf.setHandler(this); 41 | cnf.setWorkDir(output); 42 | cnf.read(BINARY); 43 | 44 | delete[] pageData; 45 | } 46 | 47 | int getStrLength(char* str) { 48 | for (int i = 0; i < 8; i++) { 49 | if (str[i] == '\0') 50 | return i; 51 | } 52 | 53 | return 9; 54 | } 55 | 56 | void Stage::extract(uint16_t pageID, std::string output) { 57 | int numStages = tableSize / 12; 58 | if (pageID > numStages) return; 59 | 60 | int strlen = getStrLength(table[pageID].name); 61 | 62 | std::string stageName; 63 | stageName.reserve(strlen); 64 | stageName.assign(table[pageID].name, strlen); 65 | 66 | if (strlen == 9) stageName[8] = '\0'; 67 | 68 | updateDir("stage", output); 69 | updateDir(stageName, output); 70 | int64_t nextOffset = getNextPageOffset(pageID); 71 | int64_t offset = table[pageID].offset * sector; 72 | int64_t size = nextOffset - offset; 73 | extractFiles(size, offset, output); 74 | } 75 | 76 | void Stage::extractAll(std::string output) { 77 | int numStages = tableSize / 12; 78 | 79 | for (int i = 0; i < numStages; i++) { 80 | extract(i, output); 81 | } 82 | } 83 | 84 | //// 85 | 86 | int32_t Stage::getSectorSize() { 87 | return this->sector; 88 | }; 89 | 90 | int64_t Stage::getNextSectorOffset(int64_t currentOffset) { 91 | return getAlignment(currentOffset, sector); 92 | }; 93 | 94 | void Stage::processQar(std::string filename, std::string region, std::string* workDir) {}; 95 | void Stage::processAfp(std::string filename, std::string region, std::string* workDir) {}; 96 | void Stage::processVram(std::string filename, std::string region, std::string* workDir) {}; 97 | void Stage::processEnc(std::string region, uint8_t** section, int64_t size, int64_t sectionSize) {}; 98 | 99 | void Stage::processFile(std::string filename, std::string region, std::string* workDir, uint8_t* fileData, int size) { 100 | writeDataToFile(fileData, size, filename, *workDir); 101 | }; -------------------------------------------------------------------------------- /mgs/archive/stage/stage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../config/cnf/cnf.h" 3 | #include "../../common/fileutil.h" 4 | 5 | struct StageTable { 6 | char name[8]; 7 | uint32_t offset; 8 | }; 9 | 10 | class Stage : public CNFHandler { 11 | public: 12 | Stage(std::string filename); 13 | Stage(std::string filename, uint32_t sector); 14 | 15 | ~Stage(); 16 | 17 | void open(); 18 | void extractAll(std::string output = ""); 19 | void extract(uint16_t pageID, std::string output = ""); 20 | private: 21 | int sector = 0x800; 22 | std::string filename; 23 | 24 | int32_t tableSize; 25 | std::vector table; 26 | 27 | int64_t getNextPageOffset(uint16_t pageID); 28 | void extractFiles(int64_t size, int64_t offset, std::string& output); 29 | 30 | int32_t getSectorSize(); 31 | int64_t getNextSectorOffset(int64_t currentOffset); 32 | void processQar(std::string filename, std::string region, std::string* workDir); 33 | void processAfp(std::string filename, std::string region, std::string* workDir); 34 | void processVram(std::string filename, std::string region, std::string* workDir); 35 | void processEnc(std::string region, uint8_t** section, int64_t size, int64_t sectionSize); 36 | void processFile(std::string filename, std::string region, std::string* workDir, uint8_t* fileData, int size); 37 | }; -------------------------------------------------------------------------------- /mgs/common/ext_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct EXT_TABLE { 4 | const char* name; 5 | uint8_t id; 6 | }; 7 | 8 | const EXT_TABLE ext_table[16] = { 9 | {"bin", 0x62}, 10 | {"con", 0x63}, 11 | {"dar", 0x64}, 12 | {"efx", 0x65}, 13 | {"gcx", 0x67}, 14 | {"hzm", 0x68}, 15 | {"img", 0x69}, 16 | {"kmd", 0x6B}, 17 | {"lit", 0x6C}, 18 | {"mdx", 0x6D}, 19 | {"oar", 0x6F}, 20 | {"pcx", 0x70}, 21 | {"rar", 0x72}, 22 | {"sgt", 0x73}, 23 | {"wvx", 0x77}, 24 | {"zmd", 0x7A}, 25 | }; 26 | 27 | inline 28 | const char* getExtForID(uint8_t id) { 29 | for (int i = 0; i < 16; i++) { 30 | if (ext_table[i].id == id) 31 | return ext_table[i].name; 32 | } 33 | return ""; 34 | } 35 | 36 | inline 37 | uint8_t getIDforExt(const char* ext) { 38 | for (int i = 0; i < 16; i++) { 39 | if (!strcmp(ext_table[i].name, ext)) 40 | return ext_table[i].id; 41 | } 42 | return -1; 43 | } -------------------------------------------------------------------------------- /mgs/common/fileutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | inline 6 | void updateDir(const std::string& path, std::string& output) { 7 | std::filesystem::path p{ output }; 8 | p.append(path); 9 | output = p.u8string(); 10 | } 11 | 12 | inline 13 | void resetDir(std::string& output) { 14 | std::filesystem::path p{ output }; 15 | output = p.parent_path().u8string(); 16 | } 17 | 18 | inline 19 | std::string getCurrentDir(const std::string& output) { 20 | std::filesystem::path p{ output }; 21 | return p.filename().u8string(); 22 | } 23 | 24 | inline 25 | std::string getExtension(const std::string& output) { 26 | std::filesystem::path p{ output }; 27 | return p.extension().u8string(); 28 | } 29 | 30 | inline 31 | std::string getExtensionlessName(const std::string& output) { 32 | std::filesystem::path p{ output }; 33 | return p.stem().u8string(); 34 | } 35 | 36 | inline 37 | bool filenameContainsString(const std::string& output, const std::string& string) { 38 | std::string filename = getExtensionlessName(output); 39 | 40 | if (filename.find(string) != std::string::npos) 41 | return true; 42 | 43 | return false; 44 | } 45 | 46 | inline 47 | bool isDirectory(const std::string& output) { 48 | std::filesystem::path p{ output }; 49 | return std::filesystem::is_directory(p); 50 | } 51 | 52 | inline 53 | bool fileExists(const std::string& output) { 54 | std::filesystem::path p{ output }; 55 | return std::filesystem::exists(p); 56 | } 57 | 58 | inline 59 | int64_t getFileSize(const std::string& input) { 60 | return std::filesystem::file_size(input); 61 | } 62 | 63 | inline 64 | int64_t getAlignment(int64_t currentOffset, int64_t alignSize) { 65 | uint64_t step = (alignSize - (currentOffset % alignSize)); 66 | if (step != alignSize) 67 | return step; 68 | return 0; 69 | } 70 | 71 | inline 72 | void writeDataToFile(uint8_t* data, int size, const std::string& filename, std::string& output) { 73 | if (!std::filesystem::exists(output)) 74 | std::filesystem::create_directories(output); 75 | 76 | updateDir(filename, output); 77 | std::ofstream ofs(output, std::ofstream::binary); 78 | ofs.write((char*)data, size); 79 | ofs.close(); 80 | resetDir(output); 81 | } -------------------------------------------------------------------------------- /mgs/common/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | inline 5 | std::string formatStrcode(std::string strcode) { 6 | uint8_t length = strcode.size(); 7 | uint8_t pad = 6 - length; 8 | std::string prefix; 9 | 10 | for (int i = 0; i < pad; i++) { 11 | prefix += "0"; 12 | } 13 | 14 | return (prefix + strcode); 15 | 16 | } 17 | 18 | inline 19 | std::string intToHexString(int value) { 20 | std::stringstream ss; 21 | ss << std::hex << value; 22 | return formatStrcode(ss.str()); 23 | } -------------------------------------------------------------------------------- /mgs/config/cnf/cnf.cpp: -------------------------------------------------------------------------------- 1 | #include "cnf.h" 2 | 3 | DataConfig::DataConfig(std::string filename) { 4 | this->filename = filename; 5 | } 6 | 7 | DataConfig::DataConfig(uint8_t* data, int size) { 8 | this->data = data; 9 | this->dataSize = size; 10 | } 11 | 12 | DataConfig::~DataConfig() { 13 | } 14 | 15 | void DataConfig::setWorkDir(std::string& workdir) { 16 | this->workdir = &workdir; 17 | } 18 | 19 | void DataConfig::setHandler(CNFHandler* cnfHandler) { 20 | this->cnfHandler = cnfHandler; 21 | } 22 | 23 | const char* DataConfig::getRegionForID(uint32_t id) { 24 | for (int i = 0; i < 7; i++) { 25 | if (cnfRegion[i].id == id) 26 | return cnfRegion[i].name; 27 | } 28 | return ""; 29 | } 30 | 31 | void DataConfig::readFlag(std::string line) { 32 | std::stringstream lineStream(line); 33 | std::vector tokens = { std::istream_iterator{lineStream}, std::istream_iterator{} }; 34 | std::string flagName = tokens[0]; 35 | 36 | currentRegion = flagName; 37 | } 38 | 39 | std::string DataConfig::getDarName() { 40 | return currentRegion == "resident" ? "res_mdl" + std::to_string(resDarCount) : "stg_tex" + std::to_string(cacDarCount); 41 | } 42 | 43 | void DataConfig::readFile(DataCNFTag tag, uint8_t* data, int size) { 44 | std::string outputName = tag.id ? intToHexString(tag.id) : getDarName(); 45 | outputName = outputName + "." + getExtForID(tag.extension); 46 | 47 | if (cnfHandler) cnfHandler->processFile(outputName, currentRegion, workdir, data, size); 48 | } 49 | 50 | void DataConfig::startSection() { 51 | section = &data[dataPtr]; 52 | } 53 | 54 | void DataConfig::endSection(DataCNFTag tag) { 55 | dataPtr += tag.offset; 56 | dataPtr += cnfHandler->getNextSectorOffset(dataPtr); 57 | } 58 | 59 | void DataConfig::readCache(DataCNFTag tag, DataCNFTag nextTag) { 60 | if (!tag.offset) startSection(); 61 | 62 | int size = nextTag.offset - tag.offset; 63 | 64 | switch (tag.extension) { 65 | case 0x62: 66 | readFile(tag, §ion[tag.offset], size); 67 | break; 68 | case 0x64: 69 | cacDarCount++; 70 | readFile(tag, §ion[tag.offset], size); 71 | break; 72 | case 0xFF: 73 | endSection(tag); 74 | break; 75 | default: 76 | readFile(tag, §ion[tag.offset], size); 77 | } 78 | } 79 | 80 | void DataConfig::readRegion(DataCNFTag tag) { 81 | switch (tag.extension) { 82 | case 0x62: 83 | if (currentRegion == "sound") currentRegion = "stage"; 84 | readFile(tag, &data[dataPtr], tag.offset); 85 | break; 86 | case 0x64: 87 | if (currentRegion != "resident") cacDarCount++; 88 | readFile(tag, &data[dataPtr], tag.offset); 89 | if (currentRegion == "resident") resDarCount++; 90 | break; 91 | default: 92 | readFile(tag, &data[dataPtr], tag.offset); 93 | } 94 | 95 | endSection(tag); 96 | } 97 | 98 | void DataConfig::readLine(DataCNFTag tag, DataCNFTag nextTag) { 99 | currentRegion = getRegionForID(tag.region); 100 | currentRegion == "cache" ? readCache(tag, nextTag) : readRegion(tag); 101 | } 102 | 103 | void DataConfig::readLine(std::string line) { 104 | switch (line.at(0)) { 105 | case 0x2E: 106 | readFlag(&line[1]); 107 | break; 108 | case 0x3F: 109 | if (cnfHandler) cnfHandler->processAfp(&line[1], currentRegion, workdir); 110 | break; 111 | case 0x40: 112 | if (cnfHandler) cnfHandler->processQar(&line[1], currentRegion, workdir); 113 | break; 114 | default: 115 | if (cnfHandler) cnfHandler->processFile(line, currentRegion, workdir, NULL, 0); 116 | } 117 | } 118 | 119 | void DataConfig::initBinaryStream() { 120 | cnf = (DataCNF*)data; 121 | dataPtr += cnf->cnfSize * cnfHandler->getSectorSize(); 122 | } 123 | 124 | void DataConfig::initTextStream() { 125 | std::string cnfTxt = std::string((char*)data, dataSize); 126 | textStream.str(cnfTxt); 127 | } 128 | 129 | void DataConfig::readBinary() { 130 | initBinaryStream(); 131 | 132 | for (int i = 0; cnf->tags[i].region != 0; i++) { 133 | readLine(cnf->tags[i], cnf->tags[i + 1]); 134 | } 135 | } 136 | 137 | void DataConfig::readASCII() { 138 | initTextStream(); 139 | 140 | std::string line; 141 | while (std::getline(textStream, line)) { 142 | readLine(line); 143 | } 144 | } 145 | 146 | void DataConfig::read(CNFTYPE type) { 147 | type == BINARY ? readBinary() : readASCII(); 148 | } -------------------------------------------------------------------------------- /mgs/config/cnf/cnf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../common/util.h" 3 | #include "../../common/ext_table.h" 4 | 5 | #include 6 | 7 | struct DataCNFTag { 8 | uint16_t id; 9 | uint8_t region; 10 | uint8_t extension; 11 | uint32_t offset; 12 | }; 13 | 14 | struct DataCNF { 15 | uint16_t cnfSize; 16 | uint16_t dataSize; 17 | DataCNFTag tags[]; 18 | }; 19 | 20 | struct CNFREGION { 21 | const char* name; 22 | int id; 23 | }; 24 | 25 | enum CNFTYPE { 26 | ASCII, 27 | BINARY 28 | }; 29 | 30 | class CNFHandler { 31 | public: 32 | virtual int32_t getSectorSize() = 0; 33 | virtual int64_t getNextSectorOffset(int64_t currentOffset) = 0; 34 | virtual void processQar(std::string filename, std::string region, std::string* workDir) = 0; 35 | virtual void processAfp(std::string filename, std::string region, std::string* workDir) = 0; 36 | virtual void processVram(std::string filename, std::string region, std::string* workDir) = 0; 37 | virtual void processEnc(std::string region, uint8_t** section, int64_t size, int64_t sectionSize) = 0; 38 | virtual void processFile(std::string filename, std::string region, std::string* workDir, uint8_t* fileData, int size) = 0; 39 | }; 40 | 41 | class DataConfig { 42 | public: 43 | DataConfig(std::string filename); 44 | DataConfig(uint8_t* data, int size); 45 | 46 | ~DataConfig(); 47 | void read(CNFTYPE type = ASCII); 48 | void setWorkDir(std::string& workdir); 49 | void setHandler(CNFHandler* cnfHandler); 50 | const char* getRegionForID(uint32_t id); 51 | private: 52 | int dataSize = 0; 53 | DataCNF* cnf = {}; 54 | uint8_t* data = {}; 55 | int resDarCount = 0; 56 | int cacDarCount = 0; 57 | std::string filename; 58 | uint8_t* section = {}; 59 | uint64_t dataPtr = 0; 60 | std::string* workdir = {}; 61 | CNFHandler* cnfHandler = {}; 62 | std::string currentRegion; 63 | std::stringstream textStream; 64 | 65 | void readASCII(); 66 | void readBinary(); 67 | void initTextStream(); 68 | void initBinaryStream(); 69 | void readLine(std::string line); 70 | void readFlag(std::string line); 71 | void readLine(DataCNFTag tag, DataCNFTag nextTag); 72 | 73 | std::string getDarName(); 74 | void readRegion(DataCNFTag tag); 75 | void readCache(DataCNFTag tag, DataCNFTag nextTag); 76 | void readDar(DataCNFTag tag, uint8_t* data, int size); 77 | void readBin(DataCNFTag tag, uint8_t* data, int size); 78 | void readFile(DataCNFTag tag, uint8_t* data, int size); 79 | 80 | void startSection(); 81 | void endSection(DataCNFTag tag); 82 | 83 | const CNFREGION cnfRegion[7] = { 84 | { "end", 0x00 }, 85 | { "nocache", 0x6E }, 86 | { "cache", 0x63 }, 87 | { "resident", 0x72 }, 88 | { "sound", 0x73 } 89 | }; 90 | }; --------------------------------------------------------------------------------