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"
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"
22 static void disas(const char*inp
, char *o
, int flags
) {
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");
39 static char *filename(const char *dir
, const char *fn
, char *buf
, size_t bsize
) {
40 snprintf(buf
, bsize
, "%s/%s", dir
, fn
);
46 static int dumprooms(const char* dir
, const char* out
, int flags
) {
47 DIR* d
= opendir(dir
);
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)) {
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
]);
64 if(!ASI_read_script(&f
, &s
)) {
65 dprintf(2, "trouble finding script in %s\n", di
->d_name
);
69 assert(l
< sizeof(buf
));
70 memcpy(buf
, di
->d_name
, l
- 4);
75 AF_dump_chunk(&f
, s
.start
, s
.len
, filename(out
, buf
, outbuf
, sizeof outbuf
));
76 disas(di
->d_name
, outbuf
, flags
);
78 char *source
= RoomFile_extract_source(&f
, &rinfo
, &sourcelen
);
84 FILE *f
= fopen(filename(out
, buf
, outbuf
, sizeof outbuf
), "w");
86 dprintf(1, "extracting room source %s -> %s\n", di
->d_name
, outbuf
);
87 fwrite(source
, 1, sourcelen
, f
);
94 dprintf(2, "warning: extraction of file %s failed\n", di
->d_name
);
102 void dump_script(AF
* f
, ASI
* s
, char* fn
, int flags
) {
104 AF_dump_chunk(f
, s
->start
, s
->len
, fn
);
105 disas("game28.dta", fn
, flags
);
108 int main(int argc
, char**argv
) {
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];
121 else mkdir(out
, S_IRWXU
| S_IRWXG
| S_IROTH
| S_IXOTH
);
126 if(!ADF_find_datafile(dir
, fnbuf
, sizeof(fnbuf
)))
128 if(!ADF_open(a
, fnbuf
)) return 1;
130 s
= ADF_get_global_script(a
);
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
++) {
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
);
143 errors
+= dumprooms(dir
, out
, flags
);
144 if(errors
) dprintf(2, "agscriptxtract: got %d errors\n", errors
);