diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/kstring.cpp | 180 | ||||
-rw-r--r-- | engines/sci/engine/message.cpp | 112 | ||||
-rw-r--r-- | engines/sci/engine/message.h | 22 |
3 files changed, 189 insertions, 125 deletions
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index bda82e1329..78fb120343 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -722,107 +722,143 @@ reg_t kGetFarText(EngineState *s, int funct_nr, int argc, reg_t *argv) { return argv[2]; } -#define DUMMY_MESSAGE "No MESSAGE support in SCI yet" +#define DUMMY_MESSAGE "Message not found!" static MessageState state; +enum kMessageFunc { + K_MESSAGE_GET, + K_MESSAGE_NEXT, + K_MESSAGE_SIZE, + K_MESSAGE_REFCOND, + K_MESSAGE_REFVERB, + K_MESSAGE_REFNOUN, + K_MESSAGE_PUSH, + K_MESSAGE_POP, + K_MESSAGE_LASTMESSAGE +}; + reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { MessageTuple tuple; + int func; + // For earlier version of of this function (GetMessage) + bool isGetMessage = argc == 4; + + if (isGetMessage) { + func = K_MESSAGE_GET; - if (argc == 4) { - // Earlier version of of this function (GetMessage) tuple.noun = UKPV(0); - int module = UKPV(1); tuple.verb = UKPV(2); tuple.cond = 0; tuple.seq = 1; + } else { + func = UKPV(0); - if (state.loadRes(s->resmgr, module, true) && state.getMessage(&tuple)) { - int len = state.getLength(); - char *buffer = kernel_dereference_char_pointer(s, argv[3], len + 1); - - if (buffer) { - state.getText(buffer); - return argv[3]; - } + if (argc >= 6) { + tuple.noun = UKPV(2); + tuple.verb = UKPV(3); + tuple.cond = UKPV(4); + tuple.seq = UKPV(5); } - - return NULL_REG; - } - - switch (UKPV(0)) { - case 0: - case 2: - case 3: - case 4: - case 5: - tuple.noun = UKPV(2); - tuple.verb = UKPV(3); - tuple.cond = UKPV(4); - tuple.seq = UKPV(5); } - switch (UKPV(0)) { - case 0 : - if (state.loadRes(s->resmgr, UKPV(1), true) && state.getMessage(&tuple)) { - char *buffer = NULL; - - if ((argc == 7) && (argv[6] != NULL_REG)) - buffer = kernel_dereference_char_pointer(s, argv[6], state.getLength() + 1); - - int talker = state.getTalker(); - - if (buffer) - state.getText(buffer); + switch (func) { + case K_MESSAGE_GET: + case K_MESSAGE_NEXT: { + reg_t bufferReg; + char *buffer = NULL; + const char *str; + reg_t retval; + + if (func == K_MESSAGE_GET) { + state.loadRes(s->resmgr, UKPV(1), true); + state.findTuple(tuple); + + if (isGetMessage) + bufferReg = (argc == 4 ? argv[3] : NULL_REG); + else + bufferReg = (argc == 7 ? argv[6] : NULL_REG); + } else { + bufferReg = (argc == 2 ? argv[1] : NULL_REG); + } - // Talker id - return make_reg(0, talker); + if (state.getMessage()) { + str = state.getText(); + if (isGetMessage) + retval = bufferReg; + else + retval = make_reg(0, state.getTalker()); } else { - char *buffer = NULL; + str = DUMMY_MESSAGE; + retval = NULL_REG; + } - if ((argc == 7) && (argv[6] != NULL_REG)) - buffer = kernel_dereference_char_pointer(s, argv[6], strlen(DUMMY_MESSAGE) + 1); + if (!bufferReg.isNull()) { + int len = strlen(str) + 1; + buffer = kernel_dereference_char_pointer(s, bufferReg, len); - if (buffer) - strcpy(buffer, DUMMY_MESSAGE); + if (buffer) { + strcpy(buffer, str); + } else { + warning("Message: buffer "PREG" invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str); - return NULL_REG; + // Set buffer to empty string if possible + buffer = kernel_dereference_char_pointer(s, bufferReg, 1); + if (buffer) + *buffer = 0; + } + + state.gotoNext(); } - case 1 : - if (state.getNext()) { - char *buffer = NULL; - if ((argc == 2) && (argv[1] != NULL_REG)) - buffer = kernel_dereference_char_pointer(s, argv[1], state.getLength() + 1); + return retval; + } + case K_MESSAGE_SIZE: { + MessageState tempState; - int talker = state.getTalker(); + if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple) && tempState.getMessage()) + return make_reg(0, strlen(tempState.getText())); + else + return NULL_REG; + } + case K_MESSAGE_REFCOND: + case K_MESSAGE_REFVERB: + case K_MESSAGE_REFNOUN: { + MessageState tempState; - if (buffer) - state.getText(buffer); + if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple)) { + MessageTuple t = tempState.getRefTuple(); + switch (func) { + case K_MESSAGE_REFCOND: + return make_reg(0, t.cond); + case K_MESSAGE_REFVERB: + return make_reg(0, t.verb); + case K_MESSAGE_REFNOUN: + return make_reg(0, t.noun); + } + } - // Talker id - return make_reg(0, talker); + return NULL_REG; + } + case K_MESSAGE_LASTMESSAGE: { + MessageTuple msg = state.getLastTuple(); + int module = state.getLastModule(); + byte *buffer = kernel_dereference_bulk_pointer(s, argv[1], 10); + + if (buffer) { + WRITE_LE_UINT16(buffer, module); + WRITE_LE_UINT16(buffer + 2, msg.noun); + WRITE_LE_UINT16(buffer + 4, msg.verb); + WRITE_LE_UINT16(buffer + 6, msg.cond); + WRITE_LE_UINT16(buffer + 8, msg.seq); } else { - char *buffer = NULL; - - if ((argc == 2) && (argv[1] != NULL_REG)) - buffer = kernel_dereference_char_pointer(s, argv[1], strlen(DUMMY_MESSAGE) + 1); - - if (buffer) - strcpy(buffer, DUMMY_MESSAGE); - - return NULL_REG; + warning("Message: buffer "PREG" invalid or too small to hold the tuple", PRINT_REG(argv[1])); } - case 2: { - MessageState tempState; - if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.getMessage(&tuple)) - return make_reg(0, tempState.getLength() + 1); - else - return NULL_REG; + return NULL_REG; } default: - warning("kMessage subfunction %i invoked (not implemented)", UKPV(0)); + warning("Message: subfunction %i invoked (not implemented)", func); } return NULL_REG; diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp index 0a6754fa03..8b137a1b29 100644 --- a/engines/sci/engine/message.cpp +++ b/engines/sci/engine/message.cpp @@ -28,29 +28,37 @@ namespace Sci { -void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) { - t->noun = *(cursor->index_record + 0); - t->verb = *(cursor->index_record + 1); +MessageTuple MessageState::getTuple() { + MessageTuple t; + + t.noun = *(_engineCursor.index_record + 0); + t.verb = *(_engineCursor.index_record + 1); if (_version == 2101) { - t->cond = 0; - t->seq = 1; + t.cond = 0; + t.seq = 1; } else { - t->cond = *(cursor->index_record + 2); - t->seq = *(cursor->index_record + 3); + t.cond = *(_engineCursor.index_record + 2); + t.seq = *(_engineCursor.index_record + 3); } + + return t; } -void MessageState::parseRef(IndexRecordCursor *cursor, MessageTuple *t) { +MessageTuple MessageState::getRefTuple() { + MessageTuple t; + if (_version == 2101) { - t->noun = 0; - t->verb = 0; - t->cond = 0; + t.noun = 0; + t.verb = 0; + t.cond = 0; } else { - t->noun = *(cursor->index_record + 7); - t->verb = *(cursor->index_record + 8); - t->cond = *(cursor->index_record + 9); + t.noun = *(_engineCursor.index_record + 7); + t.verb = *(_engineCursor.index_record + 8); + t.cond = *(_engineCursor.index_record + 9); } - t->seq = 1; + t.seq = 1; + + return t; } void MessageState::initCursor() { @@ -67,20 +75,22 @@ void MessageState::advanceCursor(bool increaseSeq) { _engineCursor.nextSeq++; } -int MessageState::getMessage(MessageTuple *t) { +int MessageState::findTuple(MessageTuple &t) { + if (_module == -1) + return 0; + // Reset the cursor initCursor(); - _engineCursor.nextSeq = t->seq; + _engineCursor.nextSeq = t.seq; // Do a linear search for the message while (1) { - MessageTuple looking_at; - parse(&_engineCursor, &looking_at); + MessageTuple looking_at = getTuple(); - if (t->noun == looking_at.noun && - t->verb == looking_at.verb && - t->cond == looking_at.cond && - t->seq == looking_at.seq) + if (t.noun == looking_at.noun && + t.verb == looking_at.verb && + t.cond == looking_at.cond && + t.seq == looking_at.seq) break; advanceCursor(false); @@ -90,15 +100,16 @@ int MessageState::getMessage(MessageTuple *t) { return 0; } - return getNext(); + return 1; } -int MessageState::getNext() { +int MessageState::getMessage() { + if (_module == -1) + return 0; + if (_engineCursor.index != _recordCount) { - MessageTuple mesg; - parse(&_engineCursor, &mesg); - MessageTuple ref; - parseRef(&_engineCursor, &ref); + MessageTuple mesg = getTuple(); + MessageTuple ref = getRefTuple(); if (_engineCursor.nextSeq == mesg.seq) { // We found the right sequence number, check for recursion @@ -107,8 +118,8 @@ int MessageState::getNext() { // Recursion, advance the current cursor and load the reference advanceCursor(true); - if (getMessage(&ref)) - return getNext(); + if (findTuple(ref)) + return getMessage(); else { // Reference not found return 0; @@ -123,7 +134,7 @@ int MessageState::getNext() { // We either ran out of records, or found an incorrect sequence number. Go to previous stack frame. if (!_cursorStack.empty()) { _engineCursor = _cursorStack.pop(); - return getNext(); + return getMessage(); } // Stack is empty, no message available @@ -134,10 +145,22 @@ int MessageState::getTalker() { return (_version == 2101) ? -1 : *(_engineCursor.index_record + 4); } -void MessageState::getText(char *buffer) { +MessageTuple &MessageState::getLastTuple() { + return _lastReturned; +} + +int MessageState::getLastModule() { + return _lastReturnedModule; +} + +char *MessageState::getText() { int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); - char *stringptr = (char *)_currentResource->data + offset; - strcpy(buffer, stringptr); + return (char *)_currentResource->data + offset; +} + +void MessageState::gotoNext() { + _lastReturned = getTuple(); + _lastReturnedModule = _module; advanceCursor(true); } @@ -148,24 +171,27 @@ int MessageState::getLength() { } int MessageState::loadRes(ResourceManager *resmgr, int module, bool lock) { - if (_module == module) - return 1; + if (_locked) { + // We already have a locked resource + if (_module == module) { + // If it's the same resource, we are done + return 1; + } - // Unlock old resource - if (_module != -1) { + // Otherwise, free the old resource resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage); - _module = -1; + _locked = false; } _currentResource = resmgr->findResource(kResourceTypeMessage, module, lock); if (_currentResource == NULL || _currentResource->data == NULL) { - warning("Message subsystem: failed to load %d.msg", module); + warning("Message: failed to load %d.msg", module); return 0; } - if (lock) - _module = module; + _module = module; + _locked = lock; _version = READ_LE_UINT16(_currentResource->data); diff --git a/engines/sci/engine/message.h b/engines/sci/engine/message.h index e8f0662440..82c5e4f721 100644 --- a/engines/sci/engine/message.h +++ b/engines/sci/engine/message.h @@ -48,30 +48,32 @@ typedef Common::Stack<IndexRecordCursor> CursorStack; class MessageState { public: - MessageState() : _module(-1) { } - int getMessage(MessageTuple *t); - int getNext(); + MessageState() : _module(-1), _locked(false) { } + int findTuple(MessageTuple &t); + MessageTuple getTuple(); + MessageTuple getRefTuple(); + int getMessage(); + void gotoNext(); + char *getText(); int getTalker(); int getLength(); - void getText(char *buffer); + MessageTuple &getLastTuple(); + int getLastModule(); int loadRes(ResourceManager *resmgr, int module, bool lock); - int isInitialized() { return _initialized; } - void initialize(ResourceManager *resmgr); - void setVersion(int version) { _version = version; } private: - void parse(IndexRecordCursor *cursor, MessageTuple *t); - void parseRef(IndexRecordCursor *cursor, MessageTuple *t); void initCursor(); void advanceCursor(bool increaseSeq); - int _initialized; Resource *_currentResource; int _module; + bool _locked; int _recordCount; byte *_indexRecords; CursorStack _cursorStack; IndexRecordCursor _engineCursor; + MessageTuple _lastReturned; + int _lastReturnedModule; int _version; }; |