1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif /* HAVE_CONFIG_H */
26
27 #define MALLOC_DEBUG
28
29 #include <sciresource.h>
30 #include <engine.h>
31 #include <console.h>
32 #include <versions.h>
33
34 #ifdef HAVE_GETOPT_H
35 #include <getopt.h>
36 #endif /* HAVE_GETOPT_H */
37
38 static int hexdump = 0;
39 static int opcode_size = 0;
40 static int verbose = 0;
41
42 static resource_mgr_t *resmgr;
43
44 #ifdef HAVE_GETOPT_LONG
45 static struct option options[] = {
46 {"version", no_argument, 0, 256},
47 {"help", no_argument, 0, 'h'},
48 {"hexdump", no_argument, &hexdump, 1},
49 {"opcode-size", no_argument, &opcode_size, 1},
50 {"verbose", no_argument, &verbose, 1},
51 {"gamedir", required_argument, 0, 'd'},
52 {0, 0, 0, 0}
53 };
54 #endif /* HAVE_GETOPT_LONG */
55
56 #define SCI_ASSUME_VERSION SCI_VERSION_FTU_NEW_SCRIPT_HEADER
57
58 typedef struct name_s {
59 int offset;
60 char *name;
61 int class_no;
62 struct name_s *next;
63 } name_t;
64
65 typedef struct area_s {
66 int start_offset;
67 int end_offset;
68 void *data;
69 struct area_s *next;
70 } area_t;
71
72 enum area_type { area_said, area_string, area_object, area_last };
73
74 typedef struct script_state_s {
75 int script_no;
76 name_t *names;
77 area_t *areas [area_last];
78
79 struct script_state_s *next;
80 } script_state_t;
81
82 typedef struct disasm_state_s {
83 char **snames;
84 int selector_count;
85 opcode *opcodes;
86 int kernel_names_nr;
87 char **kernel_names;
88 word_t **words;
89 int word_count;
90
91 char **class_names;
92 int *class_selector_count;
93 short **class_selectors;
94 int class_count;
95 int old_header;
96
97 script_state_t *scripts;
98 } disasm_state_t;
99
100 void
101 disassemble_script(disasm_state_t *d, int res_no, int pass_no);
102
103 script_state_t *
104 find_script_state(disasm_state_t *d, int script_no);
105
106 void
107 script_free_names(script_state_t *s);
108
109 void
110 script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no);
111
112 char *
113 script_find_name(script_state_t *s, int offset, int *class_no);
114
115 void
116 script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data);
117
118 void
119 script_free_areas(script_state_t *s);
120
121 int
122 script_get_area_type(script_state_t *s, int offset, void **pdata);
123
124 void
125 disasm_init(disasm_state_t *d);
126
127 void
128 disasm_free_state(disasm_state_t *d);
129
main(int argc,char ** argv)130 int main(int argc, char** argv) {
131 int i;
132 char outfilename [256];
133 int optindex = 0;
134 int c;
135 disasm_state_t disasm_state;
136 char *gamedir = NULL;
137 int res_version = SCI_VERSION_AUTODETECT;
138
139 #ifdef HAVE_GETOPT_LONG
140 while ((c = getopt_long(argc, argv, "vhxr:d:", options, &optindex)) > -1) {
141 #else /* !HAVE_GETOPT_H */
142 while ((c = getopt(argc, argv, "vhxr:d:")) > -1) {
143 #endif /* !HAVE_GETOPT_H */
144
145 switch (c) {
146 case 256:
147 printf("scidisasm ("PACKAGE") "VERSION"\n");
148 printf("This program is copyright (C) 1999 Christoph Reichenbach.\n"
149 "It comes WITHOUT WARRANTY of any kind.\n"
150 "This is free software, released under the GNU General Public License.\n");
151 exit(0);
152
153 case 'h':
154 printf("Usage: scidisasm\n"
155 "\nAvailable options:\n"
156 " --version Prints the version number\n"
157 " --help -h Displays this help message\n"
158 " --gamedir <dir> -d<dir> Read game resources from dir\n"
159 " --hexdump -x Hex dump all script resources\n"
160 " --verbose Print additional disassembly information\n"
161 " --opcode-size Print opcode size postfixes\n");
162 exit(0);
163
164 case 'd':
165 if (gamedir) sci_free(gamedir);
166 gamedir = sci_strdup(optarg);
167 break;
168
169 case 'r':
170 res_version = atoi(optarg);
171 break;
172
173 case 0: /* getopt_long already did this for us */
174 case '?':
175 /* getopt_long already printed an error message. */
176 break;
177
178 default:
179 return -1;
180 }
181 }
182
183 if (gamedir)
184 if (chdir(gamedir)) {
185 printf("Error changing to game directory '%s'\n", gamedir);
186 exit(1);
187 }
188
189 printf("Loading resources...\n");
190 if (!(resmgr = scir_new_resource_manager(sci_getcwd(), res_version,
191 1, 1024 * 128))) {
192 fprintf(stderr, "Could not find any resources; quitting.\n");
193 exit(1);
194 }
195
196 disasm_init(&disasm_state);
197
198 script_adjust_opcode_formats(resmgr->sci_version);
199
200 printf("Performing first pass...\n");
201 for (i = 0; i < resmgr->resources_nr; i++)
202 if (resmgr->resources[i].type == sci_script)
203 disassemble_script(&disasm_state,
204 resmgr->resources[i].number, 1);
205
206 printf("Performing second pass...\n");
207 for (i = 0; i < resmgr->resources_nr; i++)
208 if (resmgr->resources[i].type == sci_script) {
209 sprintf(outfilename, "%03d.script",
210 resmgr->resources[i].number);
211 open_console_file(outfilename);
212 disassemble_script(&disasm_state,
213 resmgr->resources[i].number, 2);
214 }
215
216 close_console_file();
217 disasm_free_state(&disasm_state);
218
219 free(resmgr->resource_path);
220 scir_free_resource_manager(resmgr);
221 return 0;
222 }
223
224 /* -- General operations on disasm_state_t ------------------------------- */
225
226 void
227 disasm_init(disasm_state_t *d) {
228 d->snames = vocabulary_get_snames(resmgr, &d->selector_count, SCI_ASSUME_VERSION);
229 d->opcodes = vocabulary_get_opcodes(resmgr);
230 d->kernel_names = vocabulary_get_knames(resmgr, &d->kernel_names_nr);
231 d->words = vocab_get_words(resmgr, &d->word_count);
232 d->scripts = NULL;
233 d->old_header = 0;
234
235 d->class_count = vocabulary_get_class_count(resmgr);
236 d->class_names = (char **) sci_malloc(d->class_count * sizeof(char *));
237 memset(d->class_names, 0, d->class_count * sizeof(char *));
238 d->class_selector_count = (int *) sci_malloc(d->class_count * sizeof(int));
239 memset(d->class_selector_count, 0, d->class_count * sizeof(int));
240 d->class_selectors = (short **) sci_malloc(d->class_count * sizeof(short *));
241 memset(d->class_selectors, 0, d->class_count * sizeof(short *));
242 }
243
244 void
245 disasm_free_state(disasm_state_t *d) {
246 script_state_t *s, *next_script;
247 int i;
248
249 s = d->scripts;
250 while (s) {
251 next_script = s->next;
252 script_free_names(s);
253 script_free_areas(s);
254 s = next_script;
255 }
256
257 for (i = 0; i < d->class_count; i++) {
258 if (d->class_names [i]) sci_free(d->class_names [i]);
259 if (d->class_selectors [i]) sci_free(d->class_selectors [i]);
260 }
261
262 free(d->class_names);
263 free(d->class_selectors);
264 free(d->class_selector_count);
265
266 vocabulary_free_snames(d->snames);
267 vocabulary_free_opcodes(d->opcodes);
268 vocabulary_free_knames(d->kernel_names);
269 vocab_free_words(d->words, d->word_count);
270 }
271
272 script_state_t *
273 find_script_state(disasm_state_t *d, int script_no) {
274 script_state_t *s;
275
276 for (s = d->scripts; s; s = s->next)
277 if (s->script_no == script_no) return s;
278
279 s = (script_state_t *) sci_malloc(sizeof(script_state_t));
280 memset(s, 0, sizeof(script_state_t));
281 s->script_no = script_no;
282 s->next = d->scripts;
283
284 d->scripts = s;
285 return s;
286 }
287
288 /* -- Name table operations ---------------------------------------------- */
289
290 void
291 script_free_names(script_state_t *s) {
292 name_t *p = s->names, *next_name;
293
294 while (p) {
295 next_name = p->next;
296 free(p->name);
297 free(p);
298 p = next_name;
299 }
300
301 s->names = NULL;
302 }
303
304 void
305 script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no) {
306 name_t *p;
307 char *name = script_find_name(s, aoffset, NULL);
308 if (name) return;
309
310 p = (name_t *) sci_malloc(sizeof(name_t));
311 p->offset = aoffset;
312 p->name = sci_strdup(aname);
313 p->class_no = aclass_no;
314 p->next = s->names;
315 s->names = p;
316 }
317
318 char *
319 script_find_name(script_state_t *s, int offset, int *aclass_no) {
320 name_t *p;
321
322 for (p = s->names; p; p = p->next)
323 if (p->offset == offset) {
324 if (aclass_no && p->class_no != -2) *aclass_no = p->class_no;
325 return p->name;
326 }
327
328 return NULL;
329 }
330
331 /* -- Area table operations ---------------------------------------------- */
332
333 void
334 script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data) {
335 area_t *area;
336
337 area = (area_t *) sci_malloc(sizeof(area_t));
338 area->start_offset = start_offset;
339 area->end_offset = end_offset;
340 area->data = data;
341 area->next = s->areas [type];
342
343 s->areas [type] = area;
344 }
345
346 void
347 script_free_areas(script_state_t *s) {
348 int i;
349
350 for (i = 0; i < area_last; i++) {
351 area_t *area = s->areas [i], *next_area;
352 while (area) {
353 next_area = area->next;
354 free(area);
355 area = next_area;
356 }
357 }
358 }
359
360 int
361 script_get_area_type(script_state_t *s, int offset, void **pdata) {
362 int i;
363
364 for (i = 0; i < area_last; i++) {
365 area_t *area = s->areas [i];
366 while (area) {
367 if (area->start_offset <= offset && area->end_offset >= offset) {
368 if (pdata != NULL) *pdata = area->data;
369 return i;
370 }
371 area = area->next;
372 }
373 }
374
375 return -1;
376 }
377
378 char *
379 get_selector_name(disasm_state_t *d, int selector) {
380 static char selector_name [256];
381
382 if (d->snames && selector >= 0 && selector < d->selector_count)
383 return d->snames [selector];
384 else {
385 sprintf(selector_name, "unknown_sel_%X", selector);
386 return selector_name;
387 }
388 }
389
390 const char *
391 get_class_name(disasm_state_t *d, int class_no) {
392 static char class_name [256];
393
394 if (class_no == -1)
395 return "<none>";
396 else if (class_no >= 0 && class_no < d->class_count && d->class_names [class_no])
397 return d->class_names [class_no];
398 else {
399 sprintf(class_name, "class_%d", class_no);
400 return class_name;
401 }
402 }
403
404 /* -- Code to dump individual script block types ------------------------- */
405
406 static void
407 script_dump_object(disasm_state_t *d, script_state_t *s,
408 unsigned char *data, int seeker, int objsize, int pass_no) {
409 int selectors, overloads, selectorsize;
410 int species = getInt16(data + 8 + seeker);
411 int superclass = getInt16(data + 10 + seeker);
412 int namepos = getInt16(data + 14 + seeker);
413 int i = 0;
414 short sel;
415 const char *name;
416 char buf [256];
417 short *sels;
418
419 selectors = (selectorsize = getInt16(data + seeker + 6));
420 name = namepos ? ((const char *)data + namepos) : "<unknown>";
421
422 if (pass_no == 1)
423 script_add_area(s, seeker, seeker + objsize - 1, area_object, strdup(name));
424
425 if (pass_no == 2) {
426 sciprintf(".object\n");
427 sciprintf("Name: %s\n", name);
428 sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass);
429 sciprintf("Species: %s [%x]\n", get_class_name(d, species), species);
430
431 sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff);
432
433 sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4));
434 sciprintf("Selectors [%x]:\n", selectors);
435 }
436
437 seeker += 8;
438
439 if (species < d->class_count)
440 sels = d->class_selectors [species];
441 else
442 sels = NULL;
443
444 while (selectors--) {
445 if (pass_no == 2) {
446 sel = getInt16(data + seeker) & 0xffff;
447 if (sels && (sels [i] >= 0) && (sels[i] < d->selector_count)) {
448 sciprintf(" [#%03x] %s = 0x%x\n", i, d->snames [sels [i]], sel);
449 i++;
450 } else
451 sciprintf(" [#%03x] <unknown> = 0x%x\n", i++, sel);
452 }
453
454 seeker += 2;
455 }
456
457 selectors = overloads = getInt16(data + seeker);
458
459 if (pass_no == 2)
460 sciprintf("Overloaded functions: %x\n", overloads);
461
462 seeker += 2;
463
464 while (overloads--) {
465 word selector = getInt16(data + (seeker)) & 0xffff;
466 if (d->old_header) selector >>= 1;
467
468 if (pass_no == 1) {
469 sprintf(buf, "%s::%s", name, get_selector_name(d, selector));
470 script_add_name(s, getInt16(data + seeker + selectors*2 + 2), buf, species);
471 } else {
472 sciprintf(" [%03x] %s: @", selector, get_selector_name(d, selector));
473 sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2));
474 }
475
476 seeker += 2;
477 }
478 }
479
480 static void
481 script_dump_class(disasm_state_t *d, script_state_t *s,
482 unsigned char *data, int seeker, int objsize, int pass_no) {
483 word selectors, overloads, selectorsize;
484 int species = getInt16(data + 8 + seeker);
485 int superclass = getInt16(data + 10 + seeker);
486 int namepos = getInt16(data + 14 + seeker);
487 const char *name;
488 char buf [256];
489 int i;
490
491 name = namepos ? ((const char *)data + namepos) : "<unknown>";
492 selectors = (selectorsize = getInt16(data + seeker + 6));
493
494 if (pass_no == 1) {
495 if (species >= 0 && species < d->class_count) {
496 if (!namepos) {
497 sprintf(buf, "class_%d", species);
498 d->class_names [species] = sci_strdup(buf);
499 } else
500 d->class_names [species] = sci_strdup(name);
501
502 d->class_selector_count [species] = selectors;
503 d->class_selectors [species] = (short *) sci_malloc(sizeof(short) * selectors);
504 }
505 }
506
507 if (pass_no == 2) {
508 sciprintf(".class\n");
509 sciprintf("Name: %s\n", name);
510 sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass);
511 sciprintf("Species: %x\n", species);
512 sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff);
513
514 sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4));
515 sciprintf("Selectors [%x]:\n", selectors);
516 }
517
518 seeker += 8;
519 selectorsize <<= 1;
520
521 for (i = 0; i < selectors; i++) {
522 word selector = 0xffff & getInt16(data + (seeker) + selectorsize);
523 if (d->old_header) selector >>= 1;
524
525 if (pass_no == 1) {
526 if (species >= 0 && species < d->class_count)
527 d->class_selectors [species][i] = selector;
528 } else
529 sciprintf(" [%03x] %s = 0x%x\n", selector, get_selector_name(d, selector),
530 getInt16(data + seeker) & 0xffff);
531
532 seeker += 2;
533 }
534
535 seeker += selectorsize;
536
537 selectors = overloads = getInt16(data + seeker);
538
539 sciprintf("Overloaded functions: %x\n", overloads);
540
541 seeker += 2;
542
543 while (overloads--) {
544 word selector = getInt16(data + (seeker)) & 0xffff;
545 if (d->old_header) selector >>= 1;
546
547 if (pass_no == 1) {
548 sprintf(buf, "%s::%s", name, get_selector_name(d, selector));
549 script_add_name(s, getInt16(data + seeker + selectors*2 + 2) & 0xffff, buf, species);
550 } else {
551 sciprintf(" [%03x] %s: @", selector & 0xffff, get_selector_name(d, selector));
552 sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2) & 0xffff);
553 }
554
555 seeker += 2;
556 }
557 }
558
559 static int
560 script_dump_said_string(disasm_state_t *d, unsigned char *data, int seeker) {
561 while (1) {
562 unsigned short nextitem = (unsigned char) data [seeker++];
563 if (nextitem == 0xFF) return seeker;
564
565 if (nextitem >= 0xF0) {
566 switch (nextitem) {
567 case 0xf0:
568 sciprintf(", ");
569 break;
570 case 0xf1:
571 sciprintf("& ");
572 break;
573 case 0xf2:
574 sciprintf("/ ");
575 break;
576 case 0xf3:
577 sciprintf("( ");
578 break;
579 case 0xf4:
580 sciprintf(") ");
581 break;
582 case 0xf5:
583 sciprintf("[ ");
584 break;
585 case 0xf6:
586 sciprintf("] ");
587 break;
588 case 0xf7:
589 sciprintf("# ");
590 break;
591 case 0xf8:
592 sciprintf("< ");
593 break;
594 case 0xf9:
595 sciprintf("> ");
596 break;
597 }
598 } else {
599 nextitem = nextitem << 8 | (unsigned char) data [seeker++];
600 sciprintf("%s ", vocab_get_any_group_word(nextitem, d->words, d->word_count));
601 if (verbose)
602 sciprintf("[%03x] ", nextitem);
603 }
604 }
605 }
606
607 static void
608 script_dump_said(disasm_state_t *d, script_state_t *s,
609 unsigned char *data, int seeker, int objsize, int pass_no) {
610 int _seeker = seeker + objsize - 4;
611
612 if (pass_no == 1) {
613 script_add_area(s, seeker, seeker + objsize - 1, area_said, NULL);
614 return;
615 }
616
617 sciprintf(".said\n");
618
619 while (seeker < _seeker - 1) {
620 sciprintf("%04x: ", seeker);
621 seeker = script_dump_said_string(d, data, seeker);
622 sciprintf("\n");
623 }
624 }
625
626 static void
627 script_dump_synonyms(disasm_state_t *d, script_state_t *s,
628 unsigned char *data, int seeker, int objsize, int pass_no) {
629 int _seeker = seeker + objsize - 4;
630
631 sciprintf("Synonyms:\n");
632 while (seeker < _seeker) {
633 int search = getInt16(data + seeker);
634 int replace = getInt16(data + seeker + 2);
635 seeker += 4;
636 if (search < 0) break;
637 sciprintf("%s[%03x] ==> %s[%03x]\n",
638 vocab_get_any_group_word(search, d->words, d->word_count), search,
639 vocab_get_any_group_word(replace, d->words, d->word_count), replace);
640 }
641 }
642
643 static void
644 script_dump_strings(disasm_state_t *d, script_state_t *s,
645 unsigned char *data, int seeker, int objsize, int pass_no) {
646 int endptr = seeker + objsize - 4;
647
648 if (pass_no == 1) {
649 script_add_area(s, seeker, seeker + objsize - 1, area_string, NULL);
650 return;
651 }
652
653 sciprintf(".strings\n");
654 while (data [seeker] && seeker < endptr) {
655 sciprintf("%04x: %s\n", seeker, data + seeker);
656 seeker += strlen((char *) data + seeker) + 1;
657 }
658 }
659
660 static void
661 script_dump_exports(disasm_state_t *d, script_state_t *s,
662 unsigned char *data, int seeker, int objsize, int pass_no) {
663 byte *pexport = (byte *)(data + seeker);
664 word export_count = getUInt16(pexport);
665 int i;
666 char buf [256];
667
668 pexport += 2;
669
670 if (pass_no == 2) sciprintf(".exports\n");
671
672 for (i = 0; i < export_count; i++) {
673 if (pass_no == 1) {
674 guint16 offset = getUInt16(pexport);
675 sprintf(buf, "exp_%02X", i);
676 script_add_name(s, offset, buf, -1);
677 } else
678 sciprintf("%02X: %04X\n", i, *pexport);
679 pexport += 2;
680 }
681 }
682
683 /* -- The disassembly code ----------------------------------------------- */
684
685 static void
686 script_disassemble_code(disasm_state_t *d, script_state_t *s,
687 unsigned char *data, int seeker, int objsize, int pass_no) {
688 int endptr = seeker + objsize - 4;
689 int i = 0;
690 int cur_class = -1;
691 word dest;
692 void *area_data;
693 char buf [256];
694 char *dest_name;
695
696 if (pass_no == 2) sciprintf(".code\n");
697
698 while (seeker < endptr - 1) {
699 unsigned char opsize = data [seeker];
700 unsigned char opcode = opsize >> 1;
701 word param_value;
702 char *name;
703
704 opsize &= 1; /* byte if true, word if false */
705
706 if (pass_no == 2) {
707 name = script_find_name(s, seeker, &cur_class);
708 if (name) sciprintf(" %s:\n", name);
709 sciprintf("%04X: ", seeker);
710 sciprintf("%s", d->opcodes[opcode].name);
711 if (opcode_size && formats[opcode][0])
712 sciprintf(".%c", opsize ? 'b' : 'w');
713 sciprintf("\t");
714 }
715
716 seeker++;
717
718 for (i = 0; formats[opcode][i]; i++)
719
720 switch (formats[opcode][i]) {
721
722 case Script_Invalid:
723 if (pass_no == 2) sciprintf("-Invalid operation-");
724 break;
725
726 case Script_SByte:
727 case Script_Byte:
728 if (pass_no == 2) sciprintf(" %02x", data[seeker]);
729 seeker++;
730 break;
731
732 case Script_Word:
733 case Script_SWord:
734 if (pass_no == 2)
735 sciprintf(" %04x", 0xffff & (data[seeker] | (data[seeker+1] << 8)));
736 seeker += 2;
737 break;
738
739 case Script_SVariable:
740 case Script_Variable:
741 case Script_Global:
742 case Script_Local:
743 case Script_Temp:
744 case Script_Param:
745 case Script_SRelative:
746 case Script_Property:
747 case Script_Offset:
748 if (opsize)
749 param_value = data [seeker++];
750 else {
751 param_value = 0xffff & (data[seeker] | (data[seeker+1] << 8));
752 seeker += 2;
753 }
754
755 if (pass_no == 1) {
756 if (opcode == op_jmp || opcode == op_bt || opcode == op_bnt) {
757 dest = seeker + (short) param_value;
758 sprintf(buf, "lbl_%04X", dest);
759 script_add_name(s, dest, buf, -2);
760 }
761 } else if (pass_no == 2)
762 switch (formats[opcode][i]) {
763
764 case Script_SVariable:
765 case Script_Variable:
766 if (opcode == op_callk) {
767 sciprintf(" #%s", (param_value < d->kernel_names_nr)
768 ? d->kernel_names[param_value] : "<invalid>");
769 if (verbose) sciprintf("[%x]", param_value);
770 } else if (opcode == op_class || (opcode == op_super && i == 0)) {
771 sciprintf(" %s", (d->class_names && param_value < d->class_count)
772 ? d->class_names[param_value] : "<invalid>");
773 if (verbose) sciprintf("[%x]", param_value);
774 } else sciprintf(opsize ? " %02x" : " %04x", param_value);
775
776 if (opcode == op_pushi && param_value > 0 && param_value < d->selector_count)
777 sciprintf("\t\t; selector <%s>", d->snames [param_value]);
778
779 break;
780
781 case Script_Global:
782 sciprintf(" global_%d", param_value);
783 break;
784
785 case Script_Local:
786 sciprintf(" local_%d", param_value);
787 break;
788
789 case Script_Temp:
790 sciprintf(" temp_%d", param_value);
791 break;
792
793 case Script_Param:
794 sciprintf(" param_%d", param_value);
795 break;
796
797 case Script_Offset:
798 dest = (short) param_value;
799 dest_name = script_find_name(s, dest, NULL);
800 if (dest_name)
801 sciprintf(" %s", dest_name);
802 else
803 sciprintf(" %04x", dest);
804
805 if (verbose)
806 sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value);
807
808 if (opcode == op_lofsa || opcode == op_lofss) {
809 int atype = script_get_area_type(s, dest, &area_data);
810 if (atype == area_string) {
811 strncpy(buf, (char *) &data [dest], sizeof(buf) - 1);
812 buf [sizeof(buf)-1] = 0;
813 if (strlen(buf) > 40) {
814 buf [40] = 0;
815 strcat(buf, "...");
816 }
817 sciprintf("\t\t; \"%s\"", buf);
818 } else if (atype == area_said) {
819 sciprintf("\t\t; said \"");
820 script_dump_said_string(d, data, dest);
821 sciprintf("\"\n");
822 } else if (atype == area_object)
823 sciprintf("\t\t; object <%s>", area_data);
824 }
825 break;
826
827 case Script_SRelative:
828 dest = seeker + (short) param_value;
829 dest_name = script_find_name(s, dest, NULL);
830 if (dest_name)
831 sciprintf(" %s", dest_name);
832 else
833 sciprintf(" %04x", dest);
834
835 if (verbose)
836 sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value);
837
838 if (opcode == op_lofsa || opcode == op_lofss) {
839 int atype = script_get_area_type(s, dest, &area_data);
840 if (atype == area_string) {
841 strncpy(buf, (char *) &data [dest], sizeof(buf) - 1);
842 buf [sizeof(buf)-1] = 0;
843 if (strlen(buf) > 40) {
844 buf [40] = 0;
845 strcat(buf, "...");
846 }
847 sciprintf("\t\t; \"%s\"", buf);
848 } else if (atype == area_said) {
849 sciprintf("\t\t; said \"");
850 script_dump_said_string(d, data, dest);
851 sciprintf("\"\n");
852 } else if (atype == area_object)
853 sciprintf("\t\t; object <%s>", area_data);
854 }
855 break;
856
857 case Script_Property:
858 if (cur_class != -1 && param_value / 2 < d->class_selector_count [cur_class]) {
859 sciprintf(" %s", get_selector_name(d, d->class_selectors [cur_class][param_value/2]));
860 if (verbose) sciprintf("[%x]", param_value);
861 } else
862 sciprintf(opsize ? " %02x" : " %04x", param_value);
863
864 break;
865
866 case Script_End:
867 if (pass_no == 2) sciprintf("\n");
868 break;
869
870 default:
871 sciprintf("Unexpected opcode format %d\n", (formats[opcode][i]));
872 }
873
874 default:
875 break;
876 }
877 if (pass_no == 2) sciprintf("\n");
878
879 }
880
881 }
882
883 void
884 disassemble_script_pass(disasm_state_t *d, script_state_t *s,
885 resource_t *script, int pass_no) {
886 int _seeker = 0;
887 word id = getInt16(script->data);
888
889 if (id > 15) {
890 if (pass_no == 2) sciprintf("; Old script header detected\n");
891 d->old_header = 1;
892 }
893
894 if (d->old_header) _seeker = 2;
895
896 while (_seeker < script->size) {
897 int objtype = getInt16(script->data + _seeker);
898 int objsize;
899 int seeker = _seeker + 4;
900
901 if (!objtype) return;
902
903 if (pass_no == 2)
904 sciprintf("\n");
905
906 objsize = getInt16(script->data + _seeker + 2);
907
908 if (pass_no == 2) {
909 sciprintf("; Obj type #%x, offset 0x%x, size 0x%x:\n", objtype, _seeker, objsize);
910 if (hexdump) sci_hexdump(script->data + seeker, objsize - 4, seeker);
911 }
912
913 _seeker += objsize;
914
915 switch (objtype) {
916 case sci_obj_object:
917 script_dump_object(d, s, script->data, seeker, objsize, pass_no);
918 break;
919
920 case sci_obj_code:
921 script_disassemble_code(d, s, script->data, seeker, objsize, pass_no);
922 break;
923
924 case sci_obj_synonyms:
925 script_dump_synonyms(d, s, script->data, seeker, objsize, pass_no);
926 break;
927
928 case sci_obj_said:
929 script_dump_said(d, s, script->data, seeker, objsize, pass_no);
930 break;
931
932 case sci_obj_strings:
933 script_dump_strings(d, s, script->data, seeker, objsize, pass_no);
934 break;
935
936 case sci_obj_class:
937 script_dump_class(d, s, script->data, seeker, objsize, pass_no);
938 break;
939
940 case sci_obj_exports:
941 script_dump_exports(d, s, script->data, seeker, objsize, pass_no);
942 break;
943
944 case sci_obj_pointers:
945 if (pass_no == 2) {
946 sciprintf("Pointers\n");
947 sci_hexdump(script->data + seeker, objsize - 4, seeker);
948 };
949 break;
950
951 case sci_obj_preload_text:
952 if (pass_no == 2) {
953 sciprintf("The script has a preloaded text resource\n");
954 };
955 break;
956
957 case sci_obj_localvars:
958 if (pass_no == 2) {
959 sciprintf("Local vars\n");
960 sci_hexdump(script->data + seeker, objsize - 4, seeker);
961 };
962 break;
963
964 default:
965 sciprintf("Unsupported %d!\n", objtype);
966 return;
967 }
968 }
969
970 sciprintf("Script ends without terminator\n");
971 }
972
973 void
974 disassemble_script(disasm_state_t *d, int res_no, int pass_no) {
975 resource_t *script = scir_find_resource(resmgr, sci_script, res_no, 0);
976 script_state_t *s = find_script_state(d, res_no);
977
978 if (!script) {
979 sciprintf("Script not found!\n");
980 return;
981 }
982
983 disassemble_script_pass(d, s, script, pass_no);
984 }
985