Files
respak/respak2.cpp

207 lines
5.8 KiB
C++

#include <string>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <vector>
#include <string.h>
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.substr(filename.find_first_of('/')+1), 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 );
// We use this preliminar step to replace '\' with '/', as respak2 in windows generates backslashes, which break everything
char replace[256];
strcpy(replace, file.path.c_str());
for (int i=0; i<path_size; ++i) if (replace[i] == '\\') replace[i] = '/';
fo.write( replace, 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;
}