aboutsummaryrefslogtreecommitdiff
path: root/devtools/sci/scidisasm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/sci/scidisasm.cpp')
-rw-r--r--devtools/sci/scidisasm.cpp987
1 files changed, 987 insertions, 0 deletions
diff --git a/devtools/sci/scidisasm.cpp b/devtools/sci/scidisasm.cpp
new file mode 100644
index 0000000000..39ea7f9c41
--- /dev/null
+++ b/devtools/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);
+}