[Scummvm-cvs-logs] CVS: scummvm/scumm resource_v7he.cpp,NONE,1.1 resource_v7he.h,NONE,1.1 module.mk,1.37,1.38 script_v6.cpp,1.341,1.342 scumm.cpp,1.45,1.46 scumm.h,1.407,1.408

Eugene Sandulenko sev at users.sourceforge.net
Wed Jun 23 19:37:02 CEST 2004


Update of /cvsroot/scummvm/scummvm/scumm
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32123/scumm

Modified Files:
	module.mk script_v6.cpp scumm.cpp scumm.h 
Added Files:
	resource_v7he.cpp resource_v7he.h 
Log Message:
Phase #1 of HE v7.0+ cursors. Basically it's Win32 resource extractor
incorporated from icotools, no display, just searching it in resources
and display a warning. Graphics converter is on the way.

Code is NOT endian-safe. It will not work on BE system, as was tested by
joostp. Please, fix endianess.


--- NEW FILE: resource_v7he.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/resource_v7he.cpp,v 1.1 2004/06/24 02:36:17 sev Exp $
 *
 */

#include "stdafx.h"
#include "scumm/scumm.h"
#include "scumm/intern.h"
#include "scumm/resource.h"
#include "scumm/resource_v7he.h"

namespace Scumm {

/*
 * 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 *scumm) {
	_vm = scumm;

	snprintf(_fileName, 256, "%s.he3", _vm->getGameName());
}

byte *Win32ResExtractor::extractCursor(int id) {
	char buf[20];

	snprintf(buf, 20, "%d", id);

	return extractResource("group_cursor", buf);
}

byte *Win32ResExtractor::extractResource(const char *resType, char *resName) {
	char *arg_language = NULL;
	const char *arg_type = resType;
	char *arg_name = resName;
	int arg_action = ACTION_LIST;

	_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 File;

	/* 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) {
		warning("%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");

	/* warn about more unnecessary options */
	if (!fi.is_PE_binary && arg_language != NULL)
		warning("%s: --language has no effect because file is 16-bit binary", fi.file->name());

	/* errors will be printed by the callback */
	do_resources(&fi, arg_type, arg_name, arg_language, arg_action);

	/* free stuff and close file */
	cleanup:
	if (fi.file != NULL)
		fi.file->close();
	if (fi.memory != NULL)
		free(fi.memory);

	return NULL;
}


/* 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 && !strcasecmp(type, res_types[c]))
			return res_type_ids[c];
	}

	return type;
}

void Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
                            WinResource *type_wr, WinResource *name_wr,
                            WinResource *lang_wr) {
	int size;
	bool free_it;
	void *memory;
	FILE *out;

	memory = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw);
	free_it = false;
	if (memory == NULL) {
		/* extract resource has printed error */
		return;
	}

	out = stdout;

	/* write the actual data */
	fwrite(memory, size, 1, out);
	
	if (free_it)
		free(memory);
	if (out != NULL && out != stdout)
		fclose(out);
}

/* extract_resource:
 *   Extract a resource, returning pointer to data.
 */
void *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);
		}
	}

	warning("%s: don't know how to extract resource, try `--raw'", fi->file->name());
	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.
 */
void *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang,
                                   int *ressize, bool is_icon) {
	Win32CursorIconDir *icondir;
	Win32CursorIconFileDir *fileicondir;
	char *memory;
	int c, size, offset, skipped;

	/* 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) {
			warning("%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) {
				warning("%s: icon resource `%s' is empty, skipping", fi->file->name(), name);
				skipped++;
				continue;
		    }
		    if ((uint32)iconsize != icondir->entries[c].bytes_in_res) {
				warning("%s: mismatch of size in icon resource `%s' and group", 
						fi->file->name(), name);
		    }
		    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 = (char *)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) {
			warning("%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 (void *)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\n",
		need_size, total_size, (byte *)offset - memory, size);

	if (need_size < 0 || need_size > total_size) {
		warning("%s: premature end", name);
		return false;
	}

	return true;
}


/* do_resources:
 *   Do something for each resource matching type, name and lang.
 */
void Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, int action) {
	WinResource *type_wr;
	WinResource *name_wr;
	WinResource *lang_wr;

	type_wr = (WinResource *)malloc(sizeof(WinResource)*3);
	name_wr = type_wr + 1;
	lang_wr = type_wr + 2;
	memset(type_wr, 0, sizeof(WinResource)*3);

	do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, action);

	free(type_wr);
}

/* 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))

void 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) {
	int c, rescnt;
	WinResource *wr;

	/* get a list of all resources at this level */
	wr = list_resources(fi, base, &rescnt);
	if (wr == NULL)
		return;

	/* 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)
				do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, action);
			else
				if (action == ACTION_LIST)
					print_resources(fi, wr+c, type_wr, name_wr, lang_wr);
				else
					extract_resources(fi, wr+c, type_wr, name_wr, lang_wr);
		}
	}

	/* 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));
}

void Win32ResExtractor::print_resources(WinLibrary *fi, WinResource *wr,
                          WinResource *type_wr, WinResource *name_wr,
						  WinResource *lang_wr) {
	const char *type;
	byte *offset;
	int32 id, size;

	/* get named resource type if possible */
	type = NULL;
	if ((id = strtol(type_wr->id, 0, 10)) != 0)
		type = res_type_id_to_string(id);

	/* get offset and size info on resource */
	offset = (byte *)get_resource_entry(fi, wr, &size);
	if (offset == NULL)
		return;

	warning("extractCursor(). Found cursor name: %s%s%s [offset: 0x%x size=%d]\n",
	  get_resource_id_quoted(name_wr),
	  (lang_wr->id[0] != '\0' ? " language: " : ""),
	  get_resource_id_quoted(lang_wr),
	  offset - fi->memory, 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;
}
 
void *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)) {
			warning("%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) {
			warning("%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) {
			warning("%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 */
	warning("%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;
}

} // End of namespace Scumm

--- NEW FILE: resource_v7he.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/resource_v7he.h,v 1.1 2004/06/24 02:36:17 sev Exp $
 *
 */

#ifndef RESOURCE_V7HE_H
#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 */

#define IMAGE_SCN_CNT_CODE			0x00000020
#define IMAGE_SCN_CNT_INITIALIZED_DATA		0x00000040
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA	0x00000080

#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

#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

#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 Win32ResExtractor {
 public:
	Win32ResExtractor(ScummEngine *scumm);
	~Win32ResExtractor();
	byte *extractResource(const char *resType, char *resName);
	byte *extractCursor(int id);

 private:
	bool _arg_raw;
	ScummEngine *_vm;
	char _fileName[256];

/*
 * Structures 
 */

	struct WinLibrary {
		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];
	};

	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 BITFIELDS_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 WORDS_BIGENDIAN
				uint16 __pad;
				uint16 id;
	    	    #else
				uint16 id;
				uint16 __pad;
	    	    #endif
			} s2;
		} u1;
		union {
			uint32 offset_to_data;
			struct {
	    	    #ifdef BITFIELDS_BIGENDIAN
				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;
	};

/*
 * Function Prototypes
 */

	WinResource *list_resources(WinLibrary *, WinResource *, int *);
	bool read_library(WinLibrary *);
	WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *);
	void *get_resource_entry(WinLibrary *, WinResource *, int *);
	void do_resources(WinLibrary *, const char *, char *, char *, int);
	void print_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *);
	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 *);

	void *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool);
	void extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *);
	void *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 *);
	void do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, int);
	char *get_resource_id_quoted(WinResource *);
	WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *);

	bool check_offset(byte *, int, const char *, void *, int);
};

} // End of namespace Scumm

#endif

Index: module.mk
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/module.mk,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- module.mk	6 Apr 2004 19:46:42 -0000	1.37
+++ module.mk	24 Jun 2004 02:36:17 -0000	1.38
@@ -31,6 +31,7 @@
 	scumm/resource_v2.o \
 	scumm/resource_v3.o \
 	scumm/resource_v4.o \
+	scumm/resource_v7he.o \
 	scumm/saveload.o \
 	scumm/script.o \
 	scumm/script_v2.o \

Index: script_v6.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/script_v6.cpp,v
retrieving revision 1.341
retrieving revision 1.342
diff -u -d -r1.341 -r1.342
--- script_v6.cpp	23 Jun 2004 10:52:22 -0000	1.341
+++ script_v6.cpp	24 Jun 2004 02:36:17 -0000	1.342
@@ -33,6 +33,7 @@
 #include "scumm/intern.h"
 #include "scumm/object.h"
 #include "scumm/resource.h"
+#include "scumm/resource_v7he.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"
 #include "scumm/verbs.h"
@@ -934,7 +935,7 @@
 	case 0x99: 		// SO_CURSOR_IMAGE Set cursor image
 		{
 			if (_heversion >= 70) { // Windows titles
-				warning("cursorCommand 0x99 PC_SetCursorToID(%d) stub", pop());
+				_Win32ResExtractor->extractCursor(pop());
 				break;
 			}
 			int room, obj = popRoomAndObj(&room);

Index: scumm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.cpp,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- scumm.cpp	23 Jun 2004 11:28:51 -0000	1.45
+++ scumm.cpp	24 Jun 2004 02:36:17 -0000	1.46
@@ -49,6 +49,7 @@
 #include "scumm/player_v2a.h"
 #include "scumm/player_v3a.h"
 #include "scumm/resource.h"
+#include "scumm/resource_v7he.h"
 #include "scumm/scumm.h"
 #include "scumm/scumm-md5.h"
 #include "scumm/sound.h"
@@ -839,6 +840,13 @@
 		_insane = new Insane((ScummEngine_v6 *)this);
 	else
 		_insane = 0;
+
+	// HE v7.0+
+	if (_heversion >= 70) {
+		_Win32ResExtractor = new Win32ResExtractor(this);
+	} else {
+		_Win32ResExtractor = 0;
+	}
 }
 
 ScummEngine::~ScummEngine() {

Index: scumm.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.h,v
retrieving revision 1.407
retrieving revision 1.408
diff -u -d -r1.407 -r1.408
--- scumm.h	23 Jun 2004 09:13:24 -0000	1.407
+++ scumm.h	24 Jun 2004 02:36:17 -0000	1.408
@@ -52,6 +52,7 @@
 class ScummDebugger;
 class Serializer;
 class Sound;
+class Win32ResExtractor;
 
 struct Box;
 struct BoxCoords;
@@ -1044,6 +1045,9 @@
 
 	Insane *_insane;
 
+	// HE v7.0+ games
+	Win32ResExtractor *_Win32ResExtractor;
+
 public:
 	uint16 _extraBoxFlags[65];
 





More information about the Scummvm-git-logs mailing list