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