diff options
author | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
---|---|---|
committer | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
commit | fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch) | |
tree | ce87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/scicore/old_objects.c | |
parent | 7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff) | |
download | scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2 scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip |
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/scicore/old_objects.c')
-rw-r--r-- | engines/sci/scicore/old_objects.c | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/engines/sci/scicore/old_objects.c b/engines/sci/scicore/old_objects.c new file mode 100644 index 0000000000..8408373537 --- /dev/null +++ b/engines/sci/scicore/old_objects.c @@ -0,0 +1,716 @@ +#include <sciresource.h> +#include <console.h> +#include <script.h> +#include <vocabulary.h> +#include <old_objects.h> +#include <stdio.h> +#include <stdlib.h> +#include <util.h> +#include <vm.h> +#include <assert.h> + +#ifdef SCI_CONSOLE +#define printf sciprintf +/* Yeah, I shouldn't be doing this ;-) [CJR] */ +#endif + +FLEXARRAY_NOEXTRA(object*) fobjects; + +static int knames_count; +static char** knames; +static char** snames; +static opcode* opcodes; + +object **object_map, *object_root; +int max_object; + +const char* globals[] = { + /*00*/ + "ego", + "GAMEID", + "roomXX", + "speed", + /*04*/ + "quitFlag", + "cast", + "regions", + "timer", + /*08*/ + "sounds", + "inv", + "eventHandler", + "roomNumberExit", + /*0C*/ + "previousRoomNumber", + "roomNumber", + "enterDebugModeOnRoomExit", + "score", + /*10*/ + "maximumScore", + "11", + "speed", + "13", + /*14*/ + "14", + "loadCursor", + "normalFont", + "restoreSaveFont", /*dialogFont*/ + /*18*/ + "18", + "19", + "defaultFont", + "1B", + /*1C*/ + "pointerToVersionNumber", + "locales", + "pointerToSaveGameDirectory", + "1F" +}; + +static int add_object(object* obj) +{ + FLEXARRAY_APPEND(object*, fobjects, obj, return 1); + return 0; +} + +static void dump(byte* data, int len) +{ + int i=0; + while(i<len) + { + printf("%02X ", data[i++]); + if(i%8==0) printf(" "); + if(i%16==0) printf("\n"); + } + if(i%16) printf("\n"); +} + +static void printMethod(object* obj, int meth, int indent) +{ + script_method* m=obj->methods[meth]; + int i, j; + + for(j=0; j<indent*2-1; j++) printf(" "); + printf("Method %s\n", snames[m->number]); + + for(i=0; i<m->used; i++) + { + script_opcode op=m->data[i]; + + for(j=0; j<indent; j++) printf(" "); + printf("%s ", opcodes[op.opcode].name); + + switch(op.opcode) + { + case 0x21: /*callk*/ + { + if(op.arg1>knames_count) printf("<no such kernel function %02X> ", op.arg1); + else printf("%s ", knames[op.arg1]); + printf("%02X", op.arg2); + } break; + case 0x28: /*class*/ + { + if(op.arg1>max_object) printf("<no such class %02X>", op.arg1); + else + { + /* [DJ] op.arg1+1 adjusts for the <root> object */ + if(fobjects.data[op.arg1+1]==0) printf("<null object>"); + else printf("%s", fobjects.data[op.arg1+1]->name); + } + } break; + case 0x44: + { + if(op.arg1>0x20) printf("<no such global %02X> ", op.arg1); + else printf("%s ", globals[op.arg1]); + } break; + default: + { + int args[3]; + args[0]=op.arg1; + args[1]=op.arg2; + args[2]=op.arg3; + for(j=0; j<3; j++) + { + switch(formats[op.opcode][j]) + { + case Script_Invalid: + { + printf("<invalid> "); + } break; + case Script_None: + { + j=3; + } break; + case Script_SByte: + case Script_Byte: + { + printf("%02X ", args[j]); + } break; + case Script_Word: + case Script_SVariable: + case Script_Variable: + case Script_SRelative: + case Script_Property: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: + { + printf("%04X ", args[j]); + } break; + case Script_SWord: + { + if(args[j]<0) printf("-%04X", -args[j]); + else printf("%04X", args[j]); + } break; + case Script_End: + { + printf("\n"); + return; + } break; + default: + { + printf("<unknown arg type %d> ", formats[op.opcode][j]); + } + } + } + } break; + } + printf("\n"); + } +} + +static void printObject_r(object* obj, int flags, int level) +{ + int i; + for(i=0; i<level; i++) printf(" "); + if(obj==0) printf("(null)\n"); + else + { + printf("%s\n", obj->name); + if(flags&SCRIPT_PRINT_METHODS) + { + for(i=0; i<obj->method_count; i++) + { + printMethod(obj, i, level+1); + } + } + if(flags&SCRIPT_PRINT_CHILDREN) + { + for(i=0; i<obj->children.used; i++) + { + printObject_r(obj->children.data[i], flags, level+1); + } + } + } +} + +void printObject(object* obj, int flags) +{ + printf("pO(%p, %d)\n", obj, flags); + printObject_r(obj, flags, 0); +} + +static object* object_new() +{ + object* obj= (object*)sci_malloc(sizeof(object)); + if(obj==0) return 0; + + obj->parent=0; + FLEXARRAY_INIT(object*, obj->children); + obj->name=0; + obj->selector_count=0; + obj->selector_numbers=0; + obj->methods=0; + obj->method_count=0; + + return obj; +} + +static int add_child(object* parent, object* child) +{ + FLEXARRAY_APPEND(object*, parent->children, child, return 1); + return 0; +} + +static object* fake_object(const char* reason) +{ + object* obj=object_new(); + if(obj==0) + { + #ifdef SCRIPT_DEBUG + printf("object_new failed during fake for %s\n", reason); + #endif + free(obj); + return 0; + } + if(add_child(object_root, obj)) + { + #ifdef SCRIPT_DEBUG + printf("add_child failed during fake for %s\n", reason); + #endif + free(obj); + return 0; + } + obj->name=reason; + if(add_object(obj)) + { + #ifdef SCRIPT_DEBUG + printf("add_object failed during fake for %s\n", reason); + #endif + /*FIXME: clean up parent*/ + return 0; + } + return obj; +} + +static script_method* decode_method(byte* data) +{ + script_method* m; + int done=0; + int pos=0; + static int count=0; + + count++; + + if((m= (script_method*)sci_malloc(sizeof(script_method)))==0) return 0; + FLEXARRAY_INIT(script_opcode, *m); + + while(!done) + { + int op=data[pos]>>1; + int size=2-(data[pos]&1); + int* args[3]; + int arg; + int old_pos; + + FLEXARRAY_ADD_SPACE(script_opcode, *m, 1, return 0); + old_pos=pos; + m->data[m->used-1].pos=pos; + m->data[m->used-1].opcode=op; + + /*Copy the adresses of the args to an array for convenience*/ + args[0]=&m->data[m->used-1].arg1; + args[1]=&m->data[m->used-1].arg2; + args[2]=&m->data[m->used-1].arg3; + + /*Skip past the opcode*/ + pos++; + + for(arg=0; arg<4; arg++) + { + switch(formats[op][arg]) + { + case Script_Invalid: /*Can't happen(tm)*/ + { + int i; + printf("Invalid opcode %02X at %04X in method %d\n", op, pos, count); + for(i=m->used-9; i<m->used-1; i++) + { + printf("%s[%02X] ", opcodes[m->data[i].opcode].name, m->data[i].opcode); + dump(data+m->data[i].pos, m->data[i].size); + } + printf("Dump from %04X-%04X\n", pos-16, pos+16); + dump(data + pos - 16, 32); + } break; + case Script_None: /*No more args*/ + { + arg=4; + } break; + case Script_Byte: /*Just a one byte arg*/ + case Script_SByte: + { + *args[arg]=data[pos++]; + } break; + case Script_Word: /*A two byte arg*/ + { + *args[arg]=getInt16(data+pos); + pos+=2; + } break; + case Script_SWord: /*A signed two-byte arg*/ + { + int t=getInt16(data+pos); + if(t&0x8000) *args[arg]=-(t&0x7FFF); + else *args[arg]=t; + pos+=2; + } break; + case Script_Variable: /*Size of arg depends on LSB in opcode*/ + case Script_SVariable: + case Script_SRelative: + case Script_Property: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: + { + if(size==1) *args[arg]=data[pos++]; + else + { + *args[arg]=getInt16(data+pos); + pos+=2; + } + } break; + case Script_End: /*Special tag for ret*/ + { + done=1; + arg=4; + } break; + default: /*Can't happen(tm)*/ + { + printf("Unknown argument format %d for op %02X\n", formats[op][arg], op); + } break; + } + } + fflush(stdout); + if (m->used) m->data[m->used-1].size=pos-old_pos; + } + + return m; +} + +#ifdef SCRIPT_DEBUG +void list_code_blocks(resource_t* r) +{ + int pos=getInt16(r->data+2); + while(pos<r->size-2) + { + int type=getInt16(r->data+pos); + int len=getInt16(r->data+pos+2); + if(type==2) printf("%X-%X\n", pos, pos+len); + pos+=len; + } +} +#endif + + +/*These expect the frame, the whole frame, and, well, other stuff too, + *I guess, as long as it looks like a frame*/ +static int get_type(unsigned char* obj) +{ + return getInt16(obj); +} + +static int get_length(unsigned char* obj) +{ + return getInt16(obj+2); +} + +static int get_selector_count(unsigned char* obj) +{ + return getInt16(obj+10); +} + +static int get_selector_value(unsigned char* obj, int sel) +{ + assert(sel<get_selector_count(obj)); + return getInt16(obj + 12 + sel*2); +} + +/*Bas things happen if the method offset value is wrong*/ +static unsigned char* get_method_area(unsigned char* obj) +{ + return obj+getInt16(obj+8)+10; +} + +static int get_method_count(unsigned char* obj) +{ + return getInt16(get_method_area(obj)); +} + +static int get_method_number(unsigned char* obj, int i) +{ + assert(i<get_method_count(obj)); + return getInt16(get_method_area(obj)+2+2*i); +} + +static int get_method_location(unsigned char* obj, int i) +{ + assert(i<get_method_count(obj)); + return getInt16(get_method_area(obj)+4+2*get_method_count(obj)+2*i); +} + + +/*Returns the position of the first frame of type 'type' in resource 'r', + *starting from the frame starting at 'start', or -1 on failure. + */ +static int find_frame(resource_t* r, int type, unsigned int start) +{ + int t=-1; + unsigned int pos = start; + unsigned char* frame; + + assert(start<=r->size-4); + + #ifdef SCRIPT_DEBUG + printf("Searching for frame of type %d in script %03d, starting at %#x\n", type, r->number, start); + dump(r->data+start, 32); + #endif + + /*Some times there's an extra byte at the beginning. Christoph?*/ +#if 1 + if(pos==0 && r->size>=6 && \ + !((0<getInt16(r->data)) && (10>getInt16(r->data)))) pos=2; +#else + if(pos == 0) + pos = 2; +#endif + frame = r->data + pos; + while(1) + { +#ifdef SCRIPT_DEBUG + printf("offset = %#x\n", pos); + dump(frame, 32); +#endif + t = get_type(frame); + if(t == type) + break; + + if(t == 0) + return -1; + + pos+=get_length(frame); + if(pos > (r->size - 2)) + return -1; + frame+=get_length(frame); + } + + return pos; +} + + + +/*FIXME: lots of things are identical to read_object and read_class. Some of + *these would benefit from being put in separate functions.*/ + +static object* read_object(resource_mgr_t *resmgr, int script, int positions[1000]) +{ + resource_t* r = scir_find_resource(resmgr, sci_script, script, 0); + unsigned char* raw; + int pos; + object* obj; + + printf("Searching for object in script %03d\n", script); + + if(r==0) return 0; + + /*Skip to the next object*/ + #ifdef SCRIPT_DEBUG + printf("pre skip: pos=%#x\n", positions[script]); + #endif + pos=find_frame(r, 1, positions[script]); + #ifdef SCRIPT_DEBUG + printf("post skip: pos=%#x\n", pos); + #endif + if(pos==-1) return 0; + else positions[script]=pos+get_length(r->data+pos); + #ifdef SCRIPT_DEBUG + printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data+pos)); + #endif + + /*Construct the object*/ + obj=object_new(); + raw=r->data+pos; + + /*Fill in the name*/ + if(get_selector_count(raw)<4) obj->name="<anonymous>"; + else + { + if (get_selector_value(raw, 3)) + obj->name = (char *) r->data + get_selector_value(raw, 3); + else obj->name="<null>"; + } + + /*Fill in the class*/ + if(get_selector_count(raw)==0) obj->parent=object_root; + else + { + int parent_id=get_selector_value(raw, 1); + if(parent_id>=fobjects.used) + { + free(obj); + return 0; + } + if(parent_id<1) obj->parent=object_root; + else obj->parent=fobjects.data[parent_id]; + } + + /*Add the object to the class*/ + if(!obj->parent) + { + free(obj); + return 0; + } + if(add_child(obj->parent, obj)){ + free(obj); + return 0; + } + if(add_object(obj)) + { + free(obj); + return 0; + } + + /*FIXME: decode selectors here*/ + + obj->method_count=get_method_count(raw); + obj->methods= (script_method**)sci_malloc(obj->method_count*sizeof(script_method)); + if(obj->methods==0) + { + free(obj); + return 0; + } else { + int i; + for(i=0; i<obj->method_count; i++) + { + int number=get_method_number(raw, i); + int position=get_method_location(raw, i); + + if((obj->methods[i]=decode_method(r->data+position))==0) + { + obj->method_count=i-1; + break; + } + obj->methods[i]->number=number; + } + } + + return obj; +} + +static object* read_class(resource_mgr_t *resmgr, int script, int positions[1000]) +{ + resource_t* r = scir_find_resource(resmgr, sci_script, script, 0); + unsigned char* raw; + int pos; + object* obj; + + printf("Searching for class in script %03d\n", script); + + if(r==0) return fake_object("<resource not found>"); + + /*Skip to the next class*/ + #ifdef SCRIPT_DEBUG + printf("pre skip: pos=%#x\n", positions[script]); + #endif + pos=find_frame(r, 6, positions[script]); + #ifdef SCRIPT_DEBUG + printf("post skip: pos=%#x\n", pos); + #endif + if(pos==-1) return fake_object("<no more classes in script>"); + else positions[script]=pos+get_length(r->data+pos); + #ifdef SCRIPT_DEBUG + printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data+pos)); + #endif + + /*Construct the object*/ + obj=object_new(); + raw=r->data+pos; + + /*Fill in the name*/ + if(get_selector_count(raw)<4) obj->name="<anonymous>"; + else + { + if (get_selector_value(raw, 3)) + obj->name = (char *) r->data + get_selector_value(raw, 3); + else obj->name="<null>"; + } + + /*Fill in the parent*/ + if(get_selector_count(raw)==0) obj->parent=object_root; + else + { + int superclass_id=get_selector_value(raw, 1); + printf("superclass==%d\n", superclass_id); + if(superclass_id>=fobjects.used) + { + free(obj); + return fake_object("<no such superclass>"); + } + if(superclass_id<1) obj->parent=object_root; + else obj->parent=fobjects.data[superclass_id]; + } + + /*Add the class to the hierarchy*/ + if(!obj->parent) + { + free(obj); + return fake_object("<null parent>"); + } + if(add_child(obj->parent, obj)){ + free(obj); + return fake_object("<add_child failed>"); + } + if(add_object(obj)) + { + free(obj); + return fake_object("<add_object failed>"); + } + + /*FIXME: decode selectors and methods here*/ + + return obj; +} + +void freeObject(object* obj) +{ + int i; + for(i=0; i<obj->children.used; i++) freeObject(obj->children.data[i]); + free(obj); +} + +static int objects_init(resource_mgr_t *resmgr) +{ + FLEXARRAY_INIT(object*, fobjects); + max_object=0; + + if((object_root=object_new())==0) return 1; + object_root->name="<root>"; + add_object(object_root); + + opcodes=vocabulary_get_opcodes(resmgr); + knames=vocabulary_get_knames(resmgr, &knames_count); + snames=vocabulary_get_snames(resmgr, NULL, 0); + + return 0; +} + +int loadObjects(resource_mgr_t *resmgr) +{ + int i; + int *classes, class_count; + int positions[1000]; + + if(objects_init(resmgr)) + { + #ifdef SCRIPT_DEBUG + perror("objects_init"); + #endif + return 1; + } + classes=vocabulary_get_classes(resmgr, &class_count); + + for(i=0; i<1000; i++) positions[i]=0; + for(i=0; i<class_count; i++) + { +#ifdef SCRIPT_DEBUG + printf ("\n\nReading class 0x%02X\n", i); +#endif + if(read_class(resmgr, classes[i], positions)==0) + { + #ifdef SCRIPT_DEBUG + fprintf(stderr, "Failed to load class %d, which is a parent.\n", i); + #endif + return 1; + } + } + + for(i=0; i<1000; i++) positions[i]=0; + for(i=0; i<1000; i++) while(read_object(resmgr, i, positions)); + + object_map=fobjects.data; + max_object=fobjects.used; + + return 0; +} + + |