├── .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 | };
--------------------------------------------------------------------------------