summaryrefslogtreecommitdiff
path: root/tools/asmdiff/ntrextractfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/asmdiff/ntrextractfile.c')
-rw-r--r--tools/asmdiff/ntrextractfile.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/tools/asmdiff/ntrextractfile.c b/tools/asmdiff/ntrextractfile.c
new file mode 100644
index 00000000..19869a14
--- /dev/null
+++ b/tools/asmdiff/ntrextractfile.c
@@ -0,0 +1,153 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef NDEBUG
+#ifdef _MSC_VER
+#define debug_printf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
+#else
+#define debug_printf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+#endif //_MSC_VER
+#else
+#define debug_printf(fmt, ...) ((void)0)
+#endif //NDEBUG
+
+#define FIND_FAIL (-1u)
+
+struct NtrDirHeader {
+ unsigned offset;
+ unsigned short first_file;
+ unsigned short count_or_parent;
+};
+
+static char FILEBUF[BUFSIZ];
+
+unsigned find_file(struct NtrDirHeader * fnt, const char * cfilename) {
+ unsigned file_id = fnt->first_file;
+ char * filename = strdup(cfilename);
+ char * tokenizer = filename;
+ int found = 0;
+ char * tree = (char *)fnt + fnt->offset;
+ char * token;
+
+ while ((token = strtok(tokenizer, "/")) != NULL) {
+ tokenizer = NULL;
+ debug_printf("TOKEN: %s\n", token);
+ long toklen = strlen(token);
+ while (*tree) {
+ char flag = *tree++;
+#ifndef NDEBUG
+ char *entname = malloc((flag & 0x7F) + 1);
+ *stpncpy(entname, tree, flag & 0x7F) = 0;
+ debug_printf("testing entry %s...", entname);
+ free(entname);
+#endif //NDEBUG
+ if ((toklen != (flag & 0x7F)) || strncmp(tree, token, toklen) != 0) {
+ debug_printf("no; is %s\n", (flag & 0x80) ? "dir" : "file");
+ // Next entry
+ tree += (flag & 0x7F);
+ if (flag & 0x80) {
+ tree += 2; // skip dir id
+ }
+ else {
+ file_id++;
+ }
+ }
+ else {
+ debug_printf("yes; is %s\n", (flag & 0x80) ? "dir" : "file");
+ tree += (flag & 0x7F);
+ if (flag & 0x80) {
+ // navigate to next dir
+ unsigned short dir_id = (unsigned char) tree[0] | ((unsigned char) tree[1] << 8);
+ file_id = fnt[dir_id & 0xFFF].first_file;
+ tree = (char *)fnt + fnt[dir_id & 0xFFF].offset;
+ break;
+ }
+ else {
+ found = 1;
+ token = strtok(NULL, "/");
+ goto done;
+ }
+ }
+ }
+ }
+
+done:
+ free(filename);
+ if (!found || token != NULL) {
+ file_id = FIND_FAIL;
+ }
+ return file_id;
+}
+
+int main(int argc, char ** argv) {
+ if (argc < 3) {
+ fprintf(stderr, "missing required argument: %s\n", (argc == 1) ? "BASEROM" : "FILENAME");
+ return 1;
+ }
+ FILE *baserom = fopen(argv[1], "rb");
+ if (baserom == NULL) {
+ fprintf(stderr, "unable to open ROM %s for reading\n", argv[1]);
+ return 1;
+ }
+ debug_printf("opened baserom\n");
+
+ // fnt offset, fnt size, fat offset, fat size
+ unsigned offsets[4];
+ fseek(baserom, 64, SEEK_SET);
+ if (fread(offsets, 4, 4, baserom) != 4) {
+ fprintf(stderr, "failed to read from baserom\n");
+ fclose(baserom);
+ return 1;
+ }
+ debug_printf("read offsets\n");
+
+ // read fnt
+ struct NtrDirHeader *fnt = malloc(offsets[1]);
+ if (fnt == NULL) {
+ fprintf(stderr, "unable to allocate FNT buffer\n");
+ fclose(baserom);
+ return 1;
+ }
+ fseek(baserom, offsets[0], SEEK_SET);
+ if (fread(fnt, 1, offsets[1], baserom) != offsets[1]) {
+ fprintf(stderr, "unable to read FNT\n");
+ free(fnt);
+ fclose(baserom);
+ return 1;
+ }
+ debug_printf("read fnt\n");
+
+ unsigned file_id = find_file(fnt, argv[2]);
+ free(fnt);
+ if (file_id == FIND_FAIL) {
+ fprintf(stderr, "file not found");
+ fclose(baserom);
+ return 1;
+ }
+ debug_printf("found file with id %u\n", file_id);
+
+ // Extract the file to stdout
+ if (8 * file_id >= offsets[3]) {
+ fprintf(stderr, "nitrofs lookup failed");
+ fclose(baserom);
+ return 1;
+ }
+
+ FILE *out = fdopen(dup(fileno(stdout)), "wb");
+ fseek(baserom, offsets[2] + 8 * file_id, SEEK_SET);
+ fread(offsets, 4, 2, baserom);
+ fseek(baserom, offsets[0], SEEK_SET);
+ while (offsets[1] - offsets[0] > BUFSIZ) {
+ fread(FILEBUF, 1, BUFSIZ, baserom);
+ fwrite(FILEBUF, 1, BUFSIZ, out);
+ offsets[0] += BUFSIZ;
+ }
+ fread(FILEBUF, 1, offsets[1] - offsets[0], baserom);
+ fwrite(FILEBUF, 1, offsets[1] - offsets[0], out);
+ fclose(out);
+
+ fclose(baserom);
+ return 0;
+}