diff options
Diffstat (limited to 'engines/director/lingo/lingo-bytecode.cpp')
-rw-r--r-- | engines/director/lingo/lingo-bytecode.cpp | 236 |
1 files changed, 204 insertions, 32 deletions
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp index f19ebb7768..c04515ac07 100644 --- a/engines/director/lingo/lingo-bytecode.cpp +++ b/engines/director/lingo/lingo-bytecode.cpp @@ -25,45 +25,62 @@ namespace Director { static struct LingoV4Bytecode { - const char opcode; + const uint8 opcode; const inst func; + const char *args; } lingoV4[] = { - { 0x03, Lingo::c_voidpush }, - { 0x04, Lingo::c_mul }, - { 0x05, Lingo::c_add }, - { 0x06, Lingo::c_sub }, - { 0x07, Lingo::c_div }, - { 0x08, Lingo::c_mod }, - { 0x09, Lingo::c_negate }, - { 0x0a, Lingo::c_ampersand }, - { 0x0b, Lingo::c_concat }, - { 0x0c, Lingo::c_lt }, - { 0x0d, Lingo::c_le }, - { 0x0e, Lingo::c_neq }, - { 0x0f, Lingo::c_eq }, - { 0x10, Lingo::c_gt }, - { 0x11, Lingo::c_ge }, - { 0x12, Lingo::c_and }, - { 0x13, Lingo::c_or }, - { 0x14, Lingo::c_not }, - { 0x15, Lingo::c_contains }, - { 0x16, Lingo::c_starts }, - { 0x17, Lingo::c_of }, - { 0x18, Lingo::c_hilite }, - { 0x19, Lingo::c_intersects }, - { 0x1a, Lingo::c_within }, - { 0x1b, Lingo::c_field }, - { 0x1c, Lingo::c_tell }, - { 0x1d, Lingo::c_telldone }, + { 0x03, Lingo::c_voidpush, "" }, + { 0x04, Lingo::c_mul, "" }, + { 0x05, Lingo::c_add, "" }, + { 0x06, Lingo::c_sub, "" }, + { 0x07, Lingo::c_div, "" }, + { 0x08, Lingo::c_mod, "" }, + { 0x09, Lingo::c_negate, "" }, + { 0x0a, Lingo::c_ampersand, "" }, + { 0x0b, Lingo::c_concat, "" }, + { 0x0c, Lingo::c_lt, "" }, + { 0x0d, Lingo::c_le, "" }, + { 0x0e, Lingo::c_neq, "" }, + { 0x0f, Lingo::c_eq, "" }, + { 0x10, Lingo::c_gt, "" }, + { 0x11, Lingo::c_ge, "" }, + { 0x12, Lingo::c_and, "" }, + { 0x13, Lingo::c_or, "" }, + { 0x14, Lingo::c_not, "" }, + { 0x15, Lingo::c_contains, "" }, + { 0x16, Lingo::c_starts, "" }, + { 0x17, Lingo::c_of, "" }, + { 0x18, Lingo::c_hilite, "" }, + { 0x19, Lingo::c_intersects, "" }, + { 0x1a, Lingo::c_within, "" }, + { 0x1b, Lingo::c_field, "" }, + { 0x1c, Lingo::c_tell, "" }, + { 0x1d, Lingo::c_telldone, "" }, - { 0x41, Lingo::c_intpush }, - { 0, 0 } + { 0x41, Lingo::c_intpush, "b" }, + { 0, 0, 0 } }; +void Lingo::initBytecode() { + for (LingoV4Bytecode *op = lingoV4; op->opcode; op++) { + _lingoV4[op->opcode] = new Opcode( op->func, op->args ); + } +} + void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id) { debugC(1, kDebugLingoCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id); + if (_scripts[type].contains(id)) { + delete _scripts[type][id]; + } + + _currentScript = new ScriptData; + _currentScriptType = type; + _scripts[type][id] = _currentScript; + _currentEntityId = id; + + // read the Lscr header! // unk1 for (uint32 i = 0; i < 0x10; i++) { stream.readByte(); @@ -88,9 +105,164 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty uint16 unk6 = stream.readUint16(); stream.readUint16(); uint16 consts_base = stream.readUint16(); - - // preload all the constants + + // preload all the constants! + // these are stored as a reference table of 6 byte entries, followed by a storage area. + + // copy the storage area first. + uint32 consts_store_offset = consts_offset+6*consts_count; + uint32 consts_store_size = stream.size()-consts_store_offset; + stream.seek(consts_store_offset); + byte *const_store = (byte *)malloc(consts_store_size); + stream.read(const_store, consts_store_size); + + Common::Array<Datum> const_data; + + // read each entry in the reference table. stream.seek(consts_offset); + for (uint16 i=0; i<consts_count; i++) { + Datum constant; + uint16 const_type = stream.readUint16(); + uint32 value = stream.readUint32(); + switch (const_type) { + case 1: { // String type + constant.type = STRING; + constant.u.s = new Common::String(); + if (value < consts_store_offset) { + warning("Constant string start offset is out of bounds!"); + break; + } + uint32 pointer = value - consts_store_offset; + while (pointer < consts_store_size) { + if (const_store[pointer] == '\r') { + constant.u.s += '\n'; + } else if (const_store[pointer] == '\0') { + break; + } else { + constant.u.s += const_store[pointer]; + } + pointer += 1; + } + if (pointer == consts_store_size) { + warning("Constant string has no null terminator!"); + break; + } + } + break; + case 4: // Integer type + constant.type = INT; + constant.u.i = (int)value; + break; + case 9: { // Float type + constant.type = FLOAT; + if (value < consts_store_offset) { + warning("Constant float start offset is out of bounds!"); + break; + } else if (value+4 > consts_store_offset + consts_store_size) { + warning("Constant float end offset is out of bounds!"); + break; + } + constant.u.f = *(float *)(const_store+value-consts_store_offset); + } + break; + default: + warning("Unknown constant type %d", type); + break; + } + + const_data.push_back(constant); + } + free(const_store); + + // parse each function! + // these are stored as a code storage area, followed by a reference table of 42 byte entries. + + // copy the storage area first. + uint32 code_store_size = functions_offset - code_store_offset; + stream.seek(code_store_offset); + byte *code_store = (byte *)malloc(code_store_size); + stream.read(code_store, code_store_size); + + // read each entry in the function table. + stream.seek(functions_offset); + for (uint16 i=0; i<functions_count; i++) { + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 arg_count = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 var_count = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 name_index = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 length = stream.readUint16(); + stream.readUint16(); + uint16 start_offset = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 end_offset = stream.readUint16(); + + if (start_offset < code_store_offset) { + warning("Function %d start offset is out of bounds!", i); + continue; + } else if (end_offset >= code_store_offset+code_store_size) { + warning("Function %d end offset is out of bounds!", i); + continue; + } + + uint32 pointer = start_offset-code_store_offset; + Common::Array<uint32> offset_list; + while (pointer < end_offset-code_store_offset) { + uint8 opcode = code_store[pointer]; + + pointer += 1; + if (_lingoV4.contains(opcode)) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(_lingoV4[opcode]->func); + + } else { + // unimplemented instruction + inst op_value = 0; + WRITE_UINT32(&op_value, opcode); + + if (opcode < 0x40) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop); + _currentScript->push_back(op_value); + } else if (opcode < 0x80) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop1); + _currentScript->push_back(op_value); + inst arg1 = 0; + WRITE_UINT32(&arg1, code_store[pointer]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg1); + pointer += 1; + } else { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop2); + _currentScript->push_back(op_value); + inst arg1 = 0; + WRITE_UINT32(&arg1, code_store[pointer]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg1); + inst arg2 = 0; + WRITE_UINT32(&arg2, code_store[pointer+1]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg2); + pointer += 2; + } + } + } + + } + } } |