From 6cf1de87acdb878e3a3e4ef7cc33d45adee4a592 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 Apr 2011 23:47:35 +0200 Subject: DEVTOOLS: Renamed 'tools' directory to 'devtools' --- devtools/sci/musicplayer.cpp | 103 +++++ devtools/sci/scidisasm.cpp | 987 +++++++++++++++++++++++++++++++++++++++++++ devtools/sci/scipack.cpp | 208 +++++++++ devtools/sci/scitrace.asm | 136 ++++++ 4 files changed, 1434 insertions(+) create mode 100644 devtools/sci/musicplayer.cpp create mode 100644 devtools/sci/scidisasm.cpp create mode 100644 devtools/sci/scipack.cpp create mode 100644 devtools/sci/scitrace.asm (limited to 'devtools/sci') 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 +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#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 [ ...]\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 +#endif /* HAVE_CONFIG_H */ + +#define MALLOC_DEBUG + +#include +#include +#include +#include + +#ifdef HAVE_GETOPT_H +#include +#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 -d 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 ""; + 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) : ""; + + 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] = 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) : ""; + 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] : ""); + 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] : ""); + 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 +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#define COPY_BLOCK_SIZE 512 + +unsigned short *resource_ids = NULL; + +void +help() { + printf("Usage:\n\tscipack ... \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 + -- cgit v1.2.3