123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- // C source file with the function definitions to handle J3DGRAPH files
- // check_j3dgraph_fstart() function
- // check the first 4 bytes of a j3dgraph file to see if it is valid
- bool check_j3dgraph_fstart(char * fpath)
- {
- // check params
- byte * ptr = NULL;
- bool rtn = false;
- if (fpath == NULL)
- goto end;
-
- // array for the bytes
- ptr = get_fbytes(fpath, 0, 4);
- if (ptr == NULL)
- goto end;
-
- // compare the array with J3DGRAPH_FSTART
- for (byte i = 0; i < 2; i++)
- for (byte j = 0; j < 2; j++)
- rtn = rtn || comp_bytes(ptr, J3DGRAPH_FSTART[i][j], 4);
-
- // return the result, free memory used
- end:
- free_memory(ptr);
- return rtn;
- }
- // get_j3dgraph_fendian() function
- // function to determine the endian mode of a j3dgraph file
- ENDIAN_T get_j3dgraph_fendian(char * fpath)
- {
- // check params
- ENDIAN_T endian = NO_ENDIAN;
- byte * ptr = NULL;
- if (fpath == NULL)
- goto end;
-
- // array for the bytes
- ptr = get_fbytes(fpath, 0, 4);
- if (ptr == NULL)
- goto end;
-
- // check file_start contents
- if (comp_bytes(ptr, J3DGRAPH_FSTART[0][0], 4) || comp_bytes(ptr, J3DGRAPH_FSTART[1][0], 4))
- endian = BIG;
- else if (comp_bytes(ptr, J3DGRAPH_FSTART[0][1], 4) || comp_bytes(ptr, J3DGRAPH_FSTART[1][1], 4))
- endian = LITTLE;
-
- // done
- end:
- free_memory(ptr);
- return endian;
- }
- // get_j3dgraph_str_weight() function
- // function to return the string weight of a given
- // string. String weight is defined for j3dgraph files.
- // Value is truncated to an unsigned 16 bits integer.
- // the string weight is the name I use (people use hash but
- // I honestly have not learnt much about it to use the term with property)
- // because I feel more familiar with it. The calculation process can be seen here
- // https://humming-owl.neocities.org/smg-stuff/pages/tutorials/file-formats/btp#str-weight
- umax get_j3dgraph_str_weight(void * str, umax mx_size)
- {
- // check params
- if (str == NULL)
- return 0;
-
- // get the string length
- umax str_length = get_str_byte_length_safe(str, mx_size);
- if (str_length == 0)
- return 0;
-
- // calculate the weight
- // the weight does not depend on the encoding but rather on the weight
- // of each byte of the string treated as a signed integer (char)
- // so basically some bytes add magnitude to str_weight and others
- // substract because they are read as negative. It is weird but yeah.
- umax str_weight = 0;
- for (umax i = 0; i < str_length; i++)
- str_weight += ((char *) str)[i] * powerof_uint(3, str_length - i - 1);
-
- // integer math process to get the truncated
- // part of the string weight (16 bits)
- return str_weight & 0xFFFF;
- }
- // get_j3dgraph_padding_size() function
- // function to get the size of a padding string in a j3dgraph file
- umax get_j3dgraph_padding_size(umax padding_pos, bool is_32)
- {
- umax size = 0;
- umax alignment = is_32 ? 32 : 4;
- while ((padding_pos + size) % alignment != 0)
- size++;
- return size;
- }
- // check_j3dgraph_str_tb() function
- // function to check if a j3dgraph string table is valid
- j3dgraph_str_tb_err_cd check_j3dgraph_str_tb(void * arr, umax mx_size, ENDIAN_T endian)
- {
- // check params
- if (arr == NULL || mx_size < J3DGRAPH_MIN_STR_TB_LENGTH || endian == NO_ENDIAN)
- return J3DGRAPH_STR_TB_ERR_INV_ARGS;
-
- // "valid" error to return
- j3dgraph_str_tb_err_cd soft_err = J3DGRAPH_STR_TB_ERR_NO_ERR;
-
- // check if there is actually a string table in arr
- byte * ptr = arr;
- umax tmp = 0;
- // get the element count
- umax elem_cnt = get_std_uint(16, ptr, endian);
- // check unknown 1
- if (get_std_uint(16, ptr + 2, endian) != J3DGRAPH_STR_TB_UNKNOWN_1)
- soft_err = get_min_uint(soft_err, J3DGRAPH_STR_TB_ERR_UNKNOWN_1);
- ptr += 4;
- mx_size -= 4;
-
- // check the string table information list
- if (4 * elem_cnt >= mx_size - 1)
- return J3DGRAPH_STR_TB_ERR_INV_ELEM_CNT;
- for (umax i = 0, tmp2 = 0; i < elem_cnt; i++, ptr += 4, mx_size -= 4)
- {
- // string weight and string offset
- tmp = get_std_uint(16, ptr, endian);
- tmp2 = get_std_uint(16, ptr + 2, endian);
- if (tmp2 >= ptr - (byte *) arr + mx_size - 1)
- return J3DGRAPH_STR_TB_ERR_INV_STR_OFFSET;
- // out of bounds string (the extreme case is a 1 char string at the end of the table)
- if (tmp != get_j3dgraph_str_weight((byte *) arr + tmp2, mx_size))
- soft_err = get_min_uint(soft_err, J3DGRAPH_STR_TB_ERR_INV_STR_WEIGHT);
- // I wont check if the strings are side by side
- }
-
- // change the CHAR_ARR encoding state
- char_enc old_enc = CHAR_ARR_ENC_STATE;
- set_ch_arr_enc_state(CHAR_ENC_CP932);
-
- // check the elem_cnt strings in here
- // if one is invalid then the table is invalid
- for (umax i = 0, tmp = 0; i < elem_cnt; i++) {
- tmp = get_str_byte_length_safe(ptr, mx_size);
- if (tmp == 0)
- return J3DGRAPH_STR_TB_ERR_INV_STR;
- ptr += tmp + chk_ch_int(0);
- mx_size -= tmp + chk_ch_int(0);
- }
- // reset CHAR_ARR encoding state
- set_ch_arr_enc_state(old_enc);
-
- // done!
- return soft_err;
- }
- // get_j3dgraph_str_tb_size() function
- // function to get the byte size of a j3dgraph string table
- umax get_j3dgraph_str_tb_size(void * arr, umax mx_size, ENDIAN_T endian)
- {
- // check params
- if (check_j3dgraph_str_tb(arr, mx_size, endian) < J3DGRAPH_STR_TB_ERR_NO_ERR)
- return 0;
-
- // else compute the size
- byte * ptr = arr;
- umax tmp = 0, str_tb_size = 0;
- // get element count
- tmp = get_std_uint(16, ptr, endian);
-
- // element count, unknown 1 and string inf list
- ptr += 4 + (4 * tmp);
- str_tb_size += 4 + (4 * tmp);
- // [element count] strings
- char_enc old_enc = CHAR_ARR_ENC_STATE;
- set_ch_arr_enc_state(CHAR_ENC_CP932);
- for (umax i = 0, tmp2 = 0; i < tmp; i++) {
- tmp2 = get_str_byte_length(ptr);
- ptr += tmp2 + chk_ch_int(0);
- str_tb_size += tmp2 + chk_ch_int(0);
- }
- set_ch_arr_enc_state(old_enc);
-
- // done!
- return str_tb_size;
- }
- // print_j3dgraph_str_tb() function
- // function to print the contents of a j3dgraph string table
- j3dgraph_str_tb * get_j3dgraph_str_tb(void * src, umax src_size, ENDIAN_T endian)
- {
- // check params
- j3dgraph_str_tb * str_tb = NULL;
- j3dgraph_str_tb_err_cd err_cd = 0;
- if (check_j3dgraph_str_tb(src, src_size, endian) < J3DGRAPH_STR_TB_ERR_NO_ERR)
- goto err;
-
- // allocate space for the structure
- str_tb = allocate_memory(1, sizeof(j3dgraph_str_tb));
- if (str_tb == NULL)
- goto err;
-
- // fill the structure
- byte * ptr = src;
- str_tb -> ENDIAN = endian;
- str_tb -> ERR_CD = err_cd;
- str_tb -> STR_CNT = ptr; ptr += 2;
- str_tb -> UNKNOWN_1 = ptr; ptr += 2;
- str_tb -> STR_INF_LIST = ptr;
- ptr += 4 * get_std_uint(16, str_tb -> STR_CNT, endian);
- str_tb -> STR_LIST = ptr;
-
- // done!
- return str_tb;
- // failure
- err:
- free_memory(str_tb);
- return NULL;
- }
- // close_j3dgraph_str_tb() function
- // function to free the memory used by a j3dgraph_str_tb struct
- void close_j3dgraph_str_tb(j3dgraph_str_tb * str_tb)
- {
- // check params
- if (str_tb == NULL)
- return;
- // free memory
- free_memory(str_tb);
- return;
- }
- // print_j3dgraph_str_tb() function
- // function to print the contents of a j3dgraph string table
- void print_j3dgraph_str_tb(j3dgraph_str_tb * str_tb)
- {
- // check params
- if (str_tb == NULL)
- return;
-
- // print the structure information
- umax str_cnt = get_std_uint(16, str_tb -> STR_CNT, str_tb -> ENDIAN);
- printf("Endian: %s, ", str_tb -> ENDIAN == BIG ? "BIG" : "LITTLE");
- printf("ERROR CODE: %d\n", str_tb -> ERR_CD);
- printf("String count: %llu, ", str_cnt);
- printf("Unknown 1: %04llX\n", get_std_uint(16, str_tb -> UNKNOWN_1, str_tb -> ENDIAN));
-
- // string information list
- byte * ptr = str_tb -> STR_INF_LIST;
- printf("## String inf list begin:\n");
- for (umax i = 0; i < str_cnt; i++, ptr += 4)
- printf("str[%llu] weight: 0x%04llX, offset: 0x%04llX\n", i, get_std_uint(16, ptr, str_tb -> ENDIAN),
- get_std_uint(16, ptr + 2, str_tb -> ENDIAN));
-
- // string list
- // set CHAR_ARR encoding state to CP932 (for now I believe this is the encoding of strings)
- ptr = str_tb -> STR_LIST;
- printf("## String list begin:\n");
- char_enc old_enc = CHAR_ARR_ENC_STATE;
- set_ch_arr_enc_state(CHAR_ENC_CP932);
- for (umax i = 0, tmp = 0; i < str_cnt; i++) {
- printf("str[%llu] chars: ", i);
- tmp = get_str_byte_length(ptr);
- print_chenc_arr_as_unicd(ptr, tmp);
- ptr += tmp + chk_ch_int(0);
- }
- // reset CHAR_ARR state
- set_ch_arr_enc_state(old_enc);
-
- // done!
- printf("## String table end\n");
- return;
- }
- // check_j3dgraph_inc() function
- // check a if j3dgraph file has a valid superficial structure
- j3dgraph_err_cd check_j3dgraph_inc(char * fpath)
- {
- // check params
- if (fpath == NULL)
- return J3DGRAPH_ERR_NULL_PATH;
-
- // first check the file start
- if (check_j3dgraph_fstart(fpath) == 0)
- return J3DGRAPH_ERR_FILE_START;
-
- // load file and get its size
- byte * fbytes = load_file_mem(fpath);
- if (fbytes == NULL)
- return J3DGRAPH_ERR_LOAD_MEM;
- umax fsize = get_file_size(fpath);
-
- // first file size check
- if (fsize <= 32 || (fsize % 32) != 0)
- return J3DGRAPH_ERR_FILE_SIZE;
-
- // get endianness
- ENDIAN_T fendian = get_j3dgraph_fendian(fpath);
- if (fendian == NO_ENDIAN)
- return J3DGRAPH_ERR_ENDIAN;
-
- // file size check
- umax read_fsize = get_std_uint(32, fbytes + 8, fendian);
- if (read_fsize != fsize || (read_fsize % 32) != 0)
- // ^ or some check with a minimum file size idk yet how to get
- return J3DGRAPH_ERR_FILE_SIZE;
- // get section count
- umax sec_count = get_std_uint(32, fbytes + 12, fendian);
- umax read_sec_count = 0;
-
- // check each section header
- umax sec_size_sum = 32;
- umax cur_sec_size = 0;
- for (umax i = 0; i < sec_count; i++)
- {
- // get section size (skip section start)
- cur_sec_size = get_std_uint(32, fbytes + sec_size_sum + 4, fendian);
- // check current section size
- if (cur_sec_size % 32 != 0 || cur_sec_size > fsize)
- return J3DGRAPH_ERR_SEC_SIZE;
- // go to the next section
- sec_size_sum += cur_sec_size;
- read_sec_count++;
- }
-
- // check section count
- if (read_sec_count != sec_count)
- return J3DGRAPH_ERR_SEC_CNT;
-
- // check the section sizes sum
- if (sec_size_sum != fsize)
- return J3DGRAPH_ERR_FILE_SIZE;
-
- // checks done
- free_memory(fbytes);
- return J3DGRAPH_ERR_NO_ERR;
- }
- // open_j3dgraph() function
- // function to partially fill a j3dgraph structure
- // with the information of a j3dgraph valid file
- j3dgraph * open_j3dgraph_inc(char * fpath)
- {
- // check params
- j3dgraph_err_cd err_cd = check_j3dgraph_inc(fpath);
- if (err_cd > J3DGRAPH_ERR_LN)
- goto err;
-
- // pointer to return
- j3dgraph * fptr = allocate_memory(sizeof(j3dgraph), sizeof(byte));
- if (fptr == NULL)
- goto err;
-
- // fill the structure basics
- fptr -> PATH = fpath;
- fptr -> DATA = load_file_mem(fpath);
- fptr -> FSIZE = get_file_size(fpath);
- fptr -> ENDIAN = get_j3dgraph_fendian(fpath);
- fptr -> ERR_CD = err_cd;
- fptr -> HEADER.START = (fptr -> DATA);
- fptr -> HEADER.ID = (fptr -> DATA) + 4;
- fptr -> HEADER.SIZE = (fptr -> DATA) + 8;
- fptr -> HEADER.SEC_CNT = (fptr -> DATA) + 12;
- fptr -> HEADER.UNKNOWN_1 = (fptr -> DATA) + 16;
-
- // array of pointers to structures
- fptr -> SEC_CNT = get_std_uint(32, fptr -> HEADER.SEC_CNT, fptr -> ENDIAN);
- fptr -> SEC = allocate_memory(fptr -> SEC_CNT, sizeof(void *));
- if ((fptr -> SEC) == NULL) {
- free_memory(fptr -> DATA);
- free_memory(fptr);
- goto err;
- }
-
- // fill each j3dgraph_gen_sec in fptr -> SEC
- umax fpos = 32;
- for (umax i = 0; i < (fptr -> SEC_CNT); i++)
- {
- (fptr -> SEC)[i] = allocate_memory(1, sizeof(j3dgraph_gen_sec));
- if ((fptr -> SEC) == NULL) {
- // free the previously allocated memory
- for (umax j = 0; j < i; j++)
- free_memory((fptr -> SEC)[j]);
- free_memory(fptr -> SEC);
- free_memory(fptr -> DATA);
- free_memory(fptr);
- goto err;
- }
- ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> START = fptr -> DATA + fpos;
- ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> SIZE = fptr -> DATA + fpos + 4;
- fpos += get_std_uint(32, ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> SIZE, fptr -> ENDIAN);
- }
-
- // all good
- return fptr;
- // failure
- err:
- return NULL;
- }
- // close_j3dgraph() function
- // function to release the memory used by an incomplete j3dgraph structure
- void close_j3dgraph_inc(j3dgraph * file)
- {
- // check params
- if (file == NULL)
- return;
-
- // free the sections data, SEC array, DATA and the structure itself
- // free each (file -> SEC)[i]
- for (umax i = 0; i < (file -> SEC_CNT); i++)
- free_memory((file -> SEC)[i]);
- // free the rest of the structure
- free_memory(file -> SEC);
- free_memory(file -> DATA);
- free_memory(file);
- // done
- return;
- }
- // print_j3dgraph_start() function
- // function to print the starting info of an incomplete j3dgraph struct
- void print_j3dgraph_start(j3dgraph * file)
- {
- // check params
- if (file == NULL)
- return;
-
- // file info and error code
- printf("File: %s\n", file -> PATH);
- printf("File size (bytes): %llu\n", file -> FSIZE);
- printf("File endian: %s\n", file -> ENDIAN == BIG ? "BIG" : "LITTLE");
- printf("FILE ERROR CODE: %u\n\n", file -> ERR_CD);
-
- // file header
- printf("File start: ");
- print_ascii_arr(file -> HEADER.START, 4);
- printf("File size (bytes): %llu\n", get_std_uint(32, file -> HEADER.SIZE, file -> ENDIAN));
- printf("Section count: %llu\n", get_std_uint(32, file -> HEADER.SEC_CNT, file -> ENDIAN));
- printf("Unknown 1: ");
- print_array(file -> HEADER.UNKNOWN_1, 16, 1, print_byte_hex);
-
- // done
- return;
- }
- // print_j3dgraph_inc() function
- // function to print the contents of an incomplete j3dgraph structure
- void print_j3dgraph_inc(j3dgraph * file)
- {
- // check ptr
- if (file == NULL)
- return;
-
- // starting visual queue
- printf("\n### J3DGraph incomplete struct info start ###\n\n");
- // print the start of the j3dgraph struct
- print_j3dgraph_start(file);
-
- // section headers
- for (umax i = 0; i < (file -> SEC_CNT); i++) {
- printf("\nSection start: ");
- print_ascii_arr(((j3dgraph_gen_sec *) (file -> SEC)[i]) -> START, 4);
- printf("Section size (bytes): %llu\n",
- get_std_uint(32, ((j3dgraph_gen_sec *) (file -> SEC)[i]) -> SIZE, file -> ENDIAN));
- }
-
- // end of structure
- printf("\n### J3DGraph incomplete struct info end ###\n");
- // done
- return;
- }
|