61
58
memset(_cursorCache, 0, sizeof(_cursorCache));
64
61
ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) {
65
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
66
CachedCursor *cc = &_cursorCache[i];
67
if (cc->valid && cc->id == id) {
62
for (int i = 0; i < MAX_CACHED_CURSORS; ++i)
63
if (_cursorCache[i].valid && _cursorCache[i].id == id)
64
return &_cursorCache[i];
74
69
ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() {
75
uint32 min_last_used = 0;
70
uint32 minLastUsed = 0;
76
71
CachedCursor *r = NULL;
77
73
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
78
74
CachedCursor *cc = &_cursorCache[i];
82
if (min_last_used == 0 || cc->last_used < min_last_used) {
83
min_last_used = cc->last_used;
78
if (minLastUsed == 0 || cc->lastUsed < minLastUsed) {
79
minLastUsed = cc->lastUsed;
91
87
memset(r, 0, sizeof(CachedCursor));
95
91
void ResExtractor::setCursor(int id) {
99
92
CachedCursor *cc = findCachedCursor(id);
101
95
debug(7, "Found cursor %d in cache slot %lu", id, (long)(cc - _cursorCache));
103
97
cc = getCachedCursorSlot();
104
98
assert(cc && !cc->valid);
105
cursorsize = extractResource(id, &cursorRes);
106
convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize);
100
if (!extractResource(id, cc))
101
error("Could not extract cursor %d", id);
107
103
debug(7, "Adding cursor %d to cache slot %lu", id, (long)(cc - _cursorCache));
109
105
cc->valid = true;
111
cc->last_used = g_system->getMillis();
107
cc->lastUsed = g_system->getMillis();
115
111
CursorMan.replaceCursorPalette(cc->palette, 0, cc->palSize);
117
_vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y);
118
_vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w);
113
_vm->setCursorHotspot(cc->hotspotX, cc->hotspotY);
114
_vm->setCursorFromBuffer(cc->bitmap, cc->width, cc->height, cc->width);
125
const char *res_types[] = {
127
"cursor", "bitmap", "icon", "menu", "dialog", "string",
128
"fontdir", "font", "accelerator", "rcdata", "messagelist",
129
"group_cursor", NULL, "group_icon", NULL,
130
/* the following are not defined in winbase.h, but found in wrc. */
132
"version", "dlginclude", NULL, "plugplay", "vxd",
133
"anicursor", "aniicon"
135
#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *))
137
118
Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
140
int Win32ResExtractor::extractResource(int resId, byte **data) {
143
snprintf(buf, sizeof(buf), "%d", resId);
145
return extractResource_("group_cursor", buf, data);
148
int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) {
149
char *arg_language = NULL;
150
const char *arg_type = resType;
151
char *arg_name = resName;
156
/* translate --type option from resource type string to integer */
157
arg_type = res_type_string_to_id(arg_type);
121
bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) {
165
122
if (_fileName.empty()) { // We are running for the first time
166
123
_fileName = _vm->generateFilename(-3);
170
fi.file = SearchMan.createReadStreamForMember(_fileName);
172
error("Cannot open file %s", _fileName.c_str());
175
fi.total_size = fi.file->size();
176
if (fi.total_size == -1) {
177
error("Cannot get size of file %s", _fileName.c_str());
180
if (fi.total_size == 0) {
181
error("%s: file has a size of 0", _fileName.c_str());
185
/* read all of file */
186
fi.memory = (byte *)malloc(fi.total_size);
187
if (fi.file->read(fi.memory, fi.total_size) == 0) {
188
error("Cannot read from file %s", _fileName.c_str());
192
/* identify file and find resource table */
193
if (!read_library(&fi)) {
194
/* error reported by read_library */
198
/* errors will be printed by the callback */
199
ressize = do_resources(&fi, arg_type, arg_name, arg_language, data);
201
/* free stuff and close file */
210
/* res_type_id_to_string:
211
* Translate a numeric resource type to it's corresponding string type.
212
* (For informative-ness.)
214
const char *Win32ResExtractor::res_type_id_to_string(int id) {
217
if (id > 0 && id <= (int)RES_TYPE_COUNT)
218
return res_types[id-1];
222
/* res_type_string_to_id:
223
* Translate a resource type string to integer.
224
* (Used to convert the --type option.)
226
const char *Win32ResExtractor::res_type_string_to_id(const char *type) {
227
static const char *res_type_ids[] = {
228
"-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10",
229
"-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19",
237
for (c = 0 ; c < (int)RES_TYPE_COUNT ; c++) {
238
if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c]))
239
return res_type_ids[c];
245
/* return the resource id quoted if it's a string, otherwise just return it */
246
char *Win32ResExtractor::WinResource::get_resource_id_quoted() {
247
// FIXME: Using a static var here is EVIL and in fact, broken when
248
// used multiple times in a row, e.g. in a single call to printf()
249
// or debug()... which is in fact how we use this function... :-)
250
static char tmp[WINRES_ID_MAXLEN+2];
252
if (numeric_id || id[0] == '\0')
255
sprintf(tmp, "'%s'", id);
259
int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
260
WinResource *type_wr, WinResource *name_wr,
261
WinResource *lang_wr, byte **data) {
268
error("Win32ResExtractor::extract_resources() more than one cursor");
272
*data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw);
275
error("Win32ResExtractor::extract_resources() problem with resource extraction");
279
/* get named resource type if possible */
281
if ((id = strtol(type_wr->id, 0, 10)) != 0)
282
type = res_type_id_to_string(id);
284
debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]",
285
name_wr->get_resource_id_quoted(),
286
(lang_wr->id[0] != '\0' ? " language: " : ""),
287
lang_wr->get_resource_id_quoted(), size);
293
* Extract a resource, returning pointer to data.
295
byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size,
296
bool *free_it, char *type, char *lang, bool raw) {
300
/* just return pointer to data if raw */
303
/* get_resource_entry will print possible error */
304
return get_resource_entry(fi, wr, size);
307
/* find out how to extract */
309
if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) {
310
if (intval == (int)RT_GROUP_ICON) {
312
return extract_group_icon_cursor_resource(fi, wr, lang, size, true);
314
if (intval == (int)RT_GROUP_CURSOR) {
316
return extract_group_icon_cursor_resource(fi, wr, lang, size, false);
323
/* extract_group_icon_resource:
324
* Create a complete RT_GROUP_ICON resource, that can be written to
325
* an `.ico' file without modifications. Returns an allocated
326
* memory block that should be freed with free() once used.
328
* `root' is the offset in file that specifies the resource.
329
* `base' is the offset that string pointers are calculated from.
330
* `ressize' should point to an integer variable where the size of
331
* the returned memory block will be placed.
332
* `is_icon' indicates whether resource to be extracted is icon
335
byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang,
336
int *ressize, bool is_icon) {
337
Win32CursorIconDir *icondir;
338
Win32CursorIconFileDir *fileicondir;
340
int c, offset, skipped;
343
/* get resource data and size */
344
icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size);
345
if (icondir == NULL) {
346
/* get_resource_entry will print error */
350
/* calculate total size of output file */
351
RETURN_IF_BAD_POINTER(NULL, icondir->count);
353
for (c = 0 ; c < FROM_LE_16(icondir->count) ; c++) {
359
RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]);
360
/*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c,
361
FROM_LE_32(icondir->entries[c].bytes_in_res),
362
(is_icon ? icondir->entries[c].res_info.icon.width : FROM_LE_16(icondir->entries[c].res_info.cursor.width)),
363
(is_icon ? icondir->entries[c].res_info.icon.height : FROM_LE_16(icondir->entries[c].res_info.cursor.height)),
364
FROM_LE_16(icondir->entries[c].plane_count),
365
FROM_LE_16(icondir->entries[c].bit_count));*/
367
/* find the corresponding icon resource */
368
snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
369
fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
371
error("%s: could not find `%s' in `%s' resource.",
372
_fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
376
if (get_resource_entry(fi, fwr, &iconsize) != NULL) {
378
debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", _fileName.c_str(), name);
382
if ((uint32)iconsize != FROM_LE_32(icondir->entries[c].bytes_in_res)) {
383
debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)",
384
_fileName.c_str(), name, iconsize, FROM_LE_32(icondir->entries[c].bytes_in_res));
386
size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
388
/* cursor resources have two additional WORDs that contain
391
size -= sizeof(uint16)*2;
394
offset = sizeof(Win32CursorIconFileDir) + (FROM_LE_16(icondir->count)-skipped) * sizeof(Win32CursorIconFileDirEntry);
398
/* allocate that much memory */
399
memory = (byte *)malloc(size);
400
fileicondir = (Win32CursorIconFileDir *)memory;
402
/* transfer Win32CursorIconDir structure members */
403
fileicondir->reserved = icondir->reserved;
404
fileicondir->type = icondir->type;
405
fileicondir->count = TO_LE_16(FROM_LE_16(icondir->count) - skipped);
407
/* transfer each cursor/icon: Win32CursorIconDirEntry and data */
409
for (c = 0 ; c < FROM_LE_16(icondir->count) ; c++) {
415
/* find the corresponding icon resource */
416
snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
417
fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
419
error("%s: could not find `%s' in `%s' resource.",
420
_fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
424
/* get data and size of that resource */
425
data = (byte *)get_resource_entry(fi, fwr, &size);
427
/* get_resource_entry has printed error */
435
/* copy ICONDIRENTRY (not including last dwImageOffset) */
436
memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c],
437
sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32));
439
/* special treatment for cursors */
441
fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width;
442
fileicondir->entries[c-skipped].height = TO_LE_16(FROM_LE_16(icondir->entries[c].res_info.cursor.height) / 2);
443
fileicondir->entries[c-skipped].color_count = 0;
444
fileicondir->entries[c-skipped].reserved = 0;
447
/* set image offset and increase it */
448
fileicondir->entries[c-skipped].dib_offset = TO_LE_32(offset);
450
/* transfer resource into file memory */
452
memcpy(&memory[offset], data, FROM_LE_32(icondir->entries[c].bytes_in_res));
454
fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0];
455
fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1];
456
memcpy(&memory[offset], data+sizeof(uint16)*2,
457
FROM_LE_32(icondir->entries[c].bytes_in_res)-sizeof(uint16)*2);
458
offset -= sizeof(uint16)*2;
461
/* increase the offset pointer */
462
offset += FROM_LE_32(icondir->entries[c].bytes_in_res);
469
* Check if a chunk of data (determined by offset and size)
470
* is within the bounds of the WinLibrary file.
471
* Usually not called directly.
473
bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) {
474
int need_size = (int)((byte *)offset - memory + size);
476
debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x",
477
need_size, total_size, (uint)((byte *)offset - memory), size);
479
if (need_size < 0 || need_size > total_size) {
480
error("%s: premature end", name);
125
if (!_exe.loadFromEXE(_fileName))
126
error("Cannot open file %s", _fileName.c_str());
129
Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(_exe, id);
489
* Do something for each resource matching type, name and lang.
491
int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, byte **data) {
492
WinResource *type_wr;
493
WinResource *name_wr;
494
WinResource *lang_wr;
497
type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1);
498
name_wr = type_wr + 1;
499
lang_wr = type_wr + 2;
501
size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, data);
508
/* what is each entry in this directory level for? type, name or language? */
509
#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr))
511
/* does the id of this entry match the specified id? */
512
#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x))
514
int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base,
515
WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr,
516
const char *type, char *name, char *lang, byte **data) {
521
/* get a list of all resources at this level */
522
wr = list_resources(fi, base, &rescnt);
530
/* process each resource listed */
531
for (c = 0 ; c < rescnt ; c++) {
532
/* (over)write the corresponding WinResource holder with the current */
533
memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource));
535
/* go deeper unless there is something that does NOT match */
536
if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) {
537
if (wr->is_directory)
538
size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, data);
540
size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data);
544
/* since we're moving back one level after this, unset the
545
* WinResource holder used on this level */
546
memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource));
551
bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) {
552
if (wr->numeric_id) {
558
if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2)
565
if (strcmp(wr->id, id))
572
bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) {
573
if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */
575
uint16 *mem = (uint16 *)
576
(fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING));
578
/* copy each char of the string, and terminate it */
579
RETURN_IF_BAD_POINTER(false, *mem);
580
len = FROM_LE_16(mem[0]);
581
RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len);
583
len = MIN(FROM_LE_16(mem[0]), (uint16)WINRES_ID_MAXLEN);
584
for (c = 0 ; c < len ; c++)
585
wr->id[c] = FROM_LE_16(mem[c+1]) & 0x00FF;
587
wr->numeric_id = false;
588
} else { /* Unicode string id */
589
/* translate id into a string */
590
snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value);
591
wr->numeric_id = true;
597
byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) {
600
Win32ImageResourceDataEntry *dataent;
602
dataent = (Win32ImageResourceDataEntry *) wr->children;
603
RETURN_IF_BAD_POINTER(NULL, *dataent);
604
*size = FROM_LE_32(dataent->size);
606
result = fi->memory + FROM_LE_32(dataent->offset_to_data);
608
RETURN_IF_BAD_OFFSET(NULL, result, *size);
613
Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) {
616
Win32ImageResourceDirectoryEntry *dirent
617
= (Win32ImageResourceDirectoryEntry *)(pe_res + 1);
619
/* count number of `type' resources */
620
RETURN_IF_BAD_POINTER(NULL, *dirent);
621
rescnt = FROM_LE_16(pe_res->number_of_named_entries) + FROM_LE_16(pe_res->number_of_id_entries);
624
/* allocate WinResource's */
625
wr = (WinResource *)malloc(sizeof(WinResource) * rescnt);
627
/* fill in the WinResource's */
628
for (c = 0 ; c < rescnt ; c++) {
629
RETURN_IF_BAD_POINTER(NULL, dirent[c]);
630
wr[c].this_ = pe_res;
632
wr[c].is_directory = ((FROM_LE_32(dirent[c].offset_to_data) & IMAGE_RESOURCE_DATA_IS_DIRECTORY) != 0);
633
wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
635
/* fill in wr->id, wr->numeric_id */
636
if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
647
* Return an array of WinResource's in the current
648
* resource level specified by _res->
650
Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) {
651
if (res != NULL && !res->is_directory)
654
return list_pe_resources(fi, (Win32ImageResourceDirectory *)
655
(res == NULL ? fi->first_resource : res->children),
656
(res == NULL ? 0 : res->level+1),
661
* Read header and get resource directory offset in a Windows library
665
bool Win32ResExtractor::read_library(WinLibrary *fi) {
666
/* check for DOS header signature `MZ' */
667
RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic);
668
if (FROM_LE_16(MZ_HEADER(fi->memory)->magic) == IMAGE_DOS_SIGNATURE) {
669
DOSImageHeader *mz_header = MZ_HEADER(fi->memory);
671
RETURN_IF_BAD_POINTER(false, mz_header->lfanew);
673
// Apply endian fix (currently only lfanew is used from the DOSImageHeader,
674
// so we don't bother to 'fix' the rest).
675
LE32(mz_header->lfanew);
677
if (mz_header->lfanew < sizeof(DOSImageHeader)) {
678
error("%s: not a Windows library", _fileName.c_str());
683
/* check for NT header signature `PE' */
684
RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature);
685
if (FROM_LE_32(PE_HEADER(fi->memory)->signature) == IMAGE_NT_SIGNATURE) {
686
Win32ImageNTHeaders *pe_header;
689
// Fix image header endianess
690
fix_win32_image_header_endian(PE_HEADER(fi->memory));
692
/* allocate new memory */
693
fi->total_size = calc_vma_size(fi);
694
if (fi->total_size == 0) {
695
/* calc_vma_size has reported error */
698
fi->memory = (byte *)realloc(fi->memory, fi->total_size);
700
/* relocate memory, start from last section */
701
pe_header = PE_HEADER(fi->memory);
702
RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections);
704
/* we don't need to do OFFSET checking for the sections.
705
* calc_vma_size has already done that */
706
for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) {
707
Win32ImageSectionHeader *pe_sec = PE_SECTIONS(fi->memory) + d;
709
if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
712
//if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size)
714
RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data);
715
RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data);
716
if (FROM_LE_32(pe_sec->virtual_address) != pe_sec->pointer_to_raw_data) {
717
memmove(fi->memory + pe_sec->virtual_address,
718
fi->memory + pe_sec->pointer_to_raw_data,
719
pe_sec->size_of_raw_data);
723
/* find resource directory */
724
RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
725
Win32ImageDataDirectory *dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
726
if (dir->size == 0) {
727
error("%s: file contains no resources", _fileName.c_str());
731
fix_win32_image_data_directory(dir);
733
fi->first_resource = fi->memory + dir->virtual_address;
737
/* other (unknown) header signature was found */
738
error("%s: not a Windows library", _fileName.c_str());
743
* Calculate the total amount of memory needed for a 32-bit Windows
744
* module. Returns -1 if file was too small.
746
int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
747
Win32ImageSectionHeader *seg;
748
int c, segcount, size;
751
RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections);
752
segcount = PE_HEADER(fi->memory)->file_header.number_of_sections;
754
/* If there are no segments, just process file like it is.
755
* This is (probably) not the right thing to do, but problems
756
* will be delt with later anyway.
759
return fi->total_size;
761
seg = PE_SECTIONS(fi->memory);
762
RETURN_IF_BAD_POINTER(-1, *seg);
763
for (c = 0 ; c < segcount ; c++) {
764
RETURN_IF_BAD_POINTER(0, *seg);
765
fix_win32_image_section_header(seg);
767
size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data);
768
/* I have no idea what misc.virtual_size is for... */
769
size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size);
776
Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) {
778
WinResource *return_wr;
780
wr = list_resources(fi, wr, &rescnt);
784
for (c = 0 ; c < rescnt ; c++) {
785
if (compare_resource_id(&wr[c], id)) {
786
/* duplicate WinResource and return it */
787
return_wr = (WinResource *)malloc(sizeof(WinResource));
788
memcpy(return_wr, &wr[c], sizeof(WinResource));
790
/* free old WinResource */
799
Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) {
805
wr = find_with_resource_array(fi, NULL, type);
806
if (wr == NULL || !wr->is_directory)
812
wr = find_with_resource_array(fi, wr, name);
813
if (wr == NULL || !wr->is_directory)
817
if (language == NULL)
819
wr = find_with_resource_array(fi, wr, language);
823
#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2)
826
int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
827
int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) {
828
Win32CursorIconFileDir dir;
829
Win32CursorIconFileDirEntry *entries = NULL;
834
MemoryReadStream *in = new MemoryReadStream(data, datasize);
836
if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry)))
838
fix_win32_cursor_icon_file_dir_endian(&dir);
840
if (dir.reserved != 0) {
841
error("not an icon or cursor file (reserved non-zero)");
844
if (dir.type != 1 && dir.type != 2) {
845
error("not an icon or cursor file (wrong type)");
849
entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry));
850
for (c = 0; c < dir.count; c++) {
851
if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry)))
853
fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]);
854
if (entries[c].reserved != 0)
855
error("reserved is not zero");
858
offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry));
860
for (completed = 0; completed < dir.count; ) {
861
uint32 min_offset = 0x7fffffff;
862
int previous = completed;
864
for (c = 0; c < dir.count; c++) {
865
if (entries[c].dib_offset == offset) {
866
Win32BitmapInfoHeader bitmap;
867
Win32RGBQuad *palette = NULL;
868
uint32 palette_count = 0;
869
uint32 image_size, mask_size;
870
uint32 width, height;
871
byte *image_data = NULL, *mask_data = NULL;
874
if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader)))
877
fix_win32_bitmap_info_header_endian(&bitmap);
878
if (bitmap.size < sizeof(Win32BitmapInfoHeader)) {
879
error("bitmap header is too short");
882
if (bitmap.compression != 0) {
883
error("compressed image data not supported");
886
if (bitmap.x_pels_per_meter != 0)
887
error("x_pels_per_meter field in bitmap should be zero");
888
if (bitmap.y_pels_per_meter != 0)
889
error("y_pels_per_meter field in bitmap should be zero");
890
if (bitmap.clr_important != 0)
891
error("clr_important field in bitmap should be zero");
892
if (bitmap.planes != 1)
893
error("planes field in bitmap should be one");
894
if (bitmap.size != sizeof(Win32BitmapInfoHeader)) {
895
uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader);
896
error("skipping %d bytes of extended bitmap header", skip);
897
in->seek(skip, SEEK_CUR);
899
offset += bitmap.size;
901
if (bitmap.clr_used != 0 || bitmap.bit_count < 24) {
902
palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count);
903
palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count);
904
if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count))
906
offset += sizeof(Win32RGBQuad) * palette_count;
909
width = bitmap.width;
910
height = ABS(bitmap.height)/2;
912
image_size = height * ROW_BYTES(width * bitmap.bit_count);
913
mask_size = height * ROW_BYTES(width);
915
if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
916
debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)",
918
(int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
921
image_data = (byte *)malloc(image_size);
922
if (!in->read(image_data, image_size))
925
mask_data = (byte *)malloc(mask_size);
926
if (!in->read(mask_data, mask_size))
929
offset += image_size;
934
*hotspot_x = entries[c].hotspot_x;
935
*hotspot_y = entries[c].hotspot_y;
939
*cursor = (byte *)malloc(width * height);
941
row = (byte *)malloc(width * 4);
943
for (d = 0; d < height; d++) {
945
uint32 y = (bitmap.height < 0 ? d : height - d - 1);
946
uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count;
947
uint32 mmod = y * (mask_size / height) * 8;
949
for (x = 0; x < width; x++) {
951
uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count);
953
// We set up cursor palette for default cursor, so use it
954
if (!simple_vec(mask_data, x + mmod, 1)) {
956
cursor[0][width * d + x] = 254; // white
958
cursor[0][width * d + x] = 253; // black
961
cursor[0][width * d + x] = 255; // transparent
965
if (bitmap.bit_count <= 16) {
966
if (color >= palette_count) {
967
error("color out of range in image data");
970
row[4*x+0] = palette[color].red;
971
row[4*x+1] = palette[color].green;
972
row[4*x+2] = palette[color].blue;
975
row[4*x+0] = (color >> 16) & 0xFF;
976
row[4*x+1] = (color >> 8) & 0xFF;
977
row[4*x+2] = (color >> 0) & 0xFF;
979
if (bitmap.bit_count == 32)
980
row[4*x+3] = (color >> 24) & 0xFF;
982
row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
990
if (image_data != NULL) {
1000
if (image_data != NULL) {
1006
if (entries[c].dib_offset > offset)
1007
min_offset = MIN(min_offset, entries[c].dib_offset);
1011
if (previous == completed) {
1012
if (min_offset < offset) {
1013
error("offset of bitmap header incorrect (too low)");
1016
assert(min_offset != 0x7fffffff);
1017
debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset);
1018
in->seek(min_offset - offset, SEEK_CUR);
1019
offset = min_offset;
1032
uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) {
1035
return (data[ofs/8] >> (7 - ofs%8)) & 1;
1037
return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3;
1039
return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15;
1043
return data[2*ofs] | data[2*ofs+1] << 8;
1045
return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16;
1047
return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24;
1053
void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) {
1054
LE16(obj->reserved);
1059
void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) {
1064
LE16(obj->bit_count);
1065
LE32(obj->compression);
1066
LE32(obj->size_image);
1067
LE32(obj->x_pels_per_meter);
1068
LE32(obj->y_pels_per_meter);
1069
LE32(obj->clr_used);
1070
LE32(obj->clr_important);
1073
void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) {
1074
LE16(obj->hotspot_x);
1075
LE16(obj->hotspot_y);
1076
LE32(obj->dib_size);
1077
LE32(obj->dib_offset);
1080
void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) {
1081
LE32(obj->misc.physical_address);
1082
LE32(obj->virtual_address);
1083
LE32(obj->size_of_raw_data);
1084
LE32(obj->pointer_to_raw_data);
1085
LE32(obj->pointer_to_relocations);
1086
LE32(obj->pointer_to_linenumbers);
1087
LE16(obj->number_of_relocations);
1088
LE16(obj->number_of_linenumbers);
1089
LE32(obj->characteristics);
1092
/* fix_win32_image_header_endian:
1093
* NOTE: This assumes that the optional header is always available.
1095
void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) {
1096
LE32(obj->signature);
1097
LE16(obj->file_header.machine);
1098
LE16(obj->file_header.number_of_sections);
1099
LE32(obj->file_header.time_date_stamp);
1100
LE32(obj->file_header.pointer_to_symbol_table);
1101
LE32(obj->file_header.number_of_symbols);
1102
LE16(obj->file_header.size_of_optional_header);
1103
LE16(obj->file_header.characteristics);
1105
// FIXME: Does this assert ever trigger? If so, we should modify this function
1106
// to properly deal with it.
1107
assert(obj->file_header.size_of_optional_header >= sizeof(obj->optional_header));
1108
LE16(obj->optional_header.magic);
1109
LE32(obj->optional_header.size_of_code);
1110
LE32(obj->optional_header.size_of_initialized_data);
1111
LE32(obj->optional_header.size_of_uninitialized_data);
1112
LE32(obj->optional_header.address_of_entry_point);
1113
LE32(obj->optional_header.base_of_code);
1114
LE32(obj->optional_header.base_of_data);
1115
LE32(obj->optional_header.image_base);
1116
LE32(obj->optional_header.section_alignment);
1117
LE32(obj->optional_header.file_alignment);
1118
LE16(obj->optional_header.major_operating_system_version);
1119
LE16(obj->optional_header.minor_operating_system_version);
1120
LE16(obj->optional_header.major_image_version);
1121
LE16(obj->optional_header.minor_image_version);
1122
LE16(obj->optional_header.major_subsystem_version);
1123
LE16(obj->optional_header.minor_subsystem_version);
1124
LE32(obj->optional_header.win32_version_value);
1125
LE32(obj->optional_header.size_of_image);
1126
LE32(obj->optional_header.size_of_headers);
1127
LE32(obj->optional_header.checksum);
1128
LE16(obj->optional_header.subsystem);
1129
LE16(obj->optional_header.dll_characteristics);
1130
LE32(obj->optional_header.size_of_stack_reserve);
1131
LE32(obj->optional_header.size_of_stack_commit);
1132
LE32(obj->optional_header.size_of_heap_reserve);
1133
LE32(obj->optional_header.size_of_heap_commit);
1134
LE32(obj->optional_header.loader_flags);
1135
LE32(obj->optional_header.number_of_rva_and_sizes);
1138
void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) {
1139
LE32(obj->virtual_address);
134
Graphics::WinCursor *cursor = group->cursors[0].cursor;
136
cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()];
137
cc->width = cursor->getWidth();
138
cc->height = cursor->getHeight();
139
cc->hotspotX = cursor->getHotspotX();
140
cc->hotspotY = cursor->getHotspotY();
142
// Convert from the paletted format to the SCUMM palette
143
const byte *srcBitmap = cursor->getSurface();
145
for (int i = 0; i < cursor->getWidth() * cursor->getHeight(); i++) {
146
if (srcBitmap[i] == cursor->getKeyColor()) // Transparent
148
else if (srcBitmap[i] == 0) // Black
1144
158
MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
1148
int MacResExtractor::extractResource(int id, byte **buf) {
162
bool MacResExtractor::extractResource(int id, CachedCursor *cc) {
1149
163
// Create the MacResManager if not created already
1150
164
if (_resMgr == NULL) {
1151
165
_resMgr = new Common::MacResManager();