1
/* ScummVM - Graphic Adventure Engine
3
* ScummVM is the legal property of its developers, whose names
4
* are too numerous to list here. Please refer to the COPYRIGHT
5
* file distributed with this source distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
* $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-1/tools/sci/old_objects.cpp $
22
* $Id: old_objects.cpp 38423 2009-02-17 15:59:52Z sev $
26
#include <sciresource.h>
29
#include <vocabulary.h>
30
#include <old_objects.h>
38
#define printf sciprintf
39
/* Yeah, I shouldn't be doing this ;-) [CJR] */
42
FLEXARRAY_NOEXTRA(object*) fobjects;
44
static int knames_count;
47
static opcode* opcodes;
49
object **object_map, *object_root;
52
const char* globals[] = {
71
"enterDebugModeOnRoomExit",
82
"restoreSaveFont", /*dialogFont*/
89
"pointerToVersionNumber",
91
"pointerToSaveGameDirectory",
95
static int add_object(object* obj) {
96
FLEXARRAY_APPEND(object*, fobjects, obj, return 1);
100
static void dump(byte* data, int len) {
103
printf("%02X ", data[i++]);
104
if (i % 8 == 0) printf(" ");
105
if (i % 16 == 0) printf("\n");
107
if (i % 16) printf("\n");
110
static void printMethod(object* obj, int meth, int indent) {
111
script_method* m = obj->methods[meth];
114
for (j = 0; j < indent*2 - 1; j++) printf(" ");
115
printf("Method %s\n", snames[m->number]);
117
for (i = 0; i < m->used; i++) {
118
script_opcode op = m->data[i];
120
for (j = 0; j < indent; j++) printf(" ");
121
printf("%s ", opcodes[op.opcode].name);
124
case 0x21: { /*callk*/
125
if (op.arg1 > knames_count) printf("<no such kernel function %02X> ", op.arg1);
126
else printf("%s ", knames[op.arg1]);
127
printf("%02X", op.arg2);
130
case 0x28: { /*class*/
131
if (op.arg1 > max_object) printf("<no such class %02X>", op.arg1);
133
/* [DJ] op.arg1+1 adjusts for the <root> object */
134
if (fobjects.data[op.arg1+1] == 0) printf("<null object>");
135
else printf("%s", fobjects.data[op.arg1+1]->name);
140
if (op.arg1 > 0x20) printf("<no such global %02X> ", op.arg1);
141
else printf("%s ", globals[op.arg1]);
149
for (j = 0; j < 3; j++) {
150
switch (formats[op.opcode][j]) {
151
case Script_Invalid: {
152
printf("<invalid> ");
161
printf("%02X ", args[j]);
165
case Script_SVariable:
166
case Script_Variable:
167
case Script_SRelative:
168
case Script_Property:
173
printf("%04X ", args[j]);
177
if (args[j] < 0) printf("-%04X", -args[j]);
178
else printf("%04X", args[j]);
187
printf("<unknown arg type %d> ", formats[op.opcode][j]);
198
static void printObject_r(object* obj, int flags, int level) {
200
for (i = 0; i < level; i++) printf(" ");
201
if (obj == 0) printf("(null)\n");
203
printf("%s\n", obj->name);
204
if (flags&SCRIPT_PRINT_METHODS) {
205
for (i = 0; i < obj->method_count; i++) {
206
printMethod(obj, i, level + 1);
209
if (flags&SCRIPT_PRINT_CHILDREN) {
210
for (i = 0; i < obj->children.used; i++) {
211
printObject_r(obj->children.data[i], flags, level + 1);
217
void printObject(object* obj, int flags) {
218
printf("pO(%p, %d)\n", obj, flags);
219
printObject_r(obj, flags, 0);
222
static object* object_new() {
223
object* obj = (object*)sci_malloc(sizeof(object));
224
if (obj == 0) return 0;
227
FLEXARRAY_INIT(object*, obj->children);
229
obj->selector_count = 0;
230
obj->selector_numbers = 0;
232
obj->method_count = 0;
237
static int add_child(object* parent, object* child) {
238
FLEXARRAY_APPEND(object*, parent->children, child, return 1);
242
static object* fake_object(const char* reason) {
243
object* obj = object_new();
246
printf("object_new failed during fake for %s\n", reason);
251
if (add_child(object_root, obj)) {
253
printf("add_child failed during fake for %s\n", reason);
259
if (add_object(obj)) {
261
printf("add_object failed during fake for %s\n", reason);
263
/*FIXME: clean up parent*/
269
static script_method* decode_method(byte* data) {
273
static int count = 0;
277
if ((m = (script_method*)sci_malloc(sizeof(script_method))) == 0) return 0;
278
FLEXARRAY_INIT(script_opcode, *m);
281
int op = data[pos] >> 1;
282
int size = 2 - (data[pos] & 1);
287
FLEXARRAY_ADD_SPACE(script_opcode, *m, 1, return 0);
289
m->data[m->used-1].pos = pos;
290
m->data[m->used-1].opcode = op;
292
/*Copy the adresses of the args to an array for convenience*/
293
args[0] = &m->data[m->used-1].arg1;
294
args[1] = &m->data[m->used-1].arg2;
295
args[2] = &m->data[m->used-1].arg3;
297
/*Skip past the opcode*/
300
for (arg = 0; arg < 4; arg++) {
301
switch (formats[op][arg]) {
302
case Script_Invalid: { /*Can't happen(tm)*/
304
printf("Invalid opcode %02X at %04X in method %d\n", op, pos, count);
305
for (i = m->used - 9; i < m->used - 1; i++) {
306
printf("%s[%02X] ", opcodes[m->data[i].opcode].name, m->data[i].opcode);
307
dump(data + m->data[i].pos, m->data[i].size);
309
printf("Dump from %04X-%04X\n", pos - 16, pos + 16);
310
dump(data + pos - 16, 32);
313
case Script_None: { /*No more args*/
317
case Script_Byte: /*Just a one byte arg*/
319
*args[arg] = data[pos++];
322
case Script_Word: { /*A two byte arg*/
323
*args[arg] = getInt16(data + pos);
327
case Script_SWord: { /*A signed two-byte arg*/
328
int t = getInt16(data + pos);
329
if (t&0x8000) *args[arg] = -(t & 0x7FFF);
334
case Script_Variable: /*Size of arg depends on LSB in opcode*/
335
case Script_SVariable:
336
case Script_SRelative:
337
case Script_Property:
342
if (size == 1) *args[arg] = data[pos++];
344
*args[arg] = getInt16(data + pos);
349
case Script_End: { /*Special tag for ret*/
354
default: { /*Can't happen(tm)*/
355
printf("Unknown argument format %d for op %02X\n", formats[op][arg], op);
361
if (m->used) m->data[m->used-1].size = pos - old_pos;
368
void list_code_blocks(resource_t* r) {
369
int pos = getInt16(r->data + 2);
370
while (pos < r->size - 2) {
371
int type = getInt16(r->data + pos);
372
int len = getInt16(r->data + pos + 2);
373
if (type == 2) printf("%X-%X\n", pos, pos + len);
380
/*These expect the frame, the whole frame, and, well, other stuff too,
381
*I guess, as long as it looks like a frame*/
382
static int get_type(unsigned char* obj) {
383
return getInt16(obj);
386
static int get_length(unsigned char* obj) {
387
return getInt16(obj + 2);
390
static int get_selector_count(unsigned char* obj) {
391
return getInt16(obj + 10);
394
static int get_selector_value(unsigned char* obj, int sel) {
395
assert(sel < get_selector_count(obj));
396
return getInt16(obj + 12 + sel*2);
399
/*Bas things happen if the method offset value is wrong*/
400
static unsigned char* get_method_area(unsigned char* obj) {
401
return obj + getInt16(obj + 8) + 10;
404
static int get_method_count(unsigned char* obj) {
405
return getInt16(get_method_area(obj));
408
static int get_method_number(unsigned char* obj, int i) {
409
assert(i < get_method_count(obj));
410
return getInt16(get_method_area(obj) + 2 + 2*i);
413
static int get_method_location(unsigned char* obj, int i) {
414
assert(i < get_method_count(obj));
415
return getInt16(get_method_area(obj) + 4 + 2*get_method_count(obj) + 2*i);
419
/*Returns the position of the first frame of type 'type' in resource 'r',
420
*starting from the frame starting at 'start', or -1 on failure.
422
static int find_frame(resource_t* r, int type, unsigned int start) {
424
unsigned int pos = start;
425
unsigned char* frame;
427
assert(start <= r->size - 4);
430
printf("Searching for frame of type %d in script %03d, starting at %#x\n", type, r->number, start);
431
dump(r->data + start, 32);
434
/*Some times there's an extra byte at the beginning. Christoph?*/
436
if (pos == 0 && r->size >= 6 && \
437
!((0 < getInt16(r->data)) && (10 > getInt16(r->data)))) pos = 2;
442
frame = r->data + pos;
445
printf("offset = %#x\n", pos);
455
pos += get_length(frame);
456
if (pos > (r->size - 2))
458
frame += get_length(frame);
466
/*FIXME: lots of things are identical to read_object and read_class. Some of
467
*these would benefit from being put in separate functions.*/
469
static object* read_object(resource_mgr_t *resmgr, int script, int positions[1000]) {
470
resource_t* r = scir_find_resource(resmgr, sci_script, script, 0);
475
printf("Searching for object in script %03d\n", script);
477
if (r == 0) return 0;
479
/*Skip to the next object*/
481
printf("pre skip: pos=%#x\n", positions[script]);
483
pos = find_frame(r, 1, positions[script]);
485
printf("post skip: pos=%#x\n", pos);
487
if (pos == -1) return 0;
488
else positions[script] = pos + get_length(r->data + pos);
490
printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos));
493
/*Construct the object*/
498
if (get_selector_count(raw) < 4) obj->name = "<anonymous>";
500
if (get_selector_value(raw, 3))
501
obj->name = (char *) r->data + get_selector_value(raw, 3);
502
else obj->name = "<null>";
505
/*Fill in the class*/
506
if (get_selector_count(raw) == 0) obj->parent = object_root;
508
int parent_id = get_selector_value(raw, 1);
509
if (parent_id >= fobjects.used) {
513
if (parent_id < 1) obj->parent = object_root;
514
else obj->parent = fobjects.data[parent_id];
517
/*Add the object to the class*/
522
if (add_child(obj->parent, obj)) {
526
if (add_object(obj)) {
531
/*FIXME: decode selectors here*/
533
obj->method_count = get_method_count(raw);
534
obj->methods = (script_method**)sci_malloc(obj->method_count * sizeof(script_method));
535
if (obj->methods == 0) {
540
for (i = 0; i < obj->method_count; i++) {
541
int number = get_method_number(raw, i);
542
int position = get_method_location(raw, i);
544
if ((obj->methods[i] = decode_method(r->data + position)) == 0) {
545
obj->method_count = i - 1;
548
obj->methods[i]->number = number;
555
static object* read_class(resource_mgr_t *resmgr, int script, int positions[1000]) {
556
resource_t* r = scir_find_resource(resmgr, sci_script, script, 0);
561
printf("Searching for class in script %03d\n", script);
563
if (r == 0) return fake_object("<resource not found>");
565
/*Skip to the next class*/
567
printf("pre skip: pos=%#x\n", positions[script]);
569
pos = find_frame(r, 6, positions[script]);
571
printf("post skip: pos=%#x\n", pos);
573
if (pos == -1) return fake_object("<no more classes in script>");
574
else positions[script] = pos + get_length(r->data + pos);
576
printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos));
579
/*Construct the object*/
584
if (get_selector_count(raw) < 4) obj->name = "<anonymous>";
586
if (get_selector_value(raw, 3))
587
obj->name = (char *) r->data + get_selector_value(raw, 3);
588
else obj->name = "<null>";
591
/*Fill in the parent*/
592
if (get_selector_count(raw) == 0) obj->parent = object_root;
594
int superclass_id = get_selector_value(raw, 1);
595
printf("superclass==%d\n", superclass_id);
596
if (superclass_id >= fobjects.used) {
598
return fake_object("<no such superclass>");
600
if (superclass_id < 1) obj->parent = object_root;
601
else obj->parent = fobjects.data[superclass_id];
604
/*Add the class to the hierarchy*/
607
return fake_object("<null parent>");
609
if (add_child(obj->parent, obj)) {
611
return fake_object("<add_child failed>");
613
if (add_object(obj)) {
615
return fake_object("<add_object failed>");
618
/*FIXME: decode selectors and methods here*/
623
void freeObject(object* obj) {
625
for (i = 0; i < obj->children.used; i++) freeObject(obj->children.data[i]);
629
static int objects_init(resource_mgr_t *resmgr) {
630
FLEXARRAY_INIT(object*, fobjects);
633
if ((object_root = object_new()) == 0) return 1;
634
object_root->name = "<root>";
635
add_object(object_root);
637
opcodes = vocabulary_get_opcodes(resmgr);
638
knames = vocabulary_get_knames(resmgr, &knames_count);
639
snames = vocabulary_get_snames(resmgr, NULL, 0);
644
int loadObjects(resource_mgr_t *resmgr) {
646
int *classes, class_count;
649
if (objects_init(resmgr)) {
651
perror("objects_init");
655
classes = vocabulary_get_classes(resmgr, &class_count);
657
for (i = 0; i < 1000; i++) positions[i] = 0;
658
for (i = 0; i < class_count; i++) {
660
printf("\n\nReading class 0x%02X\n", i);
662
if (read_class(resmgr, classes[i], positions) == 0) {
664
fprintf(stderr, "Failed to load class %d, which is a parent.\n", i);
670
for (i = 0; i < 1000; i++) positions[i] = 0;
671
for (i = 0; i < 1000; i++) while (read_object(resmgr, i, positions));
673
object_map = fobjects.data;
674
max_object = fobjects.used;