DataFile: add API to access spriteflags count/offset
[rofl0r-agsutils.git] / agscriptxtract.c
blobb57df31c417395295c58c384471ea086243d6d7b
1 #define _GNU_SOURCE
2 #include "DataFile.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include "version.h"
7 #define ADS ":::AGStract " VERSION " by rofl0r:::"
9 static int usage(char *argv0) {
10 dprintf(2, ADS "\nusage:\n%s [-oblf] dir [outdir]\n"
11 "extract all scripts from game files in dir\n"
12 "pass a directory with extracted game files.\n"
13 "options:\n"
14 "-o : dump offset comments in disassembly\n"
15 "-b : dump hexadecimal bytecode comments in disassembly\n"
16 "-f : dump informative original fixups section\n"
17 "-l : remove linenumber debug assembly directives [produces smaller files]\n"
18 , argv0);
19 return 1;
22 static void disas(const char*inp, char *o, int flags) {
23 //ARF_find_code_start
24 AF f_b, *f = &f_b;
25 ASI sc;
26 if(AF_open(f, o)) {
27 char s[256];
28 size_t l = strlen(o);
29 memcpy(s, o, l + 1);
30 s[l-1] = 's';
31 ASI *i = ASI_read_script(f, &sc) ? &sc : 0;
32 dprintf(1, "disassembling [%s] %s -> %s", inp, o, s);
33 if(!i || !ASI_disassemble(f, i, s, flags)) dprintf(1, " FAIL");
34 dprintf(1, "\n");
35 AF_close(f);
39 static char *filename(const char *dir, const char *fn, char *buf, size_t bsize) {
40 snprintf(buf, bsize, "%s/%s", dir, fn);
41 return buf;
44 #include "RoomFile.h"
45 #include <dirent.h>
46 static int dumprooms(const char* dir, const char* out, int flags) {
47 DIR* d = opendir(dir);
48 if(!d) return 1;
49 int errors = 0;
50 struct dirent* di = 0;
52 while((di = readdir(d))) {
53 size_t l = strlen(di->d_name);
54 if(l > 4 + 4 && !memcmp(di->d_name, "room", 4) && !memcmp(di->d_name + l - 4, ".crm", 4)) {
55 char fnbuf[512];
56 snprintf(fnbuf, sizeof(fnbuf), "%s/%s", dir, di->d_name);
57 AF f; ssize_t off; ASI s;
58 if(!AF_open(&f, fnbuf)) goto extract_error;
59 struct RoomFile rinfo = {0};
60 if(!RoomFile_read(&f, &rinfo)) goto extract_error;
61 if((off = ARF_find_code_start(&f, 0)) == -1) goto extract_error;
62 assert(off == rinfo.blockpos[BLOCKTYPE_COMPSCRIPT3]);
63 AF_set_pos(&f, off);
64 if(!ASI_read_script(&f, &s)) {
65 dprintf(2, "trouble finding script in %s\n", di->d_name);
66 continue;
68 char buf[256];
69 assert(l < sizeof(buf));
70 memcpy(buf, di->d_name, l - 4);
71 buf[l-4] = '.';
72 buf[l-3] = 'o';
73 buf[l-2] = 0;
74 char outbuf[256];
75 AF_dump_chunk(&f, s.start, s.len, filename(out, buf, outbuf, sizeof outbuf));
76 disas(di->d_name, outbuf, flags);
77 size_t sourcelen;
78 char *source = RoomFile_extract_source(&f, &rinfo, &sourcelen);
79 if(source) {
80 buf[l-3] = 'a';
81 buf[l-2] = 's';
82 buf[l-1] = 'c';
83 buf[l] = 0;
84 FILE *f = fopen(filename(out, buf, outbuf, sizeof outbuf), "w");
85 if(f) {
86 dprintf(1, "extracting room source %s -> %s\n", di->d_name, outbuf);
87 fwrite(source, 1, sourcelen, f);
88 fclose(f);
90 free(source);
92 continue;
93 extract_error:
94 dprintf(2, "warning: extraction of file %s failed\n", di->d_name);
95 ++errors;
98 closedir(d);
99 return errors;
102 void dump_script(AF* f, ASI* s, char* fn, int flags) {
103 if(!s->len) return;
104 AF_dump_chunk(f, s->start, s->len, fn);
105 disas("game28.dta", fn, flags);
108 int main(int argc, char**argv) {
109 int flags = 0, c;
110 while ((c = getopt(argc, argv, "oblf")) != EOF) switch(c) {
111 case 'o': flags |= DISAS_DEBUG_OFFSETS; break;
112 case 'b': flags |= DISAS_DEBUG_BYTECODE; break;
113 case 'l': flags |= DISAS_SKIP_LINENO; break;
114 case 'f': flags |= DISAS_DEBUG_FIXUPS; break;
115 default: return usage(argv[0]);
117 if(!argv[optind]) return usage(argv[0]);
118 char *dir = argv[optind];
119 char *out = argv[optind+1];
120 if(!out) out = ".";
121 else mkdir(out, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
123 int errors = 0;
124 ADF a_b, *a = &a_b;
125 char fnbuf[512];
126 if(!ADF_find_datafile(dir, fnbuf, sizeof(fnbuf)))
127 return 1;
128 if(!ADF_open(a, fnbuf)) return 1;
129 ASI* s;
130 s = ADF_get_global_script(a);
131 char buf[256];
132 dump_script(a->f, s, filename(out, "globalscript.o", buf, sizeof buf), flags);
133 s = ADF_get_dialog_script(a);
134 dump_script(a->f, s, filename(out, "dialogscript.o", buf, sizeof buf), flags);
135 size_t i, l = ADF_get_scriptcount(a);
136 for(i = 0; i < l; i++) {
137 char fnbuf[32];
138 s = ADF_get_script(a, i);
139 snprintf(fnbuf, sizeof(fnbuf), "gamescript%zu.o", i);
140 dump_script(a->f, s, filename(out, fnbuf, buf, sizeof buf), flags);
142 ADF_close(a);
143 errors += dumprooms(dir, out, flags);
144 if(errors) dprintf(2, "agscriptxtract: got %d errors\n", errors);
146 return !!errors;