J3DGRAPH.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. // C source file with the function definitions to handle J3DGRAPH files
  2. // check_j3dgraph_fstart() function
  3. // check the first 4 bytes of a j3dgraph file to see if it is valid
  4. bool check_j3dgraph_fstart(char * fpath)
  5. {
  6. // check params
  7. byte * ptr = NULL;
  8. bool rtn = false;
  9. if (fpath == NULL)
  10. goto end;
  11. // array for the bytes
  12. ptr = get_fbytes(fpath, 0, 4);
  13. if (ptr == NULL)
  14. goto end;
  15. // compare the array with J3DGRAPH_FSTART
  16. for (byte i = 0; i < 2; i++)
  17. for (byte j = 0; j < 2; j++)
  18. rtn = rtn || comp_bytes(ptr, J3DGRAPH_FSTART[i][j], 4);
  19. // return the result, free memory used
  20. end:
  21. free_memory(ptr);
  22. return rtn;
  23. }
  24. // get_j3dgraph_fendian() function
  25. // function to determine the endian mode of a j3dgraph file
  26. ENDIAN_T get_j3dgraph_fendian(char * fpath)
  27. {
  28. // check params
  29. ENDIAN_T endian = NO_ENDIAN;
  30. byte * ptr = NULL;
  31. if (fpath == NULL)
  32. goto end;
  33. // array for the bytes
  34. ptr = get_fbytes(fpath, 0, 4);
  35. if (ptr == NULL)
  36. goto end;
  37. // check file_start contents
  38. if (comp_bytes(ptr, J3DGRAPH_FSTART[0][0], 4) || comp_bytes(ptr, J3DGRAPH_FSTART[1][0], 4))
  39. endian = BIG;
  40. else if (comp_bytes(ptr, J3DGRAPH_FSTART[0][1], 4) || comp_bytes(ptr, J3DGRAPH_FSTART[1][1], 4))
  41. endian = LITTLE;
  42. // done
  43. end:
  44. free_memory(ptr);
  45. return endian;
  46. }
  47. // get_j3dgraph_str_weight() function
  48. // function to return the string weight of a given
  49. // string. String weight is defined for j3dgraph files.
  50. // Value is truncated to an unsigned 16 bits integer.
  51. // the string weight is the name I use (people use hash but
  52. // I honestly have not learnt much about it to use the term with property)
  53. // because I feel more familiar with it. The calculation process can be seen here
  54. // https://humming-owl.neocities.org/smg-stuff/pages/tutorials/file-formats/btp#str-weight
  55. umax get_j3dgraph_str_weight(void * str, umax mx_size)
  56. {
  57. // check params
  58. if (str == NULL)
  59. return 0;
  60. // get the string length
  61. umax str_length = get_str_byte_length_safe(str, mx_size);
  62. if (str_length == 0)
  63. return 0;
  64. // calculate the weight
  65. // the weight does not depend on the encoding but rather on the weight
  66. // of each byte of the string treated as a signed integer (char)
  67. // so basically some bytes add magnitude to str_weight and others
  68. // substract because they are read as negative. It is weird but yeah.
  69. umax str_weight = 0;
  70. for (umax i = 0; i < str_length; i++)
  71. str_weight += ((char *) str)[i] * powerof_uint(3, str_length - i - 1);
  72. // integer math process to get the truncated
  73. // part of the string weight (16 bits)
  74. return str_weight & 0xFFFF;
  75. }
  76. // get_j3dgraph_padding_size() function
  77. // function to get the size of a padding string in a j3dgraph file
  78. umax get_j3dgraph_padding_size(umax padding_pos, bool is_32)
  79. {
  80. umax size = 0;
  81. umax alignment = is_32 ? 32 : 4;
  82. while ((padding_pos + size) % alignment != 0)
  83. size++;
  84. return size;
  85. }
  86. // check_j3dgraph_str_tb() function
  87. // function to check if a j3dgraph string table is valid
  88. j3dgraph_str_tb_err_cd check_j3dgraph_str_tb(void * arr, umax mx_size, ENDIAN_T endian)
  89. {
  90. // check params
  91. if (arr == NULL || mx_size < J3DGRAPH_MIN_STR_TB_LENGTH || endian == NO_ENDIAN)
  92. return J3DGRAPH_STR_TB_ERR_INV_ARGS;
  93. // "valid" error to return
  94. j3dgraph_str_tb_err_cd soft_err = J3DGRAPH_STR_TB_ERR_NO_ERR;
  95. // check if there is actually a string table in arr
  96. byte * ptr = arr;
  97. umax tmp = 0;
  98. // get the element count
  99. umax elem_cnt = get_std_uint(16, ptr, endian);
  100. // check unknown 1
  101. if (get_std_uint(16, ptr + 2, endian) != J3DGRAPH_STR_TB_UNKNOWN_1)
  102. soft_err = get_min_uint(soft_err, J3DGRAPH_STR_TB_ERR_UNKNOWN_1);
  103. ptr += 4;
  104. mx_size -= 4;
  105. // check the string table information list
  106. if (4 * elem_cnt >= mx_size - 1)
  107. return J3DGRAPH_STR_TB_ERR_INV_ELEM_CNT;
  108. for (umax i = 0, tmp2 = 0; i < elem_cnt; i++, ptr += 4, mx_size -= 4)
  109. {
  110. // string weight and string offset
  111. tmp = get_std_uint(16, ptr, endian);
  112. tmp2 = get_std_uint(16, ptr + 2, endian);
  113. if (tmp2 >= ptr - (byte *) arr + mx_size - 1)
  114. return J3DGRAPH_STR_TB_ERR_INV_STR_OFFSET;
  115. // out of bounds string (the extreme case is a 1 char string at the end of the table)
  116. if (tmp != get_j3dgraph_str_weight((byte *) arr + tmp2, mx_size))
  117. soft_err = get_min_uint(soft_err, J3DGRAPH_STR_TB_ERR_INV_STR_WEIGHT);
  118. // I wont check if the strings are side by side
  119. }
  120. // change the CHAR_ARR encoding state
  121. char_enc old_enc = CHAR_ARR_ENC_STATE;
  122. set_ch_arr_enc_state(CHAR_ENC_CP932);
  123. // check the elem_cnt strings in here
  124. // if one is invalid then the table is invalid
  125. for (umax i = 0, tmp = 0; i < elem_cnt; i++) {
  126. tmp = get_str_byte_length_safe(ptr, mx_size);
  127. if (tmp == 0)
  128. return J3DGRAPH_STR_TB_ERR_INV_STR;
  129. ptr += tmp + chk_ch_int(0);
  130. mx_size -= tmp + chk_ch_int(0);
  131. }
  132. // reset CHAR_ARR encoding state
  133. set_ch_arr_enc_state(old_enc);
  134. // done!
  135. return soft_err;
  136. }
  137. // get_j3dgraph_str_tb_size() function
  138. // function to get the byte size of a j3dgraph string table
  139. umax get_j3dgraph_str_tb_size(void * arr, umax mx_size, ENDIAN_T endian)
  140. {
  141. // check params
  142. if (check_j3dgraph_str_tb(arr, mx_size, endian) < J3DGRAPH_STR_TB_ERR_NO_ERR)
  143. return 0;
  144. // else compute the size
  145. byte * ptr = arr;
  146. umax tmp = 0, str_tb_size = 0;
  147. // get element count
  148. tmp = get_std_uint(16, ptr, endian);
  149. // element count, unknown 1 and string inf list
  150. ptr += 4 + (4 * tmp);
  151. str_tb_size += 4 + (4 * tmp);
  152. // [element count] strings
  153. char_enc old_enc = CHAR_ARR_ENC_STATE;
  154. set_ch_arr_enc_state(CHAR_ENC_CP932);
  155. for (umax i = 0, tmp2 = 0; i < tmp; i++) {
  156. tmp2 = get_str_byte_length(ptr);
  157. ptr += tmp2 + chk_ch_int(0);
  158. str_tb_size += tmp2 + chk_ch_int(0);
  159. }
  160. set_ch_arr_enc_state(old_enc);
  161. // done!
  162. return str_tb_size;
  163. }
  164. // print_j3dgraph_str_tb() function
  165. // function to print the contents of a j3dgraph string table
  166. j3dgraph_str_tb * get_j3dgraph_str_tb(void * src, umax src_size, ENDIAN_T endian)
  167. {
  168. // check params
  169. j3dgraph_str_tb * str_tb = NULL;
  170. j3dgraph_str_tb_err_cd err_cd = 0;
  171. if (check_j3dgraph_str_tb(src, src_size, endian) < J3DGRAPH_STR_TB_ERR_NO_ERR)
  172. goto err;
  173. // allocate space for the structure
  174. str_tb = allocate_memory(1, sizeof(j3dgraph_str_tb));
  175. if (str_tb == NULL)
  176. goto err;
  177. // fill the structure
  178. byte * ptr = src;
  179. str_tb -> ENDIAN = endian;
  180. str_tb -> ERR_CD = err_cd;
  181. str_tb -> STR_CNT = ptr; ptr += 2;
  182. str_tb -> UNKNOWN_1 = ptr; ptr += 2;
  183. str_tb -> STR_INF_LIST = ptr;
  184. ptr += 4 * get_std_uint(16, str_tb -> STR_CNT, endian);
  185. str_tb -> STR_LIST = ptr;
  186. // done!
  187. return str_tb;
  188. // failure
  189. err:
  190. free_memory(str_tb);
  191. return NULL;
  192. }
  193. // close_j3dgraph_str_tb() function
  194. // function to free the memory used by a j3dgraph_str_tb struct
  195. void close_j3dgraph_str_tb(j3dgraph_str_tb * str_tb)
  196. {
  197. // check params
  198. if (str_tb == NULL)
  199. return;
  200. // free memory
  201. free_memory(str_tb);
  202. return;
  203. }
  204. // print_j3dgraph_str_tb() function
  205. // function to print the contents of a j3dgraph string table
  206. void print_j3dgraph_str_tb(j3dgraph_str_tb * str_tb)
  207. {
  208. // check params
  209. if (str_tb == NULL)
  210. return;
  211. // print the structure information
  212. umax str_cnt = get_std_uint(16, str_tb -> STR_CNT, str_tb -> ENDIAN);
  213. printf("Endian: %s, ", str_tb -> ENDIAN == BIG ? "BIG" : "LITTLE");
  214. printf("ERROR CODE: %d\n", str_tb -> ERR_CD);
  215. printf("String count: %llu, ", str_cnt);
  216. printf("Unknown 1: %04llX\n", get_std_uint(16, str_tb -> UNKNOWN_1, str_tb -> ENDIAN));
  217. // string information list
  218. byte * ptr = str_tb -> STR_INF_LIST;
  219. printf("## String inf list begin:\n");
  220. for (umax i = 0; i < str_cnt; i++, ptr += 4)
  221. printf("str[%llu] weight: 0x%04llX, offset: 0x%04llX\n", i, get_std_uint(16, ptr, str_tb -> ENDIAN),
  222. get_std_uint(16, ptr + 2, str_tb -> ENDIAN));
  223. // string list
  224. // set CHAR_ARR encoding state to CP932 (for now I believe this is the encoding of strings)
  225. ptr = str_tb -> STR_LIST;
  226. printf("## String list begin:\n");
  227. char_enc old_enc = CHAR_ARR_ENC_STATE;
  228. set_ch_arr_enc_state(CHAR_ENC_CP932);
  229. for (umax i = 0, tmp = 0; i < str_cnt; i++) {
  230. printf("str[%llu] chars: ", i);
  231. tmp = get_str_byte_length(ptr);
  232. print_chenc_arr_as_unicd(ptr, tmp);
  233. ptr += tmp + chk_ch_int(0);
  234. }
  235. // reset CHAR_ARR state
  236. set_ch_arr_enc_state(old_enc);
  237. // done!
  238. printf("## String table end\n");
  239. return;
  240. }
  241. // check_j3dgraph_inc() function
  242. // check a if j3dgraph file has a valid superficial structure
  243. j3dgraph_err_cd check_j3dgraph_inc(char * fpath)
  244. {
  245. // check params
  246. if (fpath == NULL)
  247. return J3DGRAPH_ERR_NULL_PATH;
  248. // first check the file start
  249. if (check_j3dgraph_fstart(fpath) == 0)
  250. return J3DGRAPH_ERR_FILE_START;
  251. // load file and get its size
  252. byte * fbytes = load_file_mem(fpath);
  253. if (fbytes == NULL)
  254. return J3DGRAPH_ERR_LOAD_MEM;
  255. umax fsize = get_file_size(fpath);
  256. // first file size check
  257. if (fsize <= 32 || (fsize % 32) != 0)
  258. return J3DGRAPH_ERR_FILE_SIZE;
  259. // get endianness
  260. ENDIAN_T fendian = get_j3dgraph_fendian(fpath);
  261. if (fendian == NO_ENDIAN)
  262. return J3DGRAPH_ERR_ENDIAN;
  263. // file size check
  264. umax read_fsize = get_std_uint(32, fbytes + 8, fendian);
  265. if (read_fsize != fsize || (read_fsize % 32) != 0)
  266. // ^ or some check with a minimum file size idk yet how to get
  267. return J3DGRAPH_ERR_FILE_SIZE;
  268. // get section count
  269. umax sec_count = get_std_uint(32, fbytes + 12, fendian);
  270. umax read_sec_count = 0;
  271. // check each section header
  272. umax sec_size_sum = 32;
  273. umax cur_sec_size = 0;
  274. for (umax i = 0; i < sec_count; i++)
  275. {
  276. // get section size (skip section start)
  277. cur_sec_size = get_std_uint(32, fbytes + sec_size_sum + 4, fendian);
  278. // check current section size
  279. if (cur_sec_size % 32 != 0 || cur_sec_size > fsize)
  280. return J3DGRAPH_ERR_SEC_SIZE;
  281. // go to the next section
  282. sec_size_sum += cur_sec_size;
  283. read_sec_count++;
  284. }
  285. // check section count
  286. if (read_sec_count != sec_count)
  287. return J3DGRAPH_ERR_SEC_CNT;
  288. // check the section sizes sum
  289. if (sec_size_sum != fsize)
  290. return J3DGRAPH_ERR_FILE_SIZE;
  291. // checks done
  292. free_memory(fbytes);
  293. return J3DGRAPH_ERR_NO_ERR;
  294. }
  295. // open_j3dgraph() function
  296. // function to partially fill a j3dgraph structure
  297. // with the information of a j3dgraph valid file
  298. j3dgraph * open_j3dgraph_inc(char * fpath)
  299. {
  300. // check params
  301. j3dgraph_err_cd err_cd = check_j3dgraph_inc(fpath);
  302. if (err_cd > J3DGRAPH_ERR_LN)
  303. goto err;
  304. // pointer to return
  305. j3dgraph * fptr = allocate_memory(sizeof(j3dgraph), sizeof(byte));
  306. if (fptr == NULL)
  307. goto err;
  308. // fill the structure basics
  309. fptr -> PATH = fpath;
  310. fptr -> DATA = load_file_mem(fpath);
  311. fptr -> FSIZE = get_file_size(fpath);
  312. fptr -> ENDIAN = get_j3dgraph_fendian(fpath);
  313. fptr -> ERR_CD = err_cd;
  314. fptr -> HEADER.START = (fptr -> DATA);
  315. fptr -> HEADER.ID = (fptr -> DATA) + 4;
  316. fptr -> HEADER.SIZE = (fptr -> DATA) + 8;
  317. fptr -> HEADER.SEC_CNT = (fptr -> DATA) + 12;
  318. fptr -> HEADER.UNKNOWN_1 = (fptr -> DATA) + 16;
  319. // array of pointers to structures
  320. fptr -> SEC_CNT = get_std_uint(32, fptr -> HEADER.SEC_CNT, fptr -> ENDIAN);
  321. fptr -> SEC = allocate_memory(fptr -> SEC_CNT, sizeof(void *));
  322. if ((fptr -> SEC) == NULL) {
  323. free_memory(fptr -> DATA);
  324. free_memory(fptr);
  325. goto err;
  326. }
  327. // fill each j3dgraph_gen_sec in fptr -> SEC
  328. umax fpos = 32;
  329. for (umax i = 0; i < (fptr -> SEC_CNT); i++)
  330. {
  331. (fptr -> SEC)[i] = allocate_memory(1, sizeof(j3dgraph_gen_sec));
  332. if ((fptr -> SEC) == NULL) {
  333. // free the previously allocated memory
  334. for (umax j = 0; j < i; j++)
  335. free_memory((fptr -> SEC)[j]);
  336. free_memory(fptr -> SEC);
  337. free_memory(fptr -> DATA);
  338. free_memory(fptr);
  339. goto err;
  340. }
  341. ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> START = fptr -> DATA + fpos;
  342. ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> SIZE = fptr -> DATA + fpos + 4;
  343. fpos += get_std_uint(32, ((j3dgraph_gen_sec *) (fptr -> SEC)[i]) -> SIZE, fptr -> ENDIAN);
  344. }
  345. // all good
  346. return fptr;
  347. // failure
  348. err:
  349. return NULL;
  350. }
  351. // close_j3dgraph() function
  352. // function to release the memory used by an incomplete j3dgraph structure
  353. void close_j3dgraph_inc(j3dgraph * file)
  354. {
  355. // check params
  356. if (file == NULL)
  357. return;
  358. // free the sections data, SEC array, DATA and the structure itself
  359. // free each (file -> SEC)[i]
  360. for (umax i = 0; i < (file -> SEC_CNT); i++)
  361. free_memory((file -> SEC)[i]);
  362. // free the rest of the structure
  363. free_memory(file -> SEC);
  364. free_memory(file -> DATA);
  365. free_memory(file);
  366. // done
  367. return;
  368. }
  369. // print_j3dgraph_start() function
  370. // function to print the starting info of an incomplete j3dgraph struct
  371. void print_j3dgraph_start(j3dgraph * file)
  372. {
  373. // check params
  374. if (file == NULL)
  375. return;
  376. // file info and error code
  377. printf("File: %s\n", file -> PATH);
  378. printf("File size (bytes): %llu\n", file -> FSIZE);
  379. printf("File endian: %s\n", file -> ENDIAN == BIG ? "BIG" : "LITTLE");
  380. printf("FILE ERROR CODE: %u\n\n", file -> ERR_CD);
  381. // file header
  382. printf("File start: ");
  383. print_ascii_arr(file -> HEADER.START, 4);
  384. printf("File size (bytes): %llu\n", get_std_uint(32, file -> HEADER.SIZE, file -> ENDIAN));
  385. printf("Section count: %llu\n", get_std_uint(32, file -> HEADER.SEC_CNT, file -> ENDIAN));
  386. printf("Unknown 1: ");
  387. print_array(file -> HEADER.UNKNOWN_1, 16, 1, print_byte_hex);
  388. // done
  389. return;
  390. }
  391. // print_j3dgraph_inc() function
  392. // function to print the contents of an incomplete j3dgraph structure
  393. void print_j3dgraph_inc(j3dgraph * file)
  394. {
  395. // check ptr
  396. if (file == NULL)
  397. return;
  398. // starting visual queue
  399. printf("\n### J3DGraph incomplete struct info start ###\n\n");
  400. // print the start of the j3dgraph struct
  401. print_j3dgraph_start(file);
  402. // section headers
  403. for (umax i = 0; i < (file -> SEC_CNT); i++) {
  404. printf("\nSection start: ");
  405. print_ascii_arr(((j3dgraph_gen_sec *) (file -> SEC)[i]) -> START, 4);
  406. printf("Section size (bytes): %llu\n",
  407. get_std_uint(32, ((j3dgraph_gen_sec *) (file -> SEC)[i]) -> SIZE, file -> ENDIAN));
  408. }
  409. // end of structure
  410. printf("\n### J3DGraph incomplete struct info end ###\n");
  411. // done
  412. return;
  413. }