aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kstring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kstring.cpp')
-rw-r--r--engines/sci/engine/kstring.cpp220
1 files changed, 208 insertions, 12 deletions
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 2681b612e9..9254bce9c1 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -115,12 +115,14 @@ reg_t kStrAt(EngineState *s, int argc, reg_t *argv) {
if (argc > 2) { /* Request to modify this char */
tmp.offset &= 0xff00;
tmp.offset |= newvalue;
+ tmp.segment = 0;
}
} else {
value = tmp.offset >> 8;
if (argc > 2) { /* Request to modify this char */
tmp.offset &= 0x00ff;
tmp.offset |= newvalue << 8;
+ tmp.segment = 0;
}
}
}
@@ -141,19 +143,22 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
int16 result = 0;
if (*source == '$') {
- // hexadecimal input
+ // Hexadecimal input
result = (int16)strtol(source + 1, NULL, 16);
} else {
- // decimal input, we can not use strtol/atoi in here, because sierra used atoi BUT it was a non standard compliant
- // atoi, that didnt do clipping. In SQ4 we get the door code in here and that's even larger than uint32!
+ // Decimal input. We can not use strtol/atoi in here, because while
+ // Sierra used atoi, it was a non standard compliant atoi, that didn't
+ // do clipping. In SQ4 we get the door code in here and that's even
+ // larger than uint32!
if (*source == '-') {
result = -1;
source++;
}
while (*source) {
if ((*source < '0') || (*source > '9')) {
- // Sierras atoi stopped processing at anything different than number
- // Sometimes the input has a trailing space, that's fine (example: lsl3)
+ // Sierra's atoi stopped processing at anything which is not
+ // a digit. Sometimes the input has a trailing space, that's
+ // fine (example: lsl3)
if (*source != ' ') {
// TODO: this happens in lsl5 right in the intro -> we get '1' '3' 0xCD 0xCD 0xCD 0xCD 0xCD
// find out why this happens and fix it
@@ -423,15 +428,16 @@ reg_t kGetFarText(EngineState *s, int argc, reg_t *argv) {
seeker = (char *)textres->data;
- // The second parameter (counter) determines the number of the string inside the text
- // resource.
+ // The second parameter (counter) determines the number of the string
+ // inside the text resource.
while (counter--) {
while (*seeker++)
;
}
- // If the third argument is NULL, allocate memory for the destination. This occurs in
- // SCI1 Mac games. The memory will later be freed by the game's scripts.
+ // If the third argument is NULL, allocate memory for the destination. This
+ // occurs in SCI1 Mac games. The memory will later be freed by the game's
+ // scripts.
if (argv[2] == NULL_REG)
s->_segMan->allocDynmem(strlen(seeker) + 1, "Mac FarText", &argv[2]);
@@ -560,8 +566,8 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
}
reg_t kSetQuitStr(EngineState *s, int argc, reg_t *argv) {
- Common::String quitStr = s->_segMan->getString(argv[0]);
- debug("Setting quit string to '%s'", quitStr.c_str());
+ //Common::String quitStr = s->_segMan->getString(argv[0]);
+ //debug("Setting quit string to '%s'", quitStr.c_str());
return s->r_acc;
}
@@ -578,11 +584,201 @@ reg_t kStrSplit(EngineState *s, int argc, reg_t *argv) {
// Make sure target buffer is large enough
SegmentRef buf_r = s->_segMan->dereference(argv[0]);
if (!buf_r.isValid() || buf_r.maxSize < (int)str.size() + 1) {
- warning("StrSplit: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(argv[0]), str.size() + 1, str.c_str());
+ warning("StrSplit: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'",
+ PRINT_REG(argv[0]), str.size() + 1, str.c_str());
return NULL_REG;
}
s->_segMan->strcpy(argv[0], str.c_str());
return argv[0];
}
+#ifdef ENABLE_SCI32
+
+reg_t kText(EngineState *s, int argc, reg_t *argv) {
+ switch (argv[0].toUint16()) {
+ case 0:
+ return kTextSize(s, argc - 1, argv + 1);
+ default:
+ // TODO: Other subops here too, perhaps kTextColors and kTextFonts
+ warning("kText(%d)", argv[0].toUint16());
+ break;
+ }
+
+ return s->r_acc;
+}
+
+reg_t kString(EngineState *s, int argc, reg_t *argv) {
+ switch (argv[0].toUint16()) {
+ case 0: { // New
+ reg_t stringHandle;
+ SciString *string = s->_segMan->allocateString(&stringHandle);
+ string->setSize(argv[1].toUint16());
+
+ // Make sure the first character is a null character
+ if (string->getSize() > 0)
+ string->setValue(0, 0);
+
+ return stringHandle;
+ }
+ case 1: // Size
+ return make_reg(0, s->_segMan->getString(argv[1]).size());
+ case 2: { // At (return value at an index)
+ if (argv[1].segment == s->_segMan->getStringSegmentId())
+ return make_reg(0, s->_segMan->lookupString(argv[1])->getRawData()[argv[2].toUint16()]);
+
+ return make_reg(0, s->_segMan->getString(argv[1])[argv[2].toUint16()]);
+ }
+ case 3: { // Atput (put value at an index)
+ SciString *string = s->_segMan->lookupString(argv[1]);
+
+ uint32 index = argv[2].toUint16();
+ uint32 count = argc - 3;
+
+ if (index + count > 65535)
+ break;
+
+ if (string->getSize() < index + count)
+ string->setSize(index + count);
+
+ for (uint16 i = 0; i < count; i++)
+ string->setValue(i + index, argv[i + 3].toUint16());
+
+ return argv[1]; // We also have to return the handle
+ }
+ case 4: // Free
+ // Freeing of strings is handled by the garbage collector
+ return s->r_acc;
+ case 5: { // Fill
+ SciString *string = s->_segMan->lookupString(argv[1]);
+ uint16 index = argv[2].toUint16();
+
+ // A count of -1 means fill the rest of the array
+ uint16 count = argv[3].toSint16() == -1 ? string->getSize() - index : argv[3].toUint16();
+ uint16 stringSize = string->getSize();
+
+ if (stringSize < index + count)
+ string->setSize(index + count);
+
+ for (uint16 i = 0; i < count; i++)
+ string->setValue(i + index, argv[4].toUint16());
+
+ return argv[1];
+ }
+ case 6: { // Cpy
+ const char *string2 = 0;
+ uint32 string2Size = 0;
+
+ if (argv[3].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[3]);
+ string2 = string->getRawData();
+ string2Size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[3]);
+ string2 = string.c_str();
+ string2Size = string.size() + 1;
+ }
+
+ uint32 index1 = argv[2].toUint16();
+ uint32 index2 = argv[4].toUint16();
+
+ // The original engine ignores bad copies too
+ if (index2 > string2Size)
+ break;
+
+ // A count of -1 means fill the rest of the array
+ uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16();
+
+ // We have a special case here for argv[1] being a system string
+ if (argv[1].segment == s->_segMan->getSysStringsSegment()) {
+ // Resize if necessary
+ const uint16 sysStringId = argv[1].toUint16();
+ SystemString *sysString = s->_segMan->getSystemString(sysStringId);
+ assert(sysString);
+ if ((uint32)sysString->_maxSize < index1 + count) {
+ free(sysString->_value);
+ sysString->_maxSize = index1 + count;
+ sysString->_value = (char *)calloc(index1 + count, sizeof(char));
+ }
+
+ strncpy(sysString->_value + index1, string2 + index2, count);
+ } else {
+ SciString *string1 = s->_segMan->lookupString(argv[1]);
+
+ if (string1->getSize() < index1 + count)
+ string1->setSize(index1 + count);
+
+ // Note: We're accessing from c_str() here because the
+ // string's size ignores the trailing 0 and therefore
+ // triggers an assert when doing string2[i + index2].
+ for (uint16 i = 0; i < count; i++)
+ string1->setValue(i + index1, string2[i + index2]);
+ }
+
+ } return argv[1];
+ case 7: { // Cmp
+ Common::String string1 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]);
+ Common::String string2 = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]);
+
+ if (argc == 4) // Strncmp
+ return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[3].toUint16()));
+ else // Strcmp
+ return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
+ }
+ case 8: { // Dup
+ const char *rawString = 0;
+ uint32 size = 0;
+
+ if (argv[1].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[1]);
+ rawString = string->getRawData();
+ size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[1]);
+ rawString = string.c_str();
+ size = string.size() + 1;
+ }
+
+ reg_t stringHandle;
+ SciString *dupString = s->_segMan->allocateString(&stringHandle);
+ dupString->setSize(size);
+
+ for (uint32 i = 0; i < size; i++)
+ dupString->setValue(i, rawString[i]);
+
+ return stringHandle;
+ }
+ case 9: // Getdata
+ if (!s->_segMan->isHeapObject(argv[1]))
+ return argv[1];
+
+ return readSelector(s->_segMan, argv[1], SELECTOR(data));
+ case 10: // Stringlen
+ return make_reg(0, s->_segMan->strlen(argv[1]));
+ case 11: { // Printf
+ reg_t stringHandle;
+ s->_segMan->allocateString(&stringHandle);
+
+ reg_t *adjustedArgs = new reg_t[argc];
+ adjustedArgs[0] = stringHandle;
+ memcpy(&adjustedArgs[1], argv + 1, (argc - 1) * sizeof(reg_t));
+
+ kFormat(s, argc, adjustedArgs);
+ delete[] adjustedArgs;
+ return stringHandle;
+ }
+ case 12: // Printf Buf
+ return kFormat(s, argc - 1, argv + 1);
+ case 13: { // atoi
+ Common::String string = s->_segMan->getString(argv[1]);
+ return make_reg(0, (uint16)atoi(string.c_str()));
+ }
+ default:
+ error("Unknown kString subop %d", argv[0].toUint16());
+ }
+
+ return NULL_REG;
+}
+
+#endif
+
} // End of namespace Sci