From eba1653904bd0209f00fa02ea455f7d78c533905 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 15 Feb 2006 18:48:49 +0000 Subject: o Renamed script_v6he.cpp and script_v7he.cpp to script_v60he.cpp and script_v70he.cpp respectively since we use 2 digits for HE versioning. o Also renamed resource_v7he.* to resource_he.* because it is actually not HE70-specific but is used by all HE70+ titles. svn-id: r20703 --- engines/scumm/he/resource_he.cpp | 1912 ++++++++++++++++++++++++++++++++++++ engines/scumm/he/resource_he.h | 556 +++++++++++ engines/scumm/he/resource_v7he.cpp | 1912 ------------------------------------ engines/scumm/he/resource_v7he.h | 556 ----------- engines/scumm/he/script_v100he.cpp | 2 +- engines/scumm/he/script_v60he.cpp | 1276 ++++++++++++++++++++++++ engines/scumm/he/script_v6he.cpp | 1276 ------------------------ engines/scumm/he/script_v70he.cpp | 1153 ++++++++++++++++++++++ engines/scumm/he/script_v72he.cpp | 2 +- engines/scumm/he/script_v7he.cpp | 1153 ---------------------- engines/scumm/he/script_v80he.cpp | 2 +- engines/scumm/he/script_v90he.cpp | 2 +- 12 files changed, 4901 insertions(+), 4901 deletions(-) create mode 100644 engines/scumm/he/resource_he.cpp create mode 100644 engines/scumm/he/resource_he.h delete mode 100644 engines/scumm/he/resource_v7he.cpp delete mode 100644 engines/scumm/he/resource_v7he.h create mode 100644 engines/scumm/he/script_v60he.cpp delete mode 100644 engines/scumm/he/script_v6he.cpp create mode 100644 engines/scumm/he/script_v70he.cpp delete mode 100644 engines/scumm/he/script_v7he.cpp (limited to 'engines/scumm/he') diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp new file mode 100644 index 0000000000..f7be975ca3 --- /dev/null +++ b/engines/scumm/he/resource_he.cpp @@ -0,0 +1,1912 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * Parts of code heavily based on: + * icoutils - A set of programs dealing with MS Windows icons and cursors. + * Copyright (C) 1998-2001 Oskar Liljeblad + * + * 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 "common/stdafx.h" +#include "scumm/scumm.h" +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/he/resource_he.h" +#include "scumm/sound.h" +#include "scumm/util.h" +#include "sound/wave.h" + +#include "common/stream.h" +#include "common/system.h" + +namespace Scumm { + +ResExtractor::ResExtractor(ScummEngine_v70he *scumm) + : _vm(scumm) { + + _fileName[0] = 0; + memset(_cursorCache, 0, sizeof(_cursorCache)); +} + +ResExtractor::~ResExtractor() { + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (cc->valid) { + free(cc->bitmap); + free(cc->palette); + } + } + memset(_cursorCache, 0, sizeof(_cursorCache)); +} + +ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) { + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (cc->valid && cc->id == id) { + return cc; + } + } + return NULL; +} + +ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() { + uint32 min_last_used = 0; + CachedCursor *r = NULL; + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (!cc->valid) { + return cc; + } else { + if (min_last_used == 0 || cc->last_used < min_last_used) { + min_last_used = cc->last_used; + r = cc; + } + } + } + assert(r); + free(r->bitmap); + free(r->palette); + memset(r, 0, sizeof(CachedCursor)); + return r; +} + +void ResExtractor::setCursor(int id) { + byte *cursorRes = 0; + int cursorsize; + int keycolor = 0; + CachedCursor *cc = findCachedCursor(id); + if (cc != NULL) { + debug(7, "Found cursor %d in cache slot %d", id, cc - _cursorCache); + } else { + cc = getCachedCursorSlot(); + assert(cc && !cc->valid); + cursorsize = extractResource(id, &cursorRes); + convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize); + debug(7, "Adding cursor %d to cache slot %d", id, cc - _cursorCache); + free(cursorRes); + cc->valid = true; + cc->id = id; + cc->last_used = g_system->getMillis(); + } + + if (_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette) && cc->palette) + _vm->_system->setCursorPalette(cc->palette, 0, cc->palSize); + + _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y); + _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w); +} + + +/* + * Static variables + */ +const char *res_types[] = { + /* 0x01: */ + "cursor", "bitmap", "icon", "menu", "dialog", "string", + "fontdir", "font", "accelerator", "rcdata", "messagelist", + "group_cursor", NULL, "group_icon", NULL, + /* the following are not defined in winbase.h, but found in wrc. */ + /* 0x10: */ + "version", "dlginclude", NULL, "plugplay", "vxd", + "anicursor", "aniicon" +}; +#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *)) + +Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { +} + +int Win32ResExtractor::extractResource(int resId, byte **data) { + char buf[20]; + + snprintf(buf, sizeof(buf), "%d", resId); + + return extractResource_("group_cursor", buf, data); +} + +int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) { + char *arg_language = NULL; + const char *arg_type = resType; + char *arg_name = resName; + int arg_action = ACTION_LIST; + int ressize = 0; + + _arg_raw = false; + + /* translate --type option from resource type string to integer */ + arg_type = res_type_string_to_id(arg_type); + + WinLibrary fi; + + /* initiate stuff */ + fi.memory = NULL; + fi.file = new Common::File; + + if (!_fileName[0]) { // We are running for the first time + snprintf(_fileName, 256, "%s.he3", _vm->getBaseName()); + + if (_vm->_substResFileNameIndex > 0) { + char buf1[128]; + + _vm->generateSubstResFileName(_fileName, buf1, sizeof(buf1)); + strcpy(_fileName, buf1); + } + } + + + /* get file size */ + fi.file->open(_fileName); + if (!fi.file->isOpen()) { + error("Cannot open file %s", _fileName); + } + + fi.total_size = fi.file->size(); + if (fi.total_size == -1) { + error("Cannot get size of file %s", fi.file->name()); + goto cleanup; + } + if (fi.total_size == 0) { + error("%s: file has a size of 0", fi.file->name()); + goto cleanup; + } + + /* read all of file */ + fi.memory = (byte *)malloc(fi.total_size); + if (fi.file->read(fi.memory, fi.total_size) == 0) { + error("Cannot read from file %s", fi.file->name()); + goto cleanup; + } + + /* identify file and find resource table */ + if (!read_library(&fi)) { + /* error reported by read_library */ + goto cleanup; + } + + // verbose_printf("file is a %s\n", + // fi.is_PE_binary ? "Windows NT `PE' binary" : "Windows 3.1 `NE' binary"); + + /* errors will be printed by the callback */ + ressize = do_resources(&fi, arg_type, arg_name, arg_language, arg_action, data); + + /* free stuff and close file */ + cleanup: + if (fi.file != NULL) + fi.file->close(); + if (fi.memory != NULL) + free(fi.memory); + + return ressize; +} + + +/* res_type_id_to_string: + * Translate a numeric resource type to it's corresponding string type. + * (For informative-ness.) + */ +const char *Win32ResExtractor::res_type_id_to_string(int id) { + if (id == 241) + return "toolbar"; + if (id > 0 && id <= (int)RES_TYPE_COUNT) + return res_types[id-1]; + return NULL; +} + +/* res_type_string_to_id: + * Translate a resource type string to integer. + * (Used to convert the --type option.) + */ +const char *Win32ResExtractor::res_type_string_to_id(const char *type) { + static const char *res_type_ids[] = { + "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", + "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19", + "-20", "-21", "-22" + }; + int c; + + if (type == NULL) + return NULL; + + for (c = 0 ; c < (int)RES_TYPE_COUNT ; c++) { + if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c])) + return res_type_ids[c]; + } + + return type; +} + +int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr, + WinResource *type_wr, WinResource *name_wr, + WinResource *lang_wr, byte **data) { + int size; + bool free_it; + const char *type; + int32 id; + + if (*data) { + error("Win32ResExtractor::extract_resources() more than one cursor"); + return 0; + } + + *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw); + + if (data == NULL) { + error("Win32ResExtractor::extract_resources() problem with resource extraction"); + return 0; + } + + /* get named resource type if possible */ + type = NULL; + if ((id = strtol(type_wr->id, 0, 10)) != 0) + type = res_type_id_to_string(id); + + debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]", + get_resource_id_quoted(name_wr), + (lang_wr->id[0] != '\0' ? " language: " : ""), + get_resource_id_quoted(lang_wr), size); + + return size; +} + +/* extract_resource: + * Extract a resource, returning pointer to data. + */ +byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size, + bool *free_it, char *type, char *lang, bool raw) { + char *str; + int32 intval; + + /* just return pointer to data if raw */ + if (raw) { + *free_it = false; + /* get_resource_entry will print possible error */ + return get_resource_entry(fi, wr, size); + } + + /* find out how to extract */ + str = type; + if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) { + if (intval == (int)RT_GROUP_ICON) { + *free_it = true; + return extract_group_icon_cursor_resource(fi, wr, lang, size, true); + } + if (intval == (int)RT_GROUP_CURSOR) { + *free_it = true; + return extract_group_icon_cursor_resource(fi, wr, lang, size, false); + } + } + + return NULL; +} + +/* extract_group_icon_resource: + * Create a complete RT_GROUP_ICON resource, that can be written to + * an `.ico' file without modifications. Returns an allocated + * memory block that should be freed with free() once used. + * + * `root' is the offset in file that specifies the resource. + * `base' is the offset that string pointers are calculated from. + * `ressize' should point to an integer variable where the size of + * the returned memory block will be placed. + * `is_icon' indicates whether resource to be extracted is icon + * or cursor group. + */ +byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang, + int *ressize, bool is_icon) { + Win32CursorIconDir *icondir; + Win32CursorIconFileDir *fileicondir; + byte *memory; + int c, offset, skipped; + int size; + + /* get resource data and size */ + icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size); + if (icondir == NULL) { + /* get_resource_entry will print error */ + return NULL; + } + + /* calculate total size of output file */ + RETURN_IF_BAD_POINTER(NULL, icondir->count); + skipped = 0; + for (c = 0 ; c < icondir->count ; c++) { + int level; + int iconsize; + char name[14]; + WinResource *fwr; + + RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]); + /*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c, + icondir->entries[c].bytes_in_res, + (is_icon ? icondir->entries[c].res_info.icon.width : icondir->entries[c].res_info.cursor.width), + (is_icon ? icondir->entries[c].res_info.icon.height : icondir->entries[c].res_info.cursor.height), + icondir->entries[c].plane_count, + icondir->entries[c].bit_count);*/ + + /* find the corresponding icon resource */ + snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); + fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); + if (fwr == NULL) { + error("%s: could not find `%s' in `%s' resource.", + fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); + return NULL; + } + + if (get_resource_entry(fi, fwr, &iconsize) != NULL) { + if (iconsize == 0) { + debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", fi->file->name(), name); + skipped++; + continue; + } + if ((uint32)iconsize != icondir->entries[c].bytes_in_res) { + debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)", + fi->file->name(), name, iconsize, icondir->entries[c].bytes_in_res); + } + size += iconsize; /* size += icondir->entries[c].bytes_in_res; */ + + /* cursor resources have two additional WORDs that contain + * hotspot info */ + if (!is_icon) + size -= sizeof(uint16)*2; + } + } + offset = sizeof(Win32CursorIconFileDir) + (icondir->count-skipped) * sizeof(Win32CursorIconFileDirEntry); + size += offset; + *ressize = size; + + /* allocate that much memory */ + memory = (byte *)malloc(size); + fileicondir = (Win32CursorIconFileDir *)memory; + + /* transfer Win32CursorIconDir structure members */ + fileicondir->reserved = icondir->reserved; + fileicondir->type = icondir->type; + fileicondir->count = icondir->count - skipped; + + /* transfer each cursor/icon: Win32CursorIconDirEntry and data */ + skipped = 0; + for (c = 0 ; c < icondir->count ; c++) { + int level; + char name[14]; + WinResource *fwr; + byte *data; + + /* find the corresponding icon resource */ + snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); + fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); + if (fwr == NULL) { + error("%s: could not find `%s' in `%s' resource.", + fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); + return NULL; + } + + /* get data and size of that resource */ + data = (byte *)get_resource_entry(fi, fwr, &size); + if (data == NULL) { + /* get_resource_entry has printed error */ + return NULL; + } + if (size == 0) { + skipped++; + continue; + } + + /* copy ICONDIRENTRY (not including last dwImageOffset) */ + memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c], + sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32)); + + /* special treatment for cursors */ + if (!is_icon) { + fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width; + fileicondir->entries[c-skipped].height = icondir->entries[c].res_info.cursor.height / 2; + fileicondir->entries[c-skipped].color_count = 0; + fileicondir->entries[c-skipped].reserved = 0; + } + + /* set image offset and increase it */ + fileicondir->entries[c-skipped].dib_offset = offset; + + /* transfer resource into file memory */ + if (is_icon) { + memcpy(&memory[offset], data, icondir->entries[c].bytes_in_res); + } else { + fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0]; + fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1]; + memcpy(&memory[offset], data+sizeof(uint16)*2, + icondir->entries[c].bytes_in_res-sizeof(uint16)*2); + offset -= sizeof(uint16)*2; + } + + /* increase the offset pointer */ + offset += icondir->entries[c].bytes_in_res; + } + + return memory; +} + +/* check_offset: + * Check if a chunk of data (determined by offset and size) + * is within the bounds of the WinLibrary file. + * Usually not called directly. + */ +bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) { + int need_size = (int)((byte *)offset - memory + size); + + debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x", + need_size, total_size, (byte *)offset - memory, size); + + if (need_size < 0 || need_size > total_size) { + error("%s: premature end", name); + return false; + } + + return true; +} + + +/* do_resources: + * Do something for each resource matching type, name and lang. + */ +int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, int action, byte **data) { + WinResource *type_wr; + WinResource *name_wr; + WinResource *lang_wr; + int size; + + type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1); + name_wr = type_wr + 1; + lang_wr = type_wr + 2; + + size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, action, data); + + free(type_wr); + + return size; +} + +/* what is each entry in this directory level for? type, name or language? */ +#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr)) + +/* does the id of this entry match the specified id? */ +#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x)) + +int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, + WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr, + const char *type, char *name, char *lang, int action, byte **data) { + int c, rescnt; + WinResource *wr; + uint32 size = 0; + + /* get a list of all resources at this level */ + wr = list_resources(fi, base, &rescnt); + if (wr == NULL) + if (size != 0) + return size; + else + return 0; + + /* process each resource listed */ + for (c = 0 ; c < rescnt ; c++) { + /* (over)write the corresponding WinResource holder with the current */ + memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource)); + + /* go deeper unless there is something that does NOT match */ + if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) { + if (wr->is_directory) + size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, action, data); + else + size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data); + } + } + + /* since we're moving back one level after this, unset the + * WinResource holder used on this level */ + memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource)); + + return size; +} + +/* return the resource id quoted if it's a string, otherwise just return it */ +char *Win32ResExtractor::get_resource_id_quoted(WinResource *wr) { + static char tmp[WINRES_ID_MAXLEN+2]; + + if (wr->numeric_id || wr->id[0] == '\0') + return wr->id; + + sprintf(tmp, "'%s'", wr->id); + return tmp; +} + +bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) { + if (wr->numeric_id) { + int32 cmp1, cmp2; + if (id[0] == '+') + return false; + if (id[0] == '-') + id++; + if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2) + return false; + } else { + if (id[0] == '-') + return false; + if (id[0] == '+') + id++; + if (strcmp(wr->id, id)) + return false; + } + + return true; +} + +bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) { + if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */ + int c, len; + uint16 *mem = (uint16 *) + (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING)); + + /* copy each char of the string, and terminate it */ + RETURN_IF_BAD_POINTER(false, *mem); + len = mem[0]; + RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len); + + len = MIN(mem[0], (uint16)WINRES_ID_MAXLEN); + for (c = 0 ; c < len ; c++) + wr->id[c] = mem[c+1] & 0x00FF; + wr->id[len] = '\0'; + } else { /* Unicode string id */ + /* translate id into a string */ + snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value); + } + + wr->numeric_id = (value & IMAGE_RESOURCE_NAME_IS_STRING ? false:true); + return true; +} + +byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) { + if (fi->is_PE_binary) { + Win32ImageResourceDataEntry *dataent; + + dataent = (Win32ImageResourceDataEntry *) wr->children; + RETURN_IF_BAD_POINTER(NULL, *dataent); + *size = dataent->size; + RETURN_IF_BAD_OFFSET(NULL, fi->memory + dataent->offset_to_data, *size); + + return fi->memory + dataent->offset_to_data; + } else { + Win16NENameInfo *nameinfo; + int sizeshift; + + nameinfo = (Win16NENameInfo *) wr->children; + sizeshift = *((uint16 *) fi->first_resource - 1); + *size = nameinfo->length << sizeshift; + RETURN_IF_BAD_OFFSET(NULL, fi->memory + (nameinfo->offset << sizeshift), *size); + + return fi->memory + (nameinfo->offset << sizeshift); + } +} + +bool Win32ResExtractor::decode_ne_resource_id(WinLibrary *fi, WinResource *wr, uint16 value) { + if (value & NE_RESOURCE_NAME_IS_NUMERIC) { /* numeric id */ + /* translate id into a string */ + snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value & ~NE_RESOURCE_NAME_IS_NUMERIC); + } else { /* ASCII string id */ + int len; + char *mem = (char *)NE_HEADER(fi->memory) + + NE_HEADER(fi->memory)->rsrctab + + value; + + /* copy each char of the string, and terminate it */ + RETURN_IF_BAD_POINTER(false, *mem); + len = mem[0]; + RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(char) * len); + memcpy(wr->id, &mem[1], len); + wr->id[len] = '\0'; + } + + wr->numeric_id = (value & NE_RESOURCE_NAME_IS_NUMERIC ? true:false); + return true; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) { + WinResource *wr; + int c, rescnt; + Win32ImageResourceDirectoryEntry *dirent + = (Win32ImageResourceDirectoryEntry *)(pe_res + 1); + + /* count number of `type' resources */ + RETURN_IF_BAD_POINTER(NULL, *dirent); + rescnt = pe_res->number_of_named_entries + pe_res->number_of_id_entries; + *count = rescnt; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + for (c = 0 ; c < rescnt ; c++) { + RETURN_IF_BAD_POINTER(NULL, dirent[c]); + wr[c].this_ = pe_res; + wr[c].level = level; + wr[c].is_directory = (dirent[c].u2.s.data_is_directory); + wr[c].children = fi->first_resource + dirent[c].u2.s.offset_to_directory; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_pe_resource_id (fi, wr + c, dirent[c].u1.name)) + return NULL; + } + + return wr; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_name_resources(WinLibrary *fi, WinResource *typeres, int *count) { + int c, rescnt; + WinResource *wr; + Win16NETypeInfo *typeinfo = (Win16NETypeInfo *) typeres->this_; + Win16NENameInfo *nameinfo = (Win16NENameInfo *) typeres->children; + + /* count number of `type' resources */ + RETURN_IF_BAD_POINTER(NULL, typeinfo->count); + *count = rescnt = typeinfo->count; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + for (c = 0 ; c < rescnt ; c++) { + RETURN_IF_BAD_POINTER(NULL, nameinfo[c]); + wr[c].this_ = nameinfo+c; + wr[c].is_directory = false; + wr[c].children = nameinfo+c; + wr[c].level = 1; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_ne_resource_id(fi, wr + c, (nameinfo+c)->id)) + return NULL; + } + + return wr; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_type_resources(WinLibrary *fi, int *count) { + int c, rescnt; + WinResource *wr; + Win16NETypeInfo *typeinfo; + + /* count number of `type' resources */ + typeinfo = (Win16NETypeInfo *) fi->first_resource; + RETURN_IF_BAD_POINTER(NULL, *typeinfo); + for (rescnt = 0 ; typeinfo->type_id != 0 ; rescnt++) { + typeinfo = NE_TYPEINFO_NEXT(typeinfo); + RETURN_IF_BAD_POINTER(NULL, *typeinfo); + } + *count = rescnt; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + typeinfo = (Win16NETypeInfo *) fi->first_resource; + for (c = 0 ; c < rescnt ; c++) { + wr[c].this_ = typeinfo; + wr[c].is_directory = (typeinfo->count != 0); + wr[c].children = typeinfo+1; + wr[c].level = 0; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_ne_resource_id(fi, wr + c, typeinfo->type_id)) + return NULL; + + typeinfo = NE_TYPEINFO_NEXT(typeinfo); + } + + return wr; +} + +/* list_resources: + * Return an array of WinResource's in the current + * resource level specified by res. + */ +Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) { + if (res != NULL && !res->is_directory) + return NULL; + + if (fi->is_PE_binary) { + return list_pe_resources(fi, (Win32ImageResourceDirectory *) + (res == NULL ? fi->first_resource : res->children), + (res == NULL ? 0 : res->level+1), + count); + } else { + return (res == NULL + ? list_ne_type_resources(fi, count) + : list_ne_name_resources(fi, res, count)); + } +} + +/* read_library: + * Read header and get resource directory offset in a Windows library + * (AKA module). + * + */ +bool Win32ResExtractor::read_library(WinLibrary *fi) { + /* check for DOS header signature `MZ' */ + RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic); + if (MZ_HEADER(fi->memory)->magic == IMAGE_DOS_SIGNATURE) { + DOSImageHeader *mz_header = MZ_HEADER(fi->memory); + + RETURN_IF_BAD_POINTER(false, mz_header->lfanew); + if (mz_header->lfanew < sizeof(DOSImageHeader)) { + error("%s: not a Windows library", fi->file->name()); + return false; + } + } + + /* check for OS2 (Win16) header signature `NE' */ + RETURN_IF_BAD_POINTER(false, NE_HEADER(fi->memory)->magic); + if (NE_HEADER(fi->memory)->magic == IMAGE_OS2_SIGNATURE) { + OS2ImageHeader *header = NE_HEADER(fi->memory); + + RETURN_IF_BAD_POINTER(false, header->rsrctab); + RETURN_IF_BAD_POINTER(false, header->restab); + if (header->rsrctab >= header->restab) { + error("%s: no resource directory found", fi->file->name()); + return false; + } + + fi->is_PE_binary = false; + fi->first_resource = (byte *) NE_HEADER(fi->memory) + + header->rsrctab + sizeof(uint16); + RETURN_IF_BAD_POINTER(false, *(Win16NETypeInfo *) fi->first_resource); + + return true; + } + + /* check for NT header signature `PE' */ + RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature); + if (PE_HEADER(fi->memory)->signature == IMAGE_NT_SIGNATURE) { + Win32ImageSectionHeader *pe_sec; + Win32ImageDataDirectory *dir; + Win32ImageNTHeaders *pe_header; + int d; + + /* allocate new memory */ + fi->total_size = calc_vma_size(fi); + if (fi->total_size == 0) { + /* calc_vma_size has reported error */ + return false; + } + fi->memory = (byte *)realloc(fi->memory, fi->total_size); + + /* relocate memory, start from last section */ + pe_header = PE_HEADER(fi->memory); + RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections); + + /* we don't need to do OFFSET checking for the sections. + * calc_vma_size has already done that */ + for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) { + pe_sec = PE_SECTIONS(fi->memory) + d; + + if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + continue; + + //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size) + + RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data); + RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); + if (pe_sec->virtual_address != pe_sec->pointer_to_raw_data) { + memmove(fi->memory + pe_sec->virtual_address, + fi->memory + pe_sec->pointer_to_raw_data, + pe_sec->size_of_raw_data); + } + } + + /* find resource directory */ + RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); + dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE; + if (dir->size == 0) { + error("%s: file contains no resources", fi->file->name()); + return false; + } + + fi->first_resource = fi->memory + dir->virtual_address; + fi->is_PE_binary = true; + return true; + } + + /* other (unknown) header signature was found */ + error("%s: not a Windows library", fi->file->name()); + return false; +} + +/* calc_vma_size: + * Calculate the total amount of memory needed for a 32-bit Windows + * module. Returns -1 if file was too small. + */ +int Win32ResExtractor::calc_vma_size(WinLibrary *fi) { + Win32ImageSectionHeader *seg; + int c, segcount, size; + + size = 0; + RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections); + segcount = PE_HEADER(fi->memory)->file_header.number_of_sections; + + /* If there are no segments, just process file like it is. + * This is (probably) not the right thing to do, but problems + * will be delt with later anyway. + */ + if (segcount == 0) + return fi->total_size; + + seg = PE_SECTIONS(fi->memory); + RETURN_IF_BAD_POINTER(-1, *seg); + for (c = 0 ; c < segcount ; c++) { + RETURN_IF_BAD_POINTER(0, *seg); + + size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data); + /* I have no idea what misc.virtual_size is for... */ + size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size); + seg++; + } + + return size; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) { + int c, rescnt; + WinResource *return_wr; + + wr = list_resources(fi, wr, &rescnt); + if (wr == NULL) + return NULL; + + for (c = 0 ; c < rescnt ; c++) { + if (compare_resource_id(&wr[c], id)) { + /* duplicate WinResource and return it */ + return_wr = (WinResource *)malloc(sizeof(WinResource)); + memcpy(return_wr, &wr[c], sizeof(WinResource)); + + /* free old WinResource */ + free(wr); + return return_wr; + } + } + + return NULL; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) { + WinResource *wr; + + *level = 0; + if (type == NULL) + return NULL; + wr = find_with_resource_array(fi, NULL, type); + if (wr == NULL || !wr->is_directory) + return wr; + + *level = 1; + if (name == NULL) + return wr; + wr = find_with_resource_array(fi, wr, name); + if (wr == NULL || !wr->is_directory) + return wr; + + *level = 2; + if (language == NULL) + return wr; + wr = find_with_resource_array(fi, wr, language); + return wr; +} + +#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2) + + +int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) { + Win32CursorIconFileDir dir; + Win32CursorIconFileDirEntry *entries = NULL; + uint32 offset; + uint32 c, d; + int completed; + int matched = 0; + MemoryReadStream *in = new MemoryReadStream(data, datasize); + + if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry))) + goto cleanup; + fix_win32_cursor_icon_file_dir_endian(&dir); + + if (dir.reserved != 0) { + error("not an icon or cursor file (reserved non-zero)"); + goto cleanup; + } + if (dir.type != 1 && dir.type != 2) { + error("not an icon or cursor file (wrong type)"); + goto cleanup; + } + + entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry)); + for (c = 0; c < dir.count; c++) { + if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry))) + goto cleanup; + fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]); + if (entries[c].reserved != 0) + error("reserved is not zero"); + } + + offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry)); + + for (completed = 0; completed < dir.count; ) { + uint32 min_offset = 0x7fffffff; + int previous = completed; + + for (c = 0; c < dir.count; c++) { + if (entries[c].dib_offset == offset) { + Win32BitmapInfoHeader bitmap; + Win32RGBQuad *palette = NULL; + uint32 palette_count = 0; + uint32 image_size, mask_size; + uint32 width, height; + byte *image_data = NULL, *mask_data = NULL; + byte *row = NULL; + + if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader))) + goto local_cleanup; + + fix_win32_bitmap_info_header_endian(&bitmap); + if (bitmap.size < sizeof(Win32BitmapInfoHeader)) { + error("bitmap header is too short"); + goto local_cleanup; + } + if (bitmap.compression != 0) { + error("compressed image data not supported"); + goto local_cleanup; + } + if (bitmap.x_pels_per_meter != 0) + error("x_pels_per_meter field in bitmap should be zero"); + if (bitmap.y_pels_per_meter != 0) + error("y_pels_per_meter field in bitmap should be zero"); + if (bitmap.clr_important != 0) + error("clr_important field in bitmap should be zero"); + if (bitmap.planes != 1) + error("planes field in bitmap should be one"); + if (bitmap.size != sizeof(Win32BitmapInfoHeader)) { + uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader); + error("skipping %d bytes of extended bitmap header", skip); + in->seek(skip, SEEK_CUR); + } + offset += bitmap.size; + + if (bitmap.clr_used != 0 || bitmap.bit_count < 24) { + palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count); + palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count); + if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count)) + goto local_cleanup; + offset += sizeof(Win32RGBQuad) * palette_count; + } + + width = bitmap.width; + height = ABS(bitmap.height)/2; + + image_size = height * ROW_BYTES(width * bitmap.bit_count); + mask_size = height * ROW_BYTES(width); + + if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad)) + debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)", + entries[c].dib_size, + bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad) + ); + + image_data = (byte *)malloc(image_size); + if (!in->read(image_data, image_size)) + goto local_cleanup; + + mask_data = (byte *)malloc(mask_size); + if (!in->read(mask_data, mask_size)) + goto local_cleanup; + + offset += image_size; + offset += mask_size; + completed++; + matched++; + + *hotspot_x = entries[c].hotspot_x; + *hotspot_y = entries[c].hotspot_y; + *w = width; + *h = height; + *keycolor = 0; + *cursor = (byte *)malloc(width * height); + + row = (byte *)malloc(width * 4); + + for (d = 0; d < height; d++) { + uint32 x; + uint32 y = (bitmap.height < 0 ? d : height - d - 1); + uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count; + //uint32 mmod = y * (mask_size / height) * 8; + + for (x = 0; x < width; x++) { + + uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count); + + // FIXME?: This works only with b/w cursors and white index may be + // different. But now it's enough. + if (color) { + cursor[0][width * d + x] = 15; // white in SCUMM + } else { + cursor[0][width * d + x] = 255; // transparent + } + /* + + if (bitmap.bit_count <= 16) { + if (color >= palette_count) { + error("color out of range in image data"); + goto local_cleanup; + } + row[4*x+0] = palette[color].red; + row[4*x+1] = palette[color].green; + row[4*x+2] = palette[color].blue; + + } else { + row[4*x+0] = (color >> 16) & 0xFF; + row[4*x+1] = (color >> 8) & 0xFF; + row[4*x+2] = (color >> 0) & 0xFF; + } + if (bitmap.bit_count == 32) + row[4*x+3] = (color >> 24) & 0xFF; + else + row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF; + */ + } + + } + + if (row != NULL) + free(row); + if (palette != NULL) + free(palette); + if (image_data != NULL) { + free(image_data); + free(mask_data); + } + continue; + + local_cleanup: + + if (row != NULL) + free(row); + if (palette != NULL) + free(palette); + if (image_data != NULL) { + free(image_data); + free(mask_data); + } + goto cleanup; + } else { + if (entries[c].dib_offset > offset) + min_offset = MIN(min_offset, entries[c].dib_offset); + } + } + + if (previous == completed) { + if (min_offset < offset) { + error("offset of bitmap header incorrect (too low)"); + goto cleanup; + } + debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset); + in->seek(min_offset - offset, SEEK_CUR); + offset = min_offset; + } + } + + free(entries); + return matched; + +cleanup: + + free(entries); + return -1; +} + +uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) { + switch (size) { + case 1: + return (data[ofs/8] >> (7 - ofs%8)) & 1; + case 2: + return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3; + case 4: + return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15; + case 8: + return data[ofs]; + case 16: + return data[2*ofs] | data[2*ofs+1] << 8; + case 24: + return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16; + case 32: + return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24; + } + + return 0; +} + +#define LE16(x) ((x) = TO_LE_16(x)) +#define LE32(x) ((x) = TO_LE_32(x)) + +void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) { + LE16(obj->reserved); + LE16(obj->type); + LE16(obj->count); +} + +void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) { + LE32(obj->size); + LE32(obj->width); + LE32(obj->height); + LE16(obj->planes); + LE16(obj->bit_count); + LE32(obj->compression); + LE32(obj->size_image); + LE32(obj->x_pels_per_meter); + LE32(obj->y_pels_per_meter); + LE32(obj->clr_used); + LE32(obj->clr_important); +} + +void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) { + LE16(obj->hotspot_x); + LE16(obj->hotspot_y); + LE32(obj->dib_size); + LE32(obj->dib_offset); +} + +void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) { + LE32(obj->misc.physical_address); + LE32(obj->virtual_address); + LE32(obj->size_of_raw_data); + LE32(obj->pointer_to_raw_data); + LE32(obj->pointer_to_relocations); + LE32(obj->pointer_to_linenumbers); + LE16(obj->number_of_relocations); + LE16(obj->number_of_linenumbers); + LE32(obj->characteristics); +} + +void Win32ResExtractor::fix_os2_image_header_endian(OS2ImageHeader *obj) { + LE16(obj->magic); + LE16(obj->enttab); + LE16(obj->cbenttab); + LE32(obj->crc); + LE16(obj->flags); + LE16(obj->autodata); + LE16(obj->heap); + LE16(obj->stack); + LE32(obj->csip); + LE32(obj->sssp); + LE16(obj->cseg); + LE16(obj->cmod); + LE16(obj->cbnrestab); + LE16(obj->segtab); + LE16(obj->rsrctab); + LE16(obj->restab); + LE16(obj->modtab); + LE16(obj->imptab); + LE32(obj->nrestab); + LE16(obj->cmovent); + LE16(obj->align); + LE16(obj->cres); + LE16(obj->fastload_offset); + LE16(obj->fastload_length); + LE16(obj->swaparea); + LE16(obj->expver); +} + +/* fix_win32_image_header_endian: + * NOTE: This assumes that the optional header is always available. + */ +void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) { + LE32(obj->signature); + LE16(obj->file_header.machine); + LE16(obj->file_header.number_of_sections); + LE32(obj->file_header.time_date_stamp); + LE32(obj->file_header.pointer_to_symbol_table); + LE32(obj->file_header.number_of_symbols); + LE16(obj->file_header.size_of_optional_header); + LE16(obj->file_header.characteristics); + LE16(obj->optional_header.magic); + LE32(obj->optional_header.size_of_code); + LE32(obj->optional_header.size_of_initialized_data); + LE32(obj->optional_header.size_of_uninitialized_data); + LE32(obj->optional_header.address_of_entry_point); + LE32(obj->optional_header.base_of_code); + LE32(obj->optional_header.base_of_data); + LE32(obj->optional_header.image_base); + LE32(obj->optional_header.section_alignment); + LE32(obj->optional_header.file_alignment); + LE16(obj->optional_header.major_operating_system_version); + LE16(obj->optional_header.minor_operating_system_version); + LE16(obj->optional_header.major_image_version); + LE16(obj->optional_header.minor_image_version); + LE16(obj->optional_header.major_subsystem_version); + LE16(obj->optional_header.minor_subsystem_version); + LE32(obj->optional_header.win32_version_value); + LE32(obj->optional_header.size_of_image); + LE32(obj->optional_header.size_of_headers); + LE32(obj->optional_header.checksum); + LE16(obj->optional_header.subsystem); + LE16(obj->optional_header.dll_characteristics); + LE32(obj->optional_header.size_of_stack_reserve); + LE32(obj->optional_header.size_of_stack_commit); + LE32(obj->optional_header.size_of_heap_reserve); + LE32(obj->optional_header.size_of_heap_commit); + LE32(obj->optional_header.loader_flags); + LE32(obj->optional_header.number_of_rva_and_sizes); +} + +void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) { + LE32(obj->virtual_address); + LE32(obj->size); +} + + +MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { + _resOffset = -1; +} + +int MacResExtractor::extractResource(int id, byte **buf) { + Common::File in; + int size; + + if (!_fileName[0]) // We are running for the first time + if (_vm->_substResFileNameIndex > 0) { + char buf1[128]; + + snprintf(buf1, 128, "%s.he3", _vm->getBaseName()); + _vm->generateSubstResFileName(buf1, _fileName, sizeof(buf1)); + + // Some programs write it as .bin. Try that too + if (!in.exists(_fileName)) { + strcpy(buf1, _fileName); + snprintf(_fileName, 128, "%s.bin", buf1); + + if (!in.exists(_fileName)) { + // And finally check if we have dumped resource fork + snprintf(_fileName, 128, "%s.rsrc", buf1); + if (!in.exists(_fileName)) { + error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", + buf1, buf1, buf1); + } + } + } + } + + in.open(_fileName); + if (!in.isOpen()) { + error("Cannot open file %s", _fileName); + } + + // we haven't calculated it + if (_resOffset == -1) { + if (!init(in)) + error("Resource fork is missing in file '%s'", _fileName); + in.close(); + in.open(_fileName); + } + + *buf = getResource(in, "crsr", 1000 + id, &size); + + in.close(); + + if (*buf == NULL) + error("There is no cursor ID #%d", 1000 + id); + + return size; +} + +#define MBI_INFOHDR 128 +#define MBI_ZERO1 0 +#define MBI_NAMELEN 1 +#define MBI_ZERO2 74 +#define MBI_ZERO3 82 +#define MBI_DFLEN 83 +#define MBI_RFLEN 87 +#define MAXNAMELEN 63 + +bool MacResExtractor::init(Common::File in) { + byte infoHeader[MBI_INFOHDR]; + int32 data_size, rsrc_size; + int32 data_size_pad, rsrc_size_pad; + int filelen; + + filelen = in.size(); + in.read(infoHeader, MBI_INFOHDR); + + // Maybe we have MacBinary? + if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 && + infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) { + + // Pull out fork lengths + data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN); + rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN); + + data_size_pad = (((data_size + 127) >> 7) << 7); + rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7); + + // Length check + int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; + + if (sumlen == filelen) + _resOffset = MBI_INFOHDR + data_size_pad; + } + + if (_resOffset == -1) // MacBinary check is failed + _resOffset = 0; // Maybe we have dumped fork? + + in.seek(_resOffset); + + _dataOffset = in.readUint32BE() + _resOffset; + _mapOffset = in.readUint32BE() + _resOffset; + _dataLength = in.readUint32BE(); + _mapLength = in.readUint32BE(); + + // do sanity check + if (_dataOffset >= filelen || _mapOffset >= filelen || + _dataLength + _mapLength > filelen) { + _resOffset = -1; + return false; + } + + debug(7, "got header: data %d [%d] map %d [%d]", + _dataOffset, _dataLength, _mapOffset, _mapLength); + + readMap(in); + + return true; +} + +byte *MacResExtractor::getResource(Common::File in, const char *typeID, int16 resID, int *size) { + int i; + int typeNum = -1; + int resNum = -1; + byte *buf; + int len; + + for (i = 0; i < _resMap.numTypes; i++) + if (strcmp(_resTypes[i].id, typeID) == 0) { + typeNum = i; + break; + } + + if (typeNum == -1) + return NULL; + + for (i = 0; i < _resTypes[typeNum].items; i++) + if (_resLists[typeNum][i].id == resID) { + resNum = i; + break; + } + + if (resNum == -1) + return NULL; + + in.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); + + len = in.readUint32BE(); + buf = (byte *)malloc(len); + + in.read(buf, len); + + *size = len; + + return buf; +} + +void MacResExtractor::readMap(Common::File in) { + int i, j, len; + + in.seek(_mapOffset + 22); + + _resMap.resAttr = in.readUint16BE(); + _resMap.typeOffset = in.readUint16BE(); + _resMap.nameOffset = in.readUint16BE(); + _resMap.numTypes = in.readUint16BE(); + _resMap.numTypes++; + + in.seek(_mapOffset + _resMap.typeOffset + 2); + _resTypes = new ResType[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + in.read(_resTypes[i].id, 4); + _resTypes[i].id[4] = 0; + _resTypes[i].items = in.readUint16BE(); + _resTypes[i].offset = in.readUint16BE(); + _resTypes[i].items++; + } + + _resLists = new ResPtr[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + _resLists[i] = new Resource[_resTypes[i].items]; + in.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); + + for (j = 0; j < _resTypes[i].items; j++) { + ResPtr resPtr = _resLists[i] + j; + + resPtr->id = in.readUint16BE(); + resPtr->nameOffset = in.readUint16BE(); + resPtr->dataOffset = in.readUint32BE(); + in.readUint32BE(); + resPtr->name = 0; + + resPtr->attr = resPtr->dataOffset >> 24; + resPtr->dataOffset &= 0xFFFFFF; + } + + for (j = 0; j < _resTypes[i].items; j++) { + if (_resLists[i][j].nameOffset != -1) { + in.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); + + len = in.readByte(); + _resLists[i][j].name = new byte[len + 1]; + _resLists[i][j].name[len] = 0; + in.read(_resLists[i][j].name, len); + } + } + } +} + +int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) { + Common::MemoryReadStream dis(data, datasize); + int i, b; + byte imageByte; + byte *iconData; + int numBytes; + int pixelsPerByte, bpp; + int ctSize; + byte bitmask; + int iconRowBytes, iconBounds[4]; + int ignored; + int iconDataSize; + + dis.readUint16BE(); // type + dis.readUint32BE(); // offset to pixel map + dis.readUint32BE(); // offset to pixel data + dis.readUint32BE(); // expanded cursor data + dis.readUint16BE(); // expanded data depth + dis.readUint32BE(); // reserved + + // Grab B/W icon data + *cursor = (byte *)malloc(16 * 16); + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + cursor[0][i*8+b] = (byte)((imageByte & + (0x80 >> b)) > 0? 0x0F: 0x00); + } + + // Apply mask data + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + if ((imageByte & (0x80 >> b)) == 0) + cursor[0][i*8+b] = 0xff; + } + + *hotspot_y = dis.readUint16BE(); + *hotspot_x = dis.readUint16BE(); + *w = *h = 16; + + // Use b/w cursor on backends which don't support cursor palettes + if (!_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette)) + return 1; + + dis.readUint32BE(); // reserved + dis.readUint32BE(); // cursorID + + // Color version of cursor + dis.readUint32BE(); // baseAddr + + // Keep only lowbyte for now + dis.readByte(); + iconRowBytes = dis.readByte(); + + if (!iconRowBytes) + return 1; + + iconBounds[0] = dis.readUint16BE(); + iconBounds[1] = dis.readUint16BE(); + iconBounds[2] = dis.readUint16BE(); + iconBounds[3] = dis.readUint16BE(); + + dis.readUint16BE(); // pmVersion + dis.readUint16BE(); // packType + dis.readUint32BE(); // packSize + + dis.readUint32BE(); // hRes + dis.readUint32BE(); // vRes + + dis.readUint16BE(); // pixelType + dis.readUint16BE(); // pixelSize + dis.readUint16BE(); // cmpCount + dis.readUint16BE(); // cmpSize + + dis.readUint32BE(); // planeByte + dis.readUint32BE(); // pmTable + dis.readUint32BE(); // reserved + + // Pixel data for cursor + iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]); + iconData = (byte *)malloc(iconDataSize); + dis.read(iconData, iconDataSize); + + // Color table + dis.readUint32BE(); // ctSeed + dis.readUint16BE(); // ctFlag + ctSize = dis.readUint16BE() + 1; + + *palette = (byte *)malloc(ctSize * 4); + + // Read just high byte of 16-bit color + for (int c = 0; c < ctSize; c++) { + // We just use indices 0..ctSize, so ignore color ID + dis.readUint16BE(); // colorID[c] + + palette[0][c * 4 + 0] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 1] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 2] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 3] = 0; + } + + *palSize = ctSize; + + numBytes = + (iconBounds[2] - iconBounds[0]) * + (iconBounds[3] - iconBounds[1]); + + pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes; + bpp = 8 / pixelsPerByte; + + // build a mask to make sure the pixels are properly shifted out + bitmask = 0; + for (int m = 0; m < bpp; m++) { + bitmask <<= 1; + bitmask |= 1; + } + + // Extract pixels from bytes + for (int j = 0; j < iconDataSize; j++) + for (b = 0; b < pixelsPerByte; b++) { + int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b); + + if (cursor[0][idx] != 0xff) // if mask is not there + cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask); + } + + free(iconData); + + assert(datasize - dis.pos() == 0); + + return 1; +} + + + +void ScummEngine_v70he::readRoomsOffsets() { + int num, i; + byte *ptr; + + debug(9, "readRoomOffsets()"); + + num = READ_LE_UINT16(_heV7RoomOffsets); + ptr = _heV7RoomOffsets + 2; + for (i = 0; i < num; i++) { + res.roomoffs[rtRoom][i] = READ_LE_UINT32(ptr); + ptr += 4; + } +} + +void ScummEngine_v70he::readGlobalObjects() { + int num = _fileHandle->readUint16LE(); + assert(num == _numGlobalObjects); + + _fileHandle->read(_objectStateTable, num); + _fileHandle->read(_objectOwnerTable, num); + _fileHandle->read(_objectRoomTable, num); + + _fileHandle->read(_classData, num * sizeof(uint32)); + +#if defined(SCUMM_BIG_ENDIAN) + // Correct the endianess if necessary + for (int i = 0; i != num; i++) + _classData[i] = FROM_LE_32(_classData[i]); +#endif +} + +void ScummEngine_v99he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v99he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numSprites = _fileHandle->readUint16LE(); + _numLocalScripts = _fileHandle->readUint16LE(); + _HEHeapSize = _fileHandle->readUint16LE(); + _numPalettes = _fileHandle->readUint16LE(); + _numUnk = _fileHandle->readUint16LE(); + _numTalkies = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + _numGlobalScripts = 2048; +} + +void ScummEngine_v90he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v90he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numSprites = _fileHandle->readUint16LE(); + _numLocalScripts = _fileHandle->readUint16LE(); + _HEHeapSize = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + if (_features & GF_HE_985) + _numGlobalScripts = 2048; + else + _numGlobalScripts = 200; +} + +void ScummEngine_v72he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v72he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numBitVariables = _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numVerbs = _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + _numGlobalScripts = 200; +} + +byte *ScummEngine_v72he::getStringAddress(int i) { + byte *addr = getResourceAddress(rtString, i); + if (addr == NULL) + return NULL; + return ((ScummEngine_v72he::ArrayHeader *)addr)->data; +} + +int ScummEngine_v72he::getSoundResourceSize(int id) { + const byte *ptr; + int offs, size; + + if (id > _numSounds) { + if (!_sound->getHEMusicDetails(id, offs, size)) { + debug(0, "getSoundResourceSize: musicID %d not found", id); + return 0; + } + } else { + ptr = getResourceAddress(rtSound, id); + if (!ptr) + return 0; + + if (READ_UINT32(ptr) == MKID('RIFF')) { + byte flags; + int rate; + + size = READ_BE_UINT32(ptr + 4); + Common::MemoryReadStream stream(ptr, size); + + if (!loadWAVFromStream(stream, size, rate, flags)) { + error("getSoundResourceSize: Not a valid WAV file"); + } + } else { + ptr += 8 + READ_BE_UINT32(ptr + 12); + if (READ_UINT32(ptr) == MKID('SBNG')) { + ptr += READ_BE_UINT32(ptr + 4); + } + + assert(READ_UINT32(ptr) == MKID('SDAT')); + size = READ_BE_UINT32(ptr + 4) - 8; + } + } + + return size; +} + +void ScummEngine_v80he::createSound(int snd1id, int snd2id) { + debug(0, "createSound: snd1id %d snd2id %d", snd1id, snd2id); + + byte *snd1Ptr, *snd2Ptr; + byte *sbng1Ptr, *sbng2Ptr; + byte *sdat1Ptr, *sdat2Ptr; + byte *src, *dst, *tmp; + int len, offs, size; + int sdat1size, sdat2size; + + if (snd2id == -1) { + _sndPtrOffs = 0; + _sndTmrOffs = 0; + return; + } + + if (snd1id != _curSndId) { + _curSndId = snd1id; + _sndPtrOffs = 0; + _sndTmrOffs = 0; + } + + snd1Ptr = getResourceAddress(rtSound, snd1id); + assert(snd1Ptr); + snd2Ptr = getResourceAddress(rtSound, snd2id); + assert(snd2Ptr); + + int i; + int chan = -1; + for (i = 0; i < ARRAYSIZE(_sound->_heChannel); i++) { + if (_sound->_heChannel[i].sound == snd1id) + chan = i; + } + + sbng1Ptr = heFindResource(MKID('SBNG'), snd1Ptr); + sbng2Ptr = heFindResource(MKID('SBNG'), snd2Ptr); + + if (sbng1Ptr != NULL && sbng2Ptr != NULL) { + if (chan != -1 && _sound->_heChannel[chan].codeOffs > 0) { + int curOffs = _sound->_heChannel[chan].codeOffs; + + src = snd1Ptr + curOffs; + dst = sbng1Ptr + 8; + size = READ_BE_UINT32(sbng1Ptr + 4); + len = sbng1Ptr - snd1Ptr + size - curOffs; + + byte *data = (byte *)malloc(len); + memcpy(data, src, len); + memcpy(dst, data, len); + free(data); + + dst = sbng1Ptr + 8; + while ((size = READ_LE_UINT16(dst)) != 0) + dst += size; + } else { + dst = sbng1Ptr + 8; + } + + _sound->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8; + + tmp = sbng2Ptr + 8; + while ((offs = READ_LE_UINT16(tmp)) != 0) { + tmp += offs; + } + + src = sbng2Ptr + 8; + len = tmp - sbng2Ptr - 6; + memcpy(dst, src, len); + + int32 time; + while ((size = READ_LE_UINT16(dst)) != 0) { + time = READ_LE_UINT32(dst + 2); + time += _sndTmrOffs; + WRITE_LE_UINT32(dst + 2, time); + dst += size; + } + } + + sdat1Ptr = heFindResource(MKID('SDAT'), snd1Ptr); + assert(sdat1Ptr); + sdat2Ptr = heFindResource(MKID('SDAT'), snd2Ptr); + assert(sdat2Ptr); + + sdat1size = READ_BE_UINT32(sdat1Ptr + 4) - 8 - _sndPtrOffs; + sdat2size = READ_BE_UINT32(sdat2Ptr + 4) - 8; + + debug(0, "SDAT size1 %d size2 %d", sdat1size, sdat2size); + if (sdat2size < sdat1size) { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndPtrOffs; + len = sdat2size; + + memcpy(dst, src, len); + + _sndPtrOffs += sdat2size; + _sndTmrOffs += sdat2size; + } else { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndPtrOffs; + len = sdat1size; + + memcpy(dst, src, len); + + if (sdat2size != sdat1size) { + src = sdat2Ptr + 8 + sdat1size; + dst = sdat1Ptr + 8; + len = sdat2size - sdat1size; + + memcpy(dst, src, len); + } + + _sndPtrOffs = sdat2size - sdat1size; + _sndTmrOffs += sdat2size; + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h new file mode 100644 index 0000000000..20ad0a1110 --- /dev/null +++ b/engines/scumm/he/resource_he.h @@ -0,0 +1,556 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * Parts of code heavily based on: + * icoutils - A set of programs dealing with MS Windows icons and cursors. + * Copyright (C) 1998-2001 Oskar Liljeblad + * + * 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$ + * + */ + +#if !defined(RESOURCE_HE_H) && !defined(DISABLE_HE) +#define RESOURCE_HE_H + +namespace Scumm { + +#define WINRES_ID_MAXLEN (256) + +/* + * Definitions + */ + +#define ACTION_LIST 1 /* command: list resources */ +#define ACTION_EXTRACT 2 /* command: extract resources */ +#define CALLBACK_STOP 0 /* results of ResourceCallback */ +#define CALLBACK_CONTINUE 1 +#define CALLBACK_CONTINUE_RECURS 2 + +#define MZ_HEADER(x) ((DOSImageHeader *)(x)) +#define NE_HEADER(x) ((OS2ImageHeader *)PE_HEADER(x)) +#define NE_TYPEINFO_NEXT(x) ((Win16NETypeInfo *)((byte *)(x) + sizeof(Win16NETypeInfo) + \ + ((Win16NETypeInfo *)x)->count * sizeof(Win16NENameInfo))) +#define NE_RESOURCE_NAME_IS_NUMERIC (0x8000) + +#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x) + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_SIZEOF_SHORT_NAME 8 + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +#define PE_HEADER(module) \ + ((Win32ImageNTHeaders*)((byte *)(module) + \ + (((DOSImageHeader*)(module))->lfanew))) + +#define PE_SECTIONS(module) \ + ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \ + PE_HEADER(module)->file_header.size_of_optional_header)) + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +#if !defined (WIN32) +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#endif + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +#if !defined (WIN32) +#define RT_CURSOR 1 +#define RT_BITMAP 2 +#define RT_ICON 3 +#define RT_MENU 4 +#define RT_DIALOG 5 +#define RT_STRING 6 +#define RT_FONTDIR 7 +#define RT_FONT 8 +#define RT_ACCELERATOR 9 +#define RT_RCDATA 10 +#define RT_MESSAGELIST 11 +#define RT_GROUP_CURSOR 12 +#define RT_GROUP_ICON 14 +#endif + +#define RETURN_IF_BAD_POINTER(r, x) \ + if (!check_offset(fi->memory, fi->total_size, fi->file->name(), &(x), sizeof(x))) \ + return (r); +#define RETURN_IF_BAD_OFFSET(r, x, s) \ + if (!check_offset(fi->memory, fi->total_size, fi->file->name(), x, s)) \ + return (r); + +class ScummEngine_v70he; + +class ResExtractor { +public: + ResExtractor(ScummEngine_v70he *scumm); + virtual ~ResExtractor(); + + void setCursor(int id); + + virtual int extractResource(int id, byte **buf) { return 0; }; + virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, + byte **palette, int *palSize) { return 0; }; + + enum { + MAX_CACHED_CURSORS = 10 + }; + + struct CachedCursor { + bool valid; + int id; + byte *bitmap; + int w, h; + int hotspot_x, hotspot_y; + uint32 last_used; + byte *palette; + int palSize; + }; + + ScummEngine_v70he *_vm; + + ResExtractor::CachedCursor *findCachedCursor(int id); + ResExtractor::CachedCursor *getCachedCursorSlot(); + + bool _arg_raw; + char _fileName[256]; + CachedCursor _cursorCache[MAX_CACHED_CURSORS]; + + typedef Common::MemoryReadStream MemoryReadStream; + +}; + +class Win32ResExtractor : public ResExtractor { + public: + Win32ResExtractor(ScummEngine_v70he *scumm); + ~Win32ResExtractor() {}; + int extractResource(int id, byte **data); + void setCursor(int id); + int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); + + private: + int extractResource_(const char *resType, char *resName, byte **data); +/* + * Structures + */ + +#if !defined(__GNUC__) + #pragma START_PACK_STRUCTS +#endif + + struct WinLibrary { + Common::File *file; + byte *memory; + byte *first_resource; + bool is_PE_binary; + int total_size; + }; + + struct WinResource { + char id[256]; + void *this_; + void *children; + int level; + bool numeric_id; + bool is_directory; + }; + + + struct Win32IconResDir { + byte width; + byte height; + byte color_count; + byte reserved; + }; + + struct Win32CursorDir { + uint16 width; + uint16 height; + }; + + struct Win32CursorIconDirEntry { + union { + Win32IconResDir icon; + Win32CursorDir cursor; + } res_info; + uint16 plane_count; + uint16 bit_count; + uint32 bytes_in_res; + uint16 res_id; + }; + + struct Win32CursorIconDir { + uint16 reserved; + uint16 type; + uint16 count; + Win32CursorIconDirEntry entries[1] GCC_PACK; + }; + + struct Win32CursorIconFileDirEntry { + byte width; + byte height; + byte color_count; + byte reserved; + uint16 hotspot_x; + uint16 hotspot_y; + uint32 dib_size; + uint32 dib_offset; + }; + + struct Win32CursorIconFileDir { + uint16 reserved; + uint16 type; + uint16 count; + Win32CursorIconFileDirEntry entries[1]; + }; + + struct Win32BitmapInfoHeader { + uint32 size; + int32 width; + int32 height; + uint16 planes; + uint16 bit_count; + uint32 compression; + uint32 size_image; + int32 x_pels_per_meter; + int32 y_pels_per_meter; + uint32 clr_used; + uint32 clr_important; + }; + + struct Win32RGBQuad { + byte blue; + byte green; + byte red; + byte reserved; + }; + + struct Win32ImageResourceDirectoryEntry { + union { + struct { + #ifdef SCUMM_BIGENDIAN + unsigned name_is_string:1; + unsigned name_offset:31; + #else + unsigned name_offset:31; + unsigned name_is_string:1; + #endif + } s1; + uint32 name; + struct { + #ifdef SCUMM_BIG_ENDIAN + uint16 __pad; + uint16 id; + #else + uint16 id; + uint16 __pad; + #endif + } s2; + } u1; + union { + uint32 offset_to_data; + struct { + #ifdef SCUMM_BIG_ENDIAN + unsigned data_is_directory:1; + unsigned offset_to_directory:31; + #else + unsigned offset_to_directory:31; + unsigned data_is_directory:1; + #endif + } s; + } u2; + }; + + struct Win16NETypeInfo { + uint16 type_id; + uint16 count; + uint32 resloader; // FARPROC16 - smaller? uint16? + }; + + struct Win16NENameInfo { + uint16 offset; + uint16 length; + uint16 flags; + uint16 id; + uint16 handle; + uint16 usage; + }; + + struct OS2ImageHeader { + uint16 magic; + byte ver; + byte rev; + uint16 enttab; + uint16 cbenttab; + int32 crc; + uint16 flags; + uint16 autodata; + uint16 heap; + uint16 stack; + uint32 csip; + uint32 sssp; + uint16 cseg; + uint16 cmod; + uint16 cbnrestab; + uint16 segtab; + uint16 rsrctab; + uint16 restab; + uint16 modtab; + uint16 imptab; + uint32 nrestab; + uint16 cmovent; + uint16 align; + uint16 cres; + byte exetyp; + byte flagsothers; + uint16 fastload_offset; + uint16 fastload_length; + uint16 swaparea; + uint16 expver; + }; + + struct DOSImageHeader { + uint16 magic; + uint16 cblp; + uint16 cp; + uint16 crlc; + uint16 cparhdr; + uint16 minalloc; + uint16 maxalloc; + uint16 ss; + uint16 sp; + uint16 csum; + uint16 ip; + uint16 cs; + uint16 lfarlc; + uint16 ovno; + uint16 res[4]; + uint16 oemid; + uint16 oeminfo; + uint16 res2[10]; + uint32 lfanew; + }; + + struct Win32ImageFileHeader { + uint16 machine; + uint16 number_of_sections; + uint32 time_date_stamp; + uint32 pointer_to_symbol_table; + uint32 number_of_symbols; + uint16 size_of_optional_header; + uint16 characteristics; + }; + + struct Win32ImageDataDirectory { + uint32 virtual_address; + uint32 size; + }; + + struct Win32ImageOptionalHeader { + uint16 magic; + byte major_linker_version; + byte minor_linker_version; + uint32 size_of_code; + uint32 size_of_initialized_data; + uint32 size_of_uninitialized_data; + uint32 address_of_entry_point; + uint32 base_of_code; + uint32 base_of_data; + uint32 image_base; + uint32 section_alignment; + uint32 file_alignment; + uint16 major_operating_system_version; + uint16 minor_operating_system_version; + uint16 major_image_version; + uint16 minor_image_version; + uint16 major_subsystem_version; + uint16 minor_subsystem_version; + uint32 win32_version_value; + uint32 size_of_image; + uint32 size_of_headers; + uint32 checksum; + uint16 subsystem; + uint16 dll_characteristics; + uint32 size_of_stack_reserve; + uint32 size_of_stack_commit; + uint32 size_of_heap_reserve; + uint32 size_of_heap_commit; + uint32 loader_flags; + uint32 number_of_rva_and_sizes; + Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + }; + + struct Win32ImageNTHeaders { + uint32 signature; + Win32ImageFileHeader file_header; + Win32ImageOptionalHeader optional_header; + }; + + struct Win32ImageSectionHeader { + byte name[IMAGE_SIZEOF_SHORT_NAME]; + union { + uint32 physical_address; + uint32 virtual_size; + } misc; + uint32 virtual_address; + uint32 size_of_raw_data; + uint32 pointer_to_raw_data; + uint32 pointer_to_relocations; + uint32 pointer_to_linenumbers; + uint16 number_of_relocations; + uint16 number_of_linenumbers; + uint32 characteristics; + }; + + struct Win32ImageResourceDataEntry { + uint32 offset_to_data; + uint32 size; + uint32 code_page; + uint32 resource_handle; + }; + + struct Win32ImageResourceDirectory { + uint32 characteristics; + uint32 time_date_stamp; + uint16 major_version; + uint16 minor_version; + uint16 number_of_named_entries; + uint16 number_of_id_entries; + }; + +#if !defined(__GNUC__) + #pragma END_PACK_STRUCTS +#endif + +/* + * Function Prototypes + */ + + WinResource *list_resources(WinLibrary *, WinResource *, int *); + bool read_library(WinLibrary *); + WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *); + byte *get_resource_entry(WinLibrary *, WinResource *, int *); + int do_resources(WinLibrary *, const char *, char *, char *, int, byte **); + bool compare_resource_id(WinResource *, const char *); + const char *res_type_string_to_id(const char *); + + const char *res_type_id_to_string(int); + char *get_destination_name(WinLibrary *, char *, char *, char *); + + byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool); + int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **); + byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool); + + bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32); + bool decode_ne_resource_id(WinLibrary *, WinResource *, uint16); + WinResource *list_ne_type_resources(WinLibrary *, int *); + WinResource *list_ne_name_resources(WinLibrary *, WinResource *, int *); + WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *); + int calc_vma_size(WinLibrary *); + int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, int, byte **); + char *get_resource_id_quoted(WinResource *); + WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *); + + bool check_offset(byte *, int, const char *, void *, int); + + uint32 simple_vec(byte *data, uint32 ofs, byte size); + + void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj); + void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj); + void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj); + void fix_win32_image_section_header(Win32ImageSectionHeader *obj); + void fix_os2_image_header_endian(OS2ImageHeader *obj); + void fix_win32_image_header_endian(Win32ImageNTHeaders *obj); + void fix_win32_image_data_directory(Win32ImageDataDirectory *obj); +}; + +class MacResExtractor : public ResExtractor { + +public: + MacResExtractor(ScummEngine_v70he *scumm); + ~MacResExtractor() { } + void setCursor(int id) ; + +private: + int extractResource(int id, byte **buf); + bool init(Common::File in); + void readMap(Common::File in); + byte *getResource(Common::File in, const char *typeID, int16 resID, int *size); + int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); + + struct ResMap { + int16 resAttr; + int16 typeOffset; + int16 nameOffset; + int16 numTypes; + }; + + struct ResType { + char id[5]; + int16 items; + int16 offset; + }; + + struct Resource { + int16 id; + int16 nameOffset; + byte attr; + int32 dataOffset; + byte *name; + }; + + typedef Resource *ResPtr; + +private: + int _resOffset; + int32 _dataOffset; + int32 _dataLength; + int32 _mapOffset; + int32 _mapLength; + ResMap _resMap; + ResType *_resTypes; + ResPtr *_resLists; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/he/resource_v7he.cpp b/engines/scumm/he/resource_v7he.cpp deleted file mode 100644 index 95c3c23f2b..0000000000 --- a/engines/scumm/he/resource_v7he.cpp +++ /dev/null @@ -1,1912 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2004-2006 The ScummVM project - * - * Parts of code heavily based on: - * icoutils - A set of programs dealing with MS Windows icons and cursors. - * Copyright (C) 1998-2001 Oskar Liljeblad - * - * 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 "common/stdafx.h" -#include "scumm/scumm.h" -#include "scumm/he/intern_he.h" -#include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" -#include "scumm/sound.h" -#include "scumm/util.h" -#include "sound/wave.h" - -#include "common/stream.h" -#include "common/system.h" - -namespace Scumm { - -ResExtractor::ResExtractor(ScummEngine_v70he *scumm) - : _vm(scumm) { - - _fileName[0] = 0; - memset(_cursorCache, 0, sizeof(_cursorCache)); -} - -ResExtractor::~ResExtractor() { - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (cc->valid) { - free(cc->bitmap); - free(cc->palette); - } - } - memset(_cursorCache, 0, sizeof(_cursorCache)); -} - -ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) { - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (cc->valid && cc->id == id) { - return cc; - } - } - return NULL; -} - -ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() { - uint32 min_last_used = 0; - CachedCursor *r = NULL; - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (!cc->valid) { - return cc; - } else { - if (min_last_used == 0 || cc->last_used < min_last_used) { - min_last_used = cc->last_used; - r = cc; - } - } - } - assert(r); - free(r->bitmap); - free(r->palette); - memset(r, 0, sizeof(CachedCursor)); - return r; -} - -void ResExtractor::setCursor(int id) { - byte *cursorRes = 0; - int cursorsize; - int keycolor = 0; - CachedCursor *cc = findCachedCursor(id); - if (cc != NULL) { - debug(7, "Found cursor %d in cache slot %d", id, cc - _cursorCache); - } else { - cc = getCachedCursorSlot(); - assert(cc && !cc->valid); - cursorsize = extractResource(id, &cursorRes); - convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize); - debug(7, "Adding cursor %d to cache slot %d", id, cc - _cursorCache); - free(cursorRes); - cc->valid = true; - cc->id = id; - cc->last_used = g_system->getMillis(); - } - - if (_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette) && cc->palette) - _vm->_system->setCursorPalette(cc->palette, 0, cc->palSize); - - _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y); - _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w); -} - - -/* - * Static variables - */ -const char *res_types[] = { - /* 0x01: */ - "cursor", "bitmap", "icon", "menu", "dialog", "string", - "fontdir", "font", "accelerator", "rcdata", "messagelist", - "group_cursor", NULL, "group_icon", NULL, - /* the following are not defined in winbase.h, but found in wrc. */ - /* 0x10: */ - "version", "dlginclude", NULL, "plugplay", "vxd", - "anicursor", "aniicon" -}; -#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *)) - -Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { -} - -int Win32ResExtractor::extractResource(int resId, byte **data) { - char buf[20]; - - snprintf(buf, sizeof(buf), "%d", resId); - - return extractResource_("group_cursor", buf, data); -} - -int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) { - char *arg_language = NULL; - const char *arg_type = resType; - char *arg_name = resName; - int arg_action = ACTION_LIST; - int ressize = 0; - - _arg_raw = false; - - /* translate --type option from resource type string to integer */ - arg_type = res_type_string_to_id(arg_type); - - WinLibrary fi; - - /* initiate stuff */ - fi.memory = NULL; - fi.file = new Common::File; - - if (!_fileName[0]) { // We are running for the first time - snprintf(_fileName, 256, "%s.he3", _vm->getBaseName()); - - if (_vm->_substResFileNameIndex > 0) { - char buf1[128]; - - _vm->generateSubstResFileName(_fileName, buf1, sizeof(buf1)); - strcpy(_fileName, buf1); - } - } - - - /* get file size */ - fi.file->open(_fileName); - if (!fi.file->isOpen()) { - error("Cannot open file %s", _fileName); - } - - fi.total_size = fi.file->size(); - if (fi.total_size == -1) { - error("Cannot get size of file %s", fi.file->name()); - goto cleanup; - } - if (fi.total_size == 0) { - error("%s: file has a size of 0", fi.file->name()); - goto cleanup; - } - - /* read all of file */ - fi.memory = (byte *)malloc(fi.total_size); - if (fi.file->read(fi.memory, fi.total_size) == 0) { - error("Cannot read from file %s", fi.file->name()); - goto cleanup; - } - - /* identify file and find resource table */ - if (!read_library(&fi)) { - /* error reported by read_library */ - goto cleanup; - } - - // verbose_printf("file is a %s\n", - // fi.is_PE_binary ? "Windows NT `PE' binary" : "Windows 3.1 `NE' binary"); - - /* errors will be printed by the callback */ - ressize = do_resources(&fi, arg_type, arg_name, arg_language, arg_action, data); - - /* free stuff and close file */ - cleanup: - if (fi.file != NULL) - fi.file->close(); - if (fi.memory != NULL) - free(fi.memory); - - return ressize; -} - - -/* res_type_id_to_string: - * Translate a numeric resource type to it's corresponding string type. - * (For informative-ness.) - */ -const char *Win32ResExtractor::res_type_id_to_string(int id) { - if (id == 241) - return "toolbar"; - if (id > 0 && id <= (int)RES_TYPE_COUNT) - return res_types[id-1]; - return NULL; -} - -/* res_type_string_to_id: - * Translate a resource type string to integer. - * (Used to convert the --type option.) - */ -const char *Win32ResExtractor::res_type_string_to_id(const char *type) { - static const char *res_type_ids[] = { - "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", - "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19", - "-20", "-21", "-22" - }; - int c; - - if (type == NULL) - return NULL; - - for (c = 0 ; c < (int)RES_TYPE_COUNT ; c++) { - if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c])) - return res_type_ids[c]; - } - - return type; -} - -int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr, - WinResource *type_wr, WinResource *name_wr, - WinResource *lang_wr, byte **data) { - int size; - bool free_it; - const char *type; - int32 id; - - if (*data) { - error("Win32ResExtractor::extract_resources() more than one cursor"); - return 0; - } - - *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw); - - if (data == NULL) { - error("Win32ResExtractor::extract_resources() problem with resource extraction"); - return 0; - } - - /* get named resource type if possible */ - type = NULL; - if ((id = strtol(type_wr->id, 0, 10)) != 0) - type = res_type_id_to_string(id); - - debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]", - get_resource_id_quoted(name_wr), - (lang_wr->id[0] != '\0' ? " language: " : ""), - get_resource_id_quoted(lang_wr), size); - - return size; -} - -/* extract_resource: - * Extract a resource, returning pointer to data. - */ -byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size, - bool *free_it, char *type, char *lang, bool raw) { - char *str; - int32 intval; - - /* just return pointer to data if raw */ - if (raw) { - *free_it = false; - /* get_resource_entry will print possible error */ - return get_resource_entry(fi, wr, size); - } - - /* find out how to extract */ - str = type; - if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) { - if (intval == (int)RT_GROUP_ICON) { - *free_it = true; - return extract_group_icon_cursor_resource(fi, wr, lang, size, true); - } - if (intval == (int)RT_GROUP_CURSOR) { - *free_it = true; - return extract_group_icon_cursor_resource(fi, wr, lang, size, false); - } - } - - return NULL; -} - -/* extract_group_icon_resource: - * Create a complete RT_GROUP_ICON resource, that can be written to - * an `.ico' file without modifications. Returns an allocated - * memory block that should be freed with free() once used. - * - * `root' is the offset in file that specifies the resource. - * `base' is the offset that string pointers are calculated from. - * `ressize' should point to an integer variable where the size of - * the returned memory block will be placed. - * `is_icon' indicates whether resource to be extracted is icon - * or cursor group. - */ -byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang, - int *ressize, bool is_icon) { - Win32CursorIconDir *icondir; - Win32CursorIconFileDir *fileicondir; - byte *memory; - int c, offset, skipped; - int size; - - /* get resource data and size */ - icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size); - if (icondir == NULL) { - /* get_resource_entry will print error */ - return NULL; - } - - /* calculate total size of output file */ - RETURN_IF_BAD_POINTER(NULL, icondir->count); - skipped = 0; - for (c = 0 ; c < icondir->count ; c++) { - int level; - int iconsize; - char name[14]; - WinResource *fwr; - - RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]); - /*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c, - icondir->entries[c].bytes_in_res, - (is_icon ? icondir->entries[c].res_info.icon.width : icondir->entries[c].res_info.cursor.width), - (is_icon ? icondir->entries[c].res_info.icon.height : icondir->entries[c].res_info.cursor.height), - icondir->entries[c].plane_count, - icondir->entries[c].bit_count);*/ - - /* find the corresponding icon resource */ - snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); - fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); - if (fwr == NULL) { - error("%s: could not find `%s' in `%s' resource.", - fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); - return NULL; - } - - if (get_resource_entry(fi, fwr, &iconsize) != NULL) { - if (iconsize == 0) { - debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", fi->file->name(), name); - skipped++; - continue; - } - if ((uint32)iconsize != icondir->entries[c].bytes_in_res) { - debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)", - fi->file->name(), name, iconsize, icondir->entries[c].bytes_in_res); - } - size += iconsize; /* size += icondir->entries[c].bytes_in_res; */ - - /* cursor resources have two additional WORDs that contain - * hotspot info */ - if (!is_icon) - size -= sizeof(uint16)*2; - } - } - offset = sizeof(Win32CursorIconFileDir) + (icondir->count-skipped) * sizeof(Win32CursorIconFileDirEntry); - size += offset; - *ressize = size; - - /* allocate that much memory */ - memory = (byte *)malloc(size); - fileicondir = (Win32CursorIconFileDir *)memory; - - /* transfer Win32CursorIconDir structure members */ - fileicondir->reserved = icondir->reserved; - fileicondir->type = icondir->type; - fileicondir->count = icondir->count - skipped; - - /* transfer each cursor/icon: Win32CursorIconDirEntry and data */ - skipped = 0; - for (c = 0 ; c < icondir->count ; c++) { - int level; - char name[14]; - WinResource *fwr; - byte *data; - - /* find the corresponding icon resource */ - snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); - fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); - if (fwr == NULL) { - error("%s: could not find `%s' in `%s' resource.", - fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); - return NULL; - } - - /* get data and size of that resource */ - data = (byte *)get_resource_entry(fi, fwr, &size); - if (data == NULL) { - /* get_resource_entry has printed error */ - return NULL; - } - if (size == 0) { - skipped++; - continue; - } - - /* copy ICONDIRENTRY (not including last dwImageOffset) */ - memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c], - sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32)); - - /* special treatment for cursors */ - if (!is_icon) { - fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width; - fileicondir->entries[c-skipped].height = icondir->entries[c].res_info.cursor.height / 2; - fileicondir->entries[c-skipped].color_count = 0; - fileicondir->entries[c-skipped].reserved = 0; - } - - /* set image offset and increase it */ - fileicondir->entries[c-skipped].dib_offset = offset; - - /* transfer resource into file memory */ - if (is_icon) { - memcpy(&memory[offset], data, icondir->entries[c].bytes_in_res); - } else { - fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0]; - fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1]; - memcpy(&memory[offset], data+sizeof(uint16)*2, - icondir->entries[c].bytes_in_res-sizeof(uint16)*2); - offset -= sizeof(uint16)*2; - } - - /* increase the offset pointer */ - offset += icondir->entries[c].bytes_in_res; - } - - return memory; -} - -/* check_offset: - * Check if a chunk of data (determined by offset and size) - * is within the bounds of the WinLibrary file. - * Usually not called directly. - */ -bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) { - int need_size = (int)((byte *)offset - memory + size); - - debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x", - need_size, total_size, (byte *)offset - memory, size); - - if (need_size < 0 || need_size > total_size) { - error("%s: premature end", name); - return false; - } - - return true; -} - - -/* do_resources: - * Do something for each resource matching type, name and lang. - */ -int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, int action, byte **data) { - WinResource *type_wr; - WinResource *name_wr; - WinResource *lang_wr; - int size; - - type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1); - name_wr = type_wr + 1; - lang_wr = type_wr + 2; - - size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, action, data); - - free(type_wr); - - return size; -} - -/* what is each entry in this directory level for? type, name or language? */ -#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr)) - -/* does the id of this entry match the specified id? */ -#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x)) - -int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, - WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr, - const char *type, char *name, char *lang, int action, byte **data) { - int c, rescnt; - WinResource *wr; - uint32 size = 0; - - /* get a list of all resources at this level */ - wr = list_resources(fi, base, &rescnt); - if (wr == NULL) - if (size != 0) - return size; - else - return 0; - - /* process each resource listed */ - for (c = 0 ; c < rescnt ; c++) { - /* (over)write the corresponding WinResource holder with the current */ - memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource)); - - /* go deeper unless there is something that does NOT match */ - if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) { - if (wr->is_directory) - size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, action, data); - else - size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data); - } - } - - /* since we're moving back one level after this, unset the - * WinResource holder used on this level */ - memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource)); - - return size; -} - -/* return the resource id quoted if it's a string, otherwise just return it */ -char *Win32ResExtractor::get_resource_id_quoted(WinResource *wr) { - static char tmp[WINRES_ID_MAXLEN+2]; - - if (wr->numeric_id || wr->id[0] == '\0') - return wr->id; - - sprintf(tmp, "'%s'", wr->id); - return tmp; -} - -bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) { - if (wr->numeric_id) { - int32 cmp1, cmp2; - if (id[0] == '+') - return false; - if (id[0] == '-') - id++; - if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2) - return false; - } else { - if (id[0] == '-') - return false; - if (id[0] == '+') - id++; - if (strcmp(wr->id, id)) - return false; - } - - return true; -} - -bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) { - if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */ - int c, len; - uint16 *mem = (uint16 *) - (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING)); - - /* copy each char of the string, and terminate it */ - RETURN_IF_BAD_POINTER(false, *mem); - len = mem[0]; - RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len); - - len = MIN(mem[0], (uint16)WINRES_ID_MAXLEN); - for (c = 0 ; c < len ; c++) - wr->id[c] = mem[c+1] & 0x00FF; - wr->id[len] = '\0'; - } else { /* Unicode string id */ - /* translate id into a string */ - snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value); - } - - wr->numeric_id = (value & IMAGE_RESOURCE_NAME_IS_STRING ? false:true); - return true; -} - -byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) { - if (fi->is_PE_binary) { - Win32ImageResourceDataEntry *dataent; - - dataent = (Win32ImageResourceDataEntry *) wr->children; - RETURN_IF_BAD_POINTER(NULL, *dataent); - *size = dataent->size; - RETURN_IF_BAD_OFFSET(NULL, fi->memory + dataent->offset_to_data, *size); - - return fi->memory + dataent->offset_to_data; - } else { - Win16NENameInfo *nameinfo; - int sizeshift; - - nameinfo = (Win16NENameInfo *) wr->children; - sizeshift = *((uint16 *) fi->first_resource - 1); - *size = nameinfo->length << sizeshift; - RETURN_IF_BAD_OFFSET(NULL, fi->memory + (nameinfo->offset << sizeshift), *size); - - return fi->memory + (nameinfo->offset << sizeshift); - } -} - -bool Win32ResExtractor::decode_ne_resource_id(WinLibrary *fi, WinResource *wr, uint16 value) { - if (value & NE_RESOURCE_NAME_IS_NUMERIC) { /* numeric id */ - /* translate id into a string */ - snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value & ~NE_RESOURCE_NAME_IS_NUMERIC); - } else { /* ASCII string id */ - int len; - char *mem = (char *)NE_HEADER(fi->memory) - + NE_HEADER(fi->memory)->rsrctab - + value; - - /* copy each char of the string, and terminate it */ - RETURN_IF_BAD_POINTER(false, *mem); - len = mem[0]; - RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(char) * len); - memcpy(wr->id, &mem[1], len); - wr->id[len] = '\0'; - } - - wr->numeric_id = (value & NE_RESOURCE_NAME_IS_NUMERIC ? true:false); - return true; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) { - WinResource *wr; - int c, rescnt; - Win32ImageResourceDirectoryEntry *dirent - = (Win32ImageResourceDirectoryEntry *)(pe_res + 1); - - /* count number of `type' resources */ - RETURN_IF_BAD_POINTER(NULL, *dirent); - rescnt = pe_res->number_of_named_entries + pe_res->number_of_id_entries; - *count = rescnt; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - for (c = 0 ; c < rescnt ; c++) { - RETURN_IF_BAD_POINTER(NULL, dirent[c]); - wr[c].this_ = pe_res; - wr[c].level = level; - wr[c].is_directory = (dirent[c].u2.s.data_is_directory); - wr[c].children = fi->first_resource + dirent[c].u2.s.offset_to_directory; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_pe_resource_id (fi, wr + c, dirent[c].u1.name)) - return NULL; - } - - return wr; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_name_resources(WinLibrary *fi, WinResource *typeres, int *count) { - int c, rescnt; - WinResource *wr; - Win16NETypeInfo *typeinfo = (Win16NETypeInfo *) typeres->this_; - Win16NENameInfo *nameinfo = (Win16NENameInfo *) typeres->children; - - /* count number of `type' resources */ - RETURN_IF_BAD_POINTER(NULL, typeinfo->count); - *count = rescnt = typeinfo->count; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - for (c = 0 ; c < rescnt ; c++) { - RETURN_IF_BAD_POINTER(NULL, nameinfo[c]); - wr[c].this_ = nameinfo+c; - wr[c].is_directory = false; - wr[c].children = nameinfo+c; - wr[c].level = 1; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_ne_resource_id(fi, wr + c, (nameinfo+c)->id)) - return NULL; - } - - return wr; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_type_resources(WinLibrary *fi, int *count) { - int c, rescnt; - WinResource *wr; - Win16NETypeInfo *typeinfo; - - /* count number of `type' resources */ - typeinfo = (Win16NETypeInfo *) fi->first_resource; - RETURN_IF_BAD_POINTER(NULL, *typeinfo); - for (rescnt = 0 ; typeinfo->type_id != 0 ; rescnt++) { - typeinfo = NE_TYPEINFO_NEXT(typeinfo); - RETURN_IF_BAD_POINTER(NULL, *typeinfo); - } - *count = rescnt; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - typeinfo = (Win16NETypeInfo *) fi->first_resource; - for (c = 0 ; c < rescnt ; c++) { - wr[c].this_ = typeinfo; - wr[c].is_directory = (typeinfo->count != 0); - wr[c].children = typeinfo+1; - wr[c].level = 0; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_ne_resource_id(fi, wr + c, typeinfo->type_id)) - return NULL; - - typeinfo = NE_TYPEINFO_NEXT(typeinfo); - } - - return wr; -} - -/* list_resources: - * Return an array of WinResource's in the current - * resource level specified by res. - */ -Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) { - if (res != NULL && !res->is_directory) - return NULL; - - if (fi->is_PE_binary) { - return list_pe_resources(fi, (Win32ImageResourceDirectory *) - (res == NULL ? fi->first_resource : res->children), - (res == NULL ? 0 : res->level+1), - count); - } else { - return (res == NULL - ? list_ne_type_resources(fi, count) - : list_ne_name_resources(fi, res, count)); - } -} - -/* read_library: - * Read header and get resource directory offset in a Windows library - * (AKA module). - * - */ -bool Win32ResExtractor::read_library(WinLibrary *fi) { - /* check for DOS header signature `MZ' */ - RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic); - if (MZ_HEADER(fi->memory)->magic == IMAGE_DOS_SIGNATURE) { - DOSImageHeader *mz_header = MZ_HEADER(fi->memory); - - RETURN_IF_BAD_POINTER(false, mz_header->lfanew); - if (mz_header->lfanew < sizeof(DOSImageHeader)) { - error("%s: not a Windows library", fi->file->name()); - return false; - } - } - - /* check for OS2 (Win16) header signature `NE' */ - RETURN_IF_BAD_POINTER(false, NE_HEADER(fi->memory)->magic); - if (NE_HEADER(fi->memory)->magic == IMAGE_OS2_SIGNATURE) { - OS2ImageHeader *header = NE_HEADER(fi->memory); - - RETURN_IF_BAD_POINTER(false, header->rsrctab); - RETURN_IF_BAD_POINTER(false, header->restab); - if (header->rsrctab >= header->restab) { - error("%s: no resource directory found", fi->file->name()); - return false; - } - - fi->is_PE_binary = false; - fi->first_resource = (byte *) NE_HEADER(fi->memory) - + header->rsrctab + sizeof(uint16); - RETURN_IF_BAD_POINTER(false, *(Win16NETypeInfo *) fi->first_resource); - - return true; - } - - /* check for NT header signature `PE' */ - RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature); - if (PE_HEADER(fi->memory)->signature == IMAGE_NT_SIGNATURE) { - Win32ImageSectionHeader *pe_sec; - Win32ImageDataDirectory *dir; - Win32ImageNTHeaders *pe_header; - int d; - - /* allocate new memory */ - fi->total_size = calc_vma_size(fi); - if (fi->total_size == 0) { - /* calc_vma_size has reported error */ - return false; - } - fi->memory = (byte *)realloc(fi->memory, fi->total_size); - - /* relocate memory, start from last section */ - pe_header = PE_HEADER(fi->memory); - RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections); - - /* we don't need to do OFFSET checking for the sections. - * calc_vma_size has already done that */ - for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) { - pe_sec = PE_SECTIONS(fi->memory) + d; - - if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) - continue; - - //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size) - - RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data); - RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); - if (pe_sec->virtual_address != pe_sec->pointer_to_raw_data) { - memmove(fi->memory + pe_sec->virtual_address, - fi->memory + pe_sec->pointer_to_raw_data, - pe_sec->size_of_raw_data); - } - } - - /* find resource directory */ - RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); - dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE; - if (dir->size == 0) { - error("%s: file contains no resources", fi->file->name()); - return false; - } - - fi->first_resource = fi->memory + dir->virtual_address; - fi->is_PE_binary = true; - return true; - } - - /* other (unknown) header signature was found */ - error("%s: not a Windows library", fi->file->name()); - return false; -} - -/* calc_vma_size: - * Calculate the total amount of memory needed for a 32-bit Windows - * module. Returns -1 if file was too small. - */ -int Win32ResExtractor::calc_vma_size(WinLibrary *fi) { - Win32ImageSectionHeader *seg; - int c, segcount, size; - - size = 0; - RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections); - segcount = PE_HEADER(fi->memory)->file_header.number_of_sections; - - /* If there are no segments, just process file like it is. - * This is (probably) not the right thing to do, but problems - * will be delt with later anyway. - */ - if (segcount == 0) - return fi->total_size; - - seg = PE_SECTIONS(fi->memory); - RETURN_IF_BAD_POINTER(-1, *seg); - for (c = 0 ; c < segcount ; c++) { - RETURN_IF_BAD_POINTER(0, *seg); - - size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data); - /* I have no idea what misc.virtual_size is for... */ - size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size); - seg++; - } - - return size; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) { - int c, rescnt; - WinResource *return_wr; - - wr = list_resources(fi, wr, &rescnt); - if (wr == NULL) - return NULL; - - for (c = 0 ; c < rescnt ; c++) { - if (compare_resource_id(&wr[c], id)) { - /* duplicate WinResource and return it */ - return_wr = (WinResource *)malloc(sizeof(WinResource)); - memcpy(return_wr, &wr[c], sizeof(WinResource)); - - /* free old WinResource */ - free(wr); - return return_wr; - } - } - - return NULL; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) { - WinResource *wr; - - *level = 0; - if (type == NULL) - return NULL; - wr = find_with_resource_array(fi, NULL, type); - if (wr == NULL || !wr->is_directory) - return wr; - - *level = 1; - if (name == NULL) - return wr; - wr = find_with_resource_array(fi, wr, name); - if (wr == NULL || !wr->is_directory) - return wr; - - *level = 2; - if (language == NULL) - return wr; - wr = find_with_resource_array(fi, wr, language); - return wr; -} - -#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2) - - -int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) { - Win32CursorIconFileDir dir; - Win32CursorIconFileDirEntry *entries = NULL; - uint32 offset; - uint32 c, d; - int completed; - int matched = 0; - MemoryReadStream *in = new MemoryReadStream(data, datasize); - - if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry))) - goto cleanup; - fix_win32_cursor_icon_file_dir_endian(&dir); - - if (dir.reserved != 0) { - error("not an icon or cursor file (reserved non-zero)"); - goto cleanup; - } - if (dir.type != 1 && dir.type != 2) { - error("not an icon or cursor file (wrong type)"); - goto cleanup; - } - - entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry)); - for (c = 0; c < dir.count; c++) { - if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry))) - goto cleanup; - fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]); - if (entries[c].reserved != 0) - error("reserved is not zero"); - } - - offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry)); - - for (completed = 0; completed < dir.count; ) { - uint32 min_offset = 0x7fffffff; - int previous = completed; - - for (c = 0; c < dir.count; c++) { - if (entries[c].dib_offset == offset) { - Win32BitmapInfoHeader bitmap; - Win32RGBQuad *palette = NULL; - uint32 palette_count = 0; - uint32 image_size, mask_size; - uint32 width, height; - byte *image_data = NULL, *mask_data = NULL; - byte *row = NULL; - - if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader))) - goto local_cleanup; - - fix_win32_bitmap_info_header_endian(&bitmap); - if (bitmap.size < sizeof(Win32BitmapInfoHeader)) { - error("bitmap header is too short"); - goto local_cleanup; - } - if (bitmap.compression != 0) { - error("compressed image data not supported"); - goto local_cleanup; - } - if (bitmap.x_pels_per_meter != 0) - error("x_pels_per_meter field in bitmap should be zero"); - if (bitmap.y_pels_per_meter != 0) - error("y_pels_per_meter field in bitmap should be zero"); - if (bitmap.clr_important != 0) - error("clr_important field in bitmap should be zero"); - if (bitmap.planes != 1) - error("planes field in bitmap should be one"); - if (bitmap.size != sizeof(Win32BitmapInfoHeader)) { - uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader); - error("skipping %d bytes of extended bitmap header", skip); - in->seek(skip, SEEK_CUR); - } - offset += bitmap.size; - - if (bitmap.clr_used != 0 || bitmap.bit_count < 24) { - palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count); - palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count); - if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count)) - goto local_cleanup; - offset += sizeof(Win32RGBQuad) * palette_count; - } - - width = bitmap.width; - height = ABS(bitmap.height)/2; - - image_size = height * ROW_BYTES(width * bitmap.bit_count); - mask_size = height * ROW_BYTES(width); - - if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad)) - debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)", - entries[c].dib_size, - bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad) - ); - - image_data = (byte *)malloc(image_size); - if (!in->read(image_data, image_size)) - goto local_cleanup; - - mask_data = (byte *)malloc(mask_size); - if (!in->read(mask_data, mask_size)) - goto local_cleanup; - - offset += image_size; - offset += mask_size; - completed++; - matched++; - - *hotspot_x = entries[c].hotspot_x; - *hotspot_y = entries[c].hotspot_y; - *w = width; - *h = height; - *keycolor = 0; - *cursor = (byte *)malloc(width * height); - - row = (byte *)malloc(width * 4); - - for (d = 0; d < height; d++) { - uint32 x; - uint32 y = (bitmap.height < 0 ? d : height - d - 1); - uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count; - //uint32 mmod = y * (mask_size / height) * 8; - - for (x = 0; x < width; x++) { - - uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count); - - // FIXME?: This works only with b/w cursors and white index may be - // different. But now it's enough. - if (color) { - cursor[0][width * d + x] = 15; // white in SCUMM - } else { - cursor[0][width * d + x] = 255; // transparent - } - /* - - if (bitmap.bit_count <= 16) { - if (color >= palette_count) { - error("color out of range in image data"); - goto local_cleanup; - } - row[4*x+0] = palette[color].red; - row[4*x+1] = palette[color].green; - row[4*x+2] = palette[color].blue; - - } else { - row[4*x+0] = (color >> 16) & 0xFF; - row[4*x+1] = (color >> 8) & 0xFF; - row[4*x+2] = (color >> 0) & 0xFF; - } - if (bitmap.bit_count == 32) - row[4*x+3] = (color >> 24) & 0xFF; - else - row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF; - */ - } - - } - - if (row != NULL) - free(row); - if (palette != NULL) - free(palette); - if (image_data != NULL) { - free(image_data); - free(mask_data); - } - continue; - - local_cleanup: - - if (row != NULL) - free(row); - if (palette != NULL) - free(palette); - if (image_data != NULL) { - free(image_data); - free(mask_data); - } - goto cleanup; - } else { - if (entries[c].dib_offset > offset) - min_offset = MIN(min_offset, entries[c].dib_offset); - } - } - - if (previous == completed) { - if (min_offset < offset) { - error("offset of bitmap header incorrect (too low)"); - goto cleanup; - } - debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset); - in->seek(min_offset - offset, SEEK_CUR); - offset = min_offset; - } - } - - free(entries); - return matched; - -cleanup: - - free(entries); - return -1; -} - -uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) { - switch (size) { - case 1: - return (data[ofs/8] >> (7 - ofs%8)) & 1; - case 2: - return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3; - case 4: - return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15; - case 8: - return data[ofs]; - case 16: - return data[2*ofs] | data[2*ofs+1] << 8; - case 24: - return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16; - case 32: - return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24; - } - - return 0; -} - -#define LE16(x) ((x) = TO_LE_16(x)) -#define LE32(x) ((x) = TO_LE_32(x)) - -void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) { - LE16(obj->reserved); - LE16(obj->type); - LE16(obj->count); -} - -void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) { - LE32(obj->size); - LE32(obj->width); - LE32(obj->height); - LE16(obj->planes); - LE16(obj->bit_count); - LE32(obj->compression); - LE32(obj->size_image); - LE32(obj->x_pels_per_meter); - LE32(obj->y_pels_per_meter); - LE32(obj->clr_used); - LE32(obj->clr_important); -} - -void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) { - LE16(obj->hotspot_x); - LE16(obj->hotspot_y); - LE32(obj->dib_size); - LE32(obj->dib_offset); -} - -void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) { - LE32(obj->misc.physical_address); - LE32(obj->virtual_address); - LE32(obj->size_of_raw_data); - LE32(obj->pointer_to_raw_data); - LE32(obj->pointer_to_relocations); - LE32(obj->pointer_to_linenumbers); - LE16(obj->number_of_relocations); - LE16(obj->number_of_linenumbers); - LE32(obj->characteristics); -} - -void Win32ResExtractor::fix_os2_image_header_endian(OS2ImageHeader *obj) { - LE16(obj->magic); - LE16(obj->enttab); - LE16(obj->cbenttab); - LE32(obj->crc); - LE16(obj->flags); - LE16(obj->autodata); - LE16(obj->heap); - LE16(obj->stack); - LE32(obj->csip); - LE32(obj->sssp); - LE16(obj->cseg); - LE16(obj->cmod); - LE16(obj->cbnrestab); - LE16(obj->segtab); - LE16(obj->rsrctab); - LE16(obj->restab); - LE16(obj->modtab); - LE16(obj->imptab); - LE32(obj->nrestab); - LE16(obj->cmovent); - LE16(obj->align); - LE16(obj->cres); - LE16(obj->fastload_offset); - LE16(obj->fastload_length); - LE16(obj->swaparea); - LE16(obj->expver); -} - -/* fix_win32_image_header_endian: - * NOTE: This assumes that the optional header is always available. - */ -void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) { - LE32(obj->signature); - LE16(obj->file_header.machine); - LE16(obj->file_header.number_of_sections); - LE32(obj->file_header.time_date_stamp); - LE32(obj->file_header.pointer_to_symbol_table); - LE32(obj->file_header.number_of_symbols); - LE16(obj->file_header.size_of_optional_header); - LE16(obj->file_header.characteristics); - LE16(obj->optional_header.magic); - LE32(obj->optional_header.size_of_code); - LE32(obj->optional_header.size_of_initialized_data); - LE32(obj->optional_header.size_of_uninitialized_data); - LE32(obj->optional_header.address_of_entry_point); - LE32(obj->optional_header.base_of_code); - LE32(obj->optional_header.base_of_data); - LE32(obj->optional_header.image_base); - LE32(obj->optional_header.section_alignment); - LE32(obj->optional_header.file_alignment); - LE16(obj->optional_header.major_operating_system_version); - LE16(obj->optional_header.minor_operating_system_version); - LE16(obj->optional_header.major_image_version); - LE16(obj->optional_header.minor_image_version); - LE16(obj->optional_header.major_subsystem_version); - LE16(obj->optional_header.minor_subsystem_version); - LE32(obj->optional_header.win32_version_value); - LE32(obj->optional_header.size_of_image); - LE32(obj->optional_header.size_of_headers); - LE32(obj->optional_header.checksum); - LE16(obj->optional_header.subsystem); - LE16(obj->optional_header.dll_characteristics); - LE32(obj->optional_header.size_of_stack_reserve); - LE32(obj->optional_header.size_of_stack_commit); - LE32(obj->optional_header.size_of_heap_reserve); - LE32(obj->optional_header.size_of_heap_commit); - LE32(obj->optional_header.loader_flags); - LE32(obj->optional_header.number_of_rva_and_sizes); -} - -void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) { - LE32(obj->virtual_address); - LE32(obj->size); -} - - -MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { - _resOffset = -1; -} - -int MacResExtractor::extractResource(int id, byte **buf) { - Common::File in; - int size; - - if (!_fileName[0]) // We are running for the first time - if (_vm->_substResFileNameIndex > 0) { - char buf1[128]; - - snprintf(buf1, 128, "%s.he3", _vm->getBaseName()); - _vm->generateSubstResFileName(buf1, _fileName, sizeof(buf1)); - - // Some programs write it as .bin. Try that too - if (!in.exists(_fileName)) { - strcpy(buf1, _fileName); - snprintf(_fileName, 128, "%s.bin", buf1); - - if (!in.exists(_fileName)) { - // And finally check if we have dumped resource fork - snprintf(_fileName, 128, "%s.rsrc", buf1); - if (!in.exists(_fileName)) { - error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", - buf1, buf1, buf1); - } - } - } - } - - in.open(_fileName); - if (!in.isOpen()) { - error("Cannot open file %s", _fileName); - } - - // we haven't calculated it - if (_resOffset == -1) { - if (!init(in)) - error("Resource fork is missing in file '%s'", _fileName); - in.close(); - in.open(_fileName); - } - - *buf = getResource(in, "crsr", 1000 + id, &size); - - in.close(); - - if (*buf == NULL) - error("There is no cursor ID #%d", 1000 + id); - - return size; -} - -#define MBI_INFOHDR 128 -#define MBI_ZERO1 0 -#define MBI_NAMELEN 1 -#define MBI_ZERO2 74 -#define MBI_ZERO3 82 -#define MBI_DFLEN 83 -#define MBI_RFLEN 87 -#define MAXNAMELEN 63 - -bool MacResExtractor::init(Common::File in) { - byte infoHeader[MBI_INFOHDR]; - int32 data_size, rsrc_size; - int32 data_size_pad, rsrc_size_pad; - int filelen; - - filelen = in.size(); - in.read(infoHeader, MBI_INFOHDR); - - // Maybe we have MacBinary? - if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 && - infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) { - - // Pull out fork lengths - data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN); - rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN); - - data_size_pad = (((data_size + 127) >> 7) << 7); - rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7); - - // Length check - int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; - - if (sumlen == filelen) - _resOffset = MBI_INFOHDR + data_size_pad; - } - - if (_resOffset == -1) // MacBinary check is failed - _resOffset = 0; // Maybe we have dumped fork? - - in.seek(_resOffset); - - _dataOffset = in.readUint32BE() + _resOffset; - _mapOffset = in.readUint32BE() + _resOffset; - _dataLength = in.readUint32BE(); - _mapLength = in.readUint32BE(); - - // do sanity check - if (_dataOffset >= filelen || _mapOffset >= filelen || - _dataLength + _mapLength > filelen) { - _resOffset = -1; - return false; - } - - debug(7, "got header: data %d [%d] map %d [%d]", - _dataOffset, _dataLength, _mapOffset, _mapLength); - - readMap(in); - - return true; -} - -byte *MacResExtractor::getResource(Common::File in, const char *typeID, int16 resID, int *size) { - int i; - int typeNum = -1; - int resNum = -1; - byte *buf; - int len; - - for (i = 0; i < _resMap.numTypes; i++) - if (strcmp(_resTypes[i].id, typeID) == 0) { - typeNum = i; - break; - } - - if (typeNum == -1) - return NULL; - - for (i = 0; i < _resTypes[typeNum].items; i++) - if (_resLists[typeNum][i].id == resID) { - resNum = i; - break; - } - - if (resNum == -1) - return NULL; - - in.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); - - len = in.readUint32BE(); - buf = (byte *)malloc(len); - - in.read(buf, len); - - *size = len; - - return buf; -} - -void MacResExtractor::readMap(Common::File in) { - int i, j, len; - - in.seek(_mapOffset + 22); - - _resMap.resAttr = in.readUint16BE(); - _resMap.typeOffset = in.readUint16BE(); - _resMap.nameOffset = in.readUint16BE(); - _resMap.numTypes = in.readUint16BE(); - _resMap.numTypes++; - - in.seek(_mapOffset + _resMap.typeOffset + 2); - _resTypes = new ResType[_resMap.numTypes]; - - for (i = 0; i < _resMap.numTypes; i++) { - in.read(_resTypes[i].id, 4); - _resTypes[i].id[4] = 0; - _resTypes[i].items = in.readUint16BE(); - _resTypes[i].offset = in.readUint16BE(); - _resTypes[i].items++; - } - - _resLists = new ResPtr[_resMap.numTypes]; - - for (i = 0; i < _resMap.numTypes; i++) { - _resLists[i] = new Resource[_resTypes[i].items]; - in.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); - - for (j = 0; j < _resTypes[i].items; j++) { - ResPtr resPtr = _resLists[i] + j; - - resPtr->id = in.readUint16BE(); - resPtr->nameOffset = in.readUint16BE(); - resPtr->dataOffset = in.readUint32BE(); - in.readUint32BE(); - resPtr->name = 0; - - resPtr->attr = resPtr->dataOffset >> 24; - resPtr->dataOffset &= 0xFFFFFF; - } - - for (j = 0; j < _resTypes[i].items; j++) { - if (_resLists[i][j].nameOffset != -1) { - in.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); - - len = in.readByte(); - _resLists[i][j].name = new byte[len + 1]; - _resLists[i][j].name[len] = 0; - in.read(_resLists[i][j].name, len); - } - } - } -} - -int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) { - Common::MemoryReadStream dis(data, datasize); - int i, b; - byte imageByte; - byte *iconData; - int numBytes; - int pixelsPerByte, bpp; - int ctSize; - byte bitmask; - int iconRowBytes, iconBounds[4]; - int ignored; - int iconDataSize; - - dis.readUint16BE(); // type - dis.readUint32BE(); // offset to pixel map - dis.readUint32BE(); // offset to pixel data - dis.readUint32BE(); // expanded cursor data - dis.readUint16BE(); // expanded data depth - dis.readUint32BE(); // reserved - - // Grab B/W icon data - *cursor = (byte *)malloc(16 * 16); - for (i = 0; i < 32; i++) { - imageByte = dis.readByte(); - for (b = 0; b < 8; b++) - cursor[0][i*8+b] = (byte)((imageByte & - (0x80 >> b)) > 0? 0x0F: 0x00); - } - - // Apply mask data - for (i = 0; i < 32; i++) { - imageByte = dis.readByte(); - for (b = 0; b < 8; b++) - if ((imageByte & (0x80 >> b)) == 0) - cursor[0][i*8+b] = 0xff; - } - - *hotspot_y = dis.readUint16BE(); - *hotspot_x = dis.readUint16BE(); - *w = *h = 16; - - // Use b/w cursor on backends which don't support cursor palettes - if (!_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette)) - return 1; - - dis.readUint32BE(); // reserved - dis.readUint32BE(); // cursorID - - // Color version of cursor - dis.readUint32BE(); // baseAddr - - // Keep only lowbyte for now - dis.readByte(); - iconRowBytes = dis.readByte(); - - if (!iconRowBytes) - return 1; - - iconBounds[0] = dis.readUint16BE(); - iconBounds[1] = dis.readUint16BE(); - iconBounds[2] = dis.readUint16BE(); - iconBounds[3] = dis.readUint16BE(); - - dis.readUint16BE(); // pmVersion - dis.readUint16BE(); // packType - dis.readUint32BE(); // packSize - - dis.readUint32BE(); // hRes - dis.readUint32BE(); // vRes - - dis.readUint16BE(); // pixelType - dis.readUint16BE(); // pixelSize - dis.readUint16BE(); // cmpCount - dis.readUint16BE(); // cmpSize - - dis.readUint32BE(); // planeByte - dis.readUint32BE(); // pmTable - dis.readUint32BE(); // reserved - - // Pixel data for cursor - iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]); - iconData = (byte *)malloc(iconDataSize); - dis.read(iconData, iconDataSize); - - // Color table - dis.readUint32BE(); // ctSeed - dis.readUint16BE(); // ctFlag - ctSize = dis.readUint16BE() + 1; - - *palette = (byte *)malloc(ctSize * 4); - - // Read just high byte of 16-bit color - for (int c = 0; c < ctSize; c++) { - // We just use indices 0..ctSize, so ignore color ID - dis.readUint16BE(); // colorID[c] - - palette[0][c * 4 + 0] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 1] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 2] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 3] = 0; - } - - *palSize = ctSize; - - numBytes = - (iconBounds[2] - iconBounds[0]) * - (iconBounds[3] - iconBounds[1]); - - pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes; - bpp = 8 / pixelsPerByte; - - // build a mask to make sure the pixels are properly shifted out - bitmask = 0; - for (int m = 0; m < bpp; m++) { - bitmask <<= 1; - bitmask |= 1; - } - - // Extract pixels from bytes - for (int j = 0; j < iconDataSize; j++) - for (b = 0; b < pixelsPerByte; b++) { - int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b); - - if (cursor[0][idx] != 0xff) // if mask is not there - cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask); - } - - free(iconData); - - assert(datasize - dis.pos() == 0); - - return 1; -} - - - -void ScummEngine_v70he::readRoomsOffsets() { - int num, i; - byte *ptr; - - debug(9, "readRoomOffsets()"); - - num = READ_LE_UINT16(_heV7RoomOffsets); - ptr = _heV7RoomOffsets + 2; - for (i = 0; i < num; i++) { - res.roomoffs[rtRoom][i] = READ_LE_UINT32(ptr); - ptr += 4; - } -} - -void ScummEngine_v70he::readGlobalObjects() { - int num = _fileHandle->readUint16LE(); - assert(num == _numGlobalObjects); - - _fileHandle->read(_objectStateTable, num); - _fileHandle->read(_objectOwnerTable, num); - _fileHandle->read(_objectRoomTable, num); - - _fileHandle->read(_classData, num * sizeof(uint32)); - -#if defined(SCUMM_BIG_ENDIAN) - // Correct the endianess if necessary - for (int i = 0; i != num; i++) - _classData[i] = FROM_LE_32(_classData[i]); -#endif -} - -void ScummEngine_v99he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v99he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numSprites = _fileHandle->readUint16LE(); - _numLocalScripts = _fileHandle->readUint16LE(); - _HEHeapSize = _fileHandle->readUint16LE(); - _numPalettes = _fileHandle->readUint16LE(); - _numUnk = _fileHandle->readUint16LE(); - _numTalkies = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - _numGlobalScripts = 2048; -} - -void ScummEngine_v90he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v90he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numSprites = _fileHandle->readUint16LE(); - _numLocalScripts = _fileHandle->readUint16LE(); - _HEHeapSize = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - if (_features & GF_HE_985) - _numGlobalScripts = 2048; - else - _numGlobalScripts = 200; -} - -void ScummEngine_v72he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v72he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numBitVariables = _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numVerbs = _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - _numGlobalScripts = 200; -} - -byte *ScummEngine_v72he::getStringAddress(int i) { - byte *addr = getResourceAddress(rtString, i); - if (addr == NULL) - return NULL; - return ((ScummEngine_v72he::ArrayHeader *)addr)->data; -} - -int ScummEngine_v72he::getSoundResourceSize(int id) { - const byte *ptr; - int offs, size; - - if (id > _numSounds) { - if (!_sound->getHEMusicDetails(id, offs, size)) { - debug(0, "getSoundResourceSize: musicID %d not found", id); - return 0; - } - } else { - ptr = getResourceAddress(rtSound, id); - if (!ptr) - return 0; - - if (READ_UINT32(ptr) == MKID('RIFF')) { - byte flags; - int rate; - - size = READ_BE_UINT32(ptr + 4); - Common::MemoryReadStream stream(ptr, size); - - if (!loadWAVFromStream(stream, size, rate, flags)) { - error("getSoundResourceSize: Not a valid WAV file"); - } - } else { - ptr += 8 + READ_BE_UINT32(ptr + 12); - if (READ_UINT32(ptr) == MKID('SBNG')) { - ptr += READ_BE_UINT32(ptr + 4); - } - - assert(READ_UINT32(ptr) == MKID('SDAT')); - size = READ_BE_UINT32(ptr + 4) - 8; - } - } - - return size; -} - -void ScummEngine_v80he::createSound(int snd1id, int snd2id) { - debug(0, "createSound: snd1id %d snd2id %d", snd1id, snd2id); - - byte *snd1Ptr, *snd2Ptr; - byte *sbng1Ptr, *sbng2Ptr; - byte *sdat1Ptr, *sdat2Ptr; - byte *src, *dst, *tmp; - int len, offs, size; - int sdat1size, sdat2size; - - if (snd2id == -1) { - _sndPtrOffs = 0; - _sndTmrOffs = 0; - return; - } - - if (snd1id != _curSndId) { - _curSndId = snd1id; - _sndPtrOffs = 0; - _sndTmrOffs = 0; - } - - snd1Ptr = getResourceAddress(rtSound, snd1id); - assert(snd1Ptr); - snd2Ptr = getResourceAddress(rtSound, snd2id); - assert(snd2Ptr); - - int i; - int chan = -1; - for (i = 0; i < ARRAYSIZE(_sound->_heChannel); i++) { - if (_sound->_heChannel[i].sound == snd1id) - chan = i; - } - - sbng1Ptr = heFindResource(MKID('SBNG'), snd1Ptr); - sbng2Ptr = heFindResource(MKID('SBNG'), snd2Ptr); - - if (sbng1Ptr != NULL && sbng2Ptr != NULL) { - if (chan != -1 && _sound->_heChannel[chan].codeOffs > 0) { - int curOffs = _sound->_heChannel[chan].codeOffs; - - src = snd1Ptr + curOffs; - dst = sbng1Ptr + 8; - size = READ_BE_UINT32(sbng1Ptr + 4); - len = sbng1Ptr - snd1Ptr + size - curOffs; - - byte *data = (byte *)malloc(len); - memcpy(data, src, len); - memcpy(dst, data, len); - free(data); - - dst = sbng1Ptr + 8; - while ((size = READ_LE_UINT16(dst)) != 0) - dst += size; - } else { - dst = sbng1Ptr + 8; - } - - _sound->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8; - - tmp = sbng2Ptr + 8; - while ((offs = READ_LE_UINT16(tmp)) != 0) { - tmp += offs; - } - - src = sbng2Ptr + 8; - len = tmp - sbng2Ptr - 6; - memcpy(dst, src, len); - - int32 time; - while ((size = READ_LE_UINT16(dst)) != 0) { - time = READ_LE_UINT32(dst + 2); - time += _sndTmrOffs; - WRITE_LE_UINT32(dst + 2, time); - dst += size; - } - } - - sdat1Ptr = heFindResource(MKID('SDAT'), snd1Ptr); - assert(sdat1Ptr); - sdat2Ptr = heFindResource(MKID('SDAT'), snd2Ptr); - assert(sdat2Ptr); - - sdat1size = READ_BE_UINT32(sdat1Ptr + 4) - 8 - _sndPtrOffs; - sdat2size = READ_BE_UINT32(sdat2Ptr + 4) - 8; - - debug(0, "SDAT size1 %d size2 %d", sdat1size, sdat2size); - if (sdat2size < sdat1size) { - src = sdat2Ptr + 8; - dst = sdat1Ptr + 8 + _sndPtrOffs; - len = sdat2size; - - memcpy(dst, src, len); - - _sndPtrOffs += sdat2size; - _sndTmrOffs += sdat2size; - } else { - src = sdat2Ptr + 8; - dst = sdat1Ptr + 8 + _sndPtrOffs; - len = sdat1size; - - memcpy(dst, src, len); - - if (sdat2size != sdat1size) { - src = sdat2Ptr + 8 + sdat1size; - dst = sdat1Ptr + 8; - len = sdat2size - sdat1size; - - memcpy(dst, src, len); - } - - _sndPtrOffs = sdat2size - sdat1size; - _sndTmrOffs += sdat2size; - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/he/resource_v7he.h b/engines/scumm/he/resource_v7he.h deleted file mode 100644 index 1496aa3d7f..0000000000 --- a/engines/scumm/he/resource_v7he.h +++ /dev/null @@ -1,556 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2004-2006 The ScummVM project - * - * Parts of code heavily based on: - * icoutils - A set of programs dealing with MS Windows icons and cursors. - * Copyright (C) 1998-2001 Oskar Liljeblad - * - * 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$ - * - */ - -#if !defined(RESOURCE_V7HE_H) && !defined(DISABLE_HE) -#define RESOURCE_V7HE_H - -namespace Scumm { - -#define WINRES_ID_MAXLEN (256) - -/* - * Definitions - */ - -#define ACTION_LIST 1 /* command: list resources */ -#define ACTION_EXTRACT 2 /* command: extract resources */ -#define CALLBACK_STOP 0 /* results of ResourceCallback */ -#define CALLBACK_CONTINUE 1 -#define CALLBACK_CONTINUE_RECURS 2 - -#define MZ_HEADER(x) ((DOSImageHeader *)(x)) -#define NE_HEADER(x) ((OS2ImageHeader *)PE_HEADER(x)) -#define NE_TYPEINFO_NEXT(x) ((Win16NETypeInfo *)((byte *)(x) + sizeof(Win16NETypeInfo) + \ - ((Win16NETypeInfo *)x)->count * sizeof(Win16NENameInfo))) -#define NE_RESOURCE_NAME_IS_NUMERIC (0x8000) - -#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x) - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -#define IMAGE_SIZEOF_SHORT_NAME 8 - -#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - -#define PE_HEADER(module) \ - ((Win32ImageNTHeaders*)((byte *)(module) + \ - (((DOSImageHeader*)(module))->lfanew))) - -#define PE_SECTIONS(module) \ - ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \ - PE_HEADER(module)->file_header.size_of_optional_header)) - -#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ -#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ -#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ -#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ -#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ -#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ - -#if !defined (WIN32) -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#endif - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 -#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ -#define IMAGE_DIRECTORY_ENTRY_TLS 9 -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 - -#if !defined (WIN32) -#define RT_CURSOR 1 -#define RT_BITMAP 2 -#define RT_ICON 3 -#define RT_MENU 4 -#define RT_DIALOG 5 -#define RT_STRING 6 -#define RT_FONTDIR 7 -#define RT_FONT 8 -#define RT_ACCELERATOR 9 -#define RT_RCDATA 10 -#define RT_MESSAGELIST 11 -#define RT_GROUP_CURSOR 12 -#define RT_GROUP_ICON 14 -#endif - -#define RETURN_IF_BAD_POINTER(r, x) \ - if (!check_offset(fi->memory, fi->total_size, fi->file->name(), &(x), sizeof(x))) \ - return (r); -#define RETURN_IF_BAD_OFFSET(r, x, s) \ - if (!check_offset(fi->memory, fi->total_size, fi->file->name(), x, s)) \ - return (r); - -class ScummEngine_v70he; - -class ResExtractor { -public: - ResExtractor(ScummEngine_v70he *scumm); - virtual ~ResExtractor(); - - void setCursor(int id); - - virtual int extractResource(int id, byte **buf) { return 0; }; - virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, - byte **palette, int *palSize) { return 0; }; - - enum { - MAX_CACHED_CURSORS = 10 - }; - - struct CachedCursor { - bool valid; - int id; - byte *bitmap; - int w, h; - int hotspot_x, hotspot_y; - uint32 last_used; - byte *palette; - int palSize; - }; - - ScummEngine_v70he *_vm; - - ResExtractor::CachedCursor *findCachedCursor(int id); - ResExtractor::CachedCursor *getCachedCursorSlot(); - - bool _arg_raw; - char _fileName[256]; - CachedCursor _cursorCache[MAX_CACHED_CURSORS]; - - typedef Common::MemoryReadStream MemoryReadStream; - -}; - -class Win32ResExtractor : public ResExtractor { - public: - Win32ResExtractor(ScummEngine_v70he *scumm); - ~Win32ResExtractor() {}; - int extractResource(int id, byte **data); - void setCursor(int id); - int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); - - private: - int extractResource_(const char *resType, char *resName, byte **data); -/* - * Structures - */ - -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - - struct WinLibrary { - Common::File *file; - byte *memory; - byte *first_resource; - bool is_PE_binary; - int total_size; - }; - - struct WinResource { - char id[256]; - void *this_; - void *children; - int level; - bool numeric_id; - bool is_directory; - }; - - - struct Win32IconResDir { - byte width; - byte height; - byte color_count; - byte reserved; - }; - - struct Win32CursorDir { - uint16 width; - uint16 height; - }; - - struct Win32CursorIconDirEntry { - union { - Win32IconResDir icon; - Win32CursorDir cursor; - } res_info; - uint16 plane_count; - uint16 bit_count; - uint32 bytes_in_res; - uint16 res_id; - }; - - struct Win32CursorIconDir { - uint16 reserved; - uint16 type; - uint16 count; - Win32CursorIconDirEntry entries[1] GCC_PACK; - }; - - struct Win32CursorIconFileDirEntry { - byte width; - byte height; - byte color_count; - byte reserved; - uint16 hotspot_x; - uint16 hotspot_y; - uint32 dib_size; - uint32 dib_offset; - }; - - struct Win32CursorIconFileDir { - uint16 reserved; - uint16 type; - uint16 count; - Win32CursorIconFileDirEntry entries[1]; - }; - - struct Win32BitmapInfoHeader { - uint32 size; - int32 width; - int32 height; - uint16 planes; - uint16 bit_count; - uint32 compression; - uint32 size_image; - int32 x_pels_per_meter; - int32 y_pels_per_meter; - uint32 clr_used; - uint32 clr_important; - }; - - struct Win32RGBQuad { - byte blue; - byte green; - byte red; - byte reserved; - }; - - struct Win32ImageResourceDirectoryEntry { - union { - struct { - #ifdef SCUMM_BIGENDIAN - unsigned name_is_string:1; - unsigned name_offset:31; - #else - unsigned name_offset:31; - unsigned name_is_string:1; - #endif - } s1; - uint32 name; - struct { - #ifdef SCUMM_BIG_ENDIAN - uint16 __pad; - uint16 id; - #else - uint16 id; - uint16 __pad; - #endif - } s2; - } u1; - union { - uint32 offset_to_data; - struct { - #ifdef SCUMM_BIG_ENDIAN - unsigned data_is_directory:1; - unsigned offset_to_directory:31; - #else - unsigned offset_to_directory:31; - unsigned data_is_directory:1; - #endif - } s; - } u2; - }; - - struct Win16NETypeInfo { - uint16 type_id; - uint16 count; - uint32 resloader; // FARPROC16 - smaller? uint16? - }; - - struct Win16NENameInfo { - uint16 offset; - uint16 length; - uint16 flags; - uint16 id; - uint16 handle; - uint16 usage; - }; - - struct OS2ImageHeader { - uint16 magic; - byte ver; - byte rev; - uint16 enttab; - uint16 cbenttab; - int32 crc; - uint16 flags; - uint16 autodata; - uint16 heap; - uint16 stack; - uint32 csip; - uint32 sssp; - uint16 cseg; - uint16 cmod; - uint16 cbnrestab; - uint16 segtab; - uint16 rsrctab; - uint16 restab; - uint16 modtab; - uint16 imptab; - uint32 nrestab; - uint16 cmovent; - uint16 align; - uint16 cres; - byte exetyp; - byte flagsothers; - uint16 fastload_offset; - uint16 fastload_length; - uint16 swaparea; - uint16 expver; - }; - - struct DOSImageHeader { - uint16 magic; - uint16 cblp; - uint16 cp; - uint16 crlc; - uint16 cparhdr; - uint16 minalloc; - uint16 maxalloc; - uint16 ss; - uint16 sp; - uint16 csum; - uint16 ip; - uint16 cs; - uint16 lfarlc; - uint16 ovno; - uint16 res[4]; - uint16 oemid; - uint16 oeminfo; - uint16 res2[10]; - uint32 lfanew; - }; - - struct Win32ImageFileHeader { - uint16 machine; - uint16 number_of_sections; - uint32 time_date_stamp; - uint32 pointer_to_symbol_table; - uint32 number_of_symbols; - uint16 size_of_optional_header; - uint16 characteristics; - }; - - struct Win32ImageDataDirectory { - uint32 virtual_address; - uint32 size; - }; - - struct Win32ImageOptionalHeader { - uint16 magic; - byte major_linker_version; - byte minor_linker_version; - uint32 size_of_code; - uint32 size_of_initialized_data; - uint32 size_of_uninitialized_data; - uint32 address_of_entry_point; - uint32 base_of_code; - uint32 base_of_data; - uint32 image_base; - uint32 section_alignment; - uint32 file_alignment; - uint16 major_operating_system_version; - uint16 minor_operating_system_version; - uint16 major_image_version; - uint16 minor_image_version; - uint16 major_subsystem_version; - uint16 minor_subsystem_version; - uint32 win32_version_value; - uint32 size_of_image; - uint32 size_of_headers; - uint32 checksum; - uint16 subsystem; - uint16 dll_characteristics; - uint32 size_of_stack_reserve; - uint32 size_of_stack_commit; - uint32 size_of_heap_reserve; - uint32 size_of_heap_commit; - uint32 loader_flags; - uint32 number_of_rva_and_sizes; - Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - }; - - struct Win32ImageNTHeaders { - uint32 signature; - Win32ImageFileHeader file_header; - Win32ImageOptionalHeader optional_header; - }; - - struct Win32ImageSectionHeader { - byte name[IMAGE_SIZEOF_SHORT_NAME]; - union { - uint32 physical_address; - uint32 virtual_size; - } misc; - uint32 virtual_address; - uint32 size_of_raw_data; - uint32 pointer_to_raw_data; - uint32 pointer_to_relocations; - uint32 pointer_to_linenumbers; - uint16 number_of_relocations; - uint16 number_of_linenumbers; - uint32 characteristics; - }; - - struct Win32ImageResourceDataEntry { - uint32 offset_to_data; - uint32 size; - uint32 code_page; - uint32 resource_handle; - }; - - struct Win32ImageResourceDirectory { - uint32 characteristics; - uint32 time_date_stamp; - uint16 major_version; - uint16 minor_version; - uint16 number_of_named_entries; - uint16 number_of_id_entries; - }; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - -/* - * Function Prototypes - */ - - WinResource *list_resources(WinLibrary *, WinResource *, int *); - bool read_library(WinLibrary *); - WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *); - byte *get_resource_entry(WinLibrary *, WinResource *, int *); - int do_resources(WinLibrary *, const char *, char *, char *, int, byte **); - bool compare_resource_id(WinResource *, const char *); - const char *res_type_string_to_id(const char *); - - const char *res_type_id_to_string(int); - char *get_destination_name(WinLibrary *, char *, char *, char *); - - byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool); - int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **); - byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool); - - bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32); - bool decode_ne_resource_id(WinLibrary *, WinResource *, uint16); - WinResource *list_ne_type_resources(WinLibrary *, int *); - WinResource *list_ne_name_resources(WinLibrary *, WinResource *, int *); - WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *); - int calc_vma_size(WinLibrary *); - int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, int, byte **); - char *get_resource_id_quoted(WinResource *); - WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *); - - bool check_offset(byte *, int, const char *, void *, int); - - uint32 simple_vec(byte *data, uint32 ofs, byte size); - - void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj); - void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj); - void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj); - void fix_win32_image_section_header(Win32ImageSectionHeader *obj); - void fix_os2_image_header_endian(OS2ImageHeader *obj); - void fix_win32_image_header_endian(Win32ImageNTHeaders *obj); - void fix_win32_image_data_directory(Win32ImageDataDirectory *obj); -}; - -class MacResExtractor : public ResExtractor { - -public: - MacResExtractor(ScummEngine_v70he *scumm); - ~MacResExtractor() { } - void setCursor(int id) ; - -private: - int extractResource(int id, byte **buf); - bool init(Common::File in); - void readMap(Common::File in); - byte *getResource(Common::File in, const char *typeID, int16 resID, int *size); - int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); - - struct ResMap { - int16 resAttr; - int16 typeOffset; - int16 nameOffset; - int16 numTypes; - }; - - struct ResType { - char id[5]; - int16 items; - int16 offset; - }; - - struct Resource { - int16 id; - int16 nameOffset; - byte attr; - int32 dataOffset; - byte *name; - }; - - typedef Resource *ResPtr; - -private: - int _resOffset; - int32 _dataOffset; - int32 _dataLength; - int32 _mapOffset; - int32 _mapLength; - ResMap _resMap; - ResType *_resTypes; - ResPtr *_resLists; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index c9bfeade67..414cbd62d3 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -30,7 +30,7 @@ #include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" +#include "scumm/he/resource_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" #include "scumm/he/sprite_he.h" diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp new file mode 100644 index 0000000000..9d7de59450 --- /dev/null +++ b/engines/scumm/he/script_v60he.cpp @@ -0,0 +1,1276 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 "common/stdafx.h" +#include "common/savefile.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/imuse.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/usage_bits.h" +#include "scumm/util.h" +#include "scumm/verbs.h" + +namespace Scumm { + +struct vsUnpackCtx { + uint8 size; + uint8 type; + uint8 b; + uint8 *ptr; +}; + +struct vsPackCtx { + int size; + uint8 buf[256]; +}; + +static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len); +static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b); +static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data); +static int virtScreenSavePack(byte *dst, byte *src, int len, int unk); + +// Compatibility notes: +// +// FBEAR (fbear, fbeardemo) +// transparency in akos.cpp +// negative size in file read/write + +#define OPCODE(x) _OPCODE(ScummEngine_v60he, x) + +void ScummEngine_v60he::setupOpcodes() { + static const OpcodeEntryv60he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o6_pushByteVar), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayRead), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedRead), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o6_invalid), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeByteVar), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayWrite), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedWrite), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarInc), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayInc), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarDec), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayDec), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o6_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o6_startObject), + OPCODE(o6_drawObject), + OPCODE(o6_drawObjectAt), + OPCODE(o6_invalid), + /* 64 */ + OPCODE(o6_invalid), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_stopMusic), + OPCODE(o6_freezeUnfreeze), + OPCODE(o6_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o60_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o6_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_startMusic), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o6_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o6_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_getVerbFromXY), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o6_resourceRoutines), + /* 9C */ + OPCODE(o60_roomOps), + OPCODE(o60_actorOps), + OPCODE(o6_verbOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o6_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o6_arrayOps), + OPCODE(o6_saveRestoreVerbs), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o6_invalid), + OPCODE(o6_isAnyOf), + OPCODE(o6_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o6_talkActor), + OPCODE(o6_talkEgo), + /* BC */ + OPCODE(o6_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o6_dim2dimArray), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o60_kernelGetFunctions), + OPCODE(o60_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o6_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o60_openFile), + OPCODE(o60_readFile), + /* DC */ + OPCODE(o60_writeFile), + OPCODE(o6_findAllObjects), + OPCODE(o60_deleteFile), + OPCODE(o60_rename), + /* E0 */ + OPCODE(o60_soundOps), + OPCODE(o6_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o6_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o60_seekFilePos), + OPCODE(o60_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F0 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F4 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* FC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesv60he = opcodes; +} + +void ScummEngine_v60he::executeOpcode(byte i) { + OpcodeProcv60he op = _opcodesv60he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v60he::getOpcodeDesc(byte i) { + return _opcodesv60he[i].desc; +} + +void ScummEngine_v60he::o60_setState() { + int state = pop(); + int obj = pop(); + + if (state & 0x8000) { + state &= 0x7FFF; + putState(obj, state); + if (_heversion >= 72) + removeObjectFromDrawQue(obj); + } else { + putState(obj, state); + markObjectRectAsDirty(obj); + if (_bgNeedsRedraw) + clearDrawObjectQueue(); + } +} + +void ScummEngine_v60he::o60_roomOps() { + int a, b, c, d, e; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 172: // SO_ROOM_SCROLL + b = pop(); + a = pop(); + if (a < (_screenWidth / 2)) + a = (_screenWidth / 2); + if (b < (_screenWidth / 2)) + b = (_screenWidth / 2); + if (a > _roomWidth - (_screenWidth / 2)) + a = _roomWidth - (_screenWidth / 2); + if (b > _roomWidth - (_screenWidth / 2)) + b = _roomWidth - (_screenWidth / 2); + VAR(VAR_CAMERA_MIN_X) = a; + VAR(VAR_CAMERA_MAX_X) = b; + break; + + case 174: // SO_ROOM_SCREEN + b = pop(); + a = pop(); + if (_heversion >= 71) + initScreens(a, _screenHeight); + else + initScreens(a, b); + break; + + case 175: // SO_ROOM_PALETTE + d = pop(); + c = pop(); + b = pop(); + a = pop(); + setPalColor(d, a, b, c); + break; + + case 176: // SO_ROOM_SHAKE_ON + setShake(1); + break; + + case 177: // SO_ROOM_SHAKE_OFF + setShake(0); + break; + + case 179: // SO_ROOM_INTENSITY + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, a, a, b, c); + break; + + case 180: // SO_ROOM_SAVEGAME + _saveTemporaryState = true; + _saveLoadSlot = pop(); + _saveLoadFlag = pop(); + break; + + case 181: // SO_ROOM_FADE + a = pop(); + if (_heversion >= 70) { + // Defaults to 1 but doesn't use fade effects + } else if (a) { + _switchRoomEffect = (byte)(a & 0xFF); + _switchRoomEffect2 = (byte)(a >> 8); + } else { + fadeIn(_newEffect); + } + break; + + case 182: // SO_RGB_ROOM_INTENSITY + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, b, c, d, e); + break; + + case 183: // SO_ROOM_SHADOW + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + if (_heversion == 60) + setupShadowPalette(a, b, c, d, e, 0, 256); + break; + + case 186: // SO_ROOM_TRANSFORM + d = pop(); + c = pop(); + b = pop(); + a = pop(); + palManipulateInit(a, b, c, d); + break; + + case 187: // SO_CYCLE_SPEED + b = pop(); + a = pop(); + checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)"); + _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0; + break; + + case 213: // SO_ROOM_NEW_PALETTE + a = pop(); + setPalette(a); + break; + case 220: + a = pop(); + b = pop(); + copyPalColor(a, b); + break; + case 221: + int len; + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + _saveLoadFlag = pop(); + _saveLoadSlot = 1; + _saveTemporaryState = true; + break; + case 234: // HE 7.2 + b = pop(); + a = pop(); + swapObjects(a, b); + break; + case 236: // HE 7.2 + b = pop(); + a = pop(); + setRoomPalette(a, b); + break; + default: + error("o60_roomOps: default case %d", subOp); + } +} + +void ScummEngine_v60he::swapObjects(int object1, int object2) { + int idx1 = -1, idx2 = -1; + + for (int i = 0; i < _numLocalObjects; i++) { + if (_objs[i].obj_nr == object1) + idx1 = i; + + if (_objs[i].obj_nr == object2) + idx2 = i; + } + + if (idx1 == -1 || idx2 == -1 || idx1 <= idx2) + return; + + stopObjectScript(object1); + stopObjectScript(object2); + + ObjectData tmpOd; + + memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd)); + memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd)); + memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd)); +} + +void ScummEngine_v60he::o60_actorOps() { + Actor *a; + int i, j, k; + int args[8]; + + byte subOp = fetchScriptByte(); + if (subOp == 197) { + _curActor = pop(); + return; + } + + a = derefActorSafe(_curActor, "o60_actorOps"); + if (!a) + return; + + switch (subOp) { + case 30: + // _heversion >= 70 + _actorClipOverride.bottom = pop(); + _actorClipOverride.right = pop(); + _actorClipOverride.top = pop(); + _actorClipOverride.left = pop(); + break; + case 76: // SO_COSTUME + a->setActorCostume(pop()); + break; + case 77: // SO_STEP_DIST + j = pop(); + i = pop(); + a->setActorWalkSpeed(i, j); + break; + case 78: // SO_SOUND + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; i++) + a->_sound[i] = args[i]; + break; + case 79: // SO_WALK_ANIMATION + a->_walkFrame = pop(); + break; + case 80: // SO_TALK_ANIMATION + a->_talkStopFrame = pop(); + a->_talkStartFrame = pop(); + break; + case 81: // SO_STAND_ANIMATION + a->_standFrame = pop(); + break; + case 82: // SO_ANIMATION + // dummy case in scumm6 + pop(); + pop(); + pop(); + break; + case 83: // SO_DEFAULT + a->initActor(0); + break; + case 84: // SO_ELEVATION + a->setElevation(pop()); + break; + case 85: // SO_ANIMATION_DEFAULT + a->_initFrame = 1; + a->_walkFrame = 2; + a->_standFrame = 3; + a->_talkStartFrame = 4; + a->_talkStopFrame = 5; + break; + case 86: // SO_PALETTE + j = pop(); + i = pop(); + checkRange(255, 0, i, "Illegal palette slot %d"); + a->remapActorPaletteColor(i, j); + a->_needRedraw = true; + break; + case 87: // SO_TALK_COLOR + a->_talkColor = pop(); + break; + case 88: // SO_ACTOR_NAME + loadPtrToResource(rtActorName, a->_number, NULL); + break; + case 89: // SO_INIT_ANIMATION + a->_initFrame = pop(); + break; + case 91: // SO_ACTOR_WIDTH + a->_width = pop(); + break; + case 92: // SO_SCALE + i = pop(); + a->setScale(i, i); + break; + case 93: // SO_NEVER_ZCLIP + a->_forceClip = 0; + break; + case 94: // SO_ALWAYS_ZCLIP + a->_forceClip = pop(); + break; + case 95: // SO_IGNORE_BOXES + a->_ignoreBoxes = 1; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 96: // SO_FOLLOW_BOXES + a->_ignoreBoxes = 0; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 97: // SO_ANIMATION_SPEED + a->setAnimSpeed(pop()); + break; + case 98: // SO_SHADOW + a->_shadowMode = pop(); + a->_needRedraw = true; + break; + case 99: // SO_TEXT_OFFSET + a->_talkPosY = pop(); + a->_talkPosX = pop(); + break; + case 156: // HE 7.2 + a->_charset = pop(); + break; + case 198: // SO_ACTOR_VARIABLE + i = pop(); + a->setAnimVar(pop(), i); + break; + case 215: // SO_ACTOR_IGNORE_TURNS_ON + a->_ignoreTurns = true; + break; + case 216: // SO_ACTOR_IGNORE_TURNS_OFF + a->_ignoreTurns = false; + break; + case 217: // SO_ACTOR_NEW + a->initActor(2); + break; + case 218: + a->drawActorToBackBuf(a->_pos.x, a->_pos.y); + break; + case 219: + a->_drawToBackBuf = false; + a->_needRedraw = true; + a->_needBgReset = true; + break; + case 225: + { + byte string[128]; + copyScriptString(string); + int slot = pop(); + + int len = resStrLen(string) + 1; + convertMessageToString(string, a->_heTalkQueue[slot].sentence, len); + + a->_heTalkQueue[slot].posX = a->_talkPosX; + a->_heTalkQueue[slot].posY = a->_talkPosY; + a->_heTalkQueue[slot].color = a->_talkColor; + break; + } + default: + error("o60_actorOps: default case %d", subOp); + } +} + +void ScummEngine_v60he::o60_kernelSetFunctions() { + int args[29]; + int num; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to restore images when decorating cake in + // Fatty Bear's Birthday Surprise + virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); + break; + case 3: + case 4: + case 5: + case 6: + case 8: + //Used before mini games in 3DO versions, seems safe to ignore. + break; + default: + error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num); + } +} + +void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) { + vsUnpackCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + VirtScreen &vs = virtscr[kMainVirtScreen]; + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx); + virtScreenLoadUnpack(&ctx, ah->data); + for (int j = y1; j <= y2; ++j) { + uint8 *p1 = vs.getPixels(x1, j - vs.topline); + uint8 *p2 = vs.getBackPixels(x1, j - vs.topline); + if (x2 >= x1) { + uint32 w = x2 - x1 + 1; + while (w--) { + uint8 decByte = virtScreenLoadUnpack(&ctx, 0); + *p1++ = decByte; + *p2++ = decByte; + } + } + } + markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1, USAGE_BIT_RESTORED); +} + +uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) { + uint8 decByte; + if (data != 0) { + ctx->type = 0; + ctx->ptr = data; + decByte = 0; + } else { + uint8 a; + if (ctx->type == 0) { + a = *(ctx->ptr)++; + if (a & 1) { + ctx->type = 1; + ctx->b = *(ctx->ptr)++; + } else { + ctx->type = 2; + } + ctx->size = a; + a = (a >> 1) + 1; + } else { + a = ctx->size; + } + if (ctx->type == 2) { + ctx->b = *(ctx->ptr)++; + } + ctx->size = a - 1; + if (ctx->size == 0) { + ctx->type = 0; + } + decByte = ctx->b; + } + return decByte; +} + + +void ScummEngine_v60he::o60_kernelGetFunctions() { + int args[29]; + ArrayHeader *ah; + getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to store images when decorating cake in + // Fatty Bear's Birthday Surprise + writeVar(0, 0); + ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); + virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); + push(readVar(0)); + break; + default: + error("o60_kernelGetFunctions: default case %d", args[0]); + } +} + +int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) { + int packedSize = 0; + VirtScreen &vs = virtscr[kMainVirtScreen]; + + for (int j = y1; j <= y2; ++j) { + uint8 *p = vs.getBackPixels(x1, j - vs.topline); + + int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0); + if (dst != 0) { + dst += size; + } + packedSize += size; + } + return packedSize; +} + +int virtScreenSavePack(byte *dst, byte *src, int len, int unk) { + vsPackCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + + uint8 prevByte, curByte; + + ctx.buf[0] = prevByte = *src++; + int flag = 0; + int iend = 1; + int ibeg = 0; + + for (--len; len != 0; --len, prevByte = curByte) { + bool pass = false; + + assert(iend < 0x100); + ctx.buf[iend] = curByte = *src++; + ++iend; + + if (flag == 0) { + if (iend > 0x80) { + virtScreenSavePackBuf(&ctx, dst, iend - 1); + ctx.buf[0] = curByte; + iend = 1; + ibeg = 0; + continue; + } + if (prevByte != curByte) { + ibeg = iend - 1; + continue; + } + if (iend - ibeg < 3) { + if (ibeg != 0) { + pass = true; + } else { + flag = 1; + } + } else { + if (ibeg > 0) { + virtScreenSavePackBuf(&ctx, dst, ibeg); + } + flag = 1; + } + } + if (flag == 1 || pass) { + if (prevByte != curByte || iend - ibeg > 0x80) { + virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte); + ctx.buf[0] = curByte; + iend = 1; + ibeg = 0; + flag = 0; + } + } + } + + if (flag == 0) { + virtScreenSavePackBuf(&ctx, dst, iend); + } else if (flag == 1) { + virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte); + } + return ctx.size; +} + +void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) { + if (dst) { + *dst++ = (len - 1) * 2; + } + ++ctx->size; + if (len > 0) { + ctx->size += len; + if (dst) { + memcpy(dst, ctx->buf, len); + dst += len; + } + } +} + +void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) { + if (dst) { + *dst++ = ((len - 1) * 2) | 1; + } + ++ctx->size; + if (dst) { + *dst++ = b; + } + ++ctx->size; +} + +void ScummEngine_v60he::o60_openFile() { + int mode, len, slot, l, r; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r = strlen((char*)filename); r != 0; r--) { + if (filename[r - 1] == '\\') + break; + } + + mode = pop(); + slot = -1; + for (l = 0; l < 17; l++) { + if (_hFileTable[l].isOpen() == false) { + slot = l; + break; + } + } + + if (slot != -1) { + switch(mode) { + case 1: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); + if (_hFileTable[slot].isOpen() == false) + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode); + break; + case 2: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); + break; + default: + error("o60_openFile(): wrong open file mode %d", mode); + } + + if (_hFileTable[slot].isOpen() == false) + slot = -1; + + } + push(slot); +} + +void ScummEngine_v60he::o60_closeFile() { + int slot = pop(); + if (slot != -1) + _hFileTable[slot].close(); +} + +void ScummEngine_v60he::o60_deleteFile() { + int len, r; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r = strlen((char*)filename); r != 0; r--) { + if (filename[r - 1] == '\\') + break; + } + + debug(1, "stub o60_deleteFile(\"%s\")", filename + r); +} + +void ScummEngine_v60he::o60_rename() { + int len, r1, r2; + byte filename[100],filename2[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r1 = strlen((char*)filename); r1 != 0; r1--) { + if (filename[r1 - 1] == '\\') + break; + } + + convertMessageToString(_scriptPointer, filename2, sizeof(filename2)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r2 = strlen((char*)filename2); r2 != 0; r2--) { + if (filename2[r2 - 1] == '\\') + break; + } + + debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2); +} + +int ScummEngine_v60he::readFileToArray(int slot, int32 size) { + if (size == 0) + size = _hFileTable[slot].size() - _hFileTable[slot].pos(); + + writeVar(0, 0); + + ArrayHeader *ah = defineArray(0, kByteArray, 0, size); + _hFileTable[slot].read(ah->data, size); + + return readVar(0); +} + +void ScummEngine_v60he::o60_readFile() { + int32 size = pop(); + int slot = pop(); + int val; + + // Fatty Bear uses positive values + if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) + size = -size; + + if (size == -2) { + val = _hFileTable[slot].readUint16LE(); + push(val); + } else if (size == -1) { + val = _hFileTable[slot].readByte(); + push(val); + } else { + val = readFileToArray(slot, size); + push(val); + } +} + +void ScummEngine_v60he::writeFileFromArray(int slot, int resID) { + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); + int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); + + _hFileTable[slot].write(ah->data, size); +} + +void ScummEngine_v60he::o60_writeFile() { + int32 size = pop(); + int16 resID = pop(); + int slot = pop(); + + // Fatty Bear uses positive values + if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) + size = -size; + + if (size == -2) { + _hFileTable[slot].writeUint16LE(resID); + } else if (size == -1) { + _hFileTable[slot].writeByte(resID); + } else { + writeFileFromArray(slot, resID); + } +} + +void ScummEngine_v60he::o60_soundOps() { + byte subOp = fetchScriptByte(); + int arg = pop(); + + switch (subOp) { + case 0xde: + _imuse->setMusicVolume(arg); + break; + case 0xdf: + // Used in fbear introduction + break; + case 0xe0: + // Fatty Bear's Birthday surprise uses this when playing the + // piano, but only when using one of the digitized instruments. + // See also o6_startSound(). + _sound->setOverrideFreq(arg); + break; + default: + error("o60_soundOps: default case 0x%x", subOp); + } +} + +void ScummEngine_v60he::localizeArray(int slot, byte scriptSlot) { + if (_heversion >= 80) + slot &= ~0x33539000; + + if (slot >= _numArray) + error("o60_localizeArrayToScript(%d): array slot out of range", slot); + + _arraySlot[slot] = scriptSlot; +} + +void ScummEngine_v60he::o60_localizeArrayToScript() { + int slot = pop(); + localizeArray(slot, _currentScript); +} + +void ScummEngine_v60he::o60_seekFilePos() { + int mode, offset, slot; + + mode = pop(); + offset = pop(); + slot = pop(); + + if (slot == -1) + return; + + switch (mode) { + case 1: + _hFileTable[slot].seek(offset, SEEK_SET); + break; + case 2: + _hFileTable[slot].seek(offset, SEEK_CUR); + break; + case 3: + _hFileTable[slot].seek(offset, SEEK_END); + break; + default: + error("o60_seekFilePos: default case %d", mode); + } +} + +void ScummEngine_v60he::o60_readFilePos() { + int slot = pop(); + + if (slot == -1) { + push(0); + return; + } + + push(_hFileTable[slot].pos()); +} + +void ScummEngine_v60he::o60_redimArray() { + int newX, newY; + newY = pop(); + newX = pop(); + + if (newY == 0) + SWAP(newX, newY); + + byte subOp = fetchScriptByte(); + switch (subOp) { + case 199: + redimArray(fetchScriptWord(), newX, newY, kIntArray); + break; + case 202: + redimArray(fetchScriptWord(), newX, newY, kByteArray); + break; + default: + error("o60_redimArray: default type %d", subOp); + } +} + +void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) { + // Used in mini game at Cosmic Dust Diner in puttmoon + int newSize, oldSize; + + if (readVar(arrayId) == 0) + error("redimArray: Reference to zeroed array pointer"); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); + + if (!ah) + error("redimArray: Invalid array (%d) reference", readVar(arrayId)); + + newSize = (type == kIntArray) ? 2 : 1; + oldSize = (ah->type == kIntArray) ? 2 : 1; + + newSize *= (newX + 1) * (newY + 1); + oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); + + if (newSize != oldSize) + error("redimArray: array %d redim mismatch", readVar(arrayId)); + + ah->type = TO_LE_16(type); + ah->dim1 = TO_LE_16(newY + 1); + ah->dim2 = TO_LE_16(newX + 1); +} + +void ScummEngine_v60he::decodeParseString(int m, int n) { + int i, colors; + int args[31]; + + byte b = fetchScriptByte(); + + switch (b) { + case 65: // SO_AT + _string[m].ypos = pop(); + _string[m].xpos = pop(); + _string[m].overhead = false; + break; + case 66: // SO_COLOR + _string[m].color = pop(); + break; + case 67: // SO_CLIPPED + _string[m].right = pop(); + break; + case 69: // SO_CENTER + _string[m].center = true; + _string[m].overhead = false; + break; + case 71: // SO_LEFT + _string[m].center = false; + _string[m].overhead = false; + break; + case 72: // SO_OVERHEAD + _string[m].overhead = true; + _string[m].no_talk_anim = false; + break; + case 74: // SO_MUMBLE + _string[m].no_talk_anim = true; + break; + case 75: // SO_TEXTSTRING + printString(m, _scriptPointer); + _scriptPointer += resStrLen(_scriptPointer) + 1; + break; + case 0xF9: + colors = pop(); + if (colors == 1) { + _string[m].color = pop(); + } else { + push(colors); + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + _string[m].color = _charsetColorMap[0]; + } + break; + case 0xFE: + _string[m].loadDefault(); + if (n) + _actorToPrintStrFor = pop(); + break; + case 0xFF: + _string[m].saveDefault(); + break; + default: + error("decodeParseString: default case 0x%x", b); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v6he.cpp b/engines/scumm/he/script_v6he.cpp deleted file mode 100644 index 9d7de59450..0000000000 --- a/engines/scumm/he/script_v6he.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * 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 "common/stdafx.h" -#include "common/savefile.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/imuse.h" -#include "scumm/he/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/usage_bits.h" -#include "scumm/util.h" -#include "scumm/verbs.h" - -namespace Scumm { - -struct vsUnpackCtx { - uint8 size; - uint8 type; - uint8 b; - uint8 *ptr; -}; - -struct vsPackCtx { - int size; - uint8 buf[256]; -}; - -static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len); -static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b); -static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data); -static int virtScreenSavePack(byte *dst, byte *src, int len, int unk); - -// Compatibility notes: -// -// FBEAR (fbear, fbeardemo) -// transparency in akos.cpp -// negative size in file read/write - -#define OPCODE(x) _OPCODE(ScummEngine_v60he, x) - -void ScummEngine_v60he::setupOpcodes() { - static const OpcodeEntryv60he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o6_pushByteVar), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayRead), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedRead), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o6_invalid), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeByteVar), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayWrite), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedWrite), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarInc), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayInc), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarDec), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayDec), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o6_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o6_startObject), - OPCODE(o6_drawObject), - OPCODE(o6_drawObjectAt), - OPCODE(o6_invalid), - /* 64 */ - OPCODE(o6_invalid), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_stopMusic), - OPCODE(o6_freezeUnfreeze), - OPCODE(o6_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o60_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o6_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_startMusic), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o6_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o6_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_getVerbFromXY), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o6_resourceRoutines), - /* 9C */ - OPCODE(o60_roomOps), - OPCODE(o60_actorOps), - OPCODE(o6_verbOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o6_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o6_arrayOps), - OPCODE(o6_saveRestoreVerbs), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o6_invalid), - OPCODE(o6_isAnyOf), - OPCODE(o6_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o6_talkActor), - OPCODE(o6_talkEgo), - /* BC */ - OPCODE(o6_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o6_dim2dimArray), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o60_kernelGetFunctions), - OPCODE(o60_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o6_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o60_openFile), - OPCODE(o60_readFile), - /* DC */ - OPCODE(o60_writeFile), - OPCODE(o6_findAllObjects), - OPCODE(o60_deleteFile), - OPCODE(o60_rename), - /* E0 */ - OPCODE(o60_soundOps), - OPCODE(o6_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o6_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o60_seekFilePos), - OPCODE(o60_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F0 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F4 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* FC */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesv60he = opcodes; -} - -void ScummEngine_v60he::executeOpcode(byte i) { - OpcodeProcv60he op = _opcodesv60he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v60he::getOpcodeDesc(byte i) { - return _opcodesv60he[i].desc; -} - -void ScummEngine_v60he::o60_setState() { - int state = pop(); - int obj = pop(); - - if (state & 0x8000) { - state &= 0x7FFF; - putState(obj, state); - if (_heversion >= 72) - removeObjectFromDrawQue(obj); - } else { - putState(obj, state); - markObjectRectAsDirty(obj); - if (_bgNeedsRedraw) - clearDrawObjectQueue(); - } -} - -void ScummEngine_v60he::o60_roomOps() { - int a, b, c, d, e; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 172: // SO_ROOM_SCROLL - b = pop(); - a = pop(); - if (a < (_screenWidth / 2)) - a = (_screenWidth / 2); - if (b < (_screenWidth / 2)) - b = (_screenWidth / 2); - if (a > _roomWidth - (_screenWidth / 2)) - a = _roomWidth - (_screenWidth / 2); - if (b > _roomWidth - (_screenWidth / 2)) - b = _roomWidth - (_screenWidth / 2); - VAR(VAR_CAMERA_MIN_X) = a; - VAR(VAR_CAMERA_MAX_X) = b; - break; - - case 174: // SO_ROOM_SCREEN - b = pop(); - a = pop(); - if (_heversion >= 71) - initScreens(a, _screenHeight); - else - initScreens(a, b); - break; - - case 175: // SO_ROOM_PALETTE - d = pop(); - c = pop(); - b = pop(); - a = pop(); - setPalColor(d, a, b, c); - break; - - case 176: // SO_ROOM_SHAKE_ON - setShake(1); - break; - - case 177: // SO_ROOM_SHAKE_OFF - setShake(0); - break; - - case 179: // SO_ROOM_INTENSITY - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, a, a, b, c); - break; - - case 180: // SO_ROOM_SAVEGAME - _saveTemporaryState = true; - _saveLoadSlot = pop(); - _saveLoadFlag = pop(); - break; - - case 181: // SO_ROOM_FADE - a = pop(); - if (_heversion >= 70) { - // Defaults to 1 but doesn't use fade effects - } else if (a) { - _switchRoomEffect = (byte)(a & 0xFF); - _switchRoomEffect2 = (byte)(a >> 8); - } else { - fadeIn(_newEffect); - } - break; - - case 182: // SO_RGB_ROOM_INTENSITY - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, b, c, d, e); - break; - - case 183: // SO_ROOM_SHADOW - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - if (_heversion == 60) - setupShadowPalette(a, b, c, d, e, 0, 256); - break; - - case 186: // SO_ROOM_TRANSFORM - d = pop(); - c = pop(); - b = pop(); - a = pop(); - palManipulateInit(a, b, c, d); - break; - - case 187: // SO_CYCLE_SPEED - b = pop(); - a = pop(); - checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)"); - _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0; - break; - - case 213: // SO_ROOM_NEW_PALETTE - a = pop(); - setPalette(a); - break; - case 220: - a = pop(); - b = pop(); - copyPalColor(a, b); - break; - case 221: - int len; - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - _saveLoadFlag = pop(); - _saveLoadSlot = 1; - _saveTemporaryState = true; - break; - case 234: // HE 7.2 - b = pop(); - a = pop(); - swapObjects(a, b); - break; - case 236: // HE 7.2 - b = pop(); - a = pop(); - setRoomPalette(a, b); - break; - default: - error("o60_roomOps: default case %d", subOp); - } -} - -void ScummEngine_v60he::swapObjects(int object1, int object2) { - int idx1 = -1, idx2 = -1; - - for (int i = 0; i < _numLocalObjects; i++) { - if (_objs[i].obj_nr == object1) - idx1 = i; - - if (_objs[i].obj_nr == object2) - idx2 = i; - } - - if (idx1 == -1 || idx2 == -1 || idx1 <= idx2) - return; - - stopObjectScript(object1); - stopObjectScript(object2); - - ObjectData tmpOd; - - memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd)); - memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd)); - memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd)); -} - -void ScummEngine_v60he::o60_actorOps() { - Actor *a; - int i, j, k; - int args[8]; - - byte subOp = fetchScriptByte(); - if (subOp == 197) { - _curActor = pop(); - return; - } - - a = derefActorSafe(_curActor, "o60_actorOps"); - if (!a) - return; - - switch (subOp) { - case 30: - // _heversion >= 70 - _actorClipOverride.bottom = pop(); - _actorClipOverride.right = pop(); - _actorClipOverride.top = pop(); - _actorClipOverride.left = pop(); - break; - case 76: // SO_COSTUME - a->setActorCostume(pop()); - break; - case 77: // SO_STEP_DIST - j = pop(); - i = pop(); - a->setActorWalkSpeed(i, j); - break; - case 78: // SO_SOUND - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; i++) - a->_sound[i] = args[i]; - break; - case 79: // SO_WALK_ANIMATION - a->_walkFrame = pop(); - break; - case 80: // SO_TALK_ANIMATION - a->_talkStopFrame = pop(); - a->_talkStartFrame = pop(); - break; - case 81: // SO_STAND_ANIMATION - a->_standFrame = pop(); - break; - case 82: // SO_ANIMATION - // dummy case in scumm6 - pop(); - pop(); - pop(); - break; - case 83: // SO_DEFAULT - a->initActor(0); - break; - case 84: // SO_ELEVATION - a->setElevation(pop()); - break; - case 85: // SO_ANIMATION_DEFAULT - a->_initFrame = 1; - a->_walkFrame = 2; - a->_standFrame = 3; - a->_talkStartFrame = 4; - a->_talkStopFrame = 5; - break; - case 86: // SO_PALETTE - j = pop(); - i = pop(); - checkRange(255, 0, i, "Illegal palette slot %d"); - a->remapActorPaletteColor(i, j); - a->_needRedraw = true; - break; - case 87: // SO_TALK_COLOR - a->_talkColor = pop(); - break; - case 88: // SO_ACTOR_NAME - loadPtrToResource(rtActorName, a->_number, NULL); - break; - case 89: // SO_INIT_ANIMATION - a->_initFrame = pop(); - break; - case 91: // SO_ACTOR_WIDTH - a->_width = pop(); - break; - case 92: // SO_SCALE - i = pop(); - a->setScale(i, i); - break; - case 93: // SO_NEVER_ZCLIP - a->_forceClip = 0; - break; - case 94: // SO_ALWAYS_ZCLIP - a->_forceClip = pop(); - break; - case 95: // SO_IGNORE_BOXES - a->_ignoreBoxes = 1; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 96: // SO_FOLLOW_BOXES - a->_ignoreBoxes = 0; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 97: // SO_ANIMATION_SPEED - a->setAnimSpeed(pop()); - break; - case 98: // SO_SHADOW - a->_shadowMode = pop(); - a->_needRedraw = true; - break; - case 99: // SO_TEXT_OFFSET - a->_talkPosY = pop(); - a->_talkPosX = pop(); - break; - case 156: // HE 7.2 - a->_charset = pop(); - break; - case 198: // SO_ACTOR_VARIABLE - i = pop(); - a->setAnimVar(pop(), i); - break; - case 215: // SO_ACTOR_IGNORE_TURNS_ON - a->_ignoreTurns = true; - break; - case 216: // SO_ACTOR_IGNORE_TURNS_OFF - a->_ignoreTurns = false; - break; - case 217: // SO_ACTOR_NEW - a->initActor(2); - break; - case 218: - a->drawActorToBackBuf(a->_pos.x, a->_pos.y); - break; - case 219: - a->_drawToBackBuf = false; - a->_needRedraw = true; - a->_needBgReset = true; - break; - case 225: - { - byte string[128]; - copyScriptString(string); - int slot = pop(); - - int len = resStrLen(string) + 1; - convertMessageToString(string, a->_heTalkQueue[slot].sentence, len); - - a->_heTalkQueue[slot].posX = a->_talkPosX; - a->_heTalkQueue[slot].posY = a->_talkPosY; - a->_heTalkQueue[slot].color = a->_talkColor; - break; - } - default: - error("o60_actorOps: default case %d", subOp); - } -} - -void ScummEngine_v60he::o60_kernelSetFunctions() { - int args[29]; - int num; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to restore images when decorating cake in - // Fatty Bear's Birthday Surprise - virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); - break; - case 3: - case 4: - case 5: - case 6: - case 8: - //Used before mini games in 3DO versions, seems safe to ignore. - break; - default: - error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num); - } -} - -void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) { - vsUnpackCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - VirtScreen &vs = virtscr[kMainVirtScreen]; - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx); - virtScreenLoadUnpack(&ctx, ah->data); - for (int j = y1; j <= y2; ++j) { - uint8 *p1 = vs.getPixels(x1, j - vs.topline); - uint8 *p2 = vs.getBackPixels(x1, j - vs.topline); - if (x2 >= x1) { - uint32 w = x2 - x1 + 1; - while (w--) { - uint8 decByte = virtScreenLoadUnpack(&ctx, 0); - *p1++ = decByte; - *p2++ = decByte; - } - } - } - markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1, USAGE_BIT_RESTORED); -} - -uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) { - uint8 decByte; - if (data != 0) { - ctx->type = 0; - ctx->ptr = data; - decByte = 0; - } else { - uint8 a; - if (ctx->type == 0) { - a = *(ctx->ptr)++; - if (a & 1) { - ctx->type = 1; - ctx->b = *(ctx->ptr)++; - } else { - ctx->type = 2; - } - ctx->size = a; - a = (a >> 1) + 1; - } else { - a = ctx->size; - } - if (ctx->type == 2) { - ctx->b = *(ctx->ptr)++; - } - ctx->size = a - 1; - if (ctx->size == 0) { - ctx->type = 0; - } - decByte = ctx->b; - } - return decByte; -} - - -void ScummEngine_v60he::o60_kernelGetFunctions() { - int args[29]; - ArrayHeader *ah; - getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to store images when decorating cake in - // Fatty Bear's Birthday Surprise - writeVar(0, 0); - ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); - virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); - push(readVar(0)); - break; - default: - error("o60_kernelGetFunctions: default case %d", args[0]); - } -} - -int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) { - int packedSize = 0; - VirtScreen &vs = virtscr[kMainVirtScreen]; - - for (int j = y1; j <= y2; ++j) { - uint8 *p = vs.getBackPixels(x1, j - vs.topline); - - int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0); - if (dst != 0) { - dst += size; - } - packedSize += size; - } - return packedSize; -} - -int virtScreenSavePack(byte *dst, byte *src, int len, int unk) { - vsPackCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - - uint8 prevByte, curByte; - - ctx.buf[0] = prevByte = *src++; - int flag = 0; - int iend = 1; - int ibeg = 0; - - for (--len; len != 0; --len, prevByte = curByte) { - bool pass = false; - - assert(iend < 0x100); - ctx.buf[iend] = curByte = *src++; - ++iend; - - if (flag == 0) { - if (iend > 0x80) { - virtScreenSavePackBuf(&ctx, dst, iend - 1); - ctx.buf[0] = curByte; - iend = 1; - ibeg = 0; - continue; - } - if (prevByte != curByte) { - ibeg = iend - 1; - continue; - } - if (iend - ibeg < 3) { - if (ibeg != 0) { - pass = true; - } else { - flag = 1; - } - } else { - if (ibeg > 0) { - virtScreenSavePackBuf(&ctx, dst, ibeg); - } - flag = 1; - } - } - if (flag == 1 || pass) { - if (prevByte != curByte || iend - ibeg > 0x80) { - virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte); - ctx.buf[0] = curByte; - iend = 1; - ibeg = 0; - flag = 0; - } - } - } - - if (flag == 0) { - virtScreenSavePackBuf(&ctx, dst, iend); - } else if (flag == 1) { - virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte); - } - return ctx.size; -} - -void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) { - if (dst) { - *dst++ = (len - 1) * 2; - } - ++ctx->size; - if (len > 0) { - ctx->size += len; - if (dst) { - memcpy(dst, ctx->buf, len); - dst += len; - } - } -} - -void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) { - if (dst) { - *dst++ = ((len - 1) * 2) | 1; - } - ++ctx->size; - if (dst) { - *dst++ = b; - } - ++ctx->size; -} - -void ScummEngine_v60he::o60_openFile() { - int mode, len, slot, l, r; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r = strlen((char*)filename); r != 0; r--) { - if (filename[r - 1] == '\\') - break; - } - - mode = pop(); - slot = -1; - for (l = 0; l < 17; l++) { - if (_hFileTable[l].isOpen() == false) { - slot = l; - break; - } - } - - if (slot != -1) { - switch(mode) { - case 1: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); - if (_hFileTable[slot].isOpen() == false) - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode); - break; - case 2: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); - break; - default: - error("o60_openFile(): wrong open file mode %d", mode); - } - - if (_hFileTable[slot].isOpen() == false) - slot = -1; - - } - push(slot); -} - -void ScummEngine_v60he::o60_closeFile() { - int slot = pop(); - if (slot != -1) - _hFileTable[slot].close(); -} - -void ScummEngine_v60he::o60_deleteFile() { - int len, r; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r = strlen((char*)filename); r != 0; r--) { - if (filename[r - 1] == '\\') - break; - } - - debug(1, "stub o60_deleteFile(\"%s\")", filename + r); -} - -void ScummEngine_v60he::o60_rename() { - int len, r1, r2; - byte filename[100],filename2[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r1 = strlen((char*)filename); r1 != 0; r1--) { - if (filename[r1 - 1] == '\\') - break; - } - - convertMessageToString(_scriptPointer, filename2, sizeof(filename2)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r2 = strlen((char*)filename2); r2 != 0; r2--) { - if (filename2[r2 - 1] == '\\') - break; - } - - debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2); -} - -int ScummEngine_v60he::readFileToArray(int slot, int32 size) { - if (size == 0) - size = _hFileTable[slot].size() - _hFileTable[slot].pos(); - - writeVar(0, 0); - - ArrayHeader *ah = defineArray(0, kByteArray, 0, size); - _hFileTable[slot].read(ah->data, size); - - return readVar(0); -} - -void ScummEngine_v60he::o60_readFile() { - int32 size = pop(); - int slot = pop(); - int val; - - // Fatty Bear uses positive values - if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) - size = -size; - - if (size == -2) { - val = _hFileTable[slot].readUint16LE(); - push(val); - } else if (size == -1) { - val = _hFileTable[slot].readByte(); - push(val); - } else { - val = readFileToArray(slot, size); - push(val); - } -} - -void ScummEngine_v60he::writeFileFromArray(int slot, int resID) { - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); - int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); - - _hFileTable[slot].write(ah->data, size); -} - -void ScummEngine_v60he::o60_writeFile() { - int32 size = pop(); - int16 resID = pop(); - int slot = pop(); - - // Fatty Bear uses positive values - if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) - size = -size; - - if (size == -2) { - _hFileTable[slot].writeUint16LE(resID); - } else if (size == -1) { - _hFileTable[slot].writeByte(resID); - } else { - writeFileFromArray(slot, resID); - } -} - -void ScummEngine_v60he::o60_soundOps() { - byte subOp = fetchScriptByte(); - int arg = pop(); - - switch (subOp) { - case 0xde: - _imuse->setMusicVolume(arg); - break; - case 0xdf: - // Used in fbear introduction - break; - case 0xe0: - // Fatty Bear's Birthday surprise uses this when playing the - // piano, but only when using one of the digitized instruments. - // See also o6_startSound(). - _sound->setOverrideFreq(arg); - break; - default: - error("o60_soundOps: default case 0x%x", subOp); - } -} - -void ScummEngine_v60he::localizeArray(int slot, byte scriptSlot) { - if (_heversion >= 80) - slot &= ~0x33539000; - - if (slot >= _numArray) - error("o60_localizeArrayToScript(%d): array slot out of range", slot); - - _arraySlot[slot] = scriptSlot; -} - -void ScummEngine_v60he::o60_localizeArrayToScript() { - int slot = pop(); - localizeArray(slot, _currentScript); -} - -void ScummEngine_v60he::o60_seekFilePos() { - int mode, offset, slot; - - mode = pop(); - offset = pop(); - slot = pop(); - - if (slot == -1) - return; - - switch (mode) { - case 1: - _hFileTable[slot].seek(offset, SEEK_SET); - break; - case 2: - _hFileTable[slot].seek(offset, SEEK_CUR); - break; - case 3: - _hFileTable[slot].seek(offset, SEEK_END); - break; - default: - error("o60_seekFilePos: default case %d", mode); - } -} - -void ScummEngine_v60he::o60_readFilePos() { - int slot = pop(); - - if (slot == -1) { - push(0); - return; - } - - push(_hFileTable[slot].pos()); -} - -void ScummEngine_v60he::o60_redimArray() { - int newX, newY; - newY = pop(); - newX = pop(); - - if (newY == 0) - SWAP(newX, newY); - - byte subOp = fetchScriptByte(); - switch (subOp) { - case 199: - redimArray(fetchScriptWord(), newX, newY, kIntArray); - break; - case 202: - redimArray(fetchScriptWord(), newX, newY, kByteArray); - break; - default: - error("o60_redimArray: default type %d", subOp); - } -} - -void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) { - // Used in mini game at Cosmic Dust Diner in puttmoon - int newSize, oldSize; - - if (readVar(arrayId) == 0) - error("redimArray: Reference to zeroed array pointer"); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); - - if (!ah) - error("redimArray: Invalid array (%d) reference", readVar(arrayId)); - - newSize = (type == kIntArray) ? 2 : 1; - oldSize = (ah->type == kIntArray) ? 2 : 1; - - newSize *= (newX + 1) * (newY + 1); - oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); - - if (newSize != oldSize) - error("redimArray: array %d redim mismatch", readVar(arrayId)); - - ah->type = TO_LE_16(type); - ah->dim1 = TO_LE_16(newY + 1); - ah->dim2 = TO_LE_16(newX + 1); -} - -void ScummEngine_v60he::decodeParseString(int m, int n) { - int i, colors; - int args[31]; - - byte b = fetchScriptByte(); - - switch (b) { - case 65: // SO_AT - _string[m].ypos = pop(); - _string[m].xpos = pop(); - _string[m].overhead = false; - break; - case 66: // SO_COLOR - _string[m].color = pop(); - break; - case 67: // SO_CLIPPED - _string[m].right = pop(); - break; - case 69: // SO_CENTER - _string[m].center = true; - _string[m].overhead = false; - break; - case 71: // SO_LEFT - _string[m].center = false; - _string[m].overhead = false; - break; - case 72: // SO_OVERHEAD - _string[m].overhead = true; - _string[m].no_talk_anim = false; - break; - case 74: // SO_MUMBLE - _string[m].no_talk_anim = true; - break; - case 75: // SO_TEXTSTRING - printString(m, _scriptPointer); - _scriptPointer += resStrLen(_scriptPointer) + 1; - break; - case 0xF9: - colors = pop(); - if (colors == 1) { - _string[m].color = pop(); - } else { - push(colors); - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - _string[m].color = _charsetColorMap[0]; - } - break; - case 0xFE: - _string[m].loadDefault(); - if (n) - _actorToPrintStrFor = pop(); - break; - case 0xFF: - _string[m].saveDefault(); - break; - default: - error("decodeParseString: default case 0x%x", b); - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp new file mode 100644 index 0000000000..e955f1267b --- /dev/null +++ b/engines/scumm/he/script_v70he.cpp @@ -0,0 +1,1153 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 "common/stdafx.h" + +#include "common/config-manager.h" +#include "common/system.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/verbs.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v70he, x) + +void ScummEngine_v70he::setupOpcodes() { + static const OpcodeEntryv70he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o6_pushByteVar), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayRead), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedRead), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o6_invalid), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeByteVar), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayWrite), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedWrite), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarInc), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayInc), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarDec), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayDec), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o6_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o6_startObject), + OPCODE(o6_drawObject), + OPCODE(o6_drawObjectAt), + OPCODE(o6_invalid), + /* 64 */ + OPCODE(o6_invalid), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_stopMusic), + OPCODE(o6_freezeUnfreeze), + OPCODE(o6_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o60_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o70_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_startMusic), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o70_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o70_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_getVerbFromXY), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o70_resourceRoutines), + /* 9C */ + OPCODE(o60_roomOps), + OPCODE(o60_actorOps), + OPCODE(o6_verbOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o6_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o6_arrayOps), + OPCODE(o6_saveRestoreVerbs), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o6_invalid), + OPCODE(o6_isAnyOf), + OPCODE(o70_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o6_talkActor), + OPCODE(o6_talkEgo), + /* BC */ + OPCODE(o6_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o6_dim2dimArray), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o60_kernelGetFunctions), + OPCODE(o70_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o6_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o60_openFile), + OPCODE(o60_readFile), + /* DC */ + OPCODE(o60_writeFile), + OPCODE(o6_findAllObjects), + OPCODE(o60_deleteFile), + OPCODE(o60_rename), + /* E0 */ + OPCODE(o60_soundOps), + OPCODE(o6_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o6_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o60_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o70_copyString), + OPCODE(o70_getStringWidth), + OPCODE(o70_getStringLen), + OPCODE(o70_appendString), + /* F0 */ + OPCODE(o70_concatString), + OPCODE(o70_compareString), + OPCODE(o70_isResourceLoaded), + OPCODE(o70_readINI), + /* F4 */ + OPCODE(o70_writeINI), + OPCODE(o70_getStringLenForWidth), + OPCODE(o70_getCharIndexInString), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o70_setFilePath), + OPCODE(o70_setSystemMessage), + OPCODE(o70_polygonOps), + /* FC */ + OPCODE(o70_polygonHit), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesv70he = opcodes; +} + +void ScummEngine_v70he::executeOpcode(byte i) { + OpcodeProcv70he op = _opcodesv70he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v70he::getOpcodeDesc(byte i) { + return _opcodesv70he[i].desc; +} + +int ScummEngine_v70he::getStringCharWidth(byte chr) { + int charset = _string[0]._default.charset; + + byte *ptr = getResourceAddress(rtCharset, charset); + assert(ptr); + ptr += 29; + + int spacing = 0; + + int offs = READ_LE_UINT32(ptr + chr * 4 + 4); + if (offs) { + spacing = ptr[offs] + (signed char)ptr[offs + 2]; + } + + return spacing; +} + +int ScummEngine_v70he::setupStringArray(int size) { + writeVar(0, 0); + defineArray(0, kStringArray, 0, size + 1); + writeArray(0, 0, 0, 0); + return readVar(0); +} + +void ScummEngine_v70he::appendSubstring(int dst, int src, int srcOffs, int len) { + int dstOffs, value; + int i = 0; + + if (len == -1) { + len = resStrLen(getStringAddress(src)); + srcOffs = 0; + } + + dstOffs = resStrLen(getStringAddress(dst)); + + len -= srcOffs; + len++; + + while (i < len) { + writeVar(0, src); + value = readArray(0, 0, srcOffs + i); + writeVar(0, dst); + writeArray(0, 0, dstOffs + i, value); + i++; + } + + writeArray(0, 0, dstOffs + i, 0); +} + +void ScummEngine_v70he::o70_startSound() { + int var, value; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 9: + _heSndFlags |= 4; + break; + case 23: + value = pop(); + var = pop(); + _heSndSoundId = pop(); + _sound->setSoundVar(_heSndSoundId, var, value); + break; + case 25: + value = pop(); + _heSndSoundId = pop(); + _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); + case 56: + _heSndFlags |= 16; + break; + case 164: + _heSndFlags |= 2; + break; + case 224: + _heSndSoundFreq = pop(); + break; + case 230: + _heSndChannel = pop(); + break; + case 231: + _heSndOffset = pop(); + break; + case 232: + _heSndSoundId = pop(); + _heSndOffset = 0; + _heSndSoundFreq = 11025; + _heSndChannel = VAR(VAR_SOUND_CHANNEL); + break; + case 245: + _heSndFlags |= 1; + break; + case 255: + _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); + _heSndFlags = 0; + break; + + default: + error("o70_startSound invalid case %d", subOp); + } +} + +void ScummEngine_v70he::o70_pickupObject() { + int obj, room; + + room = pop(); + obj = pop(); + if (room == 0) + room = getObjectRoom(obj); + + addObjectToInventory(obj, room); + putOwner(obj, VAR(VAR_EGO)); + if (_heversion <= 70) { + putClass(obj, kObjectClassUntouchable, 1); + putState(obj, 1); + markObjectRectAsDirty(obj); + clearDrawObjectQueue(); + } + runInventoryScript(obj); /* Difference */ +} + +void ScummEngine_v70he::o70_getActorRoom() { + int act = pop(); + + if (act < _numActors) { + Actor *a = derefActor(act, "o70_getActorRoom"); + push(a->_room); + } else + push(getObjectRoom(act)); +} + +void ScummEngine_v70he::o70_resourceRoutines() { + int objidx, resid; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 100: // SO_LOAD_SCRIPT + resid = pop(); + ensureResourceLoaded(rtScript, resid); + break; + case 101: // SO_LOAD_SOUND + resid = pop(); + ensureResourceLoaded(rtSound, resid); + break; + case 102: // SO_LOAD_COSTUME + resid = pop(); + ensureResourceLoaded(rtCostume, resid); + break; + case 103: // SO_LOAD_ROOM + resid = pop(); + ensureResourceLoaded(rtRoomImage, resid); + ensureResourceLoaded(rtRoom, resid); + break; + case 104: // SO_NUKE_SCRIPT + resid = pop(); + res.nukeResource(rtScript, resid); + break; + case 105: // SO_NUKE_SOUND + resid = pop(); + res.nukeResource(rtSound, resid); + break; + case 106: // SO_NUKE_COSTUME + resid = pop(); + res.nukeResource(rtCostume, resid); + break; + case 107: // SO_NUKE_ROOM + resid = pop(); + res.nukeResource(rtRoom, resid); + res.nukeResource(rtRoomImage, resid); + break; + case 108: // SO_LOCK_SCRIPT + resid = pop(); + if (resid >= _numGlobalScripts) + break; + res.lock(rtScript, resid); + break; + case 109: // SO_LOCK_SOUND + resid = pop(); + res.lock(rtSound, resid); + break; + case 110: // SO_LOCK_COSTUME + resid = pop(); + res.lock(rtCostume, resid); + break; + case 111: // SO_LOCK_ROOM + resid = pop(); + if (_heversion <= 71 && resid > 0x7F) + resid = _resourceMapper[resid & 0x7F]; + res.lock(rtRoom, resid); + res.lock(rtRoomImage, resid); + break; + case 112: // SO_UNLOCK_SCRIPT + resid = pop(); + if (resid >= _numGlobalScripts) + break; + res.unlock(rtScript, resid); + break; + case 113: // SO_UNLOCK_SOUND + resid = pop(); + res.unlock(rtSound, resid); + break; + case 114: // SO_UNLOCK_COSTUME + resid = pop(); + res.unlock(rtCostume, resid); + break; + case 115: // SO_UNLOCK_ROOM + resid = pop(); + if (_heversion <= 71 && resid > 0x7F) + resid = _resourceMapper[resid & 0x7F]; + res.unlock(rtRoom, resid); + res.unlock(rtRoomImage, resid); + break; + case 116: + break; + case 117: // SO_LOAD_CHARSET + resid = pop(); + loadCharset(resid); + break; + case 118: // SO_NUKE_CHARSET + resid = pop(); + nukeCharset(resid); + break; + case 119: // SO_LOAD_OBJECT + { + int obj = pop(); + int room = getObjectRoom(obj); + loadFlObject(obj, room); + break; + } + case 120: + resid = pop(); + if (resid >= _numGlobalScripts) + break; + //queueLoadResource(rtScript, resid); + break; + case 121: + resid = pop(); + //queueLoadResource(rtSound, resid); + break; + case 122: + resid = pop(); + //queueLoadResource(rtCostume, resid); + break; + case 123: + resid = pop(); + //queueLoadResource(rtRoomImage, resid); + break; + case 159: + resid = pop(); + res.unlock(rtImage, resid); + break; + case 192: + resid = pop(); + res.nukeResource(rtImage, resid); + break; + case 201: + resid = pop(); + ensureResourceLoaded(rtImage, resid); + break; + case 202: + resid = pop(); + res.lock(rtImage, resid); + break; + case 203: + resid = pop(); + //queueLoadResource(rtImage, resid); + break; + case 233: + resid = pop(); + objidx = getObjectIndex(resid); + if (objidx == -1) + break; + res.lock(rtFlObject, _objs[objidx].fl_object_index); + break; + case 235: + resid = pop(); + objidx = getObjectIndex(resid); + if (objidx == -1) + break; + res.unlock(rtFlObject, _objs[objidx].fl_object_index); + break; + case 239: + // Used in airport + break; + default: + error("o70_resourceRoutines: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_systemOps() { + byte *src, string[256]; + int id, len; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 158: + restart(); + break; + case 160: + // Confirm shutdown + shutDown(); + break; + case 244: + shutDown(); + break; + case 250: + id = pop(); + src = getStringAddress(id); + len = resStrLen(src) + 1; + memcpy(string, src, len); + debug(0, "Start executable (%s)", string); + break; + case 251: + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + debug(0, "Start executable (%s)", string); + break; + case 252: + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + debug(0, "Start game (%s)", string); + break; + case 253: + id = pop(); + src = getStringAddress(id); + len = resStrLen(src) + 1; + memcpy(string, src, len); + debug(0, "Start game (%s)", string); + break; + default: + error("o70_systemOps invalid case %d", subOp); + } +} + +void ScummEngine_v70he::o70_seekFilePos() { + int mode, offset, slot; + mode = pop(); + offset = pop(); + slot = pop(); + + if (slot == -1) + return; + + switch (mode) { + case 1: + _hFileTable[slot].seek(offset, SEEK_SET); + break; + case 2: + _hFileTable[slot].seek(offset, SEEK_CUR); + break; + case 3: + _hFileTable[slot].seek(offset, SEEK_END); + break; + default: + error("o70_seekFilePos: default case 0x%x", mode); + } +} + +void ScummEngine_v70he::o70_copyString() { + int dst, size; + int src = pop(); + + size = resStrLen(getStringAddress(src)) + 1; + dst = setupStringArray(size); + + appendSubstring(dst, src, -1, -1); + + push(dst); +} + +void ScummEngine_v70he::o70_getStringWidth() { + int array, pos, len; + int chr, width = 0; + + len = pop(); + pos = pop(); + array = pop(); + + if (len == -1) { + pos = 0; + len = resStrLen(getStringAddress(array)); + } + + writeVar(0, array); + while (pos <= len) { + chr = readArray(0, 0, pos); + if (chr == 0) + break; + width += getStringCharWidth(chr); + pos++; + } + + push(width); +} + +void ScummEngine_v70he::o70_kernelSetFunctions() { + int args[29]; + int num; + Actor *a; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to restore images when decorating cake in + // Fatty Bear's Birthday Surprise + virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); + break; + case 20: // HE72+ + a = derefActor(args[1], "o70_kernelSetFunctions: 20"); + ((ScummEngine_v71he *)this)->queueAuxBlock(a); + break; + case 21: + _skipDrawObject = 1; + break; + case 22: + _skipDrawObject = 0; + break; + case 23: + _charset->clearCharsetMask(); + _fullRedraw = true; + break; + case 24: + _skipProcessActors = 1; + redrawAllActors(); + break; + case 25: + _skipProcessActors = 0; + redrawAllActors(); + break; + case 26: + a = derefActor(args[1], "o70_kernelSetFunctions: 26"); + a->_auxBlock.r.left = 0; + a->_auxBlock.r.right = -1; + a->_auxBlock.r.top = 0; + a->_auxBlock.r.bottom = -2; + break; + case 30: + a = derefActor(args[1], "o70_kernelSetFunctions: 30"); + a->_clipOverride.bottom = args[2]; + break; + case 42: + _wiz->_rectOverrideEnabled = true; + _wiz->_rectOverride.left = args[1]; + _wiz->_rectOverride.top = args[2]; + _wiz->_rectOverride.right = args[3]; + _wiz->_rectOverride.bottom = args[4]; + break; + case 43: + _wiz->_rectOverrideEnabled = false; + break; + default: + error("o70_kernelSetFunctions: default case %d (param count %d)", args[0], num); + } +} + +void ScummEngine_v70he::o70_getStringLen() { + int id, len; + byte *addr; + + id = pop(); + + addr = getStringAddress(id); + if (!addr) + error("o70_getStringLen: Reference to zeroed array pointer (%d)", id); + + len = resStrLen(getStringAddress(id)); + push(len); +} + +void ScummEngine_v70he::o70_appendString() { + int dst, size; + + int len = pop(); + int srcOffs = pop(); + int src = pop(); + + size = len - srcOffs + 2; + dst = setupStringArray(size); + + appendSubstring(dst, src, srcOffs, len); + + push(dst); +} + +void ScummEngine_v70he::o70_concatString() { + int dst, size; + + int src2 = pop(); + int src1 = pop(); + + size = resStrLen(getStringAddress(src1)); + size += resStrLen(getStringAddress(src2)) + 1; + dst = setupStringArray(size); + + appendSubstring(dst, src1, 0, -1); + appendSubstring(dst, src2, 0, -1); + + push(dst); +} + +void ScummEngine_v70he::o70_compareString() { + int result; + + int array1 = pop(); + int array2 = pop(); + + byte *string1 = getStringAddress(array1); + if (!string1) + error("o70_compareString: Reference to zeroed array pointer (%d)", array1); + + byte *string2 = getStringAddress(array2); + if (!string2) + error("o70_compareString: Reference to zeroed array pointer (%d)", array2); + + while (*string1 == *string2) { + if (*string2 == 0) { + push(0); + return; + } + + string1++; + string2++; + } + + result = (*string1 > *string2) ? -1 : 1; + push(result); +} + +void ScummEngine_v70he::o70_isResourceLoaded() { + // Reports percentage of resource loaded by queue + int type; + + byte subOp = fetchScriptByte(); + /* int idx = */ pop(); + + switch (subOp) { + case 18: + type = rtImage; + break; + case 226: + type = rtRoom; + break; + case 227: + type = rtCostume; + break; + case 228: + type = rtSound; + break; + case 229: + type = rtScript; + break; + default: + error("o70_isResourceLoaded: default case %d", subOp); + } + + push(100); +} + +void ScummEngine_v70he::o70_readINI() { + byte option[256]; + ArrayHeader *ah; + const char *entry; + int len, type; + + convertMessageToString(_scriptPointer, option, sizeof(option)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + type = pop(); + switch (type) { + case 1: // number + if (!strcmp((char *)option, "NoPrinting")) { + push(1); + } else if (!strcmp((char *)option, "TextOn")) { + push(ConfMan.getBool("subtitles")); + } else { + push(ConfMan.getInt((char *)option)); + } + break; + case 2: // string + entry = (ConfMan.get((char *)option).c_str()); + + writeVar(0, 0); + len = resStrLen((const byte *)entry); + ah = defineArray(0, kStringArray, 0, len); + memcpy(ah->data, entry, len); + + push(readVar(0)); + break; + default: + error("o70_readINI: default type %d", type); + } + debug(1, "o70_readINI: Option %s", option); +} + +void ScummEngine_v70he::o70_writeINI() { + int type, value; + byte option[256], string[256]; + int len; + + type = pop(); + value = pop(); + + convertMessageToString(_scriptPointer, option, sizeof(option)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + switch (type) { + case 1: // number + ConfMan.set((char *)option, value); + debug(1, "o70_writeINI: Option %s Value %d", option, value); + break; + case 2: // string + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + ConfMan.set((char *)option, (char *)string); + debug(1, "o70_writeINI: Option %s String %s", option, string); + break; + default: + error("o70_writeINI: default type %d", type); + } +} + +void ScummEngine_v70he::o70_getStringLenForWidth() { + int chr, max; + int array, len, pos, width = 0; + + max = pop(); + pos = pop(); + array = pop(); + + len = resStrLen(getStringAddress(array)); + + writeVar(0, array); + while (pos <= len) { + chr = readArray(0, 0, pos); + width += getStringCharWidth(chr); + if (width >= max) { + push(pos); + return; + } + pos++; + } + + push(len); +} + +void ScummEngine_v70he::o70_getCharIndexInString() { + int array, end, len, pos, value; + + value = pop(); + end = pop(); + pos = pop(); + array = pop(); + + if (end >= 0) { + len = resStrLen(getStringAddress(array)); + if (len < end) + end = len; + } else { + end = 0; + } + + if (pos < 0) + pos = 0; + + writeVar(0, array); + if (end > pos) { + while (end >= pos) { + if (readArray(0, 0, pos) == value) { + push(pos); + return; + } + pos++; + } + } else { + while (end <= pos) { + if (readArray(0, 0, pos) == value) { + push(pos); + return; + } + pos--; + } + } + + push(-1); +} + +void ScummEngine_v70he::o70_setFilePath() { + int len; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + debug(1,"stub o70_setFilePath(%s)", filename); +} + +void ScummEngine_v70he::o70_setSystemMessage() { + int len; + byte name[255]; + + byte subOp = fetchScriptByte(); + + convertMessageToString(_scriptPointer, name, sizeof(name)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + switch (subOp) { + case 240: + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 241: // Set Version + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 242: + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 243: // Set Window Caption + _system->setWindowCaption((const char *)name); + break; + default: + error("o70_setSystemMessage: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_polygonOps() { + int vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; + int id, fromId, toId; + bool flag; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 68: // HE 100 + case 69: // HE 100 + case 246: + case 248: + vert4y = pop(); + vert4x = pop(); + vert3y = pop(); + vert3x = pop(); + vert2y = pop(); + vert2x = pop(); + vert1y = pop(); + vert1x = pop(); + flag = (subOp == 69 || subOp == 248); + id = pop(); + _wiz->polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); + break; + case 28: // HE 100 + case 247: + toId = pop(); + fromId = pop(); + _wiz->polygonErase(fromId, toId); + break; + default: + error("o70_polygonOps: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_polygonHit() { + int y = pop(); + int x = pop(); + push(_wiz->polygonHit(0, x, y)); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index b94cc06b40..a97ae843f1 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -32,7 +32,7 @@ #include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" +#include "scumm/he/resource_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" #include "scumm/util.h" diff --git a/engines/scumm/he/script_v7he.cpp b/engines/scumm/he/script_v7he.cpp deleted file mode 100644 index 400e7c0ad0..0000000000 --- a/engines/scumm/he/script_v7he.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * 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 "common/stdafx.h" - -#include "common/config-manager.h" -#include "common/system.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/he/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/verbs.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v70he, x) - -void ScummEngine_v70he::setupOpcodes() { - static const OpcodeEntryv70he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o6_pushByteVar), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayRead), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedRead), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o6_invalid), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeByteVar), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayWrite), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedWrite), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarInc), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayInc), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarDec), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayDec), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o6_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o6_startObject), - OPCODE(o6_drawObject), - OPCODE(o6_drawObjectAt), - OPCODE(o6_invalid), - /* 64 */ - OPCODE(o6_invalid), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_stopMusic), - OPCODE(o6_freezeUnfreeze), - OPCODE(o6_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o60_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o70_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_startMusic), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o70_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o70_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_getVerbFromXY), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o70_resourceRoutines), - /* 9C */ - OPCODE(o60_roomOps), - OPCODE(o60_actorOps), - OPCODE(o6_verbOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o6_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o6_arrayOps), - OPCODE(o6_saveRestoreVerbs), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o6_invalid), - OPCODE(o6_isAnyOf), - OPCODE(o70_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o6_talkActor), - OPCODE(o6_talkEgo), - /* BC */ - OPCODE(o6_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o6_dim2dimArray), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o60_kernelGetFunctions), - OPCODE(o70_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o6_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o60_openFile), - OPCODE(o60_readFile), - /* DC */ - OPCODE(o60_writeFile), - OPCODE(o6_findAllObjects), - OPCODE(o60_deleteFile), - OPCODE(o60_rename), - /* E0 */ - OPCODE(o60_soundOps), - OPCODE(o6_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o6_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o60_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o70_copyString), - OPCODE(o70_getStringWidth), - OPCODE(o70_getStringLen), - OPCODE(o70_appendString), - /* F0 */ - OPCODE(o70_concatString), - OPCODE(o70_compareString), - OPCODE(o70_isResourceLoaded), - OPCODE(o70_readINI), - /* F4 */ - OPCODE(o70_writeINI), - OPCODE(o70_getStringLenForWidth), - OPCODE(o70_getCharIndexInString), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o6_invalid), - OPCODE(o70_setFilePath), - OPCODE(o70_setSystemMessage), - OPCODE(o70_polygonOps), - /* FC */ - OPCODE(o70_polygonHit), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesv70he = opcodes; -} - -void ScummEngine_v70he::executeOpcode(byte i) { - OpcodeProcv70he op = _opcodesv70he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v70he::getOpcodeDesc(byte i) { - return _opcodesv70he[i].desc; -} - -int ScummEngine_v70he::getStringCharWidth(byte chr) { - int charset = _string[0]._default.charset; - - byte *ptr = getResourceAddress(rtCharset, charset); - assert(ptr); - ptr += 29; - - int spacing = 0; - - int offs = READ_LE_UINT32(ptr + chr * 4 + 4); - if (offs) { - spacing = ptr[offs] + (signed char)ptr[offs + 2]; - } - - return spacing; -} - -int ScummEngine_v70he::setupStringArray(int size) { - writeVar(0, 0); - defineArray(0, kStringArray, 0, size + 1); - writeArray(0, 0, 0, 0); - return readVar(0); -} - -void ScummEngine_v70he::appendSubstring(int dst, int src, int srcOffs, int len) { - int dstOffs, value; - int i = 0; - - if (len == -1) { - len = resStrLen(getStringAddress(src)); - srcOffs = 0; - } - - dstOffs = resStrLen(getStringAddress(dst)); - - len -= srcOffs; - len++; - - while (i < len) { - writeVar(0, src); - value = readArray(0, 0, srcOffs + i); - writeVar(0, dst); - writeArray(0, 0, dstOffs + i, value); - i++; - } - - writeArray(0, 0, dstOffs + i, 0); -} - -void ScummEngine_v70he::o70_startSound() { - int var, value; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 9: - _heSndFlags |= 4; - break; - case 23: - value = pop(); - var = pop(); - _heSndSoundId = pop(); - _sound->setSoundVar(_heSndSoundId, var, value); - break; - case 25: - value = pop(); - _heSndSoundId = pop(); - _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); - case 56: - _heSndFlags |= 16; - break; - case 164: - _heSndFlags |= 2; - break; - case 224: - _heSndSoundFreq = pop(); - break; - case 230: - _heSndChannel = pop(); - break; - case 231: - _heSndOffset = pop(); - break; - case 232: - _heSndSoundId = pop(); - _heSndOffset = 0; - _heSndSoundFreq = 11025; - _heSndChannel = VAR(VAR_SOUND_CHANNEL); - break; - case 245: - _heSndFlags |= 1; - break; - case 255: - _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); - _heSndFlags = 0; - break; - - default: - error("o70_startSound invalid case %d", subOp); - } -} - -void ScummEngine_v70he::o70_pickupObject() { - int obj, room; - - room = pop(); - obj = pop(); - if (room == 0) - room = getObjectRoom(obj); - - addObjectToInventory(obj, room); - putOwner(obj, VAR(VAR_EGO)); - if (_heversion <= 70) { - putClass(obj, kObjectClassUntouchable, 1); - putState(obj, 1); - markObjectRectAsDirty(obj); - clearDrawObjectQueue(); - } - runInventoryScript(obj); /* Difference */ -} - -void ScummEngine_v70he::o70_getActorRoom() { - int act = pop(); - - if (act < _numActors) { - Actor *a = derefActor(act, "o70_getActorRoom"); - push(a->_room); - } else - push(getObjectRoom(act)); -} - -void ScummEngine_v70he::o70_resourceRoutines() { - int objidx, resid; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 100: // SO_LOAD_SCRIPT - resid = pop(); - ensureResourceLoaded(rtScript, resid); - break; - case 101: // SO_LOAD_SOUND - resid = pop(); - ensureResourceLoaded(rtSound, resid); - break; - case 102: // SO_LOAD_COSTUME - resid = pop(); - ensureResourceLoaded(rtCostume, resid); - break; - case 103: // SO_LOAD_ROOM - resid = pop(); - ensureResourceLoaded(rtRoomImage, resid); - ensureResourceLoaded(rtRoom, resid); - break; - case 104: // SO_NUKE_SCRIPT - resid = pop(); - res.nukeResource(rtScript, resid); - break; - case 105: // SO_NUKE_SOUND - resid = pop(); - res.nukeResource(rtSound, resid); - break; - case 106: // SO_NUKE_COSTUME - resid = pop(); - res.nukeResource(rtCostume, resid); - break; - case 107: // SO_NUKE_ROOM - resid = pop(); - res.nukeResource(rtRoom, resid); - res.nukeResource(rtRoomImage, resid); - break; - case 108: // SO_LOCK_SCRIPT - resid = pop(); - if (resid >= _numGlobalScripts) - break; - res.lock(rtScript, resid); - break; - case 109: // SO_LOCK_SOUND - resid = pop(); - res.lock(rtSound, resid); - break; - case 110: // SO_LOCK_COSTUME - resid = pop(); - res.lock(rtCostume, resid); - break; - case 111: // SO_LOCK_ROOM - resid = pop(); - if (_heversion <= 71 && resid > 0x7F) - resid = _resourceMapper[resid & 0x7F]; - res.lock(rtRoom, resid); - res.lock(rtRoomImage, resid); - break; - case 112: // SO_UNLOCK_SCRIPT - resid = pop(); - if (resid >= _numGlobalScripts) - break; - res.unlock(rtScript, resid); - break; - case 113: // SO_UNLOCK_SOUND - resid = pop(); - res.unlock(rtSound, resid); - break; - case 114: // SO_UNLOCK_COSTUME - resid = pop(); - res.unlock(rtCostume, resid); - break; - case 115: // SO_UNLOCK_ROOM - resid = pop(); - if (_heversion <= 71 && resid > 0x7F) - resid = _resourceMapper[resid & 0x7F]; - res.unlock(rtRoom, resid); - res.unlock(rtRoomImage, resid); - break; - case 116: - break; - case 117: // SO_LOAD_CHARSET - resid = pop(); - loadCharset(resid); - break; - case 118: // SO_NUKE_CHARSET - resid = pop(); - nukeCharset(resid); - break; - case 119: // SO_LOAD_OBJECT - { - int obj = pop(); - int room = getObjectRoom(obj); - loadFlObject(obj, room); - break; - } - case 120: - resid = pop(); - if (resid >= _numGlobalScripts) - break; - //queueLoadResource(rtScript, resid); - break; - case 121: - resid = pop(); - //queueLoadResource(rtSound, resid); - break; - case 122: - resid = pop(); - //queueLoadResource(rtCostume, resid); - break; - case 123: - resid = pop(); - //queueLoadResource(rtRoomImage, resid); - break; - case 159: - resid = pop(); - res.unlock(rtImage, resid); - break; - case 192: - resid = pop(); - res.nukeResource(rtImage, resid); - break; - case 201: - resid = pop(); - ensureResourceLoaded(rtImage, resid); - break; - case 202: - resid = pop(); - res.lock(rtImage, resid); - break; - case 203: - resid = pop(); - //queueLoadResource(rtImage, resid); - break; - case 233: - resid = pop(); - objidx = getObjectIndex(resid); - if (objidx == -1) - break; - res.lock(rtFlObject, _objs[objidx].fl_object_index); - break; - case 235: - resid = pop(); - objidx = getObjectIndex(resid); - if (objidx == -1) - break; - res.unlock(rtFlObject, _objs[objidx].fl_object_index); - break; - case 239: - // Used in airport - break; - default: - error("o70_resourceRoutines: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_systemOps() { - byte *src, string[256]; - int id, len; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 158: - restart(); - break; - case 160: - // Confirm shutdown - shutDown(); - break; - case 244: - shutDown(); - break; - case 250: - id = pop(); - src = getStringAddress(id); - len = resStrLen(src) + 1; - memcpy(string, src, len); - debug(0, "Start executable (%s)", string); - break; - case 251: - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - debug(0, "Start executable (%s)", string); - break; - case 252: - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - debug(0, "Start game (%s)", string); - break; - case 253: - id = pop(); - src = getStringAddress(id); - len = resStrLen(src) + 1; - memcpy(string, src, len); - debug(0, "Start game (%s)", string); - break; - default: - error("o70_systemOps invalid case %d", subOp); - } -} - -void ScummEngine_v70he::o70_seekFilePos() { - int mode, offset, slot; - mode = pop(); - offset = pop(); - slot = pop(); - - if (slot == -1) - return; - - switch (mode) { - case 1: - _hFileTable[slot].seek(offset, SEEK_SET); - break; - case 2: - _hFileTable[slot].seek(offset, SEEK_CUR); - break; - case 3: - _hFileTable[slot].seek(offset, SEEK_END); - break; - default: - error("o70_seekFilePos: default case 0x%x", mode); - } -} - -void ScummEngine_v70he::o70_copyString() { - int dst, size; - int src = pop(); - - size = resStrLen(getStringAddress(src)) + 1; - dst = setupStringArray(size); - - appendSubstring(dst, src, -1, -1); - - push(dst); -} - -void ScummEngine_v70he::o70_getStringWidth() { - int array, pos, len; - int chr, width = 0; - - len = pop(); - pos = pop(); - array = pop(); - - if (len == -1) { - pos = 0; - len = resStrLen(getStringAddress(array)); - } - - writeVar(0, array); - while (pos <= len) { - chr = readArray(0, 0, pos); - if (chr == 0) - break; - width += getStringCharWidth(chr); - pos++; - } - - push(width); -} - -void ScummEngine_v70he::o70_kernelSetFunctions() { - int args[29]; - int num; - Actor *a; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to restore images when decorating cake in - // Fatty Bear's Birthday Surprise - virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); - break; - case 20: // HE72+ - a = derefActor(args[1], "o70_kernelSetFunctions: 20"); - ((ScummEngine_v71he *)this)->queueAuxBlock(a); - break; - case 21: - _skipDrawObject = 1; - break; - case 22: - _skipDrawObject = 0; - break; - case 23: - _charset->clearCharsetMask(); - _fullRedraw = true; - break; - case 24: - _skipProcessActors = 1; - redrawAllActors(); - break; - case 25: - _skipProcessActors = 0; - redrawAllActors(); - break; - case 26: - a = derefActor(args[1], "o70_kernelSetFunctions: 26"); - a->_auxBlock.r.left = 0; - a->_auxBlock.r.right = -1; - a->_auxBlock.r.top = 0; - a->_auxBlock.r.bottom = -2; - break; - case 30: - a = derefActor(args[1], "o70_kernelSetFunctions: 30"); - a->_clipOverride.bottom = args[2]; - break; - case 42: - _wiz->_rectOverrideEnabled = true; - _wiz->_rectOverride.left = args[1]; - _wiz->_rectOverride.top = args[2]; - _wiz->_rectOverride.right = args[3]; - _wiz->_rectOverride.bottom = args[4]; - break; - case 43: - _wiz->_rectOverrideEnabled = false; - break; - default: - error("o70_kernelSetFunctions: default case %d (param count %d)", args[0], num); - } -} - -void ScummEngine_v70he::o70_getStringLen() { - int id, len; - byte *addr; - - id = pop(); - - addr = getStringAddress(id); - if (!addr) - error("o70_getStringLen: Reference to zeroed array pointer (%d)", id); - - len = resStrLen(getStringAddress(id)); - push(len); -} - -void ScummEngine_v70he::o70_appendString() { - int dst, size; - - int len = pop(); - int srcOffs = pop(); - int src = pop(); - - size = len - srcOffs + 2; - dst = setupStringArray(size); - - appendSubstring(dst, src, srcOffs, len); - - push(dst); -} - -void ScummEngine_v70he::o70_concatString() { - int dst, size; - - int src2 = pop(); - int src1 = pop(); - - size = resStrLen(getStringAddress(src1)); - size += resStrLen(getStringAddress(src2)) + 1; - dst = setupStringArray(size); - - appendSubstring(dst, src1, 0, -1); - appendSubstring(dst, src2, 0, -1); - - push(dst); -} - -void ScummEngine_v70he::o70_compareString() { - int result; - - int array1 = pop(); - int array2 = pop(); - - byte *string1 = getStringAddress(array1); - if (!string1) - error("o70_compareString: Reference to zeroed array pointer (%d)", array1); - - byte *string2 = getStringAddress(array2); - if (!string2) - error("o70_compareString: Reference to zeroed array pointer (%d)", array2); - - while (*string1 == *string2) { - if (*string2 == 0) { - push(0); - return; - } - - string1++; - string2++; - } - - result = (*string1 > *string2) ? -1 : 1; - push(result); -} - -void ScummEngine_v70he::o70_isResourceLoaded() { - // Reports percentage of resource loaded by queue - int type; - - byte subOp = fetchScriptByte(); - /* int idx = */ pop(); - - switch (subOp) { - case 18: - type = rtImage; - break; - case 226: - type = rtRoom; - break; - case 227: - type = rtCostume; - break; - case 228: - type = rtSound; - break; - case 229: - type = rtScript; - break; - default: - error("o70_isResourceLoaded: default case %d", subOp); - } - - push(100); -} - -void ScummEngine_v70he::o70_readINI() { - byte option[256]; - ArrayHeader *ah; - const char *entry; - int len, type; - - convertMessageToString(_scriptPointer, option, sizeof(option)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - type = pop(); - switch (type) { - case 1: // number - if (!strcmp((char *)option, "NoPrinting")) { - push(1); - } else if (!strcmp((char *)option, "TextOn")) { - push(ConfMan.getBool("subtitles")); - } else { - push(ConfMan.getInt((char *)option)); - } - break; - case 2: // string - entry = (ConfMan.get((char *)option).c_str()); - - writeVar(0, 0); - len = resStrLen((const byte *)entry); - ah = defineArray(0, kStringArray, 0, len); - memcpy(ah->data, entry, len); - - push(readVar(0)); - break; - default: - error("o70_readINI: default type %d", type); - } - debug(1, "o70_readINI: Option %s", option); -} - -void ScummEngine_v70he::o70_writeINI() { - int type, value; - byte option[256], string[256]; - int len; - - type = pop(); - value = pop(); - - convertMessageToString(_scriptPointer, option, sizeof(option)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - switch (type) { - case 1: // number - ConfMan.set((char *)option, value); - debug(1, "o70_writeINI: Option %s Value %d", option, value); - break; - case 2: // string - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - ConfMan.set((char *)option, (char *)string); - debug(1, "o70_writeINI: Option %s String %s", option, string); - break; - default: - error("o70_writeINI: default type %d", type); - } -} - -void ScummEngine_v70he::o70_getStringLenForWidth() { - int chr, max; - int array, len, pos, width = 0; - - max = pop(); - pos = pop(); - array = pop(); - - len = resStrLen(getStringAddress(array)); - - writeVar(0, array); - while (pos <= len) { - chr = readArray(0, 0, pos); - width += getStringCharWidth(chr); - if (width >= max) { - push(pos); - return; - } - pos++; - } - - push(len); -} - -void ScummEngine_v70he::o70_getCharIndexInString() { - int array, end, len, pos, value; - - value = pop(); - end = pop(); - pos = pop(); - array = pop(); - - if (end >= 0) { - len = resStrLen(getStringAddress(array)); - if (len < end) - end = len; - } else { - end = 0; - } - - if (pos < 0) - pos = 0; - - writeVar(0, array); - if (end > pos) { - while (end >= pos) { - if (readArray(0, 0, pos) == value) { - push(pos); - return; - } - pos++; - } - } else { - while (end <= pos) { - if (readArray(0, 0, pos) == value) { - push(pos); - return; - } - pos--; - } - } - - push(-1); -} - -void ScummEngine_v70he::o70_setFilePath() { - int len; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - debug(1,"stub o70_setFilePath(%s)", filename); -} - -void ScummEngine_v70he::o70_setSystemMessage() { - int len; - byte name[255]; - - byte subOp = fetchScriptByte(); - - convertMessageToString(_scriptPointer, name, sizeof(name)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - switch (subOp) { - case 240: - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 241: // Set Version - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 242: - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 243: // Set Window Caption - _system->setWindowCaption((const char *)name); - break; - default: - error("o70_setSystemMessage: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_polygonOps() { - int vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; - int id, fromId, toId; - bool flag; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 68: // HE 100 - case 69: // HE 100 - case 246: - case 248: - vert4y = pop(); - vert4x = pop(); - vert3y = pop(); - vert3x = pop(); - vert2y = pop(); - vert2x = pop(); - vert1y = pop(); - vert1x = pop(); - flag = (subOp == 69 || subOp == 248); - id = pop(); - _wiz->polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); - break; - case 28: // HE 100 - case 247: - toId = pop(); - fromId = pop(); - _wiz->polygonErase(fromId, toId); - break; - default: - error("o70_polygonOps: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_polygonHit() { - int y = pop(); - int x = pop(); - push(_wiz->polygonHit(0, x, y)); -} - -} // End of namespace Scumm diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index f82aebe050..f65fdc933f 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -32,7 +32,7 @@ #include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" +#include "scumm/he/resource_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" #include "scumm/util.h" diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index 899bce8036..a4fbd65053 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -29,7 +29,7 @@ #include "scumm/he/logic_he.h" #include "scumm/object.h" #include "scumm/resource.h" -#include "scumm/he/resource_v7he.h" +#include "scumm/he/resource_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" #include "scumm/he/sprite_he.h" -- cgit v1.2.3