diff --git a/src/text/libs/dir_utils.c b/src/text/libs/io_utils.c similarity index 50% rename from src/text/libs/dir_utils.c rename to src/text/libs/io_utils.c index 3b45d700..b6d5ee5d 100644 --- a/src/text/libs/dir_utils.c +++ b/src/text/libs/io_utils.c @@ -2,7 +2,9 @@ #include #include #include -#include "dir_utils.h" +#include "io_utils.h" + +#define _READFILE_GUESS 256 void combine(char* destination, const char* path1, const char* path2) { if(path1 == NULL || path2 == NULL) { @@ -31,4 +33,45 @@ void combine(char* destination, const char* path1, const char* path2) { strcat(destination, directory_separator); strcat(destination, path2); } +} + +const char *get_filename_ext(const char *filename) { + const char *dot = strrchr(filename, '.'); + if(!dot || dot == filename) return ""; + return dot + 1; +} + +char* read_file(char* name){ + FILE* file; + file = fopen(name, "r"); + + if(!file) + return NULL; + + char* result = malloc(sizeof(char) * _READFILE_GUESS + 1); + + if(result == NULL) + return NULL; + + size_t pos = 0; + size_t capacity = _READFILE_GUESS; + char ch; + + while((ch = getc(file)) != EOF){ + result[pos++] = ch; + + if(pos >= capacity){ + capacity += _READFILE_GUESS; + result = realloc(result, sizeof(char) * capacity + 1); + if(result == NULL) + return NULL; + } + } + fclose(file); + result = realloc(result, sizeof(char) * pos); + if(result == NULL) + return NULL; + result[pos] = '\0'; + + return result; } \ No newline at end of file diff --git a/src/text/libs/dir_utils.h b/src/text/libs/io_utils.h similarity index 63% rename from src/text/libs/dir_utils.h rename to src/text/libs/io_utils.h index db0d1be9..835e4141 100644 --- a/src/text/libs/dir_utils.h +++ b/src/text/libs/io_utils.h @@ -2,5 +2,5 @@ #define DIRUTILS extern void combine(char* destination, const char* path1, const char* path2); - +extern const char *get_filename_ext(const char *filename); #endif \ No newline at end of file diff --git a/src/text/text-loader.c b/src/text/text-loader.c index 9c1ab825..e85d427d 100644 --- a/src/text/text-loader.c +++ b/src/text/text-loader.c @@ -1,87 +1,51 @@ #include "text-loader.h" #include "txtconv.h" -#include "libs/cJSON.h" #include #include #include "dialog_ids.h" -#include "game/ingame_menu.h" #include -#include "libs/dir_utils.h" +#include "libs/io_utils.h" #include +#include +#include "libs/cJSON.h" + struct DialogEntry* * dialogPool; -#define _READFILE_GUESS 256 +struct LanguageEntry* * languages; +s8 languagesAmount = 0; -#define SPANISH "./res/texts/es.json" -#define ENGLISH "./res/texts/us.json" +char* currentLanguage = "english"; -char* read_file(char* name){ - FILE* file; - file = fopen(name, "r"); - - if(!file) - return NULL; - - char* result = malloc(sizeof(char) * _READFILE_GUESS + 1); - - if(result == NULL) - return NULL; - - size_t pos = 0; - size_t capacity = _READFILE_GUESS; - char ch; - - while((ch = getc(file)) != EOF){ - result[pos++] = ch; - - if(pos >= capacity){ - capacity += _READFILE_GUESS; - result = realloc(result, sizeof(char) * capacity + 1); - if(result == NULL) - return NULL; - } - } - fclose(file); - result = realloc(result, sizeof(char) * pos); - if(result == NULL) - return NULL; - result[pos] = '\0'; - - return result; -} - -void preloadTexts(){ - - char * file = SPANISH; - - #ifndef WIN32 - char * language_file = realpath(file, NULL); - #else - char * language_file = malloc(_MAX_PATH * sizeof(char)); - _fullpath(language_file, file, _MAX_PATH ); - #endif - - printf("Loading File: %s\n", language_file); - - char * jsonTxt = read_file(language_file); +void preloadLanguageText(char* jsonTxt, s8 language){ + languages[language] = malloc (sizeof (struct LanguageEntry)); cJSON *json = cJSON_Parse(jsonTxt); + if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { fprintf(stderr, "Error before: %s\n", error_ptr); - }else{ + } else { fprintf(stderr, "Error loading the JSON file\n"); } exit(1); } + const cJSON *dialog = NULL; const cJSON *dialogs = NULL; + const cJSON *manifest = cJSON_GetObjectItemCaseSensitive(json, "manifest"); + + struct DialogEntry** entries = malloc(DIALOG_COUNT * sizeof(struct DialogEntry)); + + languages[language]->name = cJSON_GetObjectItemCaseSensitive(manifest, "languageName")->valuestring; + languages[language]->logo = cJSON_GetObjectItemCaseSensitive(manifest, "languageLogo")->valuestring; + languages[language]->placeholder = cJSON_GetObjectItemCaseSensitive(manifest, "placeholder")->valuestring; dialogs = cJSON_GetObjectItemCaseSensitive(json, "dialogs"); + int eid = 0; cJSON_ArrayForEach(dialog, dialogs) { - int id = cJSON_GetObjectItemCaseSensitive(dialog, "ID")->valueint; + int id = cJSON_GetObjectItemCaseSensitive(dialog, "ID")->valueint; struct DialogEntry *entry = malloc (sizeof (struct DialogEntry)); @@ -108,17 +72,79 @@ void preloadTexts(){ } } - entry->str = getTranslatedText(dialogTxt); - dialogPool[id] = entry; + entry->str = getTranslatedText(dialogTxt); + entries[eid] = entry; + eid++; free(dialogTxt); } + + languages[language]->entries = entries; cJSON_Delete(json); } -void alloc_dialog_pool(void){ - dialogPool = malloc(DIALOG_COUNT * sizeof(struct DialogEntry)); +void alloc_languages(void){ + languages = realloc(languages, sizeof(struct LanguageEntry*) * 30); + char * languagesDir = "./res/texts/"; + DIR *lf = opendir(languagesDir); + struct dirent *de; + while ((de = readdir(lf)) != NULL){ + const char* extension = get_filename_ext(de->d_name); + char * file = malloc(99 * sizeof(char*)); + if(strcmp(extension, "json") == 0){ + strcpy(file, ""); + strcat(file, "./res/texts/"); + strcat(file, de->d_name); + + #ifndef WIN32 + char * language_file = realpath(file, NULL); + #else + char * language_file = malloc(_MAX_PATH * sizeof(char)); + _fullpath(language_file, file, _MAX_PATH ); + #endif + + printf("Loading File: %s\n", language_file); + languagesAmount++; + + char * jsonTxt = read_file(language_file); + preloadLanguageText(jsonTxt, languagesAmount - 1); + } + } + + languages = realloc(languages, sizeof(struct LanguageEntry*) * (languagesAmount)); +} + +void selectLanguage(char* languageName){ + + char* lowerName = malloc(sizeof(languageName)); + for(char l = 0; l < sizeof(lowerName) / sizeof(char); l++) + lowerName[l] = tolower(languageName[l]); + + int id = 0; + char* languageTmp = "none"; + + for(int l = 0; l < languagesAmount; l++){ + if(strcmp(languages[l]->name, lowerName) == 0){ + id = l; + languageTmp = languages[l]->name; + break; + } + } + + currentLanguage = languageTmp; + dialogPool = languages[id]->entries; +} + +void alloc_dialog_pool(void){ + languages = malloc(sizeof(struct LanguageEntry*)); + + languages[0] = malloc (sizeof (struct LanguageEntry)); + languages[0]->name = "none"; + languages[0]->logo = "none"; + languages[0]->placeholder = "You are not supposed\nto be here.\n\nKeep this as a secret\n\n- Render96 Team"; + languages[0]->entries = malloc(DIALOG_COUNT * sizeof(struct DialogEntry)); + for(int i = 0; i < DIALOG_COUNT; i++){ struct DialogEntry *entry = malloc (sizeof (struct DialogEntry)); @@ -126,9 +152,11 @@ void alloc_dialog_pool(void){ entry->linesPerBox = 6; entry->leftOffset = 95; entry->width = 200; - entry->str = getTranslatedText("You are not supposed\nto be here.\n\nKeep this as a secret\n\n- Render96 Team"); - dialogPool[i] = entry; - } + entry->str = getTranslatedText(languages[0]->placeholder); - preloadTexts(); + languages[0]->entries[i] = entry; + } + + alloc_languages(); + selectLanguage(currentLanguage); } diff --git a/src/text/text-loader.h b/src/text/text-loader.h index a21a5dff..b078b03c 100644 --- a/src/text/text-loader.h +++ b/src/text/text-loader.h @@ -2,8 +2,20 @@ #define TXTLOADER #include "types.h" +#include "game/ingame_menu.h" + +extern char* currentLanguage; +extern s8 languagesAmount; extern struct DialogEntry ** dialogPool; +extern char* read_file(char* name); + +struct LanguageEntry { + char * name; + char * logo; + char * placeholder; + struct DialogEntry* * entries; +}; extern void alloc_dialog_pool(void); #endif \ No newline at end of file diff --git a/texts/es.json b/texts/es.json index eea01112..82edce3a 100644 --- a/texts/es.json +++ b/texts/es.json @@ -1,4 +1,9 @@ { + "manifest": { + "languageName": "Spanish", + "languageLogo": "none", + "placeholder": "You are not supposed\nto be here.\n\nKeep this as a secret\n\n- Render96 Team" + }, "dialogs": [ { "ID": 0, diff --git a/texts/us.json b/texts/us.json index 3b34d8ee..c0df63c1 100644 --- a/texts/us.json +++ b/texts/us.json @@ -1,4 +1,9 @@ -{ +{ + "manifest": { + "languageName": "English", + "languageLogo": "none", + "placeholder": "You are not supposed\nto be here.\n\nKeep this as a secret\n\n- Render96 Team" + }, "dialogs": [ { "ID": 0, diff --git a/tools/calc_bss.sh b/tools/calc_bss.sh deleted file mode 100755 index 4c1650d0..00000000 --- a/tools/calc_bss.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# Given a list of header files, compute the bss index that results from -# including them. (See prevent_bss_reordering.h for more information.) - -TEMPC=$(mktemp -t bss.XXXXXXX.c) -TEMPO=$(mktemp -t bss.XXXXXXX.o) -trap "rm -f $TEMPC $TEMPO" EXIT - -set -e - -if [[ $# = 0 ]]; then - echo "Usage: ./tools/calc_bss.sh file1.h file2.h ..." >&2 - exit 1 -fi - -if [ -z "$CROSS" ]; then - CROSS=mips-linux-gnu- -fi - -# bss indexing starts at 3 -for I in {3..255}; do - echo "char bss$I;" >> $TEMPC -done -for I in {0..2}; do - echo "char bss$I;" >> $TEMPC -done - -while [[ $# -gt 0 ]]; do - echo "#include \"$1\"" >> $TEMPC - shift -done - -echo "char measurement;" >> $TEMPC - -LINE=$(${CROSS}objdump -t $TEMPO | grep measurement | cut -d' ' -f1) -NUM=$((0x$LINE - 1)) -echo "bss index: $NUM" diff --git a/tools/libmio0.c b/tools/libmio0.c deleted file mode 100644 index 2c7a493f..00000000 --- a/tools/libmio0.c +++ /dev/null @@ -1,575 +0,0 @@ -#include -#include -#include -#if defined(_WIN32) || defined(_WIN64) -#include -#include -#endif - -#include "libmio0.h" -#include "utils.h" - -// defines - -#define MIO0_VERSION "0.1" - -#define GET_BIT(buf, bit) ((buf)[(bit) / 8] & (1 << (7 - ((bit) % 8)))) - -// types -typedef struct -{ - int *indexes; - int allocated; - int count; - int start; -} lookback; - -// functions -#define LOOKBACK_COUNT 256 -#define LOOKBACK_INIT_SIZE 128 -static lookback *lookback_init(void) -{ - lookback *lb = malloc(LOOKBACK_COUNT * sizeof(*lb)); - for (int i = 0; i < LOOKBACK_COUNT; i++) { - lb[i].allocated = LOOKBACK_INIT_SIZE; - lb[i].indexes = malloc(lb[i].allocated * sizeof(*lb[i].indexes)); - lb[i].count = 0; - lb[i].start = 0; - } - return lb; -} - -static void lookback_free(lookback *lb) -{ - for (int i = 0; i < LOOKBACK_COUNT; i++) { - free(lb[i].indexes); - } - free(lb); -} - -static inline void lookback_push(lookback *lkbk, unsigned char val, int index) -{ - lookback *lb = &lkbk[val]; - if (lb->count == lb->allocated) { - lb->allocated *= 4; - lb->indexes = realloc(lb->indexes, lb->allocated * sizeof(*lb->indexes)); - } - lb->indexes[lb->count++] = index; -} - -static void PUT_BIT(unsigned char *buf, int bit, int val) -{ - unsigned char mask = 1 << (7 - (bit % 8)); - unsigned int offset = bit / 8; - buf[offset] = (buf[offset] & ~(mask)) | (val ? mask : 0); -} - -// used to find longest matching stream in buffer -// buf: buffer -// start_offset: offset in buf to look back from -// max_search: max number of bytes to find -// found_offset: returned offset found (0 if none found) -// returns max length of matching stream (0 if none found) -static int find_longest(const unsigned char *buf, int start_offset, int max_search, int *found_offset, lookback *lkbk) -{ - int best_length = 0; - int best_offset = 0; - int cur_length; - int search_len; - int farthest, off, i; - int lb_idx; - const unsigned char first = buf[start_offset]; - lookback *lb = &lkbk[first]; - - // buf - // | off start max - // V |+i-> |+i-> | - // |--------------raw-data-----------------| - // |+i-> | |+i-> - // +cur_length - - // check at most the past 4096 values - farthest = MAX(start_offset - 4096, 0); - // find starting index - for (lb_idx = lb->start; lb_idx < lb->count && lb->indexes[lb_idx] < farthest; lb_idx++) {} - lb->start = lb_idx; - for ( ; lb_idx < lb->count && lb->indexes[lb_idx] < start_offset; lb_idx++) { - off = lb->indexes[lb_idx]; - // check at most requested max or up until start - search_len = MIN(max_search, start_offset - off); - for (i = 0; i < search_len; i++) { - if (buf[start_offset + i] != buf[off + i]) { - break; - } - } - cur_length = i; - // if matched up until start, continue matching in already matched parts - if (cur_length == search_len) { - // check at most requested max less current length - search_len = max_search - cur_length; - for (i = 0; i < search_len; i++) { - if (buf[start_offset + cur_length + i] != buf[off + i]) { - break; - } - } - cur_length += i; - } - if (cur_length > best_length) { - best_offset = start_offset - off; - best_length = cur_length; - } - } - - // return best reverse offset and length (may be 0) - *found_offset = best_offset; - return best_length; -} - -// decode MIO0 header -// returns 1 if valid header, 0 otherwise -int mio0_decode_header(const unsigned char *buf, mio0_header_t *head) -{ - if (!memcmp(buf, "MIO0", 4)) { - head->dest_size = read_u32_be(&buf[4]); - head->comp_offset = read_u32_be(&buf[8]); - head->uncomp_offset = read_u32_be(&buf[12]); - return 1; - } - return 0; -} - -void mio0_encode_header(unsigned char *buf, const mio0_header_t *head) -{ - memcpy(buf, "MIO0", 4); - write_u32_be(&buf[4], head->dest_size); - write_u32_be(&buf[8], head->comp_offset); - write_u32_be(&buf[12], head->uncomp_offset); -} - -int mio0_decode(const unsigned char *in, unsigned char *out, unsigned int *end) -{ - mio0_header_t head; - unsigned int bytes_written = 0; - int bit_idx = 0; - int comp_idx = 0; - int uncomp_idx = 0; - int valid; - - // extract header - valid = mio0_decode_header(in, &head); - // verify MIO0 header - if (!valid) { - return -2; - } - - // decode data - while (bytes_written < head.dest_size) { - if (GET_BIT(&in[MIO0_HEADER_LENGTH], bit_idx)) { - // 1 - pull uncompressed data - out[bytes_written] = in[head.uncomp_offset + uncomp_idx]; - bytes_written++; - uncomp_idx++; - } else { - // 0 - read compressed data - int idx; - int length; - int i; - const unsigned char *vals = &in[head.comp_offset + comp_idx]; - comp_idx += 2; - length = ((vals[0] & 0xF0) >> 4) + 3; - idx = ((vals[0] & 0x0F) << 8) + vals[1] + 1; - for (i = 0; i < length; i++) { - out[bytes_written] = out[bytes_written - idx]; - bytes_written++; - } - } - bit_idx++; - } - - if (end) { - *end = head.uncomp_offset + uncomp_idx; - } - - return bytes_written; -} - -int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out) -{ - unsigned char *bit_buf; - unsigned char *comp_buf; - unsigned char *uncomp_buf; - unsigned int bit_length; - unsigned int comp_offset; - unsigned int uncomp_offset; - unsigned int bytes_proc = 0; - int bytes_written; - int bit_idx = 0; - int comp_idx = 0; - int uncomp_idx = 0; - lookback *lookbacks; - - // initialize lookback buffer - lookbacks = lookback_init(); - - // allocate some temporary buffers worst case size - bit_buf = malloc((length + 7) / 8); // 1-bit/byte - comp_buf = malloc(length); // 16-bits/2bytes - uncomp_buf = malloc(length); // all uncompressed - memset(bit_buf, 0, (length + 7) / 8); - - // encode data - // special case for first byte - lookback_push(lookbacks, in[0], 0); - uncomp_buf[uncomp_idx] = in[0]; - uncomp_idx += 1; - bytes_proc += 1; - PUT_BIT(bit_buf, bit_idx++, 1); - while (bytes_proc < length) { - int offset; - int max_length = MIN(length - bytes_proc, 18); - int longest_match = find_longest(in, bytes_proc, max_length, &offset, lookbacks); - // push current byte before checking next longer match - lookback_push(lookbacks, in[bytes_proc], bytes_proc); - if (longest_match > 2) { - int lookahead_offset; - // lookahead to next byte to see if longer match - int lookahead_length = MIN(length - bytes_proc - 1, 18); - int lookahead_match = find_longest(in, bytes_proc + 1, lookahead_length, &lookahead_offset, lookbacks); - // better match found, use uncompressed + lookahead compressed - if ((longest_match + 1) < lookahead_match) { - // uncompressed byte - uncomp_buf[uncomp_idx] = in[bytes_proc]; - uncomp_idx++; - PUT_BIT(bit_buf, bit_idx, 1); - bytes_proc++; - longest_match = lookahead_match; - offset = lookahead_offset; - bit_idx++; - lookback_push(lookbacks, in[bytes_proc], bytes_proc); - } - // first byte already pushed above - for (int i = 1; i < longest_match; i++) { - lookback_push(lookbacks, in[bytes_proc + i], bytes_proc + i); - } - // compressed block - comp_buf[comp_idx] = (((longest_match - 3) & 0x0F) << 4) | - (((offset - 1) >> 8) & 0x0F); - comp_buf[comp_idx + 1] = (offset - 1) & 0xFF; - comp_idx += 2; - PUT_BIT(bit_buf, bit_idx, 0); - bytes_proc += longest_match; - } else { - // uncompressed byte - uncomp_buf[uncomp_idx] = in[bytes_proc]; - uncomp_idx++; - PUT_BIT(bit_buf, bit_idx, 1); - bytes_proc++; - } - bit_idx++; - } - - // compute final sizes and offsets - // +7 so int division accounts for all bits - bit_length = ((bit_idx + 7) / 8); - // compressed data after control bits and aligned to 4-byte boundary - comp_offset = ALIGN(MIO0_HEADER_LENGTH + bit_length, 4); - uncomp_offset = comp_offset + comp_idx; - bytes_written = uncomp_offset + uncomp_idx; - - // output header - memcpy(out, "MIO0", 4); - write_u32_be(&out[4], length); - write_u32_be(&out[8], comp_offset); - write_u32_be(&out[12], uncomp_offset); - // output data - memcpy(&out[MIO0_HEADER_LENGTH], bit_buf, bit_length); - memcpy(&out[comp_offset], comp_buf, comp_idx); - memcpy(&out[uncomp_offset], uncomp_buf, uncomp_idx); - - // free allocated buffers - free(bit_buf); - free(comp_buf); - free(uncomp_buf); - lookback_free(lookbacks); - - return bytes_written; -} - -static FILE *mio0_open_out_file(const char *out_file) { - if (strcmp(out_file, "-") == 0) { -#if defined(_WIN32) || defined(_WIN64) - _setmode(_fileno(stdout), _O_BINARY); -#endif - return stdout; - } else { - return fopen(out_file, "wb"); - } -} - -int mio0_decode_file(const char *in_file, unsigned long offset, const char *out_file) -{ - mio0_header_t head; - FILE *in; - FILE *out; - unsigned char *in_buf = NULL; - unsigned char *out_buf = NULL; - long file_size; - int ret_val = 0; - size_t bytes_read; - int bytes_decoded; - int bytes_written; - int valid; - - in = fopen(in_file, "rb"); - if (in == NULL) { - return 1; - } - - // allocate buffer to read from offset to end of file - fseek(in, 0, SEEK_END); - file_size = ftell(in); - in_buf = malloc(file_size - offset); - fseek(in, offset, SEEK_SET); - - // read bytes - bytes_read = fread(in_buf, 1, file_size - offset, in); - if (bytes_read != file_size - offset) { - ret_val = 2; - goto free_all; - } - - // verify header - valid = mio0_decode_header(in_buf, &head); - if (!valid) { - ret_val = 3; - goto free_all; - } - out_buf = malloc(head.dest_size); - - // decompress MIO0 encoded data - bytes_decoded = mio0_decode(in_buf, out_buf, NULL); - if (bytes_decoded < 0) { - ret_val = 3; - goto free_all; - } - - // open output file - out = mio0_open_out_file(out_file); - if (out == NULL) { - ret_val = 4; - goto free_all; - } - - // write data to file - bytes_written = fwrite(out_buf, 1, bytes_decoded, out); - if (bytes_written != bytes_decoded) { - ret_val = 5; - } - - // clean up - if (out != stdout) { - fclose(out); - } -free_all: - if (out_buf) { - free(out_buf); - } - if (in_buf) { - free(in_buf); - } - fclose(in); - - return ret_val; -} - -int mio0_encode_file(const char *in_file, const char *out_file) -{ - FILE *in; - FILE *out; - unsigned char *in_buf = NULL; - unsigned char *out_buf = NULL; - size_t file_size; - size_t bytes_read; - int bytes_encoded; - int bytes_written; - int ret_val = 0; - - in = fopen(in_file, "rb"); - if (in == NULL) { - return 1; - } - - // allocate buffer to read entire contents of files - fseek(in, 0, SEEK_END); - file_size = ftell(in); - fseek(in, 0, SEEK_SET); - in_buf = malloc(file_size); - - // read bytes - bytes_read = fread(in_buf, 1, file_size, in); - if (bytes_read != file_size) { - ret_val = 2; - goto free_all; - } - - // allocate worst case length - out_buf = malloc(MIO0_HEADER_LENGTH + ((file_size+7)/8) + file_size); - - // compress data in MIO0 format - bytes_encoded = mio0_encode(in_buf, file_size, out_buf); - - // open output file - out = mio0_open_out_file(out_file); - if (out == NULL) { - ret_val = 4; - goto free_all; - } - - // write data to file - bytes_written = fwrite(out_buf, 1, bytes_encoded, out); - if (bytes_written != bytes_encoded) { - ret_val = 5; - } - - // clean up - if (out != stdout) { - fclose(out); - } -free_all: - if (out_buf) { - free(out_buf); - } - if (in_buf) { - free(in_buf); - } - fclose(in); - - return ret_val; -} - -// mio0 standalone executable -#ifdef MIO0_STANDALONE -typedef struct -{ - char *in_filename; - char *out_filename; - unsigned int offset; - int compress; -} arg_config; - -static arg_config default_config = -{ - NULL, - NULL, - 0, - 1 -}; - -static void print_usage(void) -{ - ERROR("Usage: mio0 [-c / -d] [-o OFFSET] FILE [OUTPUT]\n" - "\n" - "mio0 v" MIO0_VERSION ": MIO0 compression and decompression tool\n" - "\n" - "Optional arguments:\n" - " -c compress raw data into MIO0 (default: compress)\n" - " -d decompress MIO0 into raw data\n" - " -o OFFSET starting offset in FILE (default: 0)\n" - "\n" - "File arguments:\n" - " FILE input file\n" - " [OUTPUT] output file (default: FILE.out), \"-\" for stdout\n"); - exit(1); -} - -// parse command line arguments -static void parse_arguments(int argc, char *argv[], arg_config *config) -{ - int i; - int file_count = 0; - if (argc < 2) { - print_usage(); - exit(1); - } - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] != '\0') { - switch (argv[i][1]) { - case 'c': - config->compress = 1; - break; - case 'd': - config->compress = 0; - break; - case 'o': - if (++i >= argc) { - print_usage(); - } - config->offset = strtoul(argv[i], NULL, 0); - break; - default: - print_usage(); - break; - } - } else { - switch (file_count) { - case 0: - config->in_filename = argv[i]; - break; - case 1: - config->out_filename = argv[i]; - break; - default: // too many - print_usage(); - break; - } - file_count++; - } - } - if (file_count < 1) { - print_usage(); - } -} - -int main(int argc, char *argv[]) -{ - char out_filename[FILENAME_MAX]; - arg_config config; - int ret_val; - - // get configuration from arguments - config = default_config; - parse_arguments(argc, argv, &config); - if (config.out_filename == NULL) { - config.out_filename = out_filename; - sprintf(config.out_filename, "%s.out", config.in_filename); - } - - // operation - if (config.compress) { - ret_val = mio0_encode_file(config.in_filename, config.out_filename); - } else { - ret_val = mio0_decode_file(config.in_filename, config.offset, config.out_filename); - } - - switch (ret_val) { - case 1: - ERROR("Error opening input file \"%s\"\n", config.in_filename); - break; - case 2: - ERROR("Error reading from input file \"%s\"\n", config.in_filename); - break; - case 3: - ERROR("Error decoding MIO0 data. Wrong offset (0x%X)?\n", config.offset); - break; - case 4: - ERROR("Error opening output file \"%s\"\n", config.out_filename); - break; - case 5: - ERROR("Error writing bytes to output file \"%s\"\n", config.out_filename); - break; - } - - return ret_val; -} -#endif // MIO0_STANDALONE - diff --git a/tools/libmio0.h b/tools/libmio0.h deleted file mode 100644 index 5b38ac77..00000000 --- a/tools/libmio0.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef LIBMIO0_H_ -#define LIBMIO0_H_ - -// defines - -#define MIO0_HEADER_LENGTH 16 - -// typedefs - -typedef struct -{ - unsigned int dest_size; - unsigned int comp_offset; - unsigned int uncomp_offset; -} mio0_header_t; - -// function prototypes - -// decode MIO0 header -// returns 1 if valid header, 0 otherwise -int mio0_decode_header(const unsigned char *buf, mio0_header_t *head); - -// encode MIO0 header from struct -void mio0_encode_header(unsigned char *buf, const mio0_header_t *head); - -// decode MIO0 data in memory -// in: buffer containing MIO0 data -// out: buffer for output data -// end: output offset of the last byte decoded from in (set to NULL if unwanted) -// returns bytes extracted to 'out' or negative value on failure -int mio0_decode(const unsigned char *in, unsigned char *out, unsigned int *end); - -// encode MIO0 data in memory -// in: buffer containing raw data -// out: buffer for MIO0 data -// returns size of compressed data in 'out' including MIO0 header -int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out); - -// decode an entire MIO0 block at an offset from file to output file -// in_file: input filename -// offset: offset to start decoding from in_file -// out_file: output filename -int mio0_decode_file(const char *in_file, unsigned long offset, const char *out_file); - -// encode an entire file -// in_file: input filename containing raw data to be encoded -// out_file: output filename to write MIO0 compressed data to -int mio0_encode_file(const char *in_file, const char *out_file); - -#endif // LIBMIO0_H_ diff --git a/tools/patch_libmalloc.py b/tools/patch_libmalloc.py deleted file mode 100755 index 582504bf..00000000 --- a/tools/patch_libmalloc.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -# Patches the malloc() function in libmalloc.so to allocate more than the -# specified number of bytes. This is needed to work around issues with the -# compiler occasionally crashing. -# -# This script replaces the "move a1, a0" (00 80 28 25) instruction with -# "addiu a1, a0, n" (24 85 nn nn), which causes the malloc function to add n to -# the size parameter that was passed in. - -import hashlib -import os.path -import sys - -# file to patch -filename = 'tools/ido5.3_compiler/lib/libmalloc.so' -# Expected (unpatched) hash of file -filehash = 'adde672b5d79b52ca3cce9a47c7cb648' -# location in file to patch -address = 0xAB4 - -# Get parameter -if len(sys.argv) != 2: - print('Usage: ' + sys.argv[0] + ' n\n where n is the number of extra bytes to allocate in malloc()') - exit(1) -n = int(sys.argv[1]) - -# Original instruction "move a1, a0" -oldinsn = bytearray([0x00, 0x80, 0x28, 0x25]) - -# New instruction "addiu a1, a0, n" -newinsn = bytearray([0x24, 0x85, (n >> 8) & 0xFF, (n & 0xFF)]) - -# Patch the file -try: - with open(filename, 'rb+') as f: - # Read file contents - contents = bytearray(f.read()) - - # Unpatch the file by restoring original instruction - contents[address:address+4] = oldinsn - - # Verify the (unpatched) hash of the file - md5 = hashlib.md5() - md5.update(contents) - if md5.hexdigest() != filehash: - print('Error: ' + filename + ' does not appear to be the correct version.') - exit(1) - - # Patch the file - if n != 0: - contents[address:address+4] = newinsn - - # Write file - f.seek(0, os.SEEK_SET) - f.write(contents) -except IOError as e: - print('Error: Could not open library file for writing: ' + str(e))