201 lines
5.5 KiB
C++
201 lines
5.5 KiB
C++
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <filesystem>
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
namespace fs = std::filesystem;
|
|
|
|
struct file_t
|
|
{
|
|
string path;
|
|
uint32_t size;
|
|
uint32_t offset;
|
|
};
|
|
|
|
vector<file_t> toc;
|
|
|
|
void printHelp()
|
|
{
|
|
cout << "Usage: respak2 <command>" << endl;
|
|
cout << endl << "Valid commands:" << endl;
|
|
cout << "-p: Pack all files and folders within the 'data' folder into a file named 'data.jf2'." << endl;
|
|
cout << "-u: Unpack all files inside the file 'data.jf2' into the 'data' folder." << endl;
|
|
cout << "-l: List the contents of the 'data.jf2' file." << endl;
|
|
exit(1);
|
|
}
|
|
|
|
void printErrorAndExit(string errorMsg) {
|
|
cout << errorMsg << endl;
|
|
exit(1);
|
|
}
|
|
|
|
bool createDirectories(const string& dirName)
|
|
{
|
|
fs::path path(dirName);
|
|
|
|
std::error_code err;
|
|
if (!fs::create_directories(path.remove_filename(), err))
|
|
{
|
|
if (fs::exists(path.remove_filename()))
|
|
{
|
|
return true; // the folder probably already existed
|
|
}
|
|
|
|
printf("createDirectories: FAILED to create [%s], err:%s\n", dirName.c_str(), err.message().c_str());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void printDirectory(string path, int tabs=0)
|
|
{
|
|
for (const auto & entry : fs::directory_iterator(path))
|
|
{
|
|
for(int i=0;i<tabs;++i) cout << '\t';
|
|
cout << entry.path().string() << endl;
|
|
if (entry.is_directory()) printDirectory(entry.path().string(),tabs+1);
|
|
}
|
|
}
|
|
|
|
void packDirectory(string path, ofstream& fo, uint32_t& num_files, uint32_t& offset)
|
|
{
|
|
for (const auto & entry : fs::directory_iterator(path))
|
|
{
|
|
if (entry.is_directory())
|
|
packDirectory(entry.path().string(), fo, num_files, offset);
|
|
else
|
|
{
|
|
const string filename = entry.path().string();
|
|
ifstream fi(filename, ios::binary |ios::ate);
|
|
if (!fi.is_open()) printErrorAndExit("ERROR: Error al obrir l'arxiu '"+filename+"'.");
|
|
const uint32_t size = fi.tellg();
|
|
fi.seekg(0);
|
|
fo << fi.rdbuf();
|
|
fi.close();
|
|
toc.push_back({filename, size, offset});
|
|
cout << filename << ":" << size << ":" << offset << endl;
|
|
num_files++;
|
|
offset+=size;
|
|
}
|
|
}
|
|
}
|
|
|
|
void doPack()
|
|
{
|
|
//printDirectory("data");
|
|
|
|
uint32_t num_files = 0;
|
|
uint32_t toc_offset = 12;
|
|
|
|
ofstream fo ("data.jf2", ios::binary);
|
|
if (!fo.is_open()) printErrorAndExit("ERROR: No s'ha pogut obrir l'arxiu 'data.jf2'.");
|
|
fo.write("PK2",4);
|
|
fo.write( (char*)&num_files, 4 );
|
|
fo.write( (char*)&toc_offset, 4 );
|
|
|
|
packDirectory("data", fo, num_files, toc_offset);
|
|
|
|
for (auto file : toc)
|
|
{
|
|
fo.write( (char*)&file.offset, 4 );
|
|
fo.write( (char*)&file.size, 4 );
|
|
const uint8_t path_size = file.path.size();
|
|
fo.write( (char*)&path_size, 1 );
|
|
fo.write( file.path.c_str(), path_size );
|
|
}
|
|
|
|
fo.seekp(4);
|
|
fo.write( (char*)&num_files, 4 );
|
|
fo.write( (char*)&toc_offset, 4 );
|
|
|
|
fo.close();
|
|
}
|
|
|
|
void doUnpack()
|
|
{
|
|
ifstream fi ("data.jf2", ios::binary);
|
|
if (!fi.is_open()) printErrorAndExit("ERROR: No s'ha pogut obrir l'arxiu 'data.jf2'.");
|
|
char header[4];
|
|
fi.read(header, 4);
|
|
uint32_t num_files, toc_offset;
|
|
fi.read((char*)&num_files, 4);
|
|
fi.read((char*)&toc_offset, 4);
|
|
fi.seekg(toc_offset);
|
|
|
|
for (int i=0; i<num_files; ++i)
|
|
{
|
|
uint32_t file_offset, file_size;
|
|
fi.read( (char*)&file_offset, 4 );
|
|
fi.read( (char*)&file_size, 4 );
|
|
uint8_t path_size;
|
|
fi.read( (char*)&path_size, 1 );
|
|
char file_name[path_size+1];
|
|
fi.read( file_name, path_size );
|
|
file_name[path_size] = 0;
|
|
string filename = file_name;
|
|
// cout << filename << " : " << file_size << " : " << file_offset << endl;
|
|
toc.push_back({filename, file_size, file_offset});
|
|
}
|
|
|
|
for (auto file : toc)
|
|
{
|
|
fi.seekg(file.offset);
|
|
if (!createDirectories(file.path)) printErrorAndExit("ERROR: No s'ha pogut crear la ruta '"+file.path+"'.");
|
|
ofstream fo (file.path, ios::binary);
|
|
if (!fo.is_open()) printErrorAndExit("ERROR: No s'ha pogut obrir l'arxiu '"+file.path+"'.");
|
|
char* buffer = (char*)malloc(file.size);
|
|
fi.read(buffer, file.size);
|
|
fo.write(buffer, file.size);
|
|
fo.close();
|
|
}
|
|
|
|
fi.close();
|
|
}
|
|
|
|
void doList()
|
|
{
|
|
ifstream fi ("data.jf2", ios::binary);
|
|
if (!fi.is_open()) printErrorAndExit("ERROR: No s'ha pogut obrir l'arxiu 'data.jf2'.");
|
|
char header[4];
|
|
fi.read(header, 4);
|
|
uint32_t num_files, toc_offset;
|
|
fi.read((char*)&num_files, 4);
|
|
fi.read((char*)&toc_offset, 4);
|
|
fi.seekg(toc_offset);
|
|
|
|
for (int i=0; i<num_files; ++i)
|
|
{
|
|
uint32_t file_offset, file_size;
|
|
fi.read( (char*)&file_offset, 4 );
|
|
fi.read( (char*)&file_size, 4 );
|
|
uint8_t path_size;
|
|
fi.read( (char*)&path_size, 1 );
|
|
char file_name[path_size+1];
|
|
fi.read( file_name, path_size );
|
|
file_name[path_size] = 0;
|
|
string filename = file_name;
|
|
cout << filename << " : " << file_size << " : " << file_offset << endl;
|
|
toc.push_back({filename, file_size, file_offset});
|
|
}
|
|
fi.close();
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if (argc<2) printHelp();
|
|
|
|
string command = argv[1];
|
|
|
|
if ( command == "-p" )
|
|
doPack();
|
|
else if ( command == "-u" )
|
|
doUnpack();
|
|
else if ( command == "-l" )
|
|
doList();
|
|
else
|
|
printHelp();
|
|
|
|
return 0;
|
|
} |