numerous cleanups
This commit is contained in:
parent
00c52cc6be
commit
b4d661b6ee
131
bindat_to_gcdl.c
131
bindat_to_gcdl.c
|
@ -15,6 +15,14 @@
|
|||
#include "utils.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int returncode, validation_result;
|
||||
uint8_t *compressed_bin = NULL;
|
||||
uint8_t *compressed_dat = NULL;
|
||||
uint8_t *decompressed_bin = NULL;
|
||||
uint8_t *decompressed_dat = NULL;
|
||||
uint8_t *final_bin = NULL;
|
||||
uint8_t *final_dat = NULL;
|
||||
|
||||
if (argc != 4) {
|
||||
printf("Usage: bindat_to_gcdl quest.bin quest.dat output.qst\n");
|
||||
return 1;
|
||||
|
@ -29,88 +37,95 @@ int main(int argc, char *argv[]) {
|
|||
/** validate lengths of the given quest .bin and .dat files, to make sure they fit into the packet structs **/
|
||||
|
||||
const char *bin_base_filename = path_to_filename(bin_filename);
|
||||
if (strlen(bin_base_filename) > 16) {
|
||||
if (strlen(bin_base_filename) > QUEST_FILENAME_MAX_LENGTH) {
|
||||
printf("Bin filename is too long to fit in a QST file header. Maximum length is 16 including file extension.\n");
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
const char *dat_base_filename = path_to_filename(dat_filename);
|
||||
if (strlen(dat_base_filename) > 16) {
|
||||
if (strlen(dat_base_filename) > QUEST_FILENAME_MAX_LENGTH) {
|
||||
printf("Dat filename is too long to fit in a QST file header. Maximum length is 16 including file extension.\n");
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
/** read in given quest .bin and .dat files **/
|
||||
|
||||
uint8_t *compressed_bin, *compressed_dat;
|
||||
uint32_t compressed_bin_size, compressed_dat_size;
|
||||
|
||||
if (read_file(bin_filename, &compressed_bin, &compressed_bin_size)) {
|
||||
printf("Error reading bin file: %s\n", bin_filename);
|
||||
return 1;
|
||||
printf("Reading quest .bin file %s ...\n", bin_filename);
|
||||
returncode = read_file(bin_filename, &compressed_bin, &compressed_bin_size);
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) reading bin file: %s\n", returncode, get_error_message(returncode), bin_filename);
|
||||
goto error;
|
||||
}
|
||||
if (read_file(dat_filename, &compressed_dat, &compressed_dat_size)) {
|
||||
printf("Error reading dat file: %s\n", dat_filename);
|
||||
return 1;
|
||||
|
||||
printf("Reading quest .dat file %s ...\n", dat_filename);
|
||||
returncode = read_file(dat_filename, &compressed_dat, &compressed_dat_size);
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) reading dat file: %s\n", returncode, get_error_message(returncode), dat_filename);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
/** prs decompress the .bin file. store the prs decompressed data sizes for both the .bin and .dat files **/
|
||||
|
||||
uint8_t *decompressed_bin;
|
||||
uint32_t decompressed_bin_size, decompressed_dat_size;
|
||||
/** prs decompress the .bin file, parse out it's header and validate it **/
|
||||
printf("Decompressing and validating .bin file ...\n");
|
||||
|
||||
uint32_t decompressed_bin_size;
|
||||
result = fuzziqer_prs_decompress_buf(compressed_bin, &decompressed_bin, compressed_bin_size);
|
||||
if (result < 0) {
|
||||
printf("prs_decompress_buf() error %d with bin file data: %s\n", result, bin_filename);
|
||||
return 1;
|
||||
printf("Error code %d decompressing .dat data.\n", result);
|
||||
goto error;
|
||||
}
|
||||
decompressed_bin_size = (uint32_t)result;
|
||||
|
||||
result = fuzziqer_prs_decompress_size(compressed_dat, compressed_dat_size);
|
||||
if (result < 0) {
|
||||
printf("prs_decompress_size() error %d with dat file data: %s\n", result, dat_filename);
|
||||
return 1;
|
||||
}
|
||||
decompressed_dat_size = (uint32_t)result;
|
||||
|
||||
|
||||
/** parse quest .bin header from decompressed .bin file data. also set the "download" flag in the .bin header **/
|
||||
|
||||
QUEST_BIN_HEADER *bin_header = (QUEST_BIN_HEADER*)decompressed_bin;
|
||||
validation_result = validate_quest_bin(bin_header, decompressed_bin_size, true);
|
||||
if (validation_result) {
|
||||
printf("Aborting due to invalid quest .bin data.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// TODO: validations might need tweaking ...
|
||||
if (bin_header->object_code_offset != 468) {
|
||||
printf("Quest bin file invalid (unexpected object_code_offset = %d).\n", bin_header->object_code_offset);
|
||||
return 1;
|
||||
|
||||
/** prs decompress the .dat file and validate it **/
|
||||
printf("Decompressing and validating .dat file ...\n");
|
||||
|
||||
uint32_t decompressed_dat_size;
|
||||
result = fuzziqer_prs_decompress_buf(compressed_dat, &decompressed_dat, compressed_dat_size);
|
||||
if (result < 0) {
|
||||
printf("Error code %d decompressing .dat data.\n", result);
|
||||
goto error;
|
||||
}
|
||||
if (bin_header->bin_size != decompressed_bin_size) {
|
||||
printf("Quest bin file invalid (decompressed size does not match header bin_size value: %d).\n", bin_header->bin_size);
|
||||
return 1;
|
||||
}
|
||||
if (strlen(bin_header->name) == 0) {
|
||||
printf("Quest bin file invalid or missing quest name.\n");
|
||||
return 1;
|
||||
}
|
||||
if (bin_header->quest_number == 0) {
|
||||
printf("Quest bin file invalid (quest_number is zero).\n");
|
||||
return 1;
|
||||
decompressed_dat_size = result;
|
||||
|
||||
validation_result = validate_quest_dat(decompressed_dat, decompressed_dat_size, true);
|
||||
if (validation_result != QUESTDAT_ERROR_EOF_EMPTY_TABLE) {
|
||||
printf("Aborting due to invalid quest .dat data.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
printf("Quest: id=%d (%d), episode=%d, download=%d, unknown=0x%02x, name=\"%s\", compressed_bin_size=%d, compressed_dat_size=%d\n",
|
||||
bin_header->quest_number_byte,
|
||||
bin_header->quest_number_word,
|
||||
bin_header->episode+1,
|
||||
bin_header->download,
|
||||
bin_header->unknown,
|
||||
bin_header->name,
|
||||
compressed_bin_size,
|
||||
compressed_dat_size);
|
||||
|
||||
|
||||
/** set the "download" flag in the .bin header and then re-compress the .bin data **/
|
||||
printf("Setting .bin header 'download' flag and re-compressing .bin file data ...\n");
|
||||
|
||||
bin_header->download = 1; // gamecube pso client will not find quests on a memory card if this is not set!
|
||||
|
||||
printf("Quest: id=%d, download=%d, language=0x%02x, name=%s\n", bin_header->quest_number, bin_header->download, bin_header->language, bin_header->name);
|
||||
|
||||
|
||||
/** re-compress bin data, so it includes our modified header "download" flag **/
|
||||
|
||||
uint8_t *recompressed_bin;
|
||||
|
||||
result = fuzziqer_prs_compress(decompressed_bin, &recompressed_bin, decompressed_bin_size);
|
||||
if (result < 0) {
|
||||
printf("prs_compress() error %d with modified bin file data: %s\n", result, bin_filename);
|
||||
return 1;
|
||||
printf("Error code %d re-compressing .bin file data.\n", result);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// overwrite old compressed bin data, since we don't need it anymore
|
||||
|
@ -121,11 +136,12 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
/** encrypt compressed .bin and .dat file data, using PC crypt method with randomly generated crypt key.
|
||||
prefix unencrypted download quest chunks header to prs compressed + encrypted .bin and .dat file data. **/
|
||||
printf("Preparing final .qst file data ... \n");
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
uint32_t final_bin_size = compressed_bin_size + sizeof(DOWNLOAD_QUEST_CHUNKS_HEADER);
|
||||
uint8_t *final_bin = malloc(final_bin_size);
|
||||
final_bin = malloc(final_bin_size);
|
||||
memset(final_bin, 0, final_bin_size);
|
||||
uint8_t *crypt_compressed_bin = final_bin + sizeof(DOWNLOAD_QUEST_CHUNKS_HEADER);
|
||||
DOWNLOAD_QUEST_CHUNKS_HEADER *bin_dlchunks_header = (DOWNLOAD_QUEST_CHUNKS_HEADER*)final_bin;
|
||||
|
@ -134,7 +150,7 @@ int main(int argc, char *argv[]) {
|
|||
memcpy(crypt_compressed_bin, compressed_bin, compressed_bin_size);
|
||||
|
||||
uint32_t final_dat_size = compressed_dat_size + sizeof(DOWNLOAD_QUEST_CHUNKS_HEADER);
|
||||
uint8_t *final_dat = malloc(final_dat_size);
|
||||
final_dat = malloc(final_dat_size);
|
||||
memset(final_dat, 0, final_dat_size);
|
||||
uint8_t *crypt_compressed_dat = final_dat + sizeof(DOWNLOAD_QUEST_CHUNKS_HEADER);
|
||||
DOWNLOAD_QUEST_CHUNKS_HEADER *dat_dlchunks_header = (DOWNLOAD_QUEST_CHUNKS_HEADER*)final_dat;
|
||||
|
@ -162,11 +178,12 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
/** write out the .qst file. chunk data is written out as interleaved 0xA7 packets containing 1024 bytes each */
|
||||
printf("Writing out %s ...\n", output_qst_filename);
|
||||
|
||||
FILE *fp = fopen(output_qst_filename, "wb");
|
||||
if (!fp) {
|
||||
printf("Error creating output .qst file: %s\n", output_qst_filename);
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
fwrite(&qst_bin_header, sizeof(qst_bin_header), 1, fp);
|
||||
|
@ -210,11 +227,15 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
fclose(fp);
|
||||
|
||||
returncode = 0;
|
||||
goto quit;
|
||||
error:
|
||||
returncode = 1;
|
||||
quit:
|
||||
free(decompressed_bin);
|
||||
free(final_bin);
|
||||
free(final_dat);
|
||||
free(compressed_bin);
|
||||
free(compressed_dat);
|
||||
|
||||
return 0;
|
||||
return returncode;
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ int main(int argc, char *argv[]) {
|
|||
/** decompress loaded quest .bin data and validate it **/
|
||||
printf("Validating quest .bin data ...\n");
|
||||
|
||||
result = prs_decompress_buf(bin_data, &decompressed_bin_data, bin_data_size);
|
||||
//result = prs_decompress_buf(bin_data, &decompressed_bin_data, bin_data_size);
|
||||
result = fuzziqer_prs_decompress_buf(bin_data, &decompressed_bin_data, bin_data_size);
|
||||
if (result < 0) {
|
||||
printf("Error code %d decompressing .bin data.\n", result);
|
||||
goto error;
|
||||
|
@ -247,7 +248,7 @@ int main(int argc, char *argv[]) {
|
|||
printf("Writing compressed quest .bin data to %s ...\n", out_filename);
|
||||
result = write_file(out_filename, bin_data, bin_data_size);
|
||||
if (result) {
|
||||
printf("Error code %d writing out file.\n", result);
|
||||
printf("Error code %d writing out file: %s\n", result, get_error_message(result));
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ int main(int argc, char *argv[]) {
|
|||
printf("Writing compressed quest .dat data to %s ...\n", out_filename);
|
||||
result = write_file(out_filename, dat_data, dat_data_size);
|
||||
if (result) {
|
||||
printf("Error code %d writing out file.\n", result);
|
||||
printf("Error code %d writing out file: %s\n", result, get_error_message(result));
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
117
gen_qst_header.c
117
gen_qst_header.c
|
@ -9,18 +9,13 @@
|
|||
#include "quests.h"
|
||||
#include "textconv.h"
|
||||
|
||||
int write_qst_header(const char *filename, const QST_HEADER *header) {
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if (!fp)
|
||||
return ERROR_CREATING_FILE;
|
||||
|
||||
fwrite(header, sizeof(QST_HEADER), 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int returncode, validation_result;
|
||||
uint8_t *bin_data = NULL;
|
||||
uint8_t *dat_data = NULL;
|
||||
char *bin_hdr_file = NULL;
|
||||
char *dat_hdr_file = NULL;
|
||||
|
||||
if (argc != 3) {
|
||||
printf("Usage: gen_qst_header quest.bin quest.dat\n");
|
||||
return 1;
|
||||
|
@ -30,85 +25,93 @@ int main(int argc, char *argv[]) {
|
|||
const char *dat_file = argv[2];
|
||||
|
||||
const char *bin_base_filename = path_to_filename(bin_file);
|
||||
if (strlen(bin_base_filename) > 16) {
|
||||
if (strlen(bin_base_filename) > QUEST_FILENAME_MAX_LENGTH) {
|
||||
printf("Bin filename is too long to fit in a QST header. Maximum length is 16 including file extension.\n");
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
const char *dat_base_filename = path_to_filename(dat_file);
|
||||
if (strlen(dat_base_filename) > 16) {
|
||||
if (strlen(dat_base_filename) > QUEST_FILENAME_MAX_LENGTH) {
|
||||
printf("Dat filename is too long to fit in a QST header. Maximum length is 16 including file extension.\n");
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
size_t bin_compressed_size, dat_compressed_size;
|
||||
|
||||
if (get_filesize(bin_file, &bin_compressed_size)) {
|
||||
printf("Error getting size of bin file: %s\n", bin_file);
|
||||
return 1;
|
||||
returncode = get_filesize(bin_file, &bin_compressed_size);
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) getting size of bin file: %s\n", returncode, get_error_message(returncode), bin_file);
|
||||
goto error;
|
||||
}
|
||||
if (get_filesize(dat_file, &dat_compressed_size)) {
|
||||
printf("Error getting size of dat file: %s\n", dat_file);
|
||||
return 1;
|
||||
returncode = get_filesize(dat_file, &dat_compressed_size);
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) getting size of dat file: %s\n", returncode, get_error_message(returncode), dat_file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
uint8_t *bin_data;
|
||||
|
||||
size_t bin_decompressed_size = prs_decompress_file(bin_file, &bin_data);
|
||||
if (bin_decompressed_size < 0) {
|
||||
printf("Error opening and decompressing bin file: %s\n", bin_file);
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
uint8_t *dat_data;
|
||||
size_t dat_decompressed_size = prs_decompress_file(dat_file, &dat_data);
|
||||
if (dat_decompressed_size < 0) {
|
||||
printf("Error opening and decompressing dat file: %s\n", dat_file);
|
||||
return 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
QUEST_BIN_HEADER *bin_header = (QUEST_BIN_HEADER*)bin_data;
|
||||
|
||||
sjis_to_utf8(bin_header->name, sizeof(bin_header->name));
|
||||
sjis_to_utf8(bin_header->short_description, sizeof(bin_header->short_description));
|
||||
sjis_to_utf8(bin_header->long_description, sizeof(bin_header->long_description));
|
||||
|
||||
if (bin_header->object_code_offset != 468) {
|
||||
printf("Quest bin file invalid (unexpected object_code_offset = %d).\n", bin_header->object_code_offset);
|
||||
return 1;
|
||||
}
|
||||
if (bin_header->bin_size != bin_decompressed_size) {
|
||||
printf("Quest bin file invalid (decompressed size does not match bin_size value: %d).\n", bin_header->bin_size);
|
||||
return 1;
|
||||
}
|
||||
if (strlen(bin_header->name) == 0) {
|
||||
printf("Quest bin file invalid or missing quest name.\n");
|
||||
return 1;
|
||||
}
|
||||
if (bin_header->quest_number == 0) {
|
||||
printf("Quest bin file invalid (quest_number is zero?).\n");
|
||||
return 1;
|
||||
validation_result = validate_quest_bin(bin_header, bin_decompressed_size, true);
|
||||
if (validation_result) {
|
||||
printf("Aborting due to invalid quest .bin data.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
printf("Quest: id=%d, language=0x%04x, name=%s\n", bin_header->quest_number, bin_header->language, bin_header->name);
|
||||
//sjis_to_utf8(bin_header->name, sizeof(bin_header->name));
|
||||
//sjis_to_utf8(bin_header->short_description, sizeof(bin_header->short_description));
|
||||
//sjis_to_utf8(bin_header->long_description, sizeof(bin_header->long_description));
|
||||
|
||||
printf("Quest: id=%d (%d), episode=%d, download=%d, unknown=0x%02x, name=\"%s\", compressed_bin_size=%ld, compressed_dat_size=%ld\n",
|
||||
bin_header->quest_number_byte,
|
||||
bin_header->quest_number_word,
|
||||
bin_header->episode+1,
|
||||
bin_header->download,
|
||||
bin_header->unknown,
|
||||
bin_header->name,
|
||||
bin_compressed_size,
|
||||
dat_compressed_size);
|
||||
|
||||
|
||||
QST_HEADER qst_bin_header, qst_dat_header;
|
||||
|
||||
generate_qst_header(bin_base_filename, bin_compressed_size, bin_header, &qst_bin_header);
|
||||
generate_qst_header(dat_base_filename, dat_compressed_size, bin_header, &qst_dat_header);
|
||||
|
||||
char *bin_hdr_file = append_string(bin_file, ".hdr");
|
||||
char *dat_hdr_file = append_string(dat_file, ".hdr");
|
||||
bin_hdr_file = append_string(bin_file, ".hdr");
|
||||
dat_hdr_file = append_string(dat_file, ".hdr");
|
||||
|
||||
if (write_qst_header(bin_hdr_file, &qst_bin_header)) {
|
||||
return 1;
|
||||
}
|
||||
if (write_qst_header(dat_hdr_file, &qst_dat_header)) {
|
||||
return 1;
|
||||
returncode = write_file(bin_hdr_file, &qst_bin_header, sizeof(QST_HEADER));
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) writing out bin header file: %s\n", returncode, get_error_message(returncode), bin_hdr_file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
returncode = write_file(dat_hdr_file, &qst_dat_header, sizeof(QST_HEADER));
|
||||
if (returncode) {
|
||||
printf("Error code %d (%s) writing out dat header file: %s\n", returncode, get_error_message(returncode), dat_hdr_file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
returncode = 0;
|
||||
goto quit;
|
||||
error:
|
||||
returncode = 1;
|
||||
quit:
|
||||
free(bin_hdr_file);
|
||||
free(dat_hdr_file);
|
||||
free(bin_data);
|
||||
free(dat_data);
|
||||
|
||||
return 0;
|
||||
return returncode;
|
||||
}
|
||||
|
|
12
quests.c
12
quests.c
|
@ -5,7 +5,7 @@
|
|||
#include "retvals.h"
|
||||
#include "quests.h"
|
||||
|
||||
int generate_qst_header(const char *src_file, size_t src_file_size, QUEST_BIN_HEADER *bin_header, QST_HEADER *out_header) {
|
||||
int generate_qst_header(const char *src_file, size_t src_file_size, const QUEST_BIN_HEADER *bin_header, QST_HEADER *out_header) {
|
||||
if (!src_file || !bin_header || !out_header)
|
||||
return ERROR_INVALID_PARAMS;
|
||||
|
||||
|
@ -39,7 +39,7 @@ int generate_qst_data_chunk(const char *base_filename, uint8_t counter, const ui
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
int validate_quest_bin(QUEST_BIN_HEADER *header, uint32_t length, bool print_errors) {
|
||||
int validate_quest_bin(const QUEST_BIN_HEADER *header, uint32_t length, bool print_errors) {
|
||||
int result = 0;
|
||||
|
||||
// TODO: validations might need tweaking ...
|
||||
|
@ -71,7 +71,7 @@ int validate_quest_bin(QUEST_BIN_HEADER *header, uint32_t length, bool print_err
|
|||
return result;
|
||||
}
|
||||
|
||||
int validate_quest_dat(uint8_t *data, uint32_t length, bool print_errors) {
|
||||
int validate_quest_dat(const uint8_t *data, uint32_t length, bool print_errors) {
|
||||
int result = 0;
|
||||
int table_index = 0;
|
||||
|
||||
|
@ -92,15 +92,15 @@ int validate_quest_dat(uint8_t *data, uint32_t length, bool print_errors) {
|
|||
// all zeros seems to be used to indicate end of file ???
|
||||
if ((offset + sizeof(QUEST_DAT_TABLE_HEADER)) == length) {
|
||||
if (print_errors)
|
||||
printf("Quest dat file issue: empty table encountered at end of file\n");
|
||||
printf("Quest dat file warning: empty table encountered at end of file (probably normal?)\n");
|
||||
result |= QUESTDAT_ERROR_EOF_EMPTY_TABLE;
|
||||
} else {
|
||||
if (print_errors)
|
||||
printf("Quest dat file issue: empty table encountered at table index %d\n", table_index);
|
||||
printf("Quest dat file warning: empty table encountered at table index %d\n", table_index);
|
||||
result |= QUESTDAT_ERROR_EMPTY_TABLE;
|
||||
}
|
||||
|
||||
} else if (table_header->table_size == (table_header->table_body_size - 16)) {
|
||||
} else if (table_header->table_size == (table_header->table_body_size - sizeof(QUEST_DAT_TABLE_HEADER))) {
|
||||
if (print_errors)
|
||||
printf("Quest dat file issue: mismatching table_size (%d) and table_body_size (%d) found in table index %d\n",
|
||||
table_header->table_size,
|
||||
|
|
25
quests.h
25
quests.h
|
@ -23,13 +23,15 @@
|
|||
#define PACKET_ID_QUEST_CHUNK_ONLINE 0x13
|
||||
#define PACKET_ID_QUEST_CHUNK_DOWNLOAD 0xa7
|
||||
|
||||
// quest .bin file header (after file contents have been prs-decompressed)
|
||||
#define QUEST_FILENAME_MAX_LENGTH 16
|
||||
|
||||
// decompressed quest .bin file header
|
||||
typedef struct _PACKED_ {
|
||||
uint32_t object_code_offset;
|
||||
uint32_t function_offset_table_offset;
|
||||
uint32_t bin_size;
|
||||
uint32_t xffffffff; // always 0xffffffff ?
|
||||
uint8_t download;
|
||||
uint32_t xffffffff; // always 0xffffffff ?
|
||||
uint8_t download; // must be '1' to be usable as an offline quest (played from memory card)
|
||||
|
||||
// have seen some projects define this field as language. "newserv" just calls it unknown? i've seen multiple
|
||||
// values present for english language quests ...
|
||||
|
@ -58,6 +60,7 @@ typedef struct _PACKED_ {
|
|||
char long_description[288];
|
||||
} QUEST_BIN_HEADER;
|
||||
|
||||
// decompressed quest .dat file table header
|
||||
typedef struct _PACKED_ {
|
||||
uint32_t type;
|
||||
uint32_t table_size;
|
||||
|
@ -65,7 +68,7 @@ typedef struct _PACKED_ {
|
|||
uint32_t table_body_size;
|
||||
} QUEST_DAT_TABLE_HEADER;
|
||||
|
||||
// .qst file header, for either the embedded bin or dat quest data
|
||||
// .qst file header, for either the embedded bin or dat quest data (there should be two of these per .qst file).
|
||||
typedef struct _PACKED_ {
|
||||
// 0xA6 = download to memcard, 0x44 = download for online play
|
||||
// (quest file data chunks must then be encoded accordingly. 0xA6 = use 0xA7, and 0x44 = use 0x13)
|
||||
|
@ -87,27 +90,31 @@ typedef struct _PACKED_ {
|
|||
// ... and so, this value is also probably unimportant?
|
||||
uint16_t flags;
|
||||
|
||||
char filename[16];
|
||||
char filename[QUEST_FILENAME_MAX_LENGTH];
|
||||
uint32_t size;
|
||||
} QST_HEADER;
|
||||
|
||||
// .qst raw .bin/.dat file data packet. the original .bin/.dat file data is broken down into as many of these structs
|
||||
// as is necessary to fit into the resulting .qst file
|
||||
typedef struct _PACKED_ {
|
||||
uint8_t pkt_id;
|
||||
uint8_t pkt_flags;
|
||||
uint16_t pkt_size;
|
||||
char filename[16];
|
||||
char filename[QUEST_FILENAME_MAX_LENGTH];
|
||||
uint8_t data[1024];
|
||||
uint32_t size;
|
||||
} QST_DATA_CHUNK;
|
||||
|
||||
// for download/offline .qst files only. the raw .bin/.dat file data needs to be prefixed with one of these structs
|
||||
// before being turned into QST_DATA_CHUNKs. only one of these is needed per each .bin/.dat file.
|
||||
typedef struct _PACKED_ {
|
||||
uint32_t decompressed_size;
|
||||
uint32_t crypt_key;
|
||||
} DOWNLOAD_QUEST_CHUNKS_HEADER;
|
||||
|
||||
int generate_qst_header(const char *src_file, size_t src_file_size, QUEST_BIN_HEADER *bin_header, QST_HEADER *out_header);
|
||||
int generate_qst_header(const char *src_file, size_t src_file_size, const QUEST_BIN_HEADER *bin_header, QST_HEADER *out_header);
|
||||
int generate_qst_data_chunk(const char *base_filename, uint8_t counter, const uint8_t *src, uint32_t size, QST_DATA_CHUNK *out_chunk);
|
||||
int validate_quest_bin(QUEST_BIN_HEADER *header, uint32_t length, bool print_errors);
|
||||
int validate_quest_dat(uint8_t *data, uint32_t length, bool print_errors);
|
||||
int validate_quest_bin(const QUEST_BIN_HEADER *header, uint32_t length, bool print_errors);
|
||||
int validate_quest_dat(const uint8_t *data, uint32_t length, bool print_errors);
|
||||
|
||||
#endif
|
||||
|
|
2
utils.c
2
utils.c
|
@ -49,7 +49,7 @@ int read_file(const char *filename, uint8_t** out_file_data, uint32_t *out_file_
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
int write_file(const char *filename, const uint8_t *data, size_t size) {
|
||||
int write_file(const char *filename, const void *data, size_t size) {
|
||||
if (!filename || !data || size == 0)
|
||||
return ERROR_INVALID_PARAMS;
|
||||
|
||||
|
|
2
utils.h
2
utils.h
|
@ -6,7 +6,7 @@
|
|||
#include "retvals.h"
|
||||
|
||||
int read_file(const char *filename, uint8_t** out_file_data, uint32_t *out_file_size);
|
||||
int write_file(const char *filename, const uint8_t *data, size_t size);
|
||||
int write_file(const char *filename, const void *data, size_t size);
|
||||
int get_filesize(const char *filename, size_t *out_size);
|
||||
const char* path_to_filename(const char *path);
|
||||
char* append_string(const char *a, const char *b);
|
||||
|
|
Loading…
Reference in a new issue