Wrote this as a request, and I figured it'll also help teach some people about the structure of the SAH. Might even help you implement something similiar over your own without needing to pay for it, but who knows, one can always dream.
Code:
/**
* Author: Triston Plummer ("Cups")
* Date: 22/10/2016
*
* Used for decrypting Shen1l's XOR file count encryption for the SAH format.
*/
#include <fstream>
#include <iostream>
#include <vector>
// The encryption keys
int keys[4] = { 0x22, 0x68, 0x61, 0x74 };
// A file structure
#pragma pack(push, 1)
struct File {
// The amount of bytes in the files name
uint32_t name_length;
// The name of the file
char* file_name;
// The offset of the files data
uint64_t offset;
// The length of the files data
uint64_t length;
};
#pragma pack(pop)
// A folder structure
#pragma pack(push, 1)
struct Folder {
// The amount of bytes in the folder name
uint32_t name_length;
// The name of the folder
char* folder_name;
// The number of files in the folder
uint32_t file_count;
// The number of sub-directories contained within this folder
uint32_t sub_folder_count;
// The files contained within this folder
std::vector<File> files;
// The folders contained within this folder
std::vector<Folder> folders;
// The parent folder
Folder* parent_folder;
};
#pragma pack(pop)
// Writes the folder and it's data to the output file
void write_folder(Folder* folder, std::ofstream* output);
// Reads a folder
void read_folder(Folder* folder, std::ifstream* input);
int main(int argc, char** argv) {
// A series of null bytes, used for writing
char null_array[50] = { 0 };
// The file instance
std::ifstream* input = new std::ifstream((argc >= 2 ? argv[1] : "data.sah"), std::ifstream::in | std::ifstream::binary);
// If the file couldn't be opened
if (!input->is_open()) {
std::cout << "Unable to open the file specified!" << std::endl;
return 1;
}
// The file header
char header[3];
input->read((char*) &header, 3);
// Skip the next 4 bytes
input->ignore(4);
// The total number of files in the header
int total_number_files;
// Read the total number of files
input->read((char*) &total_number_files, 4);
// Skip the next 45 bytes (we should now be at an offset of 56)
input->ignore(45);
// The root directory
struct Folder root_directory;
// Define the values for the root directory
root_directory.folder_name = "Data\0";
// Read the folder
read_folder(&root_directory, input);
// Close the header file
input->close();
// Write the decrypted header file
std::ofstream* output = new std::ofstream((argc >= 3 ? argv[2] : "data_decrypted.sah"), std::ios::out | std::ios::binary);
// If the file was opened
if (!output->is_open()) {
std::cout << "Error writing" << std::endl;
return 1;
}
// Write the 3-byte header
output->write("SAH", 3);
// Write the 4 null bytes
output->write((char*) null_array, 4);
// Write the total number of files
output->write((char*) &total_number_files, 4);
// Write the 45 null bytes
output->write((char*) null_array, 40);
// Write a "1" followed by 4 null bytes
output->write((char*) "\x01\0\0\0\0", 5);
// Writes the root folder
write_folder(&root_directory, output);
// Append 8 null bytes
output->write((char*) null_array, 8);
// Close the output file
output->close();
return 0;
}
/**
* Recursively reads a specified folder
*
* [MENTION=1985011]param[/MENTION] folder
* The folder to read
*
* [MENTION=1985011]param[/MENTION] input
* The input file
*/
void read_folder(Folder* folder, std::ifstream* input) {
// The number of files in the current directory
int number_files_current_dir;
input->read((char*) &number_files_current_dir, 4);
// Decrypt the value
for (int i = 0; i < 4; i++) {
number_files_current_dir ^= keys[i];
}
// The number of files in the directory
folder->file_count = number_files_current_dir;
// Loop through the files in the current directory
for (int i = 0; i < folder->file_count; i++) {
// The current file being read
struct File current_file;
// The length of the file name
input->read((char*) ¤t_file.name_length, 4);
// The file name
char* name = new char[current_file.name_length];
input->read((char*) name, current_file.name_length);
current_file.file_name = name;
// The offset and length
input->read((char*) ¤t_file.offset, 8);
input->read((char*) ¤t_file.length, 8);
// Add the file to the root directory instance
folder->files.push_back(current_file);
}
// The number of sub-folders in the current directory
int sub_folder_count;
input->read((char*) &sub_folder_count, 4);
folder->sub_folder_count = sub_folder_count;
// Loop through the sub-directories
for (int i = 0; i < folder->sub_folder_count; i++) {
// The sub-directory
struct Folder directory;
// Define the directories parent folder
directory.parent_folder = folder;
// The length of the folder name
input->read((char*) &directory.name_length, 4);
// The folder name
char* name = new char[directory.name_length];
input->read((char*) name, directory.name_length);
directory.folder_name = name;
// Read the sub-directory
read_folder(&directory, input);
// Add the directory to the list of sub-folders
folder->folders.push_back(directory);
}
}
/**
* Recursively writes a specified folder to an output file
*
* [MENTION=1985011]param[/MENTION] folder
* The folder to write
*
* [MENTION=1985011]param[/MENTION] output
* The output file
*/
void write_folder(Folder* folder, std::ofstream* output) {
// Write the number of files in the current folder
output->write((char*) &folder->file_count, 4);
// Loop through the files in the current directory, and write them
for (auto &file : folder->files) {
// The number of bytes in the file name
output->write((char*) &file.name_length, 4);
// The name of the file
output->write((char*) file.file_name, file.name_length);
// The offset and length of the file
output->write((char*) &file.offset, 8);
output->write((char*) &file.length, 8);
}
// Write the number of sub-directories in the current directory
output->write((char*) &folder->sub_folder_count, 4);
// Loop through the sub-directories
for (auto &sub_folder : folder->folders) {
// The number of bytes in the folder name
output->write((char*) &sub_folder.name_length, 4);
// The name of the folder
output->write((char*) sub_folder.folder_name, sub_folder.name_length);
// Write the current folder
write_folder(&sub_folder, output);
}
}






to add my game and updater 