Skip to content

Commit

Permalink
Merge pull request #1 from Jayveer/feature/darqar
Browse files Browse the repository at this point in the history
Added support to extract from dar and qar files
  • Loading branch information
Jayveer authored Jan 23, 2021
2 parents 5b2a2d0 + 43fd835 commit c458648
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 14 deletions.
4 changes: 4 additions & 0 deletions Chrysalis.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
<ClCompile Include="mgs\common\decryptor\decryptor.cpp" />
<ClCompile Include="interface\cli\cli.cpp" />
<ClCompile Include="mgs\common\game\game.cpp" />
<ClCompile Include="mgs\dar\dar.cpp" />
<ClCompile Include="mgs\qar\qar.cpp" />
<ClCompile Include="mgs\slot\slot.cpp" />
<ClCompile Include="mgs\slot\stage\stages.cpp" />
<ClCompile Include="mgs\slot\stage\stage.cpp" />
Expand All @@ -173,6 +175,8 @@
<ClInclude Include="mgs\common\strcode.h" />
<ClInclude Include="mgs\common\util.h" />
<ClInclude Include="interface\cli\cli.h" />
<ClInclude Include="mgs\dar\dar.h" />
<ClInclude Include="mgs\qar\qar.h" />
<ClInclude Include="mgs\slot\slot.h" />
<ClInclude Include="mgs\slot\stage\stage.h" />
</ItemGroup>
Expand Down
12 changes: 12 additions & 0 deletions Chrysalis.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
<ClCompile Include="mgs\common\game\game.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mgs\dar\dar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mgs\qar\qar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mgs\common\decryptor\decryptor.h">
Expand Down Expand Up @@ -83,6 +89,12 @@
<ClInclude Include="mgs\common\game\game.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mgs\dar\dar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mgs\qar\qar.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Library Include="mgs\3rdparty\zlib\zlib.lib" />
Expand Down
3 changes: 1 addition & 2 deletions Chrysalis.vcxproj.user
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
<ShowAllFiles>true</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>cache.qar</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ Chrysalis is a free open source tool designed to be used with the game Metal Gea

This project uses [Zlib](https://github.com/madler/zlib) by [Mark Adler](https://github.com/madler)


### Latest Changes
- Added support to extrtact dar and qar archives

### To Do
- Add Support for some of the simpler archive formats
- Find out how slot lookup is hashed
- Add multithreaded extract
- Create GUI variant
- Clean up the code

## Usage

Currently only a CLI version of the application exists. The filename of the file to extract is mandatory whilst all other inputs are optional and will revert to defaults if not set. If extracting from the PSP version of the game it is possible to simply drag the file on the executable to extract it, this will extract all files. It is possible to extract a specfic page but it's numbered index when extracting slot files, as well as extracting a specific stage by providing its name when extracting stage files.
Currently only a CLI version of the application exists. The filename of the file to extract is mandatory whilst all other inputs are optional and will revert to defaults if not set. If extracting from the PSP version of the game it is possible to simply drag the file on the executable to extract it, this will extract all files. It is possible to extract a specfic page using its numbered index when extracting slot files, as well as extracting a specific stage by providing its name when extracting stage files.

If extracting SLOT.DAT it is required to have SLOT.KEY alongside it in the same directory.

Expand Down Expand Up @@ -54,6 +57,15 @@ Chrysalis.exe -ps3 "path\to\STAGEDAT.PDT" "init" "path\to\output"
```
Adding an output path at the end will extract the files to a specified folder of your choice.

```
Chrysalis.exe "path\to\cache.dar" "path\to\output"
```
It's also possible to extract from dar and qar archives. The Platform option is unnecessary here.

```
Chrysalis.exe "path\to\cache.qar" "path\to\output"
```
Extracting from Qar.

## License
[MIT](LICENSE.md)
Expand Down
45 changes: 42 additions & 3 deletions interface/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ void CLI::processSlot() {
pageID == -1 ? slot.extractAll(input, output) : slot.extract(input, pageID, output);
}

void CLI::processDar() {
std::string input = argv[currentArg];
std::string output = "";
currentArg++;

if (currentArg == argc - 1) output = argv[currentArg];

if (!verifyFile(input)) return;

Dar dar = Dar(input);
dar.open();

printf("Extracting Dar...");
dar.extract(output);
}

void CLI::processQar() {
std::string input = argv[currentArg];
std::string stageName = "";
std::string output = "";
currentArg++;

if (currentArg == argc - 1) output = argv[currentArg];

if (!verifyFile(input)) return;

Qar qar = Qar(input);
qar.open();

printf("Extracting Qar...");
qar.extract(output);
}

void CLI::processStage() {
std::string input = argv[currentArg];
std::string stageName = "";
Expand Down Expand Up @@ -86,11 +119,17 @@ bool CLI::verifyFile(std::string& file) {

void CLI::processFile() {
std::string filepath = argv[currentArg];
if (getCurrentDir(filepath) == "SLOT.DAT") processSlot();
if (getCurrentDir(filepath) == "STAGEDAT.PDT") processStage();
if (getCurrentDir(filepath) == "SLOT.DAT") { processSlot(); return; }
if (getCurrentDir(filepath) == "STAGEDAT.PDT") { processStage(); return; }
if (getCurrentDir(filepath) == "stagedata.pdt") { processStage(); return; }
if (getExtension(filepath) == ".dar") { processDar(); return; }
if (getExtension(filepath) == ".qar") { processQar(); return; }

printf("sorry the file %s is not currently supported", filepath.c_str());
}

void CLI::setCommand(char* arg) {

if (!strcmp(arg, "-extract") || !strcmp(arg, "-e")) {
command = EXTRACT;
return;
Expand All @@ -106,7 +145,7 @@ void CLI::setCommand(char* arg) {
return;
}

printf("command not recogized");
printf("command not recognised");
}

void CLI::run(std::string programName, std::string version) {
Expand Down
9 changes: 7 additions & 2 deletions interface/cli/cli.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
#include <filesystem>

#include "../../mgs/qar/qar.h"
#include "../../mgs/dar/dar.h";
#include "../../mgs/slot/stage/stage.h";

typedef enum CLI_COMMAND {
Expand All @@ -21,9 +23,11 @@ class CLI {
int currentArg = 1;
CLI_COMMAND command = EXTRACT;

void printUsage();
void printUsage();
bool checkInput();
void processArgs();
void processQar();
void processDar();
void processFile();
void processSlot();
void processStage();
Expand All @@ -37,12 +41,13 @@ class CLI {
const char* EXIT_MESSAGE = "Exiting\n";
const char* USAGE_MESSAGE = "Usage:\t Chrysalis.exe <options> SLOT.DAT [PAGEID] [OUTPUTDIRECTORY] \n"
"\t Chrysalis.exe <options> STAGEDAT.PDT [STAGENAME] [OUTPUTDIRECTORY] \n"
"\t Chrysalis.exe <options> cache.dar [OUTPUTDIRECTORY] \n"
"\t Chrysalis.exe <options> cache.qar [OUTPUTDIRECTORY] \n"
"\t options: -PSP/-psp to extract PSP game files (default value) \n"
"\t\t -PS3/-ps3 to extract PS3 game files \n"
"\t\t -extract/-e to extract (default value) redundant for now \n\n"
"Options are not required and will revert to defaults if not supplied\n"
"If PAGEID or STAGENAME aren't provided all files will be extracted\n"
"IF OUTPUTDIRECTORY is not provided files will be extracted to wherever the tool is run from\n"
"SLOT.KEY is required to be in the same directory as SLOT.DAT\n";

};
29 changes: 28 additions & 1 deletion mgs/common/fileutil.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <fstream>
#include <filesystem>

inline
Expand All @@ -20,6 +21,12 @@ std::string getCurrentDir(std::string& output) {
return p.filename().u8string();
}

inline
std::string getExtension(std::string& output) {
std::filesystem::path p{ output };
return p.extension().u8string();
}

inline
bool isDirectory(std::string& output) {
std::filesystem::path p{ output };
Expand All @@ -30,4 +37,24 @@ inline
bool fileExists(std::string& output) {
std::filesystem::path p{ output };
return std::filesystem::exists(p);
}
}

inline
int64_t getAlignment(int64_t currentOffset, int64_t alignSize) {
uint64_t step = (alignSize - (currentOffset % alignSize));
if (step != alignSize)
return step;
return 0;
}

inline
void writeDataToFile(uint8_t* data, int size, const std::string& filename, std::string& output) {
if (!std::filesystem::exists(output))
std::filesystem::create_directories(output);

updateDir(filename, output);
std::ofstream ofs(output, std::ofstream::binary);
ofs.write((char*)data, size);
ofs.close();
resetDir(output);
}
52 changes: 52 additions & 0 deletions mgs/dar/dar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "dar.h"

Dar::Dar(std::string filename) {
this->filename = filename;
}

Dar::~Dar() {

}

int32_t Dar::getNumFiles() {
return this->numFiles;
}

std::vector<uint8_t> Dar::getFile(int32_t i) {
return this->files[i].data;
}

void Dar::open() {
std::ifstream darDat;
darDat.open(filename, std::ios::binary);
darDat.read((char*)&this->numFiles, 4);

for (int i = 0; i < this->numFiles; i++) {
int align;
DarEntry entry;

std::getline(darDat, entry.filename, '\0');
align = getAlignment(darDat.tellg(), 4);
darDat.seekg(align, darDat.cur);

darDat.read((char*)&entry.size, 4);
align = getAlignment(darDat.tellg(), 16);
darDat.seekg(align, darDat.cur);

entry.data.resize(entry.size);
darDat.read((char*)&entry.data[0], entry.size);
darDat.seekg(1, darDat.cur);

files.push_back(entry);
}

darDat.close();
}

void Dar::extract(std::string output) {
updateDir("Dar", output);

for (int i = 0; i < this->numFiles; i++) {
writeDataToFile(&files[i].data[0], files[i].size, files[i].filename, output);
}
}
30 changes: 30 additions & 0 deletions mgs/dar/dar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once
#include "../common/fileutil.h"

#include <string>
#include <fstream>

struct DarEntry {
std::string filename;
uint32_t size;
std::vector<uint8_t> data;
};

struct DarHeader {
int32_t numFiles;
};

class Dar {
public:
Dar(std::string filename);
~Dar();

void open();
int32_t getNumFiles();
void extract(std::string output = "");
std::vector<uint8_t> getFile(int32_t i);
private:
int32_t numFiles;
std::vector<DarEntry> files;
std::string filename = "cache.dar";
};
47 changes: 47 additions & 0 deletions mgs/qar/qar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "qar.h"

Qar::Qar(std::string filename) {
this->filename = filename;
}

Qar::~Qar() {

}

void Qar::open() {
std::ifstream qarDat;
qarDat.open(filename, std::ios::binary);

qarDat.seekg(-4, qarDat.end);
qarDat.read((char*)&header.offset, 4);

qarDat.seekg(header.offset, qarDat.beg);
qarDat.read((char*)&header.numFiles, 4);

header.dataInfo.resize(header.numFiles);
qarDat.read((char*)&header.dataInfo[0], header.numFiles * sizeof(QarDataInfo));

header.filenames.resize(header.numFiles);
for (int i = 0; i < header.numFiles; i++) {
std::getline(qarDat, header.filenames[i], '\0');
}

qarDat.seekg(0, qarDat.beg);
txpFiles.resize(header.numFiles);

for (int i = 0; i < header.numFiles; i++) {
int size = header.dataInfo[i].fileSize;
txpFiles[i].resize(size);
qarDat.read((char*)&txpFiles[i][0], size);
}

qarDat.close();
}

void Qar::extract(std::string output) {
updateDir("Qar", output);

for (int i = 0; i < header.numFiles; i++) {
writeDataToFile(&txpFiles[i][0], header.dataInfo[i].fileSize, header.filenames[i], output);
}
}
Loading

0 comments on commit c458648

Please sign in to comment.