diff options
Diffstat (limited to 'tools/sci/scidisasm.cpp')
-rw-r--r-- | tools/sci/scidisasm.cpp | 987 |
1 files changed, 987 insertions, 0 deletions
diff --git a/tools/sci/scidisasm.cpp b/tools/sci/scidisasm.cpp new file mode 100644 index 0000000000..39ea7f9c41 --- /dev/null +++ b/tools/sci/scidisasm.cpp @@ -0,0 +1,987 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ + +#define MALLOC_DEBUG + +#include <sciresource.h> +#include <engine.h> +#include <console.h> +#include <versions.h> + +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif /* HAVE_GETOPT_H */ + +static int hexdump = 0; +static int opcode_size = 0; +static int verbose = 0; + +static resource_mgr_t *resmgr; + +#ifdef HAVE_GETOPT_LONG +static struct option options[] = { + {"version", no_argument, 0, 256}, + {"help", no_argument, 0, 'h'}, + {"hexdump", no_argument, &hexdump, 1}, + {"opcode-size", no_argument, &opcode_size, 1}, + {"verbose", no_argument, &verbose, 1}, + {"gamedir", required_argument, 0, 'd'}, + {0, 0, 0, 0} +}; +#endif /* HAVE_GETOPT_LONG */ + +#define SCI_ASSUME_VERSION SCI_VERSION_FTU_NEW_SCRIPT_HEADER + +typedef struct name_s { + int offset; + char *name; + int class_no; + struct name_s *next; +} name_t; + +typedef struct area_s { + int start_offset; + int end_offset; + void *data; + struct area_s *next; +} area_t; + +enum area_type { area_said, area_string, area_object, area_last }; + +typedef struct script_state_s { + int script_no; + name_t *names; + area_t *areas [area_last]; + + struct script_state_s *next; +} script_state_t; + +typedef struct disasm_state_s { + char **snames; + int selector_count; + opcode *opcodes; + int kernel_names_nr; + char **kernel_names; + word_t **words; + int word_count; + + char **class_names; + int *class_selector_count; + short **class_selectors; + int class_count; + int old_header; + + script_state_t *scripts; +} disasm_state_t; + +void +disassemble_script(disasm_state_t *d, int res_no, int pass_no); + +script_state_t * +find_script_state(disasm_state_t *d, int script_no); + +void +script_free_names(script_state_t *s); + +void +script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no); + +char * +script_find_name(script_state_t *s, int offset, int *class_no); + +void +script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data); + +void +script_free_areas(script_state_t *s); + +int +script_get_area_type(script_state_t *s, int offset, void **pdata); + +void +disasm_init(disasm_state_t *d); + +void +disasm_free_state(disasm_state_t *d); + +int main(int argc, char** argv) { + int i; + char outfilename [256]; + int optindex = 0; + int c; + disasm_state_t disasm_state; + char *gamedir = NULL; + int res_version = SCI_VERSION_AUTODETECT; + +#ifdef HAVE_GETOPT_LONG + while ((c = getopt_long(argc, argv, "vhxr:d:", options, &optindex)) > -1) { +#else /* !HAVE_GETOPT_H */ + while ((c = getopt(argc, argv, "vhxr:d:")) > -1) { +#endif /* !HAVE_GETOPT_H */ + + switch (c) { + case 256: + printf("scidisasm ("PACKAGE") "VERSION"\n"); + printf("This program is copyright (C) 1999 Christoph Reichenbach.\n" + "It comes WITHOUT WARRANTY of any kind.\n" + "This is free software, released under the GNU General Public License.\n"); + exit(0); + + case 'h': + printf("Usage: scidisasm\n" + "\nAvailable options:\n" + " --version Prints the version number\n" + " --help -h Displays this help message\n" + " --gamedir <dir> -d<dir> Read game resources from dir\n" + " --hexdump -x Hex dump all script resources\n" + " --verbose Print additional disassembly information\n" + " --opcode-size Print opcode size postfixes\n"); + exit(0); + + case 'd': + if (gamedir) sci_free(gamedir); + gamedir = sci_strdup(optarg); + break; + + case 'r': + res_version = atoi(optarg); + break; + + case 0: /* getopt_long already did this for us */ + case '?': + /* getopt_long already printed an error message. */ + break; + + default: + return -1; + } + } + + if (gamedir) + if (chdir(gamedir)) { + printf("Error changing to game directory '%s'\n", gamedir); + exit(1); + } + + printf("Loading resources...\n"); + if (!(resmgr = scir_new_resource_manager(sci_getcwd(), res_version, + 1, 1024 * 128))) { + fprintf(stderr, "Could not find any resources; quitting.\n"); + exit(1); + } + + disasm_init(&disasm_state); + + script_adjust_opcode_formats(resmgr->sci_version); + + printf("Performing first pass...\n"); + for (i = 0; i < resmgr->resources_nr; i++) + if (resmgr->resources[i].type == sci_script) + disassemble_script(&disasm_state, + resmgr->resources[i].number, 1); + + printf("Performing second pass...\n"); + for (i = 0; i < resmgr->resources_nr; i++) + if (resmgr->resources[i].type == sci_script) { + sprintf(outfilename, "%03d.script", + resmgr->resources[i].number); + open_console_file(outfilename); + disassemble_script(&disasm_state, + resmgr->resources[i].number, 2); + } + + close_console_file(); + disasm_free_state(&disasm_state); + + free(resmgr->resource_path); + scir_free_resource_manager(resmgr); + return 0; +} + +/* -- General operations on disasm_state_t ------------------------------- */ + +void +disasm_init(disasm_state_t *d) { + d->snames = vocabulary_get_snames(resmgr, &d->selector_count, SCI_ASSUME_VERSION); + d->opcodes = vocabulary_get_opcodes(resmgr); + d->kernel_names = vocabulary_get_knames(resmgr, &d->kernel_names_nr); + d->words = vocab_get_words(resmgr, &d->word_count); + d->scripts = NULL; + d->old_header = 0; + + d->class_count = vocabulary_get_class_count(resmgr); + d->class_names = (char **) sci_malloc(d->class_count * sizeof(char *)); + memset(d->class_names, 0, d->class_count * sizeof(char *)); + d->class_selector_count = (int *) sci_malloc(d->class_count * sizeof(int)); + memset(d->class_selector_count, 0, d->class_count * sizeof(int)); + d->class_selectors = (short **) sci_malloc(d->class_count * sizeof(short *)); + memset(d->class_selectors, 0, d->class_count * sizeof(short *)); +} + +void +disasm_free_state(disasm_state_t *d) { + script_state_t *s, *next_script; + int i; + + s = d->scripts; + while (s) { + next_script = s->next; + script_free_names(s); + script_free_areas(s); + s = next_script; + } + + for (i = 0; i < d->class_count; i++) { + if (d->class_names [i]) sci_free(d->class_names [i]); + if (d->class_selectors [i]) sci_free(d->class_selectors [i]); + } + + free(d->class_names); + free(d->class_selectors); + free(d->class_selector_count); + + vocabulary_free_snames(d->snames); + vocabulary_free_opcodes(d->opcodes); + vocabulary_free_knames(d->kernel_names); + vocab_free_words(d->words, d->word_count); +} + +script_state_t * +find_script_state(disasm_state_t *d, int script_no) { + script_state_t *s; + + for (s = d->scripts; s; s = s->next) + if (s->script_no == script_no) return s; + + s = (script_state_t *) sci_malloc(sizeof(script_state_t)); + memset(s, 0, sizeof(script_state_t)); + s->script_no = script_no; + s->next = d->scripts; + + d->scripts = s; + return s; +} + +/* -- Name table operations ---------------------------------------------- */ + +void +script_free_names(script_state_t *s) { + name_t *p = s->names, *next_name; + + while (p) { + next_name = p->next; + free(p->name); + free(p); + p = next_name; + } + + s->names = NULL; +} + +void +script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no) { + name_t *p; + char *name = script_find_name(s, aoffset, NULL); + if (name) return; + + p = (name_t *) sci_malloc(sizeof(name_t)); + p->offset = aoffset; + p->name = sci_strdup(aname); + p->class_no = aclass_no; + p->next = s->names; + s->names = p; +} + +char * +script_find_name(script_state_t *s, int offset, int *aclass_no) { + name_t *p; + + for (p = s->names; p; p = p->next) + if (p->offset == offset) { + if (aclass_no && p->class_no != -2) *aclass_no = p->class_no; + return p->name; + } + + return NULL; +} + +/* -- Area table operations ---------------------------------------------- */ + +void +script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data) { + area_t *area; + + area = (area_t *) sci_malloc(sizeof(area_t)); + area->start_offset = start_offset; + area->end_offset = end_offset; + area->data = data; + area->next = s->areas [type]; + + s->areas [type] = area; +} + +void +script_free_areas(script_state_t *s) { + int i; + + for (i = 0; i < area_last; i++) { + area_t *area = s->areas [i], *next_area; + while (area) { + next_area = area->next; + free(area); + area = next_area; + } + } +} + +int +script_get_area_type(script_state_t *s, int offset, void **pdata) { + int i; + + for (i = 0; i < area_last; i++) { + area_t *area = s->areas [i]; + while (area) { + if (area->start_offset <= offset && area->end_offset >= offset) { + if (pdata != NULL) *pdata = area->data; + return i; + } + area = area->next; + } + } + + return -1; +} + +char * +get_selector_name(disasm_state_t *d, int selector) { + static char selector_name [256]; + + if (d->snames && selector >= 0 && selector < d->selector_count) + return d->snames [selector]; + else { + sprintf(selector_name, "unknown_sel_%X", selector); + return selector_name; + } +} + +const char * +get_class_name(disasm_state_t *d, int class_no) { + static char class_name [256]; + + if (class_no == -1) + return "<none>"; + else if (class_no >= 0 && class_no < d->class_count && d->class_names [class_no]) + return d->class_names [class_no]; + else { + sprintf(class_name, "class_%d", class_no); + return class_name; + } +} + +/* -- Code to dump individual script block types ------------------------- */ + +static void +script_dump_object(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int selectors, overloads, selectorsize; + int species = getInt16(data + 8 + seeker); + int superclass = getInt16(data + 10 + seeker); + int namepos = getInt16(data + 14 + seeker); + int i = 0; + short sel; + const char *name; + char buf [256]; + short *sels; + + selectors = (selectorsize = getInt16(data + seeker + 6)); + name = namepos ? ((const char *)data + namepos) : "<unknown>"; + + if (pass_no == 1) + script_add_area(s, seeker, seeker + objsize - 1, area_object, strdup(name)); + + if (pass_no == 2) { + sciprintf(".object\n"); + sciprintf("Name: %s\n", name); + sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass); + sciprintf("Species: %s [%x]\n", get_class_name(d, species), species); + + sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff); + + sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4)); + sciprintf("Selectors [%x]:\n", selectors); + } + + seeker += 8; + + if (species < d->class_count) + sels = d->class_selectors [species]; + else + sels = NULL; + + while (selectors--) { + if (pass_no == 2) { + sel = getInt16(data + seeker) & 0xffff; + if (sels && (sels [i] >= 0) && (sels[i] < d->selector_count)) { + sciprintf(" [#%03x] %s = 0x%x\n", i, d->snames [sels [i]], sel); + i++; + } else + sciprintf(" [#%03x] <unknown> = 0x%x\n", i++, sel); + } + + seeker += 2; + } + + selectors = overloads = getInt16(data + seeker); + + if (pass_no == 2) + sciprintf("Overloaded functions: %x\n", overloads); + + seeker += 2; + + while (overloads--) { + word selector = getInt16(data + (seeker)) & 0xffff; + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + sprintf(buf, "%s::%s", name, get_selector_name(d, selector)); + script_add_name(s, getInt16(data + seeker + selectors*2 + 2), buf, species); + } else { + sciprintf(" [%03x] %s: @", selector, get_selector_name(d, selector)); + sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2)); + } + + seeker += 2; + } +} + +static void +script_dump_class(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + word selectors, overloads, selectorsize; + int species = getInt16(data + 8 + seeker); + int superclass = getInt16(data + 10 + seeker); + int namepos = getInt16(data + 14 + seeker); + const char *name; + char buf [256]; + int i; + + name = namepos ? ((const char *)data + namepos) : "<unknown>"; + selectors = (selectorsize = getInt16(data + seeker + 6)); + + if (pass_no == 1) { + if (species >= 0 && species < d->class_count) { + if (!namepos) { + sprintf(buf, "class_%d", species); + d->class_names [species] = sci_strdup(buf); + } else + d->class_names [species] = sci_strdup(name); + + d->class_selector_count [species] = selectors; + d->class_selectors [species] = (short *) sci_malloc(sizeof(short) * selectors); + } + } + + if (pass_no == 2) { + sciprintf(".class\n"); + sciprintf("Name: %s\n", name); + sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass); + sciprintf("Species: %x\n", species); + sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff); + + sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4)); + sciprintf("Selectors [%x]:\n", selectors); + } + + seeker += 8; + selectorsize <<= 1; + + for (i = 0; i < selectors; i++) { + word selector = 0xffff & getInt16(data + (seeker) + selectorsize); + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + if (species >= 0 && species < d->class_count) + d->class_selectors [species][i] = selector; + } else + sciprintf(" [%03x] %s = 0x%x\n", selector, get_selector_name(d, selector), + getInt16(data + seeker) & 0xffff); + + seeker += 2; + } + + seeker += selectorsize; + + selectors = overloads = getInt16(data + seeker); + + sciprintf("Overloaded functions: %x\n", overloads); + + seeker += 2; + + while (overloads--) { + word selector = getInt16(data + (seeker)) & 0xffff; + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + sprintf(buf, "%s::%s", name, get_selector_name(d, selector)); + script_add_name(s, getInt16(data + seeker + selectors*2 + 2) & 0xffff, buf, species); + } else { + sciprintf(" [%03x] %s: @", selector & 0xffff, get_selector_name(d, selector)); + sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2) & 0xffff); + } + + seeker += 2; + } +} + +static int +script_dump_said_string(disasm_state_t *d, unsigned char *data, int seeker) { + while (1) { + unsigned short nextitem = (unsigned char) data [seeker++]; + if (nextitem == 0xFF) return seeker; + + if (nextitem >= 0xF0) { + switch (nextitem) { + case 0xf0: + sciprintf(", "); + break; + case 0xf1: + sciprintf("& "); + break; + case 0xf2: + sciprintf("/ "); + break; + case 0xf3: + sciprintf("( "); + break; + case 0xf4: + sciprintf(") "); + break; + case 0xf5: + sciprintf("[ "); + break; + case 0xf6: + sciprintf("] "); + break; + case 0xf7: + sciprintf("# "); + break; + case 0xf8: + sciprintf("< "); + break; + case 0xf9: + sciprintf("> "); + break; + } + } else { + nextitem = nextitem << 8 | (unsigned char) data [seeker++]; + sciprintf("%s ", vocab_get_any_group_word(nextitem, d->words, d->word_count)); + if (verbose) + sciprintf("[%03x] ", nextitem); + } + } +} + +static void +script_dump_said(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int _seeker = seeker + objsize - 4; + + if (pass_no == 1) { + script_add_area(s, seeker, seeker + objsize - 1, area_said, NULL); + return; + } + + sciprintf(".said\n"); + + while (seeker < _seeker - 1) { + sciprintf("%04x: ", seeker); + seeker = script_dump_said_string(d, data, seeker); + sciprintf("\n"); + } +} + +static void +script_dump_synonyms(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int _seeker = seeker + objsize - 4; + + sciprintf("Synonyms:\n"); + while (seeker < _seeker) { + int search = getInt16(data + seeker); + int replace = getInt16(data + seeker + 2); + seeker += 4; + if (search < 0) break; + sciprintf("%s[%03x] ==> %s[%03x]\n", + vocab_get_any_group_word(search, d->words, d->word_count), search, + vocab_get_any_group_word(replace, d->words, d->word_count), replace); + } +} + +static void +script_dump_strings(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int endptr = seeker + objsize - 4; + + if (pass_no == 1) { + script_add_area(s, seeker, seeker + objsize - 1, area_string, NULL); + return; + } + + sciprintf(".strings\n"); + while (data [seeker] && seeker < endptr) { + sciprintf("%04x: %s\n", seeker, data + seeker); + seeker += strlen((char *) data + seeker) + 1; + } +} + +static void +script_dump_exports(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + byte *pexport = (byte *)(data + seeker); + word export_count = getUInt16(pexport); + int i; + char buf [256]; + + pexport += 2; + + if (pass_no == 2) sciprintf(".exports\n"); + + for (i = 0; i < export_count; i++) { + if (pass_no == 1) { + guint16 offset = getUInt16(pexport); + sprintf(buf, "exp_%02X", i); + script_add_name(s, offset, buf, -1); + } else + sciprintf("%02X: %04X\n", i, *pexport); + pexport += 2; + } +} + +/* -- The disassembly code ----------------------------------------------- */ + +static void +script_disassemble_code(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int endptr = seeker + objsize - 4; + int i = 0; + int cur_class = -1; + word dest; + void *area_data; + char buf [256]; + char *dest_name; + + if (pass_no == 2) sciprintf(".code\n"); + + while (seeker < endptr - 1) { + unsigned char opsize = data [seeker]; + unsigned char opcode = opsize >> 1; + word param_value; + char *name; + + opsize &= 1; /* byte if true, word if false */ + + if (pass_no == 2) { + name = script_find_name(s, seeker, &cur_class); + if (name) sciprintf(" %s:\n", name); + sciprintf("%04X: ", seeker); + sciprintf("%s", d->opcodes[opcode].name); + if (opcode_size && formats[opcode][0]) + sciprintf(".%c", opsize ? 'b' : 'w'); + sciprintf("\t"); + } + + seeker++; + + for (i = 0; formats[opcode][i]; i++) + + switch (formats[opcode][i]) { + + case Script_Invalid: + if (pass_no == 2) sciprintf("-Invalid operation-"); + break; + + case Script_SByte: + case Script_Byte: + if (pass_no == 2) sciprintf(" %02x", data[seeker]); + seeker++; + break; + + case Script_Word: + case Script_SWord: + if (pass_no == 2) + sciprintf(" %04x", 0xffff & (data[seeker] | (data[seeker+1] << 8))); + seeker += 2; + break; + + case Script_SVariable: + case Script_Variable: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: + case Script_SRelative: + case Script_Property: + case Script_Offset: + if (opsize) + param_value = data [seeker++]; + else { + param_value = 0xffff & (data[seeker] | (data[seeker+1] << 8)); + seeker += 2; + } + + if (pass_no == 1) { + if (opcode == op_jmp || opcode == op_bt || opcode == op_bnt) { + dest = seeker + (short) param_value; + sprintf(buf, "lbl_%04X", dest); + script_add_name(s, dest, buf, -2); + } + } else if (pass_no == 2) + switch (formats[opcode][i]) { + + case Script_SVariable: + case Script_Variable: + if (opcode == op_callk) { + sciprintf(" #%s", (param_value < d->kernel_names_nr) + ? d->kernel_names[param_value] : "<invalid>"); + if (verbose) sciprintf("[%x]", param_value); + } else if (opcode == op_class || (opcode == op_super && i == 0)) { + sciprintf(" %s", (d->class_names && param_value < d->class_count) + ? d->class_names[param_value] : "<invalid>"); + if (verbose) sciprintf("[%x]", param_value); + } else sciprintf(opsize ? " %02x" : " %04x", param_value); + + if (opcode == op_pushi && param_value > 0 && param_value < d->selector_count) + sciprintf("\t\t; selector <%s>", d->snames [param_value]); + + break; + + case Script_Global: + sciprintf(" global_%d", param_value); + break; + + case Script_Local: + sciprintf(" local_%d", param_value); + break; + + case Script_Temp: + sciprintf(" temp_%d", param_value); + break; + + case Script_Param: + sciprintf(" param_%d", param_value); + break; + + case Script_Offset: + dest = (short) param_value; + dest_name = script_find_name(s, dest, NULL); + if (dest_name) + sciprintf(" %s", dest_name); + else + sciprintf(" %04x", dest); + + if (verbose) + sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value); + + if (opcode == op_lofsa || opcode == op_lofss) { + int atype = script_get_area_type(s, dest, &area_data); + if (atype == area_string) { + strncpy(buf, (char *) &data [dest], sizeof(buf) - 1); + buf [sizeof(buf)-1] = 0; + if (strlen(buf) > 40) { + buf [40] = 0; + strcat(buf, "..."); + } + sciprintf("\t\t; \"%s\"", buf); + } else if (atype == area_said) { + sciprintf("\t\t; said \""); + script_dump_said_string(d, data, dest); + sciprintf("\"\n"); + } else if (atype == area_object) + sciprintf("\t\t; object <%s>", area_data); + } + break; + + case Script_SRelative: + dest = seeker + (short) param_value; + dest_name = script_find_name(s, dest, NULL); + if (dest_name) + sciprintf(" %s", dest_name); + else + sciprintf(" %04x", dest); + + if (verbose) + sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value); + + if (opcode == op_lofsa || opcode == op_lofss) { + int atype = script_get_area_type(s, dest, &area_data); + if (atype == area_string) { + strncpy(buf, (char *) &data [dest], sizeof(buf) - 1); + buf [sizeof(buf)-1] = 0; + if (strlen(buf) > 40) { + buf [40] = 0; + strcat(buf, "..."); + } + sciprintf("\t\t; \"%s\"", buf); + } else if (atype == area_said) { + sciprintf("\t\t; said \""); + script_dump_said_string(d, data, dest); + sciprintf("\"\n"); + } else if (atype == area_object) + sciprintf("\t\t; object <%s>", area_data); + } + break; + + case Script_Property: + if (cur_class != -1 && param_value / 2 < d->class_selector_count [cur_class]) { + sciprintf(" %s", get_selector_name(d, d->class_selectors [cur_class][param_value/2])); + if (verbose) sciprintf("[%x]", param_value); + } else + sciprintf(opsize ? " %02x" : " %04x", param_value); + + break; + + case Script_End: + if (pass_no == 2) sciprintf("\n"); + break; + + default: + sciprintf("Unexpected opcode format %d\n", (formats[opcode][i])); + } + + default: + break; + } + if (pass_no == 2) sciprintf("\n"); + + } + +} + +void +disassemble_script_pass(disasm_state_t *d, script_state_t *s, + resource_t *script, int pass_no) { + int _seeker = 0; + word id = getInt16(script->data); + + if (id > 15) { + if (pass_no == 2) sciprintf("; Old script header detected\n"); + d->old_header = 1; + } + + if (d->old_header) _seeker = 2; + + while (_seeker < script->size) { + int objtype = getInt16(script->data + _seeker); + int objsize; + int seeker = _seeker + 4; + + if (!objtype) return; + + if (pass_no == 2) + sciprintf("\n"); + + objsize = getInt16(script->data + _seeker + 2); + + if (pass_no == 2) { + sciprintf("; Obj type #%x, offset 0x%x, size 0x%x:\n", objtype, _seeker, objsize); + if (hexdump) sci_hexdump(script->data + seeker, objsize - 4, seeker); + } + + _seeker += objsize; + + switch (objtype) { + case sci_obj_object: + script_dump_object(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_code: + script_disassemble_code(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_synonyms: + script_dump_synonyms(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_said: + script_dump_said(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_strings: + script_dump_strings(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_class: + script_dump_class(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_exports: + script_dump_exports(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_pointers: + if (pass_no == 2) { + sciprintf("Pointers\n"); + sci_hexdump(script->data + seeker, objsize - 4, seeker); + }; + break; + + case sci_obj_preload_text: + if (pass_no == 2) { + sciprintf("The script has a preloaded text resource\n"); + }; + break; + + case sci_obj_localvars: + if (pass_no == 2) { + sciprintf("Local vars\n"); + sci_hexdump(script->data + seeker, objsize - 4, seeker); + }; + break; + + default: + sciprintf("Unsupported %d!\n", objtype); + return; + } + } + + sciprintf("Script ends without terminator\n"); +} + +void +disassemble_script(disasm_state_t *d, int res_no, int pass_no) { + resource_t *script = scir_find_resource(resmgr, sci_script, res_no, 0); + script_state_t *s = find_script_state(d, res_no); + + if (!script) { + sciprintf("Script not found!\n"); + return; + } + + disassemble_script_pass(d, s, script, pass_no); +} |