~ubuntu-branches/ubuntu/raring/scummvm/raring

« back to all changes in this revision

Viewing changes to engines/scumm/he/resource_he.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mto: (21.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20110525190223-fiqm0oaec714xk31
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * along with this program; if not, write to the Free Software
19
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-1/engines/scumm/he/resource_he.cpp $
22
 
 * $Id: resource_he.cpp 49307 2010-05-29 08:14:50Z eriktorbjorn $
 
21
 * $URL$
 
22
 * $Id$
23
23
 *
24
24
 */
25
25
 
26
 
 
27
26
#include "scumm/scumm.h"
28
27
#include "scumm/file.h"
29
28
#include "scumm/he/intern_he.h"
31
30
#include "scumm/he/resource_he.h"
32
31
#include "scumm/he/sound_he.h"
33
32
 
34
 
#include "sound/decoders/wave.h"
 
33
#include "audio/decoders/wave.h"
35
34
#include "graphics/cursorman.h"
 
35
#include "graphics/wincursor.h"
36
36
 
37
37
#include "common/archive.h"
38
 
#include "common/stream.h"
 
38
#include "common/memstream.h"
39
39
#include "common/system.h"
40
40
 
41
41
namespace Scumm {
42
42
 
43
 
#define LE16(x)      ((x) = TO_LE_16(x))
44
 
#define LE32(x)      ((x) = TO_LE_32(x))
45
 
 
46
 
 
47
43
ResExtractor::ResExtractor(ScummEngine_v70he *scumm)
48
44
        : _vm(scumm) {
49
45
 
58
54
                        free(cc->palette);
59
55
                }
60
56
        }
 
57
 
61
58
        memset(_cursorCache, 0, sizeof(_cursorCache));
62
59
}
63
60
 
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) {
68
 
                        return cc;
69
 
                }
70
 
        }
 
62
        for (int i = 0; i < MAX_CACHED_CURSORS; ++i)
 
63
                if (_cursorCache[i].valid && _cursorCache[i].id == id)
 
64
                        return &_cursorCache[i];
 
65
 
71
66
        return NULL;
72
67
}
73
68
 
74
69
ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() {
75
 
        uint32 min_last_used = 0;
 
70
        uint32 minLastUsed = 0;
76
71
        CachedCursor *r = NULL;
 
72
 
77
73
        for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
78
74
                CachedCursor *cc = &_cursorCache[i];
79
 
                if (!cc->valid) {
 
75
                if (!cc->valid)
80
76
                        return cc;
81
 
                } else {
82
 
                        if (min_last_used == 0 || cc->last_used < min_last_used) {
83
 
                                min_last_used = cc->last_used;
84
 
                                r = cc;
85
 
                        }
 
77
 
 
78
                if (minLastUsed == 0 || cc->lastUsed < minLastUsed) {
 
79
                        minLastUsed = cc->lastUsed;
 
80
                        r = cc;
86
81
                }
87
82
        }
 
83
 
88
84
        assert(r);
89
 
        free(r->bitmap);
90
 
        free(r->palette);
 
85
        delete[] r->bitmap;
 
86
        delete[] r->palette;
91
87
        memset(r, 0, sizeof(CachedCursor));
92
88
        return r;
93
89
}
94
90
 
95
91
void ResExtractor::setCursor(int id) {
96
 
        byte *cursorRes = 0;
97
 
        int cursorsize;
98
 
        int keycolor = 0;
99
92
        CachedCursor *cc = findCachedCursor(id);
 
93
 
100
94
        if (cc != NULL) {
101
95
                debug(7, "Found cursor %d in cache slot %lu", id, (long)(cc - _cursorCache));
102
96
        } else {
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);
 
99
 
 
100
                if (!extractResource(id, cc))
 
101
                        error("Could not extract cursor %d", id);
 
102
 
107
103
                debug(7, "Adding cursor %d to cache slot %lu", id, (long)(cc - _cursorCache));
108
 
                free(cursorRes);
 
104
 
109
105
                cc->valid = true;
110
106
                cc->id = id;
111
 
                cc->last_used = g_system->getMillis();
 
107
                cc->lastUsed = g_system->getMillis();
112
108
        }
113
109
 
114
110
        if (cc->palette)
115
111
                CursorMan.replaceCursorPalette(cc->palette, 0, cc->palSize);
116
112
 
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);
119
115
}
120
116
 
121
117
 
122
 
/*
123
 
 * Static variables
124
 
 */
125
 
const char *res_types[] = {
126
 
        /* 0x01: */
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. */
131
 
        /* 0x10: */
132
 
        "version", "dlginclude", NULL, "plugplay", "vxd",
133
 
        "anicursor", "aniicon"
134
 
};
135
 
#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *))
136
 
 
137
118
Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
138
119
}
139
120
 
140
 
int Win32ResExtractor::extractResource(int resId, byte **data) {
141
 
        char buf[20];
142
 
 
143
 
        snprintf(buf, sizeof(buf), "%d", resId);
144
 
 
145
 
        return extractResource_("group_cursor", buf, data);
146
 
}
147
 
 
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;
152
 
        int ressize = 0;
153
 
 
154
 
        _arg_raw = false;
155
 
 
156
 
        /* translate --type option from resource type string to integer */
157
 
        arg_type = res_type_string_to_id(arg_type);
158
 
 
159
 
        WinLibrary fi;
160
 
 
161
 
        /* initiate stuff */
162
 
        fi.memory = NULL;
163
 
        fi.file = NULL;
164
 
 
 
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);
167
 
        }
168
 
 
169
 
        /* get file size */
170
 
        fi.file = SearchMan.createReadStreamForMember(_fileName);
171
 
        if (!fi.file) {
172
 
                error("Cannot open file %s", _fileName.c_str());
173
 
        }
174
 
 
175
 
        fi.total_size = fi.file->size();
176
 
        if (fi.total_size == -1) {
177
 
                error("Cannot get size of file %s", _fileName.c_str());
178
 
                goto cleanup;
179
 
        }
180
 
        if (fi.total_size == 0) {
181
 
                error("%s: file has a size of 0", _fileName.c_str());
182
 
                goto cleanup;
183
 
        }
184
 
 
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());
189
 
                goto cleanup;
190
 
        }
191
 
 
192
 
        /* identify file and find resource table */
193
 
        if (!read_library(&fi)) {
194
 
                /* error reported by read_library */
195
 
                goto cleanup;
196
 
        }
197
 
 
198
 
        /* errors will be printed by the callback */
199
 
        ressize = do_resources(&fi, arg_type, arg_name, arg_language, data);
200
 
 
201
 
        /* free stuff and close file */
202
 
        cleanup:
203
 
        delete fi.file;
204
 
        free(fi.memory);
205
 
 
206
 
        return ressize;
207
 
}
208
 
 
209
 
 
210
 
/* res_type_id_to_string:
211
 
 *   Translate a numeric resource type to it's corresponding string type.
212
 
 *   (For informative-ness.)
213
 
 */
214
 
const char *Win32ResExtractor::res_type_id_to_string(int id) {
215
 
        if (id == 241)
216
 
                return "toolbar";
217
 
        if (id > 0 && id <= (int)RES_TYPE_COUNT)
218
 
                return res_types[id-1];
219
 
        return NULL;
220
 
}
221
 
 
222
 
/* res_type_string_to_id:
223
 
 *   Translate a resource type string to integer.
224
 
 *   (Used to convert the --type option.)
225
 
 */
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",
230
 
                "-20", "-21", "-22"
231
 
        };
232
 
        int c;
233
 
 
234
 
        if (type == NULL)
235
 
                return NULL;
236
 
 
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];
240
 
        }
241
 
 
242
 
        return type;
243
 
}
244
 
 
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];
251
 
 
252
 
        if (numeric_id || id[0] == '\0')
253
 
                return id;
254
 
 
255
 
        sprintf(tmp, "'%s'", id);
256
 
        return tmp;
257
 
}
258
 
 
259
 
int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
260
 
                            WinResource *type_wr, WinResource *name_wr,
261
 
                                                        WinResource *lang_wr, byte **data) {
262
 
        int size;
263
 
        bool free_it;
264
 
        const char *type;
265
 
        int32 id;
266
 
 
267
 
        if (*data) {
268
 
                error("Win32ResExtractor::extract_resources() more than one cursor");
269
 
                return 0;
270
 
        }
271
 
 
272
 
        *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw);
273
 
 
274
 
        if (data == NULL) {
275
 
                error("Win32ResExtractor::extract_resources() problem with resource extraction");
276
 
                return 0;
277
 
        }
278
 
 
279
 
        /* get named resource type if possible */
280
 
        type = NULL;
281
 
        if ((id = strtol(type_wr->id, 0, 10)) != 0)
282
 
                type = res_type_id_to_string(id);
283
 
 
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);
288
 
 
289
 
        return size;
290
 
}
291
 
 
292
 
/* extract_resource:
293
 
 *   Extract a resource, returning pointer to data.
294
 
 */
295
 
byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size,
296
 
                  bool *free_it, char *type, char *lang, bool raw) {
297
 
        char *str;
298
 
        int32 intval;
299
 
 
300
 
        /* just return pointer to data if raw */
301
 
        if (raw) {
302
 
                *free_it = false;
303
 
                /* get_resource_entry will print possible error */
304
 
                return get_resource_entry(fi, wr, size);
305
 
        }
306
 
 
307
 
        /* find out how to extract */
308
 
        str = type;
309
 
        if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) {
310
 
                if (intval == (int)RT_GROUP_ICON) {
311
 
                        *free_it = true;
312
 
                        return extract_group_icon_cursor_resource(fi, wr, lang, size, true);
313
 
                }
314
 
                if (intval == (int)RT_GROUP_CURSOR) {
315
 
                        *free_it = true;
316
 
                        return extract_group_icon_cursor_resource(fi, wr, lang, size, false);
317
 
                }
318
 
        }
319
 
 
320
 
        return NULL;
321
 
}
322
 
 
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.
327
 
 *
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
333
 
 *   or cursor group.
334
 
 */
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;
339
 
        byte *memory;
340
 
        int c, offset, skipped;
341
 
        int size;
342
 
 
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 */
347
 
                return NULL;
348
 
        }
349
 
 
350
 
        /* calculate total size of output file */
351
 
        RETURN_IF_BAD_POINTER(NULL, icondir->count);
352
 
        skipped = 0;
353
 
        for (c = 0 ; c < FROM_LE_16(icondir->count) ; c++) {
354
 
                int level;
355
 
                int iconsize;
356
 
                char name[14];
357
 
                WinResource *fwr;
358
 
 
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));*/
366
 
 
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);
370
 
                if (fwr == NULL) {
371
 
                        error("%s: could not find `%s' in `%s' resource.",
372
 
                                        _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
373
 
                        return NULL;
374
 
                }
375
 
 
376
 
                if (get_resource_entry(fi, fwr, &iconsize) != NULL) {
377
 
                    if (iconsize == 0) {
378
 
                                debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", _fileName.c_str(), name);
379
 
                                skipped++;
380
 
                                continue;
381
 
                    }
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));
385
 
                    }
386
 
                    size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
387
 
 
388
 
                    /* cursor resources have two additional WORDs that contain
389
 
                     * hotspot info */
390
 
                    if (!is_icon)
391
 
                        size -= sizeof(uint16)*2;
392
 
                }
393
 
        }
394
 
        offset = sizeof(Win32CursorIconFileDir) + (FROM_LE_16(icondir->count)-skipped) * sizeof(Win32CursorIconFileDirEntry);
395
 
        size += offset;
396
 
        *ressize = size;
397
 
 
398
 
        /* allocate that much memory */
399
 
        memory = (byte *)malloc(size);
400
 
        fileicondir = (Win32CursorIconFileDir *)memory;
401
 
 
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);
406
 
 
407
 
        /* transfer each cursor/icon: Win32CursorIconDirEntry and data */
408
 
        skipped = 0;
409
 
        for (c = 0 ; c < FROM_LE_16(icondir->count) ; c++) {
410
 
                int level;
411
 
                char name[14];
412
 
                WinResource *fwr;
413
 
                byte *data;
414
 
 
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);
418
 
                if (fwr == NULL) {
419
 
                        error("%s: could not find `%s' in `%s' resource.",
420
 
                                _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
421
 
                        return NULL;
422
 
                }
423
 
 
424
 
                /* get data and size of that resource */
425
 
                data = (byte *)get_resource_entry(fi, fwr, &size);
426
 
                if (data == NULL) {
427
 
                        /* get_resource_entry has printed error */
428
 
                        return NULL;
429
 
                }
430
 
                if (size == 0) {
431
 
                    skipped++;
432
 
                    continue;
433
 
                }
434
 
 
435
 
                /* copy ICONDIRENTRY (not including last dwImageOffset) */
436
 
                memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c],
437
 
                        sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32));
438
 
 
439
 
                /* special treatment for cursors */
440
 
                if (!is_icon) {
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;
445
 
                }
446
 
 
447
 
                /* set image offset and increase it */
448
 
                fileicondir->entries[c-skipped].dib_offset = TO_LE_32(offset);
449
 
 
450
 
                /* transfer resource into file memory */
451
 
                if (is_icon) {
452
 
                        memcpy(&memory[offset], data, FROM_LE_32(icondir->entries[c].bytes_in_res));
453
 
                } else {
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;
459
 
                }
460
 
 
461
 
                /* increase the offset pointer */
462
 
                offset += FROM_LE_32(icondir->entries[c].bytes_in_res);
463
 
        }
464
 
 
465
 
        return memory;
466
 
}
467
 
 
468
 
/* check_offset:
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.
472
 
 */
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);
475
 
 
476
 
        debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x",
477
 
                need_size, total_size, (uint)((byte *)offset - memory), size);
478
 
 
479
 
        if (need_size < 0 || need_size > total_size) {
480
 
                error("%s: premature end", name);
 
124
 
 
125
                if (!_exe.loadFromEXE(_fileName))
 
126
                        error("Cannot open file %s", _fileName.c_str());
 
127
        }
 
128
 
 
129
        Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(_exe, id);
 
130
 
 
131
        if (!group)
481
132
                return false;
482
 
        }
483
 
 
484
 
        return true;
485
 
}
486
 
 
487
 
 
488
 
/* do_resources:
489
 
 *   Do something for each resource matching type, name and lang.
490
 
 */
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;
495
 
        int size;
496
 
 
497
 
        type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1);
498
 
        name_wr = type_wr + 1;
499
 
        lang_wr = type_wr + 2;
500
 
 
501
 
        size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, data);
502
 
 
503
 
        free(type_wr);
504
 
 
505
 
        return size;
506
 
}
507
 
 
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))
510
 
 
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))
513
 
 
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) {
517
 
        int c, rescnt;
518
 
        WinResource *wr;
519
 
        uint32 size = 0;
520
 
 
521
 
        /* get a list of all resources at this level */
522
 
        wr = list_resources(fi, base, &rescnt);
523
 
        if (wr == NULL) {
524
 
                if (size != 0)
525
 
                        return size;
526
 
                else
527
 
                        return 0;
528
 
        }
529
 
 
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));
534
 
 
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);
539
 
                        else
540
 
                                size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data);
541
 
                }
542
 
        }
543
 
 
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));
547
 
 
548
 
        return size;
549
 
}
550
 
 
551
 
bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) {
552
 
        if (wr->numeric_id) {
553
 
                int32 cmp1, cmp2;
554
 
                if (id[0] == '+')
555
 
                        return false;
556
 
                if (id[0] == '-')
557
 
                        id++;
558
 
                if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2)
559
 
                        return false;
560
 
        } else {
561
 
                if (id[0] == '-')
562
 
                        return false;
563
 
                if (id[0] == '+')
564
 
                        id++;
565
 
                if (strcmp(wr->id, id))
566
 
                        return false;
567
 
        }
568
 
 
569
 
        return true;
570
 
}
571
 
 
572
 
bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) {
573
 
        if (value & IMAGE_RESOURCE_NAME_IS_STRING) {    /* numeric id */
574
 
                int c, len;
575
 
                uint16 *mem = (uint16 *)
576
 
                  (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING));
577
 
 
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);
582
 
 
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;
586
 
                wr->id[len] = '\0';
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;
592
 
        }
593
 
 
594
 
        return true;
595
 
}
596
 
 
597
 
byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) {
598
 
        byte *result;
599
 
 
600
 
        Win32ImageResourceDataEntry *dataent;
601
 
 
602
 
        dataent = (Win32ImageResourceDataEntry *) wr->children;
603
 
        RETURN_IF_BAD_POINTER(NULL, *dataent);
604
 
        *size = FROM_LE_32(dataent->size);
605
 
 
606
 
        result = fi->memory + FROM_LE_32(dataent->offset_to_data);
607
 
 
608
 
        RETURN_IF_BAD_OFFSET(NULL, result, *size);
609
 
 
610
 
        return result;
611
 
}
612
 
 
613
 
Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) {
614
 
        WinResource *wr;
615
 
        int c, rescnt;
616
 
        Win32ImageResourceDirectoryEntry *dirent
617
 
          = (Win32ImageResourceDirectoryEntry *)(pe_res + 1);
618
 
 
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);
622
 
        *count = rescnt;
623
 
 
624
 
        /* allocate WinResource's */
625
 
        wr = (WinResource *)malloc(sizeof(WinResource) * rescnt);
626
 
 
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;
631
 
                wr[c].level = level;
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);
634
 
 
635
 
                /* fill in wr->id, wr->numeric_id */
636
 
                if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
637
 
                        free(wr);
638
 
                        return NULL;
639
 
                }
640
 
        }
641
 
 
642
 
        return wr;
643
 
}
644
 
 
645
 
 
646
 
/* list_resources:
647
 
 *   Return an array of WinResource's in the current
648
 
 *   resource level specified by _res->
649
 
 */
650
 
Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) {
651
 
        if (res != NULL && !res->is_directory)
652
 
                return NULL;
653
 
 
654
 
        return list_pe_resources(fi, (Win32ImageResourceDirectory *)
655
 
                         (res == NULL ? fi->first_resource : res->children),
656
 
                         (res == NULL ? 0 : res->level+1),
657
 
                         count);
658
 
}
659
 
 
660
 
/* read_library:
661
 
 *   Read header and get resource directory offset in a Windows library
662
 
 *    (AKA module).
663
 
 *
664
 
 */
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);
670
 
 
671
 
                RETURN_IF_BAD_POINTER(false, mz_header->lfanew);
672
 
 
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);
676
 
 
677
 
                if (mz_header->lfanew < sizeof(DOSImageHeader)) {
678
 
                        error("%s: not a Windows library", _fileName.c_str());
679
 
                        return false;
680
 
                }
681
 
        }
682
 
 
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;
687
 
                int d;
688
 
 
689
 
                // Fix image header endianess
690
 
                fix_win32_image_header_endian(PE_HEADER(fi->memory));
691
 
 
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 */
696
 
                        return false;
697
 
                }
698
 
                fi->memory = (byte *)realloc(fi->memory, fi->total_size);
699
 
 
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);
703
 
 
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;
708
 
 
709
 
                        if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
710
 
                                continue;
711
 
 
712
 
                        //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size)
713
 
 
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);
720
 
                        }
721
 
                }
722
 
 
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());
728
 
                        return false;
729
 
                }
730
 
 
731
 
                fix_win32_image_data_directory(dir);
732
 
 
733
 
                fi->first_resource = fi->memory + dir->virtual_address;
734
 
                return true;
735
 
        }
736
 
 
737
 
        /* other (unknown) header signature was found */
738
 
        error("%s: not a Windows library", _fileName.c_str());
739
 
        return false;
740
 
}
741
 
 
742
 
/* calc_vma_size:
743
 
 *   Calculate the total amount of memory needed for a 32-bit Windows
744
 
 *   module. Returns -1 if file was too small.
745
 
 */
746
 
int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
747
 
    Win32ImageSectionHeader *seg;
748
 
    int c, segcount, size;
749
 
 
750
 
        size = 0;
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;
753
 
 
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.
757
 
         */
758
 
        if (segcount == 0)
759
 
                return fi->total_size;
760
 
 
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);
766
 
 
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);
770
 
                seg++;
771
 
    }
772
 
 
773
 
    return size;
774
 
}
775
 
 
776
 
Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) {
777
 
        int c, rescnt;
778
 
        WinResource *return_wr;
779
 
 
780
 
        wr = list_resources(fi, wr, &rescnt);
781
 
        if (wr == NULL)
782
 
                return NULL;
783
 
 
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));
789
 
 
790
 
                        /* free old WinResource */
791
 
                        free(wr);
792
 
                        return return_wr;
793
 
                }
794
 
        }
795
 
 
796
 
        return NULL;
797
 
}
798
 
 
799
 
Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) {
800
 
        WinResource *wr;
801
 
 
802
 
        *level = 0;
803
 
        if (type == NULL)
804
 
                return NULL;
805
 
        wr = find_with_resource_array(fi, NULL, type);
806
 
        if (wr == NULL || !wr->is_directory)
807
 
                return wr;
808
 
 
809
 
        *level = 1;
810
 
        if (name == NULL)
811
 
                return wr;
812
 
        wr = find_with_resource_array(fi, wr, name);
813
 
        if (wr == NULL || !wr->is_directory)
814
 
                return wr;
815
 
 
816
 
        *level = 2;
817
 
        if (language == NULL)
818
 
                return wr;
819
 
        wr = find_with_resource_array(fi, wr, language);
820
 
        return wr;
821
 
}
822
 
 
823
 
#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2)
824
 
 
825
 
 
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;
830
 
        uint32 offset;
831
 
        uint32 c, d;
832
 
        int completed;
833
 
        int matched = 0;
834
 
        MemoryReadStream *in = new MemoryReadStream(data, datasize);
835
 
 
836
 
        if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry)))
837
 
                goto cleanup;
838
 
        fix_win32_cursor_icon_file_dir_endian(&dir);
839
 
 
840
 
        if (dir.reserved != 0) {
841
 
                error("not an icon or cursor file (reserved non-zero)");
842
 
                goto cleanup;
843
 
        }
844
 
        if (dir.type != 1 && dir.type != 2) {
845
 
                error("not an icon or cursor file (wrong type)");
846
 
                goto cleanup;
847
 
        }
848
 
 
849
 
        entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry));
850
 
        for (c = 0; c < dir.count; c++) {
851
 
                if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry)))
852
 
                        goto cleanup;
853
 
                fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]);
854
 
                if (entries[c].reserved != 0)
855
 
                        error("reserved is not zero");
856
 
        }
857
 
 
858
 
        offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry));
859
 
 
860
 
        for (completed = 0; completed < dir.count; ) {
861
 
                uint32 min_offset = 0x7fffffff;
862
 
                int previous = completed;
863
 
 
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;
872
 
                                byte *row = NULL;
873
 
 
874
 
                                if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader)))
875
 
                                        goto local_cleanup;
876
 
 
877
 
                                fix_win32_bitmap_info_header_endian(&bitmap);
878
 
                                if (bitmap.size < sizeof(Win32BitmapInfoHeader)) {
879
 
                                        error("bitmap header is too short");
880
 
                                        goto local_cleanup;
881
 
                                }
882
 
                                if (bitmap.compression != 0) {
883
 
                                        error("compressed image data not supported");
884
 
                                        goto local_cleanup;
885
 
                                }
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);
898
 
                                }
899
 
                                offset += bitmap.size;
900
 
 
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))
905
 
                                                goto local_cleanup;
906
 
                                        offset += sizeof(Win32RGBQuad) * palette_count;
907
 
                                }
908
 
 
909
 
                                width = bitmap.width;
910
 
                                height = ABS(bitmap.height)/2;
911
 
 
912
 
                                image_size = height * ROW_BYTES(width * bitmap.bit_count);
913
 
                                mask_size = height * ROW_BYTES(width);
914
 
 
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)",
917
 
                                            entries[c].dib_size,
918
 
                                            (int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
919
 
                                        );
920
 
 
921
 
                                image_data = (byte *)malloc(image_size);
922
 
                                if (!in->read(image_data, image_size))
923
 
                                        goto local_cleanup;
924
 
 
925
 
                                mask_data = (byte *)malloc(mask_size);
926
 
                                if (!in->read(mask_data, mask_size))
927
 
                                        goto local_cleanup;
928
 
 
929
 
                                offset += image_size;
930
 
                                offset += mask_size;
931
 
                                completed++;
932
 
                                matched++;
933
 
 
934
 
                                *hotspot_x = entries[c].hotspot_x;
935
 
                                *hotspot_y = entries[c].hotspot_y;
936
 
                                *w = width;
937
 
                                *h = height;
938
 
                                *keycolor = 0;
939
 
                                *cursor = (byte *)malloc(width * height);
940
 
 
941
 
                                row = (byte *)malloc(width * 4);
942
 
 
943
 
                                for (d = 0; d < height; d++) {
944
 
                                        uint32 x;
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;
948
 
 
949
 
                                        for (x = 0; x < width; x++) {
950
 
 
951
 
                                                uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count);
952
 
 
953
 
                                                // We set up cursor palette for default cursor, so use it
954
 
                                                if (!simple_vec(mask_data, x + mmod, 1)) {
955
 
                                                        if (color) {
956
 
                                                                cursor[0][width * d + x] = 254; // white
957
 
                                                        } else {
958
 
                                                                cursor[0][width * d + x] = 253; // black
959
 
                                                        }
960
 
                                                } else {
961
 
                                                        cursor[0][width * d + x] = 255; // transparent
962
 
                                                }
963
 
                                                /*
964
 
 
965
 
                                                if (bitmap.bit_count <= 16) {
966
 
                                                        if (color >= palette_count) {
967
 
                                                                error("color out of range in image data");
968
 
                                                                goto local_cleanup;
969
 
                                                        }
970
 
                                                        row[4*x+0] = palette[color].red;
971
 
                                                        row[4*x+1] = palette[color].green;
972
 
                                                        row[4*x+2] = palette[color].blue;
973
 
 
974
 
                                                } else {
975
 
                                                        row[4*x+0] = (color >> 16) & 0xFF;
976
 
                                                        row[4*x+1] = (color >>  8) & 0xFF;
977
 
                                                        row[4*x+2] = (color >>  0) & 0xFF;
978
 
                                                }
979
 
                                                if (bitmap.bit_count == 32)
980
 
                                                    row[4*x+3] = (color >> 24) & 0xFF;
981
 
                                                else
982
 
                                                    row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
983
 
                                                */
984
 
                                        }
985
 
 
986
 
                                }
987
 
 
988
 
                                free(row);
989
 
                                free(palette);
990
 
                                if (image_data != NULL) {
991
 
                                        free(image_data);
992
 
                                        free(mask_data);
993
 
                                }
994
 
                                continue;
995
 
 
996
 
                        local_cleanup:
997
 
 
998
 
                                free(row);
999
 
                                free(palette);
1000
 
                                if (image_data != NULL) {
1001
 
                                        free(image_data);
1002
 
                                        free(mask_data);
1003
 
                                }
1004
 
                                goto cleanup;
1005
 
                        } else {
1006
 
                                if (entries[c].dib_offset > offset)
1007
 
                                        min_offset = MIN(min_offset, entries[c].dib_offset);
1008
 
                        }
1009
 
                }
1010
 
 
1011
 
                if (previous == completed) {
1012
 
                        if (min_offset < offset) {
1013
 
                                error("offset of bitmap header incorrect (too low)");
1014
 
                                goto cleanup;
1015
 
                        }
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;
1020
 
                }
1021
 
        }
1022
 
 
1023
 
        free(entries);
1024
 
        return matched;
1025
 
 
1026
 
cleanup:
1027
 
 
1028
 
        free(entries);
1029
 
        return -1;
1030
 
}
1031
 
 
1032
 
uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) {
1033
 
        switch (size) {
1034
 
        case 1:
1035
 
                return (data[ofs/8] >> (7 - ofs%8)) & 1;
1036
 
        case 2:
1037
 
                return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3;
1038
 
        case 4:
1039
 
                return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15;
1040
 
        case 8:
1041
 
                return data[ofs];
1042
 
        case 16:
1043
 
                return data[2*ofs] | data[2*ofs+1] << 8;
1044
 
        case 24:
1045
 
                return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16;
1046
 
        case 32:
1047
 
                return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24;
1048
 
        }
1049
 
 
1050
 
        return 0;
1051
 
}
1052
 
 
1053
 
void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) {
1054
 
    LE16(obj->reserved);
1055
 
        LE16(obj->type);
1056
 
    LE16(obj->count);
1057
 
}
1058
 
 
1059
 
void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) {
1060
 
    LE32(obj->size);
1061
 
    LE32(obj->width);
1062
 
    LE32(obj->height);
1063
 
    LE16(obj->planes);
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);
1071
 
}
1072
 
 
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);
1078
 
}
1079
 
 
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);
1090
 
}
1091
 
 
1092
 
/* fix_win32_image_header_endian:
1093
 
 * NOTE: This assumes that the optional header is always available.
1094
 
 */
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);
1104
 
 
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);
1136
 
}
1137
 
 
1138
 
void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) {
1139
 
    LE32(obj->virtual_address);
1140
 
    LE32(obj->size);
1141
 
}
1142
 
 
 
133
 
 
134
        Graphics::WinCursor *cursor = group->cursors[0].cursor;
 
135
 
 
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();
 
141
 
 
142
        // Convert from the paletted format to the SCUMM palette
 
143
        const byte *srcBitmap = cursor->getSurface();
 
144
 
 
145
        for (int i = 0; i < cursor->getWidth() * cursor->getHeight(); i++) {
 
146
                if (srcBitmap[i] == cursor->getKeyColor()) // Transparent
 
147
                        cc->bitmap[i] = 255;
 
148
                else if (srcBitmap[i] == 0)                // Black
 
149
                        cc->bitmap[i] = 253;
 
150
                else                                       // White
 
151
                        cc->bitmap[i] = 254;
 
152
        }
 
153
 
 
154
        delete group;
 
155
        return true;
 
156
}
1143
157
 
1144
158
MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
1145
159
        _resMgr = NULL;
1146
160
}
1147
161
 
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();
1153
167
                        error("Cannot open file %s", _fileName.c_str());
1154
168
        }
1155
169
 
1156
 
        Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', 1000 + id);
 
170
        Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', id + 1000);
1157
171
        
1158
172
        if (!dataStream)
1159
 
                error("There is no cursor ID #%d", 1000 + id);
1160
 
        
1161
 
        uint32 size = dataStream->size();
1162
 
        *buf = (byte *)malloc(size);
1163
 
        dataStream->read(*buf, size);
 
173
                return false;
 
174
 
 
175
        int keyColor; // HACK: key color is ignored
 
176
        _resMgr->convertCrsrCursor(dataStream, &cc->bitmap, cc->width, cc->height, cc->hotspotX, cc->hotspotY,
 
177
                                                keyColor, _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette),
 
178
                                                &cc->palette, cc->palSize);
 
179
 
1164
180
        delete dataStream;
1165
 
 
1166
 
        return size;
1167
 
}
1168
 
 
1169
 
int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
1170
 
                          int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) {
1171
 
                          
1172
 
        _resMgr->convertCrsrCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor,
1173
 
                                                _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize);
1174
 
        return 1;
 
181
        return true;
1175
182
}
1176
183
 
1177
184
void ScummEngine_v70he::readRoomsOffsets() {
1325
332
                if (!ptr)
1326
333
                        return 0;
1327
334
 
1328
 
                if (READ_BE_UINT32(ptr) == MKID_BE('RIFF')) {
 
335
                if (READ_BE_UINT32(ptr) == MKTAG('R','I','F','F')) {
1329
336
                        byte flags;
1330
337
                        int rate;
1331
338
 
1337
344
                        }
1338
345
                } else {
1339
346
                        ptr += 8 + READ_BE_UINT32(ptr + 12);
1340
 
                        if (READ_BE_UINT32(ptr) == MKID_BE('SBNG')) {
 
347
                        if (READ_BE_UINT32(ptr) == MKTAG('S','B','N','G')) {
1341
348
                                ptr += READ_BE_UINT32(ptr + 4);
1342
349
                        }
1343
350
 
1344
 
                        assert(READ_BE_UINT32(ptr) == MKID_BE('SDAT'));
 
351
                        assert(READ_BE_UINT32(ptr) == MKTAG('S','D','A','T'));
1345
352
                        size = READ_BE_UINT32(ptr + 4) - 8;
1346
353
                }
1347
354
        }