aboutsummaryrefslogtreecommitdiff
path: root/devtools/sci
diff options
context:
space:
mode:
authorMax Horn2011-04-09 23:47:35 +0200
committerMax Horn2011-04-09 23:47:35 +0200
commit6cf1de87acdb878e3a3e4ef7cc33d45adee4a592 (patch)
treed20295fc02d514a62ee4f22a5a34136316d0916c /devtools/sci
parentae49865e9e48b8569922d2ea1792541fb23b4a64 (diff)
downloadscummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.tar.gz
scummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.tar.bz2
scummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.zip
DEVTOOLS: Renamed 'tools' directory to 'devtools'
Diffstat (limited to 'devtools/sci')
-rw-r--r--devtools/sci/musicplayer.cpp103
-rw-r--r--devtools/sci/scidisasm.cpp987
-rw-r--r--devtools/sci/scipack.cpp208
-rw-r--r--devtools/sci/scitrace.asm136
4 files changed, 1434 insertions, 0 deletions
diff --git a/devtools/sci/musicplayer.cpp b/devtools/sci/musicplayer.cpp
new file mode 100644
index 0000000000..139ce451ef
--- /dev/null
+++ b/devtools/sci/musicplayer.cpp
@@ -0,0 +1,103 @@
+/* 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 */
+
+#include <sfx_iterator_internal.h>
+#include <sfx_engine.h>
+#include <sfx_core.h>
+#include <resource.h>
+
+#define DUMMY_SOUND_HANDLE 0xdeadbeef
+
+static song_iterator_t *
+build_iterator(resource_mgr_t *resmgr, int song_nr, int type, songit_id_t id) {
+ resource_t *song = scir_find_resource(resmgr, sci_sound, song_nr, 0);
+
+ if (!song)
+ return NULL;
+
+ return songit_new(song->data, song->size, type, id);
+}
+
+int main(int argc, char** argv) {
+ resource_mgr_t *resmgr;
+ sfx_state_t sound;
+ int res_version = SCI_VERSION_AUTODETECT;
+ int sound_nr;
+ song_handle_t dummy1;
+ int dummy2;
+ int arg;
+ int it_type = SCI_SONG_ITERATOR_TYPE_SCI0;
+ song_iterator_t *base, *ff;
+
+ printf("FreeSCI %s music player Copyright (C) 1999-2007\n", VERSION);
+ printf(" Dmitry Jemerov, Christopher T. Lansdown, Sergey Lapin, Rickard Lind,\n"
+ " Carl Muckenhoupt, Christoph Reichenbach, Magnus Reftel, Lars Skovlund,\n"
+ " Rink Springer, Petr Vyhnak, Solomon Peachy, Matt Hargett, Alex Angas\n"
+ " Walter van Niftrik, Rainer Canavan, Ruediger Hanke, Hugues Valois\n"
+ "This program is free software. You can copy and/or modify it freely\n"
+ "according to the terms of the GNU general public license, v2.0\n"
+ "or any later version, at your option.\n"
+ "It comes with ABSOLUTELY NO WARRANTY.\n");
+ if (argc < 3) {
+ fprintf(stderr, "Syntax: %s <resource dir> <sound number> [<sound number> ...]\n", argv[0]);
+ return 1;
+ }
+
+ if (!(resmgr = scir_new_resource_manager(argv[1], res_version,
+ 0, 1024 * 128))) {
+ fprintf(stderr, "Could not find any resources; quitting.\n");
+ return 2;
+ }
+
+ if (resmgr->sci_version >= SCI_VERSION_01)
+ it_type = SCI_SONG_ITERATOR_TYPE_SCI1;
+
+ sfx_init(&sound, resmgr, 0);
+ sfx_set_volume(&sound, 127);
+
+ arg = 2 - 1;
+ while (++arg < argc) {
+ sound_nr = atoi(argv[arg]);
+ base = ff = build_iterator(resmgr, sound_nr, it_type,
+ DUMMY_SOUND_HANDLE);
+ printf("Playing resource %d...\n", sound_nr);
+ if (sfx_add_song(&sound, ff,
+ 0, DUMMY_SOUND_HANDLE, sound_nr)) {
+ fprintf(stderr, "Could not start sound resource. Does it exist?\n");
+ return 2;
+ }
+ sfx_song_set_status(&sound, DUMMY_SOUND_HANDLE, SOUND_STATUS_PLAYING);
+ while (sfx_poll(&sound, &dummy1, &dummy2) != SI_FINISHED) {};
+ }
+ sfx_exit(&sound);
+ scir_free_resource_manager(resmgr);
+ return 0;
+}
+
+
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);
+}
diff --git a/devtools/sci/scipack.cpp b/devtools/sci/scipack.cpp
new file mode 100644
index 0000000000..f70d91fabc
--- /dev/null
+++ b/devtools/sci/scipack.cpp
@@ -0,0 +1,208 @@
+/* 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$
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sciresource.h>
+#include <resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define COPY_BLOCK_SIZE 512
+
+unsigned short *resource_ids = NULL;
+
+void
+help() {
+ printf("Usage:\n\tscipack <file_0> ... <file_n>\n"
+ "\nBuilds an uncompressed SCI0 resource.000 and a resource.map\n");
+}
+
+int /* Returns resource ID on success, -1 on error */
+test_file(char *filename) {
+ char *dot = strchr(filename, '.');
+ char *endptr;
+ FILE *f;
+ int res_type, res_index;
+
+ if (!dot) {
+ fprintf(stderr, "Must contain a period");
+ return -1;
+ }
+
+ *dot = 0;
+
+ for (res_type = 0; res_type < sci_invalid_resource
+ && scumm_stricmp(filename, sci_resource_types[res_type]); res_type++);
+
+ *dot = '.';
+
+ if (res_type == sci_invalid_resource) {
+ fprintf(stderr, "Invalid resource type");
+ return -1;
+ }
+
+ ++dot;
+ res_index = strtol(dot, &endptr, 10);
+
+ if (!*dot || *endptr) {
+ fprintf(stderr, "Invalid resource index");
+ return -1;
+ }
+
+ if (res_index < 0) {
+ fprintf(stderr, "Negative resource index");
+ return -1;
+ }
+
+ if (res_index >= 1000) {
+ fprintf(stderr, "Resource index too large");
+ return -1;
+ }
+
+ f = fopen(filename, "r");
+ if (!f) {
+ perror("While asserting file");
+ return -1;
+ }
+ fclose(f);
+
+ return (res_type << 11) | res_index;
+}
+
+int
+build_file_ids(int count, char **names) {
+ int i;
+ int error = 0;
+
+ resource_ids = (unsigned short*) malloc(sizeof(unsigned short) * count);
+
+ for (i = 0; i < count; i++) {
+ int id = test_file(names[i]);
+ if (id < 0) {
+ error = -1;
+ fprintf(stderr, ": %s\n", names[i]);
+ } else resource_ids[i] = id;
+ }
+
+ return error;
+}
+
+
+static inline void
+write_uint16(int fd, unsigned int uint) {
+ unsigned char upper = (uint >> 8) & 0xff;
+ unsigned char lower = (uint) & 0xff;
+
+ if ((write(fd, &upper, 1) < 1)
+ || (write(fd, &lower, 1) < 1)) {
+ perror("While writing");
+ exit(1);
+ }
+}
+
+int
+write_files(int count, char **names) {
+ int resource_000, resource_map;
+ int i;
+
+ resource_000 = creat("resource.000", 0644);
+ if (resource_000 < 0) {
+ perror("While creating 'resource.000'");
+ return -1;
+ }
+
+ resource_map = creat("resource.map", 0644);
+ if (resource_map < 0) {
+ perror("While creating 'resource.map'");
+ return -1;
+ }
+
+ for (i = 0; i < count; i++) {
+ int fd = open(names[i], O_RDONLY);
+ struct stat fdstat;
+ int fdsize;
+ unsigned char buf[512];
+ int j;
+ long offset = lseek(resource_000, SEEK_CUR, 0);
+ int top_offset = (offset >> 16) & 0xffff;
+ int bot_offset = offset & 0xffff;
+
+ if (fd < 0) {
+ perror(names[i]);
+ return -1;
+ }
+ fstat(fd, &fdstat);
+ fdsize = fdstat.st_size;
+
+ write_uint16(resource_000, resource_ids[i]);
+ write_uint16(resource_000, fdsize);
+ write_uint16(resource_000, fdsize);
+ write_uint16(resource_000, 0);
+
+ do {
+ j = read(fd, buf, COPY_BLOCK_SIZE);
+ write(resource_000, buf, j);
+ } while (j == COPY_BLOCK_SIZE);
+ close(fd);
+
+ write_uint16(resource_map, resource_ids[i]);
+ write_uint16(resource_map, bot_offset);
+ write_uint16(resource_map, top_offset);
+ }
+
+ /* Terminate resource 000 */
+ write_uint16(resource_000, 0);
+
+ /* Terminate resource map */
+ write_uint16(resource_map, 0xffff);
+ write_uint16(resource_map, 0xffff);
+
+ close(resource_000);
+ close(resource_map);
+}
+
+
+int
+main(int argc, char **argv) {
+ printf("scipack.c Copyright (C) 2002 Christoph Reichenbach\n"
+ "This program is FREE SOFTWARE. You may copy it and/or re-distribute it\n"
+ "according to the terms of the GNU General Public License. See LICENSING\n"
+ "for details.\n");
+
+ if (argc < 1)
+ help();
+
+ if (build_file_ids(argc - 1, argv + 1))
+ return -1;
+
+ if (write_files(argc - 1, argv + 1))
+ return -1;
+ free(resource_ids);
+}
diff --git a/devtools/sci/scitrace.asm b/devtools/sci/scitrace.asm
new file mode 100644
index 0000000000..360e0b7ffc
--- /dev/null
+++ b/devtools/sci/scitrace.asm
@@ -0,0 +1,136 @@
+; 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$
+;
+;---------------------------------------------------------------------------
+;
+; SCITRACE
+; TSR for logging specific calls inside sierra sci
+; Written by M. Kiewitz
+;
+;---------------------------------------------------------------------------
+
+; Simply replace 51h 51h 51h 51h in sierra sci with
+; CDh 90h 90h 90h. This code will then log copyrect calls to scitrace.bin
+
+ .286
+
+code_seg segment public
+ assume cs:code_seg, ds:nothing, es:nothing
+ org 00100h
+
+scitrace: jmp install_my_prog
+
+;---------------------------------------------------------------------------
+
+filename: db 'SCITRACE.BIN', 0
+
+inthandler: push ax
+ push bx
+ push cx
+ push dx
+ push ds
+ push cs
+ pop ds
+ mov ah, 3Dh
+ mov al, 1
+ mov dx, offset filename
+ xor cl, cl
+ int 21h
+ pop ds
+ jc int_error
+ mov bx, ax
+ mov ax, 4202h
+ xor cx, cx
+ xor dx, dx
+ int 21h
+ mov dx, si
+ mov ah, 40h
+ mov cx, 8
+ int 21h
+ mov ah, 3Eh
+ int 21h
+int_error: pop dx
+ pop cx
+ pop bx
+ pop ax
+ movsw
+ movsw
+ movsw
+ movsw
+ iret
+
+end_of_tsr:
+
+;---------------------------------------------------------------------------
+
+titlestr: db 'SCITRACE - written by M. Kiewitz',13,10,'$'
+errorfile: db 'error creating file',13,10,'$'
+
+;---------------------------------------------------------------------------
+
+install_my_prog:
+ push cs
+ pop ds
+ mov ah, 09h
+ mov dx, offset titlestr
+ int 21h
+
+ mov ah, 3Ch
+ mov cx, 0
+ mov dx, offset filename
+ int 21h
+ jnc valid_open
+ mov ah, 09h
+ mov dx, offset errorfile
+ int 21h
+ mov ax, 6200h
+ int 21h
+ mov es, bx
+ mov ax, 4C00h
+ int 21h
+
+valid_open: mov bx, ax
+ mov ah, 3Eh
+ int 21h
+
+NowInstallTSR:
+ mov ax, 2590h
+ mov dx, offset inthandler
+ int 21h ; int 90h pointer <- ds:dx
+
+ mov ax, ds:[002ch] ; get envt segment
+ mov es, ax
+ mov ax, 4900h
+ int 21h
+
+ mov dx, offset end_of_tsr
+ add dx, 15
+ shr dx, 4
+ mov ax, 3100h
+ int 21h
+
+;---------------------------------------------------------------------------
+
+code_seg ends
+ end scitrace
+