Common::String Kernel::lookupText(reg_t address, int index) { char *seeker; Resource *textres; if (address.getSegment()) return _segMan->getString(address); int textlen; int _index = index; textres = _resMan->findResource(ResourceId(kResourceTypeText, address.getOffset()), 0); if (!textres) { error("text.%03d not found", address.getOffset()); return NULL; /* Will probably segfault */ } textlen = textres->size; seeker = (char *) textres->data; while (index--) while ((textlen--) && (*seeker++)) ; if (textlen) return seeker; error("Index %d out of bounds in text.%03d", _index, address.getOffset()); return NULL; }
SegmentRef Script::dereference(reg_t pointer) { if (pointer.getOffset() > _buf->size()) { error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script %d segment (script size=%u)", PRINT_REG(pointer), _nr, _buf->size()); return SegmentRef(); } SegmentRef ret; ret.isRaw = true; ret.maxSize = _buf->size() - pointer.getOffset(); ret.raw = _buf->getUnsafeDataAt(pointer.getOffset(), ret.maxSize); return ret; }
static void patchGameSaveRestoreCodeSci2(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) { Script *script = segMan->getScript(methodAddress.getSegment()); byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); int kcallOffset; if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) { if (doRestore) { memcpy(patchPtr, patchGameRestoreSci2, sizeof(patchGameRestoreSci2)); kcallOffset = 9; } else { memcpy(patchPtr, patchGameSaveSci2, sizeof(patchGameSaveSci2)); kcallOffset = 10; } } else { if (doRestore) { memcpy(patchPtr, patchGameRestoreSci21, sizeof(patchGameRestoreSci21)); kcallOffset = 10; } else { memcpy(patchPtr, patchGameSaveSci21, sizeof(patchGameSaveSci21)); kcallOffset = 11; } } patchPtr[kcallOffset] = id; if (g_sci->isBE()) { SWAP(patchPtr[kcallOffset + 1], patchPtr[kcallOffset + 2]); } }
static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) { Script *script = segMan->getScript(methodAddress.getSegment()); byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave)); patchPtr[8] = id; }
reg_t reg_t::operator+(const reg_t right) const { if (isPointer() && right.isNumber()) { // Pointer arithmetics. Only some pointer types make sense here SegmentObj *mobj = g_sci->getEngineState()->_segMan->getSegmentObj(getSegment()); if (!mobj) error("[VM]: Attempt to add %d to invalid pointer %04x:%04x", right.getOffset(), PRINT_REG(*this)); switch (mobj->getType()) { case SEG_TYPE_LOCALS: case SEG_TYPE_SCRIPT: case SEG_TYPE_STACK: case SEG_TYPE_DYNMEM: return make_reg(getSegment(), getOffset() + right.toSint16()); default: return lookForWorkaround(right, "addition"); } } else if (isNumber() && right.isPointer()) { // Adding a pointer to a number, flip the order return right + *this; } else if (isNumber() && right.isNumber()) { // Normal arithmetics return make_reg(0, toSint16() + right.toSint16()); } else { return lookForWorkaround(right, "addition"); } }
static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) { Script *script = segMan->getScript(methodAddress.getSegment()); byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21)); if (doRestore) patchPtr[2] = 0x78; // push1 patchPtr[9] = id; }
static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) { Script *script = segMan->getScript(methodAddress.getSegment()); byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); if (getSciVersion() <= SCI_VERSION_1_1) memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave)); else // SCI2+ memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2)); patchPtr[8] = id; }
Common::Array<reg_t> Script::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; if (addr.getOffset() <= _buf->size() && addr.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && offsetIsObject(addr.getOffset())) { const Object *obj = getObject(addr.getOffset()); if (obj) { // Note all local variables, if we have a local variable environment if (_localsSegment) tmp.push_back(make_reg(_localsSegment, 0)); for (uint i = 0; i < obj->getVarCount(); i++) tmp.push_back(obj->getVariable(i)); } else { error("Request for outgoing script-object reference at %04x:%04x failed in script %d", PRINT_REG(addr), _nr); } } else { /* warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/ /* Happens e.g. when we're looking into strings */ } return tmp; }
void GfxMenu::kernelSetAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value) { GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); if (!itemEntry) { // PQ2 demo calls this, for example, but has no menus (bug report #3034507). Some SCI // fan games (Al Pond 2, Aquarius) call this too on non-existent menu items. The // original interpreter ignored these as well. debugC(kDebugLevelGraphics, "Tried to setAttribute() on non-existent menu-item %d:%d", menuId, itemId); return; } switch (attributeId) { case SCI_MENU_ATTRIBUTE_ENABLED: itemEntry->enabled = !value.isNull(); break; case SCI_MENU_ATTRIBUTE_SAID: itemEntry->saidVmPtr = value; break; case SCI_MENU_ATTRIBUTE_TEXT: itemEntry->text = _segMan->getString(value); itemEntry->textVmPtr = value; // We assume here that no script ever creates a separatorLine dynamically break; case SCI_MENU_ATTRIBUTE_KEYPRESS: itemEntry->keyPress = tolower(value.getOffset()); itemEntry->keyModifier = 0; // TODO: Find out how modifier is handled debug("setAttr keypress %X %X", value.getSegment(), value.getOffset()); break; case SCI_MENU_ATTRIBUTE_TAG: itemEntry->tag = value.getOffset(); break; default: // Happens when loading a game in LSL3 - attribute 1A warning("setAttribute() called with unsupported attributeId %X", attributeId); } }
uint16 Kernel::findRegType(reg_t reg) { // No segment? Must be integer if (!reg.getSegment()) return SIG_TYPE_INTEGER | (reg.getOffset() ? 0 : SIG_TYPE_NULL); if (reg.getSegment() == 0xFFFF) return SIG_TYPE_UNINITIALIZED; // Otherwise it's an object SegmentObj *mobj = _segMan->getSegmentObj(reg.getSegment()); if (!mobj) return SIG_TYPE_ERROR; uint16 result = 0; if (!mobj->isValidOffset(reg.getOffset())) result |= SIG_IS_INVALID; switch (mobj->getType()) { case SEG_TYPE_SCRIPT: if (reg.getOffset() <= (*(Script *)mobj).getBufSize() && reg.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && (*(Script *)mobj).offsetIsObject(reg.getOffset())) { result |= ((Script *)mobj)->getObject(reg.getOffset()) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE; } else result |= SIG_TYPE_REFERENCE; break; case SEG_TYPE_CLONES: result |= SIG_TYPE_OBJECT; break; case SEG_TYPE_LOCALS: case SEG_TYPE_STACK: case SEG_TYPE_DYNMEM: case SEG_TYPE_HUNK: #ifdef ENABLE_SCI32 case SEG_TYPE_ARRAY: case SEG_TYPE_STRING: #endif result |= SIG_TYPE_REFERENCE; break; case SEG_TYPE_LISTS: result |= SIG_TYPE_LIST; break; case SEG_TYPE_NODES: result |= SIG_TYPE_NODE; break; default: return SIG_TYPE_ERROR; } return result; }
void GuestAdditions::patchGameSaveRestoreSCI32(Script &script) const { const ObjMap &objMap = script.getObjectMap(); for (ObjMap::const_iterator it = objMap.begin(); it != objMap.end(); ++it) { const Object &obj = it->_value; if (strncmp(_segMan->getObjectName(obj.getPos()), "SRDialog", 8) != 0) { continue; } const uint16 methodCount = obj.getMethodCount(); for (uint16 methodNr = 0; methodNr < methodCount; ++methodNr) { const uint16 selectorId = obj.getFuncSelector(methodNr); const Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "doit") { const reg_t methodAddress = obj.getFunction(methodNr); byte *patchPtr = const_cast<byte *>(script.getBuf(methodAddress.getOffset())); memcpy(patchPtr, SRDialogPatch, sizeof(SRDialogPatch)); break; } } } }
void GfxControls32::destroyScrollWindow(const reg_t id) { ScrollWindow *scrollWindow = getScrollWindow(id); scrollWindow->hide(); _scrollWindows.erase(id.getOffset()); delete scrollWindow; }