aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/kstring.cpp180
-rw-r--r--engines/sci/engine/message.cpp112
-rw-r--r--engines/sci/engine/message.h22
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;
};