tab.c (2877B)
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include "tab.h"
5 #include "fs.h"
6 #include "api.h"
7
8 typedef struct {
9 uint32_t offset;
10 uint32_t size;
11 bool present;
12 } ta_tab_entry;
13
14 #ifdef TA_EMBED_GAME
15 extern unsigned char ta_game_tab[];
16 extern unsigned int ta_game_tab_len;
17 #endif
18
19 #ifdef TA_EMBED_GAME
20 extern unsigned char ta_game_tab[];
21 extern unsigned int ta_game_tab_len;
22 #endif
23
24 static ta_fs_file tab_file;
25 static bool embedded;
26 static ta_tab_entry entries[TA_TAB_MAX_FILES + 1];
27 static bool loaded;
28
29 static uint32_t read_le32(const uint8_t *data) {
30 return (uint32_t)data[0] | ((uint32_t)data[1] << 8) | ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24);
31 }
32
33 static bool parse(const uint8_t *data, size_t length) {
34 if (length < TA_TAB_HEADER_SIZE + TA_TAB_ENTRY_SIZE) {
35 return false;
36 }
37
38 if (data[0] != TA_TAB_MAGIC_0 || data[1] != TA_TAB_MAGIC_1 || data[2] != TA_TAB_MAGIC_2 || data[3] != TA_TAB_MAGIC_3) {
39 return false;
40 }
41
42 if (data[4] != TA_TAB_VERSION) {
43 return false;
44 }
45
46 size_t position = TA_TAB_HEADER_SIZE;
47
48 while (1) {
49 if (length - position < TA_TAB_ENTRY_SIZE) {
50 return false;
51 }
52
53 uint8_t file = data[position];
54
55 if (file == TA_TAB_END) {
56 break;
57 }
58
59 uint32_t size = read_le32(data + position + 1);
60 uint32_t offset = read_le32(data + position + 5);
61
62 if (entries[file].present || offset > length || size > length - offset) {
63 return false;
64 }
65
66 entries[file].offset = offset;
67 entries[file].size = size;
68 entries[file].present = true;
69
70 position += TA_TAB_ENTRY_SIZE;
71 }
72
73 return entries[TA_TAB_MAIN_PROGRAM].present;
74 }
75
76 bool ta_tab_load(const char *path) {
77 ta_tab_unload();
78
79 #ifdef TA_EMBED_GAME
80 (void)path;
81
82 tab_file.data = (char *)ta_game_tab;
83 tab_file.size = ta_game_tab_len;
84 embedded = true;
85 #else
86 tab_file = ta_read_file(path);
87 #endif
88
89 if (tab_file.data == NULL) {
90 return false;
91 }
92
93 if (!parse((const uint8_t *)tab_file.data, tab_file.size)) {
94 ta_tab_unload();
95
96 return false;
97 }
98
99 loaded = true;
100
101 return true;
102 }
103
104 void ta_tab_unload(void) {
105 if (tab_file.data != NULL && !embedded) {
106 ta_close_file(&tab_file);
107 }
108
109 embedded = false;
110
111 tab_file.data = NULL;
112 tab_file.size = 0;
113
114 for (uint32_t i = 0; i <= TA_TAB_MAX_FILES; i++) {
115 entries[i].offset = 0;
116 entries[i].size = 0;
117 entries[i].present = false;
118 }
119
120 loaded = false;
121 }
122
123 bool ta_tab_find(uint8_t file, const uint8_t **data, uint32_t *size) {
124 if (!loaded || file == TA_TAB_END || !entries[file].present) {
125 return false;
126 }
127
128 *data = (const uint8_t *)tab_file.data + entries[file].offset;
129 *size = entries[file].size;
130
131 return true;
132 }