void do_write_block(caValue* blockName, caValue* contents, caValue* reply) { Term* term = find_global(as_cstring(blockName)); // Create the block if needed if (term == NULL) term = apply(global_root_block(), FUNCS.section_block, TermList(), blockName); // Import the new block contents Block* block = nested_contents(term); rewrite_block(block, contents, reply); }
/** * add new symbol to global table * @param sname * @param identity * @param type * @param offset size in bytes * @param storage * @return new index */ int add_global (char *sname, int identity, int type, int offset, int storage) { SYMBOL *symbol; char *buffer_ptr; if ((current_symbol_table_idx = find_global(sname)) > -1) { return (current_symbol_table_idx); } if (global_table_index >= NUMBER_OF_GLOBALS) { error ("global symbol table overflow"); return (0); } current_symbol_table_idx = global_table_index; symbol = &symbol_table[current_symbol_table_idx]; buffer_ptr = symbol->name; /* FIXME: only copy so many bytes */ while (alphanumeric(*buffer_ptr++ = *sname++)); symbol->identity = identity; symbol->type = type; symbol->storage = storage; symbol->offset = offset; global_table_index++; return (current_symbol_table_idx); }
void newfunc_typed(int storage, char *n, int type) { int idx; SYMBOL *symbol; char an[NAMESIZE]; fexitlab = getlabel(); if ((idx = find_global(n)) > -1) { symbol = &symbol_table[idx]; if (symbol->identity != FUNCTION) multidef(n); } else { /* extern implies global scope */ idx = add_global(n, FUNCTION, CINT, 0, storage == EXTERN ? PUBLIC : storage); symbol = &symbol_table[idx]; } local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; argstk = 0; // ANSI style argument declaration if (doAnsiArguments()) { if (storage == EXTERN) { need_semicolon(); return; } /* No body .. just a definition */ if (match(";")) return; } else { // K&R style argument declaration while (!match(")")) { if (symname(an)) { if (find_locale(an) > -1) multidef(an); else { /* FIXME: struct */ add_local(an, 0, 0, argstk, AUTO); argstk = argstk + INTSIZE; } } else { error("illegal argument name"); junk(); } blanks(); if (!streq(line + lptr, ")")) { if (!match(",")) error("expected comma"); } if (endst()) break; } if (storage == EXTERN) { need_semicolon(); return; } /* No body .. just a definition */ if (match(";")) return; stkp = 0; argtop = argstk; while (argstk) { if ((type = get_type()) != -1) { notvoid(type); getarg(type); need_semicolon(); } else { error("wrong number args"); break; } } } if (symbol->offset == FUNCTION) multidef(n); symbol->offset = FUNCTION; output_string(n); output_label_terminator(); newline(); gen_prologue(); statement(YES); print_label(fexitlab); output_label_terminator(); newline(); gen_epilogue(); gen_modify_stack(0); gen_ret(); stkp = 0; local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; }
/** * declare a static variable * @param type * @param storage * @param mtag tag of struct whose members are being declared, or zero * @param otag tag of struct object being declared. only matters if mtag is non-zero * @param is_struct struct or union or no meaning * @return 1 if a function was parsed */ int declare_global(int type, int storage, TAG_SYMBOL *mtag, int otag, int is_struct) { int dim, identity; char sname[NAMESIZE]; FOREVER { FOREVER { if (endst ()) return 0; dim = 1; if (match ("*")) { identity = POINTER; } else { identity = VARIABLE; } if (!symname (sname)) illname (); if (match ("(")) { /* FIXME: We need to deal with pointer types properly here */ if (identity == POINTER) type = CINT; newfunc_typed(storage, sname, type); /* Can't int foo(x){blah),a=4; */ return 1; } /* FIXME: we need to deal with extern properly here */ if (find_global (sname) > -1) multidef (sname); if (identity == VARIABLE) notvoid(type); if (match ("[")) { dim = needsub (); //if (dim || storage == EXTERN) { identity = ARRAY; //} else { // identity = POINTER; //} } // add symbol if (mtag == 0) { // real variable, not a struct/union member identity = initials(sname, type, identity, dim, otag); add_global (sname, identity, type, (dim == 0 ? -1 : dim), storage); if (type == STRUCT) { symbol_table[current_symbol_table_idx].tagidx = otag; } break; } else if (is_struct) { // structure member, mtag->size is offset add_member(sname, identity, type, mtag->size, storage); // store (correctly scaled) size of member in tag table entry if (identity == POINTER) type = CINT; scale_const(type, otag, &dim); mtag->size += dim; } else { // union member, offset is always zero add_member(sname, identity, type, 0, storage); // store maximum member size in tag table entry if (identity == POINTER) type = CINT; scale_const(type, otag, &dim); if (mtag->size < dim) mtag->size = dim; } } if (!match (",")) return 0; } }
static PyObject * marshal_Load_internal(PyObject *py_stream, PyObject *py_callback, int skipcrc) { // Return value: New Reference char *stream; Py_ssize_t size; char *s; char *end; int type = -1; // current object type int shared = -1; // indicates whether current object is shared int i; char *error = "NO ERROR SPECIFIED"; char errortext[256]; Py_ssize_t length = 0; // generic length value. int shared_mapsize; int shared_count; // shared object index counter int *shared_map; // points to shared object mapping at end of stream PyObject **shared_obj = NULL; // holds the shared objects PyObject *obj = NULL; // currently decoded object PyObject *result = NULL; // final result int ct_ix = 0; struct Container ct_stack[MAX_DEPTH]; struct Container *container = &ct_stack[0]; if(PyString_AsStringAndSize(py_stream, &stream, &size) == -1) return NULL; s = stream; container->obj = NULL; container->type = 0; container->free = -1; container->index = 0; if(size < 6 || *s++ != PROTOCOL_ID) { int offset = 0; result = unpickle(py_stream, &offset); if(!result) goto cleanup; return result; } // how many shared objects in this stream? shared_mapsize = *(int32_t *)s; s += 4; // Security Check: assert there is enough data for that many items. if((5 + shared_mapsize*4) > size) { PyErr_Format(UnmarshalError, "Not enough room in stream for map. Wanted %d, but have only %d bytes remaining...", (shared_mapsize*4), ((int)size-5)); goto cleanup; } // ok, we got the map data right here... shared_map = (int32_t *)&stream[size - shared_mapsize * 4]; // Security Check #2: assert all map entries are between 1 and shared_mapsize for(i=0; i<shared_mapsize; i++) { if( (shared_map[i] > shared_mapsize) || (shared_map[i] < 1) ) { PyErr_SetString(UnmarshalError, "Bogus map data in marshal stream"); goto cleanup; } } // the start of which is incidentally also the end of the object data. end = (char *)shared_map; // create object table shared_obj = PyMem_MALLOC(shared_mapsize * sizeof(PyObject *)); if(!shared_obj) goto cleanup; // zero out object table for(shared_count = 0; shared_count < shared_mapsize; shared_count++) shared_obj[shared_count] = NULL; shared_count = 0; // start decoding. while(s < end) { // This outer loop is responsible for reading and decoding the next // object from the stream. The object is then handed to the inner loop, // which adds it to the current container, or returns it to the caller. // get type of next object to decode and check shared flag type = *s++; shared = type & SHARED_FLAG; type &= ~SHARED_FLAG; // if token uses a normal length value, read it now. if(needlength[type]) { READ_LENGTH; } else length = 0; #if MARSHAL_DEBUG // if(shared) { char text[220]; DEBUG_INDENT; sprintf(text, "pos:%4d type:%s(0x%02x) shared:%d len:%4d map:[", s-stream, tokenname[type], type, shared?1:0, length); printf(text); for(i=0; i<shared_mapsize; i++) printf("%d(%d),", shared_obj[i], shared_obj[i] ? ((PyObject *)(shared_obj[i]))->ob_refcnt : 0); printf("]\r\n"); } #endif // MARSHAL_DEBUG switch(type) { // // break statement: // attempts to add the newly decoded object (in the obj variable) to // the currently building container object. // // continue statement: // indicates the decoded object or type marker was handled/consumed // by the case and should _not_ be added to the currently building // container object or used in any other way; immediately decode a // new object // //--------------------------------------------------------------------- // SCALAR TYPES //--------------------------------------------------------------------- case TYPE_INT8: CHECK_SIZE(1); obj = PyInt_FromLong(*(int8_t *)s); s++; break; case TYPE_INT16: CHECK_SIZE(2); obj = PyInt_FromLong(*(int16_t *)s); s += 2; break; case TYPE_INT32: CHECK_SIZE(4); obj = PyInt_FromLong(*(int32_t *)s); s += 4; break; case TYPE_INT64: CHECK_SIZE(8); obj = PyLong_FromLongLong(*(int64_t *)s); s += 8; break; case TYPE_LONG: CHECK_SIZE(length); if(!length) obj = PyLong_FromLong(0); else { obj = _PyLong_FromByteArray((unsigned char *)s, length, 1, 1); Py_INCREF(obj); } CHECK_SHARED(obj); s += length; break; case TYPE_FLOAT: CHECK_SIZE(8); obj = PyFloat_FromDouble(*(double *)s); s += 8; break; case TYPE_CHECKSUM: CHECK_SIZE(4); if(!skipcrc && (*(uint32_t *)s != (uint32_t)adler32(1, s, (unsigned long)(end-s)))) { error = "checksum error"; goto fail; } s += 4; // because this type does not yield an object, go grab another // object right away! continue; //--------------------------------------------------------------------- // STRING TYPES //--------------------------------------------------------------------- case TYPE_STRINGR: if (length < 1 || length >= PyList_GET_SIZE(string_table)) { if(PyList_GET_SIZE(string_table)) PyErr_Format(UnmarshalError, "Invalid string table index %d", (int)length); else PyErr_SetString(PyExc_RuntimeError, "_stringtable not initialized"); goto cleanup; } obj = PyList_GET_ITEM(string_table, length); Py_INCREF(obj); break; case TYPE_STRING: // appears to be deprecated since machoVersion 213 CHECK_SIZE(1); length = *(unsigned char *)s++; CHECK_SIZE(length); obj = PyString_FromStringAndSize(s, length); s += length; break; case TYPE_STRING1: CHECK_SIZE(1); obj = PyString_FromStringAndSize(s, 1); s++; break; case TYPE_STREAM: // fallthrough, can be treated as string. case TYPE_STRINGL: // fallthrough, deprecated since machoVersion 213 case TYPE_BUFFER: // Type identifier re-used by CCP. treat as string. CHECK_SIZE(length); obj = PyString_FromStringAndSize(s, length); s += length; CHECK_SHARED(obj); break; case TYPE_UNICODE1: CHECK_SIZE(2); #ifdef Py_UNICODE_WIDE obj = _PyUnicodeUCS4_FromUCS2((void *)s, 1); #else obj = PyUnicode_FromWideChar((wchar_t *)s, 1); #endif s += 2; break; case TYPE_UNICODE: CHECK_SIZE(length*2); #ifdef Py_UNICODE_WIDE obj = _PyUnicodeUCS4_FromUCS2((void *)s, (int)length); #else obj = PyUnicode_FromWideChar((wchar_t *)s, length); #endif s += length*2; break; case TYPE_UTF8: CHECK_SIZE(length); obj = PyUnicode_DecodeUTF8(s, length, NULL); s += length; break; //--------------------------------------------------------------------- // SEQUENCE/MAPPING TYPES //--------------------------------------------------------------------- case TYPE_TUPLE1: NEW_SEQUENCE(TYPE_TUPLE, 1); continue; case TYPE_TUPLE2: NEW_SEQUENCE(TYPE_TUPLE, 2); continue; case TYPE_TUPLE: NEW_SEQUENCE(TYPE_TUPLE, (int)length); continue; case TYPE_LIST0: obj = PyList_New(0); CHECK_SHARED(obj); break; case TYPE_LIST1: NEW_SEQUENCE(TYPE_LIST, 1); continue; case TYPE_LIST: NEW_SEQUENCE(TYPE_LIST, (int)length); continue; case TYPE_DICT: if(length) { CHECK_SIZE(length*2); PUSH_CONTAINER(TYPE_DICT, (int)length*2); container->obj = PyDict_New(); container->obj2 = NULL; container->index = 0; CHECK_SHARED(container->obj); continue; } else { obj = PyDict_New(); CHECK_SHARED(obj); break; } //--------------------------------------------------------------------- // OBJECT TYPES //--------------------------------------------------------------------- case TYPE_REF: // length value is index in sharedobj array! if((length < 1 || length > shared_mapsize)) { error = "Shared reference index out of range"; goto fail; } if(!(obj = shared_obj[length-1])) { error = "Shared reference points to invalid object"; goto fail; } Py_INCREF(obj); //printf("Getting object %d from %d (refs:%d)\r\n", (int)obj, length-1, obj->ob_refcnt); break; case TYPE_GLOBAL: { PyObject *name; CHECK_SIZE(length); name = PyString_FromStringAndSize(s, length); if(!name) goto cleanup; s += length; if(!(obj = find_global(name))) { // exception should be set by find_global goto cleanup; } Py_DECREF(name); CHECK_SHARED(obj); break; } case TYPE_DBROW: case TYPE_INSTANCE: case TYPE_NEWOBJ: case TYPE_REDUCE: PUSH_CONTAINER(type, -1); container->obj = NULL; RESERVE_SLOT(container->index); continue; case TYPE_MARK: // this is a marker, not a real object. list/dict iterators check // for this type, but it can't be instantiated. break; default: if((obj = constants[type])) { Py_INCREF(obj); } else { error = "Unsupported type"; goto fail; } } // object decoding and construction done! if(!obj && type != TYPE_MARK) { // if obj is somehow NULL, whatever caused it is expected to have // set an exception at this point. goto cleanup; } #if MARSHAL_DEBUG /* if(obj && obj->ob_refcnt < 0) { char b[200]; sprintf(b, "type: %d, refcount: %d", type, obj->ob_refcnt); DEBUG(b); } */ if(obj) { DEBUG_INDENT; printf("`-- "); PyObject_Print(obj, stdout, 0); printf("\r\n"); fflush(stdout); } else { DEBUG_INDENT; printf("*** MARK\r\n"); } #endif // MARSHAL_DEBUG while(1) { // This inner loop does one of two things: // // - return the finished object to the caller if we're at the root // container. // // - add the object to the current container in a container- // specific manner. note that ownership of the reference is to be // given to the container object. #if MARSHAL_DEBUG { //char text[220]; DEBUG_INDENT; printf("container ix:%d (%08lx) type:%s[0x%02x] free:%d index:%d\r\n", ct_ix, container->obj, tokenname[container->type], container->type, container->free, container->index); } #endif // MARSHAL_DEBUG /* if(!container->obj) { error = "Root container popped off stack"; goto fail; } */ switch(container->type) { case TYPE_TUPLE: // tuples steal references. PyTuple_SET_ITEM(container->obj, container->index++, obj); break; case TYPE_LIST: // lists steal references. PyList_SET_ITEM(container->obj, container->index++, obj); break; case TYPE_DBROW: if(container->obj) { // we have an initialized DBRow. current object is a // non-scalar object for the row. append it. if(!dbrow_append_internal((PyDBRowObject *)container->obj, obj)) { // append call will have set an exception here. goto cleanup; } } else { // we now have a DBRowDescriptor, and the header data // should follow. Pull it and create the DBRow. READ_LENGTH; CHECK_SIZE(length); container->obj = PyDBRow_New((PyDBRowDescriptorObject *)obj, s, (int)length); container->free = 1+((PyDBRowDescriptorObject *)obj)->rd_num_objects; if(!container->obj) goto cleanup; Py_DECREF(obj); s += length; // add as shared object, if neccessary... UPDATE_SLOT(container->index, container->obj); } break; case TYPE_INSTANCE: { PyObject *cls; if(container->free == -1) { // create class instance if(!(cls = find_global(obj))) goto cleanup; container->obj = PyInstance_NewRaw(cls, 0); Py_DECREF(cls); if(!container->obj) goto cleanup; UPDATE_SLOT(container->index, container->obj); Py_DECREF(obj); break; } if(container->free == -2) { container->free = 1; // set state. if(!set_state(container->obj, obj)) goto cleanup; Py_DECREF(obj); break; } error = "invalid container state"; goto fail; } case TYPE_NEWOBJ: { PyObject *cls, *args, *__new__, *state; // instantiate the object... if(!(args = PyTuple_GetItem(obj, 0))) goto cleanup; if(!(cls = PyTuple_GetItem(args, 0))) goto cleanup; __new__ = PyObject_GetAttr(cls, py__new__); if(!__new__) goto cleanup; container->obj = PyObject_CallObject(__new__, args); Py_DECREF(__new__); if(!container->obj) goto cleanup; // add as shared object, if neccessary... UPDATE_SLOT(container->index, container->obj); // is there state data? if(PyTuple_GET_SIZE(obj) > 1) { state = PyTuple_GET_ITEM(obj, 1); if(!set_state(container->obj, state)) goto cleanup; } Py_DECREF(obj); // switch to list iterator LIST_ITERATOR; break; } case TYPE_REDUCE: { PyObject *callable, *args, *state; if(!(args = PyTuple_GetItem(obj, 1))) goto cleanup; if(!(callable = PyTuple_GET_ITEM(obj, 0))) goto cleanup; if(!(container->obj = PyObject_CallObject(callable, args))) goto cleanup; UPDATE_SLOT(container->index, container->obj); if(PyTuple_GET_SIZE(obj) > 2) { state = PyTuple_GET_ITEM(obj, 2); if(!set_state(container->obj, state)) goto cleanup; } Py_DECREF(obj); // switch to list iterator LIST_ITERATOR; break; } case TYPE_LIST_ITERATOR: if(type == TYPE_MARK) { // clear mark so nested iterator containers do not get terminated prematurely. type = -1; // decref the append method Py_XDECREF(container->obj2); container->obj2 = NULL; container->type = TYPE_DICT_ITERATOR; break; } if(!container->obj2) { // grab the append method from the container and keep // it around for speed. if(!(container->obj2 = PyObject_GetAttr(container->obj, pyappend))) goto cleanup; } if(!PyObject_CallFunctionObjArgs(container->obj2, obj, NULL)) goto cleanup; #if MARSHAL_DEBUG DEBUG_INDENT; printf("Appended %08lx to %08lx\r\n", obj, container->obj); #endif // MARSHAL_DEBUG Py_DECREF(obj); break; case TYPE_DICT_ITERATOR: if(type == TYPE_MARK) { // clear mark so nested iterator containers do not get terminated prematurely. type = -1; // we're done with dict iter. container is finished. container->free = 1; break; } POPULATE_DICT(container->obj2, obj); break; case TYPE_DICT: POPULATE_DICT(obj, container->obj2); break; case 0: // we're at the root. return the object to caller. result = obj; // avoid decreffing this object. obj = NULL; goto cleanup; } container->free--; if(container->free) // still room in this container. // break out of container handling to get next object for it. break; // this container is done, it is the next object to put into the // container under it! obj = container->obj; // switch context to said older container POP_CONTAINER; } // we've processed the object. clear it for next one. obj = NULL; } // if we get here, we're out of data, but it's a "clean" eof; we ran out // of data while expecting a new object... error = "Not enough objects in stream"; fail: PyErr_Format(UnmarshalError, "%s - type:0x%02x ctype:0x%02x len:%d share:%d pos:%d size:%d", error, type, container->type, (int)length, shared, (int)(s-stream), (int)(size)); cleanup: // on any error the current object we were working on will be unassociated // with anything, decref it. if decode was succesful or an object failed to // be created, it will be NULL anyway. Py_XDECREF(obj); // same story for containers... while(container->type) { Py_XDECREF(container->obj); // possibly unassociated object for dict entry? if(container->type == TYPE_DICT || container->type == TYPE_DICT_ITERATOR) { Py_XDECREF(container->obj2); } POP_CONTAINER; } if(shared_obj) { /* shared object list held a safety ref to all objects, decref em */ int i; for(i=0; i<shared_mapsize; i++) Py_XDECREF(shared_obj[i]); /* and free the list */ PyMem_FREE(shared_obj); } return result; }
int primary(LVALUE *lval) { char sname[NAMESIZE]; int num[1], k, symbol_table_idx, offset, reg; SYMBOL *symbol; lval->ptr_type = 0; // clear pointer/array type lval->tagsym = 0; if (match ("(")) { k = hier1 (lval); needbrack (")"); return (k); } if (amatch("sizeof", 6)) { needbrack("("); gen_immediate(); if (amatch("int", 3)) output_number(INTSIZE); else if (amatch("char", 4)) output_number(1); else if (symname(sname)) { if (((symbol_table_idx = find_locale(sname)) > -1) || ((symbol_table_idx = find_global(sname)) > -1)) { symbol = &symbol_table[symbol_table_idx]; if (symbol->storage == LSTATIC) error("sizeof local static"); offset = symbol->offset; if ((symbol->type & CINT) || (symbol->identity == POINTER)) offset *= INTSIZE; else if (symbol->type == STRUCT) offset *= tag_table[symbol->tagidx].size; output_number(offset); } else { error("sizeof undeclared variable"); output_number(0); } } else { error("sizeof only on type or variable"); } needbrack(")"); newline(); lval->symbol = 0; lval->indirect = 0; return(0); } if (symname (sname)) { if ((symbol_table_idx = find_locale(sname)) > -1) { symbol = &symbol_table[symbol_table_idx]; reg = gen_get_locale(symbol); lval->symbol = symbol; lval->indirect = symbol->type; if (symbol->type == STRUCT) { lval->tagsym = &tag_table[symbol->tagidx]; } if (symbol->identity == ARRAY || (symbol->identity == VARIABLE && symbol->type == STRUCT)) { lval->ptr_type = symbol->type; return reg; } if (symbol->identity == POINTER) { lval->indirect = CINT; lval->ptr_type = symbol->type; } return FETCH | reg; } if ((symbol_table_idx = find_global(sname)) > -1) { symbol = &symbol_table[symbol_table_idx]; if (symbol->identity != FUNCTION) { lval->symbol = symbol; lval->indirect = 0; if (symbol->type == STRUCT) { lval->tagsym = &tag_table[symbol->tagidx]; } if (symbol->identity != ARRAY && (symbol->identity != VARIABLE || symbol->type != STRUCT)) { if (symbol->identity == POINTER) { lval->ptr_type = symbol->type; } return FETCH | HL_REG; } gen_immediate(); output_string(symbol->name); newline(); lval->indirect = symbol->type; lval->ptr_type = symbol->type; return 0; } } blanks(); if (ch() != '(') error("undeclared variable"); symbol_table_idx = add_global(sname, FUNCTION, CINT, 0, PUBLIC); symbol = &symbol_table[symbol_table_idx]; lval->symbol = symbol; lval->indirect = 0; return 0; } lval->symbol = 0; lval->indirect = 0; if (constant(num)) return 0; else { error("invalid expression"); gen_immediate(); output_number(0); newline(); junk(); return 0; } }
int main(int argc, char *argv[]){ unsigned i, addr; int SimsVersion = 0; int overwrite = 0; int ShowAddresses = 0; int length; char *basename; char *path[filecount] = {NULL}; uint8_t *data[filecount-1] = {NULL}; size_t filesize[filecount-1]; FILE * hFile; const global_t * Globals; size_t GlobalCount; uint32_t SymbolTable = 0; uint32_t BaseSoundID = 0, BaseSoundIDSet = 0; /* collected data */ addresslist_t AddressList; /**** ** Parse the command-line arguments */ if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ printf("Usage: hitdump [-ts1|-tso] [-f] [-a] [-o outfile.txt] [-hsm infile.hsm]\n" " [-hot infile.hot] [-evt infile.evt] infile.hit\n" "Disassemble a HIT binary.\n" "\n" "The HSM, HOT, and EVT files are not strictly necessary but\n" "each help in their own way to provide labels for addresses.\n" "Use -f to force overwriting without confirmation.\n" "Use -a to show addresses (verbose).\n" "\n" "Report bugs to <*****@*****.**>.\n" "hitutils is maintained by the Niotso project.\n" "Home page: <http://www.niotso.org/>\n"); return 0; } for(i=1; i<(unsigned)argc-1; i++){ if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1; else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO; else if(!strcmp(argv[i], "-f")) overwrite = 1; else if(!strcmp(argv[i], "-a")) ShowAddresses = 1; else if(i != (unsigned)argc-2){ if(!strcmp(argv[i], "-out")) path[out] = argv[++i]; else if(!strcmp(argv[i], "-hsm")) path[hsm] = argv[++i]; else if(!strcmp(argv[i], "-hot")) path[hot] = argv[++i]; else if(!strcmp(argv[i], "-evt")) path[evt] = argv[++i]; else break; } else break; } if(!SimsVersion){ fprintf(stderr, "%sSims version not specified. (Use -ts1 or -tso.)\n", "hitdump: Error: "); return -1; } if(SimsVersion == VERSION_TS1){ Globals = TS1Globals; GlobalCount = TS1GlobalCount; }else{ Globals = TSOGlobals; GlobalCount = TSOGlobalCount; } path[hit] = argv[i]; length = strlen(path[hit]); if(path[out] == NULL){ path[out] = malloc(max(length+1, 5)); strcpy(path[out], path[hit]); strcpy(path[out] + max(length-4, 0), ".txt"); } length = max(length+1-4, 1); basename = malloc(length); memcpy(basename, path[hit], length-1); basename[length-1] = '\0'; /**** ** Read all of the requested files */ for(i=0; i<filecount-1; i++){ if(!path[i]) continue; hFile = fopen(path[i], "rb"); if(hFile == NULL){ if(i != hit){ fprintf(stderr, "%sCould not open file: %s\n", "hitdump: Warning: ", path[i]); continue; }else{ fprintf(stderr, "%sCould not open file: %s\n", "hitdump: Error: ", path[i]); return -1; } } fseek(hFile, 0, SEEK_END); filesize[i] = ftell(hFile); if(filesize[i] == 0){ fclose(hFile); if(i != hit){ fprintf(stderr, "%sFile is invalid: %s\n", "hitdump: Warning: ", path[i]); continue; }else{ fprintf(stderr, "%sFile is invalid: %s\n", "hitdump: Error: ", path[i]); return -1; } } data[i] = malloc(filesize[i]); if(data[i] == NULL){ fclose(hFile); if(i != hit){ fprintf(stderr, "%sCould not allocate memory for file: %s\n", "hitdump: Warning: ", path[i]); continue; }else{ fprintf(stderr, "%sCould not allocate memory for file: %s\n", "hitdump: Error: ", path[i]); return -1; } } fseek(hFile, 0, SEEK_SET); if(fread(data[i], 1, filesize[i], hFile) != filesize[i]){ fclose(hFile); if(i != hit){ fprintf(stderr, "%sCould not read file: %s\n", "hitdump: Warning: ", path[i]); continue; }else{ fprintf(stderr, "%sCould not read file: %s\n", "hitdump: Error: ", path[i]); return -1; } } fclose(hFile); } /**** ** Open the output file for writing */ if(!overwrite){ hFile = fopen(path[out], "rb"); if(hFile != NULL){ /* File exists */ char c; fclose(hFile); fprintf(stderr, "hitdump: File \"%s\" exists.\nContinue anyway? (y/n) ", path[out]); c = getchar(); if(c != 'y' && c != 'Y'){ printf("\nAborted.\n"); return -1; } } } hFile = fopen(path[out], "wb"); if(hFile == NULL){ fprintf(stderr, "%sCould not open file: %s\n", "hitdump: Error: ", path[out]); return -1; } /**** ** Verify the header of the HIT file */ if(filesize[hit] < 16 || memcmp(data[hit], HITHeader, 16)){ fprintf(stderr, "%sFile is invalid: %s\n", "hitdump: Error: ", path[hit]); return -1; } /**** ** Build up the address list */ AddressList.Size = 32; AddressList.Count = 0; AddressList.Entries = malloc(32 * sizeof(address_t)); read_hit_addresses(data[hit], filesize[hit], &AddressList, &SymbolTable); if(data[evt]) read_evt_addresses(data[evt], filesize[evt], &AddressList); if(data[hsm]) read_hsm_addresses(data[hsm], filesize[hsm], &AddressList); if(data[hot]) read_hot_addresses(data[hot], filesize[hot], &AddressList); /* scan_branch_destinations(data[hit], filesize[hit], &AddressList); */ for(i=0; i<AddressList.Count; i++){ if(AddressList.Entries[i].SoundID != 0 && (!BaseSoundIDSet || AddressList.Entries[i].SoundID < BaseSoundID)){ BaseSoundID = AddressList.Entries[i].SoundID; BaseSoundIDSet = 1; } if(ShowAddresses){ printf("Address %u:\n Exported: %u\n TrackID: %u\n SoundID: %u\n Name: %s\n LogicalAddress: %u\n", i, AddressList.Entries[i].Exported, AddressList.Entries[i].TrackID, AddressList.Entries[i].SoundID, AddressList.Entries[i].Name, AddressList.Entries[i].LogicalAddress ); } } /**** ** Perform the disassembly */ fprintf(hFile, "BASEID_TRACKDATA %u\r\n" "\r\n" ";\r\n" "; generated by hitdump.\r\n" ";\r\n" "\r\n" "; useful symbols:\r\n" "; kSndobPlay = 1\r\n" "; tkd_Generic 1\r\n" "; tkd_GenericLooped 2\r\n" "; tkd_GenericHitList 3\r\n" "\r\n" "INCLUDE defaultsyms.txt\r\n" "INCLUDE SimsGlobals.txt\r\n" "\r\n" "LIST [Options] Version=1\r\n" "LIST [Options] LoadPriority=2\r\n" "\r\n" ";LIST [EventMappingEquate] kSndobPlay=1\r\n" "; --- end of standard intro text ---\r\n" "\r\n" "SYMBOLFILE %s%s\r\n" "INIFILE %s.ini", BaseSoundID, path[hsm] ? path[hsm] : basename, path[hsm] ? "" : ".hsm", basename); fprintf(hFile, "\r\n\r\nBINARY\r\n["); for(addr=16; addr<filesize[hit];){ unsigned i; uint8_t opcode; const instruction_t * instruction; uint32_t operands; const address_t * Address; int HadSymbolTable = 0; if(SymbolTable && addr == SymbolTable){ if(addr != 16) fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n["); fprintf(hFile, "\r\n" "\t69\r\n" "\t78\r\n" "\t84\r\n" "\t80\r\n"); for(addr+=4; memcmp(data[hit]+addr, "EENT", 4); addr+=8){ uint32_t TrackID = read_uint32(data[hit]+addr), LogicalAddress = read_uint32(data[hit]+addr+4); Address = find_address_by_logical_address(&AddressList, LogicalAddress); fprintf(hFile, "\r\n\t#%u\t\t#", TrackID); if(Address && Address->Name) fprintf(hFile, "%s", Address->Name); else fprintf(hFile, "%u", LogicalAddress); } if(addr-4 != SymbolTable) fprintf(hFile, "\r\n"); fprintf(hFile, "\r\n" "\t69\r\n" "\t69\r\n" "\t78\r\n" "\t84"); if(addr+4 == filesize[hit]) break; fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n["); addr += 4; SymbolTable = 0; HadSymbolTable++; } Address = find_address_by_logical_address(&AddressList, addr); if(Address){ if(!HadSymbolTable && addr != 16 && Address->Exported) fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n["); if(Address->Name) fprintf(hFile, "\r\n%s", Address->Name); } opcode = data[hit][addr]; if(opcode == 0 || opcode > 96){ fprintf(stderr, "%sIllegal opcode 0x%02X at address 0x%08X.\n", "hitdump: Error: ", opcode, addr); return -1; } instruction = Instructions + opcode - 1; operands = instruction->Operands; if(operands == UNIMPLEMENTED){ fprintf(stderr, "%sUnimplemented instruction '%s' at address 0x%08X.\n", "hitdump: Error: ", instruction->Name, addr); return -1; } addr++; if(filesize[hit] - addr < (operands & 15)){ fprintf(stderr, "%sInsufficient operand bytes for '%s' instruction at address 0x%08X (%u of %u supplied).\n", "hitdump: Error: ", instruction->Name, addr, filesize[hit] - addr, instruction->Operands); return -1; } fprintf(hFile, "\r\n\t\t%s", instruction->Name); for(i=0; (operands >>= 4) != 0; i++){ int type = operands & 15; const char *position[] = {"first","second","third","fourth"}; if(type == o_byte){ fprintf(hFile, " #%u", data[hit][addr]); addr += 1; }else if(type == o_dword){ fprintf(hFile, " #%u", read_uint32(data[hit]+addr)); addr += 4; }else if(type == o_address){ int LogicalAddress = read_uint32(data[hit]+addr); Address = find_address_by_logical_address(&AddressList, LogicalAddress); if(Address && Address->Name) fprintf(hFile, " #%s", Address->Name); else fprintf(hFile, " #%u", LogicalAddress); addr += 4; }else if(type == o_variable){ int x = data[hit][addr]; if(x > 16){ const char * Global = find_global(x, Globals, GlobalCount); if(Global == NULL){ fprintf(stderr, "%sInvalid %s operand 0x%02X for '%s' instruction at address 0x%08X (expected %s).\n", "hitdump: Error: ", position[i], x, instruction->Name, addr, "argument, register, or global"); return -1; } fprintf(hFile, " %s", Global); } else fprintf(hFile, " %s", Registers[x]); addr += 1; }else if(type == o_jump){ unsigned x = 0; if(filesize[hit]-addr >= 4) x = read_uint32(data[hit]+addr); else if(data[hit][addr] != 0x05 && data[hit][addr] != 0x06){ fprintf(stderr, "%sInsufficient operand bytes for '%s' instruction at address 0x%08X (%u of %u supplied).\n", "hitdump: Error: ", instruction->Name, addr, filesize[hit] - addr, 4); return -1; } if(x >= 16 && x < filesize[hit]){ Address = find_address_by_logical_address(&AddressList, x); if(Address && Address->Name) fprintf(hFile, " #%s", Address->Name); else fprintf(hFile, " #%u", x); addr += 4; }else{ x = data[hit][addr]; if(x > 16){ const char * Global = find_global(x, Globals, GlobalCount); if(Global == NULL){ fprintf(stderr, "%sInvalid %s operand 0x%02X for '%s' instruction at address 0x%08X (expected %s).\n", "hitdump: Error: ", position[i], x, instruction->Name, addr, "argument, register, or global"); return -1; } fprintf(hFile, " %s", Global); } else fprintf(hFile, " %s", Registers[x]); addr += (data[hit][addr] != 0x05 && data[hit][addr] != 0x06) ? 4 : 1; } } } } fprintf(hFile, "\r\n]\r\n\r\n"); fclose(hFile); return 0; }