aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/kernel.h4
-rw-r--r--engines/sci/engine/kfile.cpp177
-rw-r--r--engines/sci/engine/kgraphics.cpp130
-rw-r--r--engines/sci/engine/kmenu.cpp7
-rw-r--r--engines/sci/engine/kmisc.cpp38
-rw-r--r--engines/sci/engine/kpathing.cpp69
-rw-r--r--engines/sci/engine/kstring.cpp197
-rw-r--r--engines/sci/gfx/gfx_gui.cpp2
-rw-r--r--engines/sci/gfx/gfx_state_internal.h2
-rw-r--r--engines/sci/gfx/gfx_widgets.cpp1
-rw-r--r--engines/sci/gfx/menubar.cpp24
-rw-r--r--engines/sci/gfx/menubar.h2
12 files changed, 291 insertions, 362 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 79da7032e0..9d20a99b58 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -216,9 +216,9 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc
* @param s The current state
* @param address The address to look up
* @param index The relative index
- * @return The referenced text, or NULL on error.
+ * @return The referenced text, or empty string on error.
*/
-char *kernel_lookup_text(EngineState *s, reg_t address, int index);
+Common::String kernel_lookup_text(EngineState *s, reg_t address, int index);
/******************** Priority macros/functions ********************/
/**
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 372e7b8aa9..f4b54765f4 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -197,11 +197,11 @@ void file_open(EngineState *s, const char *filename, int mode) {
}
reg_t kFOpen(EngineState *s, int, int argc, reg_t *argv) {
- char *name = s->segMan->derefString(argv[0]);
+ Common::String name = s->segMan->getString(argv[0]);
int mode = argv[1].toUint16();
- debug(3, "kFOpen(%s,0x%x)", name, mode);
- file_open(s, name, mode);
+ debug(3, "kFOpen(%s,0x%x)", name.c_str(), mode);
+ file_open(s, name.c_str(), mode);
return s->r_acc;
}
@@ -250,9 +250,9 @@ void fwrite_wrapper(EngineState *s, int handle, const char *data, int length) {
reg_t kFPuts(EngineState *s, int, int argc, reg_t *argv) {
int handle = argv[0].toUint16();
- char *data = s->segMan->derefString(argv[1]);
+ Common::String data = s->segMan->getString(argv[1]);
- fwrite_wrapper(s, handle, data, strlen(data));
+ fwrite_wrapper(s, handle, data.c_str(), data.size());
return s->r_acc;
}
@@ -307,12 +307,13 @@ static void fseek_wrapper(EngineState *s, int handle, int offset, int whence) {
}
reg_t kFGets(EngineState *s, int, int argc, reg_t *argv) {
- char *dest = s->segMan->derefString(argv[0]);
int maxsize = argv[1].toUint16();
+ char *buf = new char[maxsize];
int handle = argv[2].toUint16();
debug(3, "kFGets(%d,%d)", handle, maxsize);
- fgets_wrapper(s, dest, maxsize, handle);
+ fgets_wrapper(s, buf, maxsize, handle);
+ s->segMan->memcpy(argv[0], (const byte*)buf, maxsize);
return argv[0];
}
@@ -320,14 +321,12 @@ reg_t kFGets(EngineState *s, int, int argc, reg_t *argv) {
* Writes the cwd to the supplied address and returns the address in acc.
*/
reg_t kGetCWD(EngineState *s, int, int argc, reg_t *argv) {
- char *targetaddr = s->segMan->derefString(argv[0]);
-
// We do not let the scripts see the file system, instead pretending
// we are always in the same directory.
// TODO/FIXME: Is "/" a good value? Maybe "" or "." or "C:\" are better?
- strcpy(targetaddr, "/");
+ s->segMan->strcpy(argv[0], "/");
- debug(3, "kGetCWD() -> %s", targetaddr);
+ debug(3, "kGetCWD() -> %s", "/");
return argv[0];
}
@@ -352,58 +351,50 @@ enum {
reg_t kDeviceInfo(EngineState *s, int, int argc, reg_t *argv) {
int mode = argv[0].toUint16();
- char *game_prefix, *input_s, *output_s;
switch (mode) {
- case K_DEVICE_INFO_GET_DEVICE:
- input_s = s->segMan->derefString(argv[1]);
- output_s = s->segMan->derefString(argv[2]);
- assert(input_s != output_s);
+ case K_DEVICE_INFO_GET_DEVICE: {
+ Common::String input_str = s->segMan->getString(argv[1]);
- strcpy(output_s, "/");
- debug(3, "K_DEVICE_INFO_GET_DEVICE(%s) -> %s", input_s, output_s);
+ s->segMan->strcpy(argv[2], "/");
+ debug(3, "K_DEVICE_INFO_GET_DEVICE(%s) -> %s", input_str.c_str(), "/");
break;
-
+ }
case K_DEVICE_INFO_GET_CURRENT_DEVICE:
- output_s = s->segMan->derefString(argv[1]);
-
- strcpy(output_s, "/");
- debug(3, "K_DEVICE_INFO_GET_CURRENT_DEVICE() -> %s", output_s);
+ s->segMan->strcpy(argv[1], "/");
+ debug(3, "K_DEVICE_INFO_GET_CURRENT_DEVICE() -> %s", "/");
break;
case K_DEVICE_INFO_PATHS_EQUAL: {
- char *path1_s = s->segMan->derefString(argv[1]);
- char *path2_s = s->segMan->derefString(argv[2]);
- debug(3, "K_DEVICE_INFO_PATHS_EQUAL(%s,%s)", path1_s, path2_s);
+ Common::String path1_s = s->segMan->getString(argv[1]);
+ Common::String path2_s = s->segMan->getString(argv[2]);
+ debug(3, "K_DEVICE_INFO_PATHS_EQUAL(%s,%s)", path1_s.c_str(), path2_s.c_str());
- return make_reg(0, Common::matchString(path2_s, path1_s, false, true));
+ return make_reg(0, Common::matchString(path2_s.c_str(), path1_s.c_str(), false, true));
}
break;
- case K_DEVICE_INFO_IS_FLOPPY:
- input_s = s->segMan->derefString(argv[1]);
- debug(3, "K_DEVICE_INFO_IS_FLOPPY(%s)", input_s);
+ case K_DEVICE_INFO_IS_FLOPPY: {
+ Common::String input_str = s->segMan->getString(argv[1]);
+ debug(3, "K_DEVICE_INFO_IS_FLOPPY(%s)", input_str.c_str());
return NULL_REG; /* Never */
-
+ }
/* SCI uses these in a less-than-portable way to delete savegames.
** Read http://www-plan.cs.colorado.edu/creichen/freesci-logs/2005.10/log20051019.html
** for more information on our workaround for this.
*/
case K_DEVICE_INFO_GET_SAVECAT_NAME: {
- output_s = s->segMan->derefString(argv[1]);
- game_prefix = s->segMan->derefString(argv[2]);
-
- sprintf(output_s, "__throwaway");
- debug(3, "K_DEVICE_INFO_GET_SAVECAT_NAME(%s) -> %s", game_prefix, output_s);
+ Common::String game_prefix = s->segMan->getString(argv[2]);
+ s->segMan->strcpy(argv[1], "__throwaway");
+ debug(3, "K_DEVICE_INFO_GET_SAVECAT_NAME(%s) -> %s", game_prefix.c_str(), "__throwaway");
}
break;
case K_DEVICE_INFO_GET_SAVEFILE_NAME: {
- output_s = s->segMan->derefString(argv[1]);
- game_prefix = s->segMan->derefString(argv[2]);
+ Common::String game_prefix = s->segMan->getString(argv[2]);
int savegame_id = argv[3].toUint16();
- sprintf(output_s, "__throwaway");
- debug(3, "K_DEVICE_INFO_GET_SAVEFILE_NAME(%s,%d) -> %s", game_prefix, savegame_id, output_s);
+ s->segMan->strcpy(argv[1], "__throwaway");
+ debug(3, "K_DEVICE_INFO_GET_SAVEFILE_NAME(%s,%d) -> %s", game_prefix.c_str(), savegame_id, "__throwaway");
delete_savegame(s, savegame_id);
}
break;
@@ -428,9 +419,9 @@ reg_t kGetSaveDir(EngineState *s, int, int argc, reg_t *argv) {
}
reg_t kCheckFreeSpace(EngineState *s, int, int argc, reg_t *argv) {
- char *path = s->segMan->derefString(argv[0]);
+ Common::String path = s->segMan->getString(argv[0]);
- debug(3, "kCheckFreeSpace(%s)", path);
+ debug(3, "kCheckFreeSpace(%s)", path.c_str());
// We simply always pretend that there is enough space.
// The alternative would be to write a big test file, which is not nice
// on systems where doing so is very slow.
@@ -486,10 +477,10 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
}
reg_t kCheckSaveGame(EngineState *s, int, int argc, reg_t *argv) {
- char *game_id = s->segMan->derefString(argv[0]);
+ Common::String game_id = s->segMan->getString(argv[0]);
int savedir_nr = argv[1].toUint16();
- debug(3, "kCheckSaveGame(%s, %d)", game_id, savedir_nr);
+ debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), savedir_nr);
Common::Array<SavegameDesc> saves;
listSavegames(saves);
@@ -522,12 +513,11 @@ reg_t kCheckSaveGame(EngineState *s, int, int argc, reg_t *argv) {
}
reg_t kGetSaveFiles(EngineState *s, int, int argc, reg_t *argv) {
- char *game_id = s->segMan->derefString(argv[0]);
- char *nametarget = s->segMan->derefString(argv[1]);
- reg_t nametarget_base = argv[1];
+ Common::String game_id = s->segMan->getString(argv[0]);
+ reg_t nametarget = argv[1];
reg_t *nameoffsets = s->segMan->derefRegPtr(argv[2], 0);
- debug(3, "kGetSaveFiles(%s,%s)", game_id, nametarget);
+ debug(3, "kGetSaveFiles(%s)", game_id.c_str());
Common::Array<SavegameDesc> saves;
listSavegames(saves);
@@ -556,29 +546,34 @@ reg_t kGetSaveFiles(EngineState *s, int, int argc, reg_t *argv) {
++s->r_acc.offset; // Increase number of files found
nameoffsets++; // Make sure the next ID string address is written to the next pointer
- strncpy(nametarget, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH); // Copy identifier string
- *(nametarget + SCI_MAX_SAVENAME_LENGTH - 1) = 0; // Make sure it's terminated
- nametarget += SCI_MAX_SAVENAME_LENGTH; // Increase name offset pointer accordingly
- nametarget_base.offset += SCI_MAX_SAVENAME_LENGTH;
+ Common::String name = meta.savegame_name;
+ if (name.size() > SCI_MAX_SAVENAME_LENGTH-1)
+ name = Common::String(meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH-1);
+ s->segMan->strcpy(nametarget, name.c_str());
+
+ // Increase name offset pointer accordingly
+ nametarget.offset += SCI_MAX_SAVENAME_LENGTH;
}
delete in;
}
}
//free(gfname);
- *nametarget = 0; // Terminate list
+ s->segMan->strcpy(nametarget, ""); // Terminate list
return s->r_acc;
}
reg_t kSaveGame(EngineState *s, int, int argc, reg_t *argv) {
- char *game_id = s->segMan->derefString(argv[0]);
+ Common::String game_id = s->segMan->getString(argv[0]);
int savedir_nr = argv[1].toUint16();
int savedir_id; // Savegame ID, derived from savedir_nr and the savegame ID list
- char *game_description = s->segMan->derefString(argv[2]);
- char *version = argc > 3 ? strdup(s->segMan->derefString(argv[3])) : NULL;
+ Common::String game_description = s->segMan->getString(argv[2]);
+ Common::String version;
+ if (argc > 3)
+ version = s->segMan->getString(argv[3]);
- debug(3, "kSaveGame(%s,%d,%s,%s)", game_id, savedir_nr, game_description, version);
+ debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), savedir_nr, game_description.c_str(), version.c_str());
Common::Array<SavegameDesc> saves;
listSavegames(saves);
@@ -623,7 +618,7 @@ reg_t kSaveGame(EngineState *s, int, int argc, reg_t *argv) {
return NULL_REG;
}
- if (gamestate_save(s, out, game_description, version)) {
+ if (gamestate_save(s, out, game_description.c_str(), version.c_str())) {
warning("Saving the game failed.");
s->r_acc = NULL_REG;
} else {
@@ -642,10 +637,10 @@ reg_t kSaveGame(EngineState *s, int, int argc, reg_t *argv) {
}
reg_t kRestoreGame(EngineState *s, int, int argc, reg_t *argv) {
- char *game_id = s->segMan->derefString(argv[0]);
+ Common::String game_id = s->segMan->getString(argv[0]);
int savedir_nr = argv[1].toUint16();
- debug(3, "kRestoreGame(%s,%d)", game_id, savedir_nr);
+ debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savedir_nr);
Common::Array<SavegameDesc> saves;
listSavegames(saves);
@@ -668,7 +663,7 @@ reg_t kRestoreGame(EngineState *s, int, int argc, reg_t *argv) {
shrink_execution_stack(s, s->execution_stack_base + 1);
} else {
s->r_acc = make_reg(0, 1);
- warning("Restoring failed (game_id = '%s')", game_id);
+ warning("Restoring failed (game_id = '%s')", game_id.c_str());
}
return s->r_acc;
}
@@ -681,12 +676,12 @@ reg_t kRestoreGame(EngineState *s, int, int argc, reg_t *argv) {
}
reg_t kValidPath(EngineState *s, int, int argc, reg_t *argv) {
- const char *path = s->segMan->derefString(argv[0]);
+ Common::String path = s->segMan->getString(argv[0]);
// FIXME: For now, we only accept the (fake) root dir "/" as a valid path.
- s->r_acc = make_reg(0, 0 == strcmp(path, "/"));
+ s->r_acc = make_reg(0, path == "/");
- debug(3, "kValidPath(%s) -> %d", path, s->r_acc.offset);
+ debug(3, "kValidPath(%s) -> %d", path.c_str(), s->r_acc.offset);
return s->r_acc;
}
@@ -732,14 +727,12 @@ void DirSeeker::nextFile() {
return;
}
- char *mem = _vm->segMan->derefString(_outbuffer);
- memset(mem, 0, 13);
-
// TODO: Transform the string back into a format usable by the SCI scripts.
// I.e., strip any TARGET- prefix.
- const char *string = _iter->c_str();
- assert(string);
- strncpy(mem, string, 12);
+ Common::String string = *_iter;
+ if (string.size() > 12)
+ string = Common::String(string.c_str(), 12);
+ _vm->segMan->strcpy(_outbuffer, string.c_str());
// Return the result and advance the list iterator :)
_vm->r_acc = _outbuffer;
@@ -753,11 +746,11 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
switch (func_nr) {
case K_FILEIO_OPEN : {
- char *name = s->segMan->derefString(argv[1]);
+ Common::String name = s->segMan->getString(argv[1]);
int mode = argv[2].toUint16();
- file_open(s, name, mode);
- debug(3, "K_FILEIO_OPEN(%s,0x%x)", name, mode);
+ file_open(s, name.c_str(), mode);
+ debug(3, "K_FILEIO_OPEN(%s,0x%x)", name.c_str(), mode);
break;
}
case K_FILEIO_CLOSE : {
@@ -769,25 +762,29 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
}
case K_FILEIO_READ_RAW : {
int handle = argv[1].toUint16();
- char *dest = s->segMan->derefString(argv[2]);
int size = argv[3].toUint16();
+ char *buf = new char[size];
debug(3, "K_FILEIO_READ_RAW(%d,%d)", handle, size);
- fread_wrapper(s, dest, size, handle);
+ fread_wrapper(s, buf, size, handle);
+ s->segMan->memcpy(argv[2], (const byte*)buf, size);
+ delete[] buf;
break;
}
case K_FILEIO_WRITE_RAW : {
int handle = argv[1].toUint16();
- char *buf = s->segMan->derefString(argv[2]);
int size = argv[3].toUint16();
+ char *buf = new char[size];
+ s->segMan->memcpy((byte*)buf, argv[2], size);
debug(3, "K_FILEIO_WRITE_RAW(%d,%d)", handle, size);
fwrite_wrapper(s, handle, buf, size);
+ delete[] buf;
break;
}
case K_FILEIO_UNLINK : {
- char *name = s->segMan->derefString(argv[1]);
- debug(3, "K_FILEIO_UNLINK(%s)", name);
+ Common::String name = s->segMan->getString(argv[1]);
+ debug(3, "K_FILEIO_UNLINK(%s)", name.c_str());
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
const Common::String wrappedName = ((Sci::SciEngine*)g_engine)->wrapFilename(name);
@@ -797,25 +794,27 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
break;
}
case K_FILEIO_READ_STRING : {
- char *dest = s->segMan->derefString(argv[1]);
int size = argv[2].toUint16();
+ char *buf = new char[size];
int handle = argv[3].toUint16();
debug(3, "K_FILEIO_READ_STRING(%d,%d)", handle, size);
- fgets_wrapper(s, dest, size, handle);
+ fgets_wrapper(s, buf, size, handle);
+ s->segMan->memcpy(argv[1], (const byte*)buf, size);
+ delete[] buf;
return argv[1];
}
case K_FILEIO_WRITE_STRING : {
int handle = argv[1].toUint16();
int size = argv[3].toUint16();
- char *buf = s->segMan->derefString(argv[2]);
+ Common::String str = s->segMan->getString(argv[2]);
debug(3, "K_FILEIO_WRITE_STRING(%d,%d)", handle, size);
// CHECKME: Is the size parameter used at all?
// In the LSL5 password protection it is zero, and we should
// then write a full string. (Not sure if it should write the
// terminating zero.)
- fwrite_wrapper(s, handle, buf, strlen(buf));
+ fwrite_wrapper(s, handle, str.c_str(), str.size());
break;
}
case K_FILEIO_SEEK : {
@@ -828,16 +827,16 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
break;
}
case K_FILEIO_FIND_FIRST : {
- char *mask = s->segMan->derefString(argv[1]);
+ Common::String mask = s->segMan->getString(argv[1]);
reg_t buf = argv[2];
int attr = argv[3].toUint16(); // We won't use this, Win32 might, though...
- debug(3, "K_FILEIO_FIND_FIRST(%s,0x%x)", mask, attr);
+ debug(3, "K_FILEIO_FIND_FIRST(%s,0x%x)", mask.c_str(), attr);
#ifndef WIN32
- if (strcmp(mask, "*.*") == 0)
- strcpy(mask, "*"); // For UNIX
+ if (mask == "*.*")
+ mask = "*"; // For UNIX
#endif
- s->_dirseeker.firstFile(mask, buf);
+ s->_dirseeker.firstFile(mask.c_str(), buf);
break;
}
@@ -847,7 +846,7 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
break;
}
case K_FILEIO_FILE_EXISTS : {
- char *name = s->segMan->derefString(argv[1]);
+ Common::String name = s->segMan->getString(argv[1]);
// Check for regular file
bool exists = Common::File::exists(name);
@@ -859,7 +858,7 @@ reg_t kFileIO(EngineState *s, int, int argc, reg_t *argv) {
exists = !saveFileMan->listSavefiles(name).empty();
}
- debug(3, "K_FILEIO_FILE_EXISTS(%s) -> %d", name, exists);
+ debug(3, "K_FILEIO_FILE_EXISTS(%s) -> %d", name.c_str(), exists);
return make_reg(0, exists);
}
default :
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index fc72e6e3f1..b57fc32dcf 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -445,7 +445,7 @@ void _k_graph_rebuild_port_with_color(EngineState *s, gfx_color_t newbgcolor) {
newport = sciw_new_window(s, port->zone, port->_font, port->_color, newbgcolor,
s->titlebar_port->_font, s->ega_colors[15], s->ega_colors[8],
- port->title_text, port->port_flags & ~kWindowTransparent);
+ port->_title_text.c_str(), port->port_flags & ~kWindowTransparent);
if (s->dyn_views) {
int found = 0;
@@ -602,29 +602,32 @@ reg_t kGraph(EngineState *s, int, int argc, reg_t *argv) {
reg_t kTextSize(EngineState *s, int, int argc, reg_t *argv) {
int width, height;
- char *text = argv[1].segment ? s->segMan->derefString(argv[1]) : NULL;
- const char *sep = NULL;
+ Common::String text = s->segMan->getString(argv[1]);
reg_t *dest = s->segMan->derefRegPtr(argv[0], 4);
int maxwidth = (argc > 3) ? argv[3].toUint16() : 0;
int font_nr = argv[2].toUint16();
- if ((argc > 4) && (argv[4].segment))
- sep = s->segMan->derefString(argv[4]);
+ Common::String sep_str;
+ const char *sep = NULL;
+ if ((argc > 4) && (argv[4].segment)) {
+ sep_str = s->segMan->getString(argv[4]);
+ sep = sep_str.c_str();
+ }
if (maxwidth < 0)
maxwidth = 0;
dest[0] = dest[1] = NULL_REG;
- if (!text || !*text || !dest) { // Empty text
+ if (text.empty() || !dest) { // Empty text
dest[2] = dest[3] = make_reg(0, 0);
debugC(2, kDebugLevelStrings, "GetTextSize: Empty string\n");
return s->r_acc;
}
- gfxop_get_text_params(s->gfx_state, font_nr, s->strSplit(text, sep).c_str(), maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE,
+ gfxop_get_text_params(s->gfx_state, font_nr, s->strSplit(text.c_str(), sep).c_str(), maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE,
&width, &height, 0, NULL, NULL, NULL);
- debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text, width, height);
+ debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text.c_str(), width, height);
dest[2] = make_reg(0, height);
// dest[3] = make_reg(0, maxwidth? maxwidth : width);
@@ -1303,7 +1306,9 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse);
static void disableCertainButtons(SegManager *segMan, Common::String gameName, reg_t obj) {
reg_t text_pos = GET_SEL32(obj, text);
- char *text = text_pos.isNull() ? NULL : segMan->derefString(text_pos);
+ Common::String text;
+ if (!text_pos.isNull())
+ text = segMan->getString(text_pos);
int type = GET_SEL32V(obj, type);
int state = GET_SEL32V(obj, state);
@@ -1327,15 +1332,15 @@ static void disableCertainButtons(SegManager *segMan, Common::String gameName, r
* that game - bringing the save/load dialog on a par with SCI0.
*/
// NOTE: This _only_ works with the English version
- if (type == K_CONTROL_BUTTON && text && (gameName == "sq4") &&
- getSciVersion() < SCI_VERSION_1_1 && !strcmp(text, " Delete ")) {
+ if (type == K_CONTROL_BUTTON && (gameName == "sq4") &&
+ getSciVersion() < SCI_VERSION_1_1 && text == " Delete ") {
PUT_SEL32V(obj, state, (state | kControlStateDisabled) & ~kControlStateEnabled);
}
// Disable the "Change Directory" button, as we don't allow the game engine to
// change the directory where saved games are placed
// NOTE: This _only_ works with the English version
- if (type == K_CONTROL_BUTTON && text && !strcmp(text, "Change\r\nDirectory")) {
+ if (type == K_CONTROL_BUTTON && text == "Change\r\nDirectory") {
PUT_SEL32V(obj, state, (state | kControlStateDisabled) & ~kControlStateEnabled);
}
}
@@ -1369,13 +1374,13 @@ void update_cursor_limits(int *display_offset, int *cursor, int max_displayed) {
#define _K_EDIT_DELETE \
if (cursor < textlen) { \
- memmove(text + cursor, text + cursor + 1, textlen - cursor +1); \
+ text.deleteChar(cursor); \
}
#define _K_EDIT_BACKSPACE \
if (cursor) { \
--cursor; \
- memmove(text + cursor, text + cursor + 1, textlen - cursor +1); \
+ text.deleteChar(cursor); \
--textlen; \
}
@@ -1401,15 +1406,17 @@ reg_t kEditControl(EngineState *s, int, int argc, reg_t *argv) {
reg_t text_pos = GET_SEL32(obj, text);
int display_offset = 0;
- char *text = s->segMan->derefString(text_pos);
+ Common::String text = s->segMan->getString(text_pos);
int textlen;
+#if 0
if (!text) {
warning("Could not draw control: %04x:%04x does not reference text", PRINT_REG(text_pos));
return s->r_acc;
}
+#endif
- textlen = strlen(text);
+ textlen = text.size();
cursor += display_offset;
@@ -1432,7 +1439,7 @@ reg_t kEditControl(EngineState *s, int, int argc, reg_t *argv) {
if (cursor > 0) --cursor;
break;
case 'k':
- text[cursor] = 0;
+ text = Common::String(text.c_str(), cursor);
break; // Terminate string
case 'h':
_K_EDIT_BACKSPACE;
@@ -1503,20 +1510,20 @@ reg_t kEditControl(EngineState *s, int, int argc, reg_t *argv) {
if (cursor == textlen) {
if (textlen < max) {
- text[cursor++] = key;
- text[cursor] = 0; // Terminate string
+ text += key;
+ cursor++;
}
} else if (inserting) {
if (textlen < max) {
int i;
for (i = textlen + 2; i >= cursor; i--)
- text[i] = text[i - 1];
- text[cursor++] = key;
+ text.setChar(text[i - 1], i);
+ text.setChar(key, cursor++);
}
} else { // Overwriting
- text[cursor++] = key;
+ text.setChar(key, cursor++);
}
if (max_displayed < max)
@@ -1528,6 +1535,7 @@ reg_t kEditControl(EngineState *s, int, int argc, reg_t *argv) {
}
PUT_SEL32V(obj, cursor, cursor); // Write back cursor position
+ s->segMan->strcpy(text_pos, text.c_str()); // Write back string
}
case K_CONTROL_ICON:
@@ -1564,7 +1572,9 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
int font_nr = GET_SEL32V(obj, font);
reg_t text_pos = GET_SEL32(obj, text);
- const char *text = text_pos.isNull() ? NULL : s->segMan->derefString(text_pos);
+ Common::String text;
+ if (!text_pos.isNull())
+ text = s->segMan->getString(text_pos);
int view = GET_SEL32V(obj, view);
int cel = sign_extend_byte(GET_SEL32V(obj, cel));
int loop = sign_extend_byte(GET_SEL32V(obj, loop));
@@ -1578,7 +1588,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
switch (type) {
case K_CONTROL_BUTTON:
debugC(2, kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d\n", PRINT_REG(obj), x, y);
- ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, s->strSplit(text, NULL).c_str(), font_nr,
+ ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, s->strSplit(text.c_str(), NULL).c_str(), font_nr,
(int8)(state & kControlStateFramed), (int8)inverse, (int8)(state & kControlStateDisabled)));
break;
@@ -1587,7 +1597,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x to %d,%d, mode=%d\n", PRINT_REG(obj), x, y, mode);
- ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, s->strSplit(text).c_str(), font_nr, mode,
+ ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, s->strSplit(text.c_str()).c_str(), font_nr, mode,
(int8)(!!(state & kControlStateDitherFramed)), (int8)inverse));
break;
@@ -1597,11 +1607,11 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
max = GET_SEL32V(obj, max);
cursor = GET_SEL32V(obj, cursor);
- if (cursor > (signed)strlen(text))
- cursor = strlen(text);
+ if (cursor > (signed)text.size())
+ cursor = text.size();
// update_cursor_limits(&s->save_dir_edit_offset, &cursor, max); FIXME: get rid of this?
- ADD_TO_CURRENT_PICTURE_PORT(sciw_new_edit_control(s->port, obj, area, text, font_nr, (unsigned)cursor, (int8)inverse));
+ ADD_TO_CURRENT_PICTURE_PORT(sciw_new_edit_control(s->port, obj, area, text.c_str(), font_nr, (unsigned)cursor, (int8)inverse));
break;
case K_CONTROL_ICON:
@@ -1614,8 +1624,6 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
case K_CONTROL_CONTROL:
case K_CONTROL_CONTROL_ALIAS: {
- const char **entries_list = NULL;
- const char *seeker;
int entries_nr;
int lsTop = GET_SEL32V(obj, lsTop) - text_pos.offset;
int list_top = 0;
@@ -1627,29 +1635,41 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) {
cursor = GET_SEL32V(obj, cursor) - text_pos.offset;
entries_nr = 0;
- seeker = text;
- while (seeker[0]) { // Count string entries in NULL terminated string list
+
+ // NOTE: most types of pointer dereferencing don't like odd offsets
+ assert((entry_size & 1) == 0);
+
+ reg_t seeker = text_pos;
+ // Count string entries in NULL terminated string list
+ while (s->segMan->strlen(seeker) > 0) {
++entries_nr;
- seeker += entry_size;
+ seeker.offset += entry_size;
}
+ // TODO: This is rather convoluted... It would be a lot cleaner
+ // if sciw_new_list_control would take a list of Common::String
+ Common::String *strings = 0;
+ const char **entries_list = NULL;
+
if (entries_nr) { // determine list_top, selection, and the entries_list
- seeker = text;
+ seeker = text_pos;
entries_list = (const char**)malloc(sizeof(char *) * entries_nr);
+ strings = new Common::String[entries_nr];
for (i = 0; i < entries_nr; i++) {
- entries_list[i] = seeker;
- seeker += entry_size ;
- if ((seeker - text) == lsTop)
+ strings[i] = s->segMan->getString(seeker);
+ entries_list[i] = strings[i].c_str();
+ seeker.offset += entry_size;
+ if ((seeker.offset - text_pos.offset) == lsTop)
list_top = i + 1;
- if ((seeker - text) == cursor)
+ if ((seeker.offset - text_pos.offset) == cursor)
selection = i + 1;
}
}
-
ADD_TO_CURRENT_PICTURE_PORT(sciw_new_list_control(s->port, obj, area, font_nr, entries_list, entries_nr,
list_top, selection, (int8)inverse));
- if (entries_nr)
- free(entries_list);
+
+ free(entries_list);
+ delete[] strings;
}
break;
@@ -2511,10 +2531,14 @@ reg_t kNewWindow(EngineState *s, int, int argc, reg_t *argv) {
lWhite.alpha = 0;
lWhite.priority = -1;
lWhite.control = -1;
- const char *title = argv[4 + argextra].segment ? s->segMan->derefString(argv[4 + argextra]) : NULL;
+ Common::String title;
+ if (argv[4 + argextra].segment) {
+ title = s->segMan->getString(argv[4 + argextra]);
+ title = s->strSplit(title.c_str(), NULL);
+ }
window = sciw_new_window(s, gfx_rect(x, y, xl, yl), s->titlebar_port->_font, fgcolor, bgcolor,
- s->titlebar_port->_font, lWhite, black, title ? s->strSplit(title, NULL).c_str() : NULL, flags);
+ s->titlebar_port->_font, lWhite, black, title.c_str(), flags);
// PQ3 and SCI1.1 games have the interpreter store underBits implicitly
if (argextra)
@@ -3113,7 +3137,7 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
int temp;
bool save_under = false;
gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 };
- char *text;
+ Common::String text;
GfxPort *port = (s->port) ? s->port : s->picture_port;
bool update_immediately = true;
@@ -3139,16 +3163,18 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
if (textp.segment) {
argpt = 1;
- text = s->segMan->derefString(textp);
+ text = s->segMan->getString(textp);
} else {
argpt = 2;
text = kernel_lookup_text(s, textp, index);
}
+#if 0
if (!text) {
error("Display with invalid reference %04x:%04x", PRINT_REG(textp));
return NULL_REG;
}
+#endif
while (argpt < argc) {
switch (argv[argpt++].toUint16()) {
@@ -3251,7 +3277,7 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
if (halign == ALIGN_LEFT) {
// If the text does not fit on the screen, move it to the left and upwards until it does
- gfxop_get_text_params(s->gfx_state, font_nr, text, area.width, &area.width, &area.height, 0, NULL, NULL, NULL);
+ gfxop_get_text_params(s->gfx_state, font_nr, text.c_str(), area.width, &area.width, &area.height, 0, NULL, NULL, NULL);
// Make the text fit on the screen
if (area.x + area.width > 320)
@@ -3275,7 +3301,7 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
assert_primary_widget_lists(s);
- text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0);
+ text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text.c_str()).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0);
if (!text_handle) {
error("Display: Failed to create text widget");
@@ -3293,7 +3319,7 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
debugC(2, kDebugLevelGraphics, "Saving (%d, %d) size (%d, %d) as %04x:%04x\n", save_area.x, save_area.y, save_area.width, save_area.height, PRINT_REG(s->r_acc));
}
- debugC(2, kDebugLevelGraphics, "Display: Commiting text '%s'\n", text);
+ debugC(2, kDebugLevelGraphics, "Display: Commiting text '%s'\n", text.c_str());
//ADD_TO_CURRENT_PICTURE_PORT(text_handle);
@@ -3307,12 +3333,12 @@ reg_t kDisplay(EngineState *s, int, int argc, reg_t *argv) {
}
static reg_t kShowMovie_Windows(EngineState *s, int argc, reg_t *argv) {
- const char *filename = s->segMan->derefString(argv[1]);
+ Common::String filename = s->segMan->getString(argv[1]);
Graphics::AVIPlayer *player = new Graphics::AVIPlayer(g_system);
if (!player->open(filename)) {
- warning("Failed to open movie file %s", filename);
+ warning("Failed to open movie file %s", filename.c_str());
return s->r_acc;
}
@@ -3386,13 +3412,13 @@ static reg_t kShowMovie_Windows(EngineState *s, int argc, reg_t *argv) {
}
static reg_t kShowMovie_DOS(EngineState *s, int argc, reg_t *argv) {
- const char *filename = s->segMan->derefString(argv[0]);
+ Common::String filename = s->segMan->getString(argv[0]);
int delay = argv[1].toUint16(); // Time between frames in ticks
int frameNr = 0;
SeqDecoder seq;
if (!seq.loadFile(filename) && !seq.loadFile(Common::String("SEQ/") + filename)) {
- warning("Failed to open movie file %s", filename);
+ warning("Failed to open movie file %s", filename.c_str());
return s->r_acc;
}
diff --git a/engines/sci/engine/kmenu.cpp b/engines/sci/engine/kmenu.cpp
index c57006c3a9..5a1f32e876 100644
--- a/engines/sci/engine/kmenu.cpp
+++ b/engines/sci/engine/kmenu.cpp
@@ -34,8 +34,8 @@
namespace Sci {
reg_t kAddMenu(EngineState *s, int, int argc, reg_t *argv) {
- char *name = s->segMan->derefString(argv[0]);
- char *contents = s->segMan->derefString(argv[1]);
+ Common::String name = s->segMan->getString(argv[0]);
+ Common::String contents = s->segMan->getString(argv[1]);
s->_menubar->addMenu(s->gfx_state, name,
contents, s->titlebar_port->_font, argv[1]);
@@ -78,8 +78,7 @@ reg_t kDrawStatus(EngineState *s, int, int argc, reg_t *argv) {
s->status_bar_background = bgcolor;
if (text.segment) {
- const char *tmp = s->segMan->derefString(text);
- s->_statusBarText = tmp ? tmp : "";
+ s->_statusBarText = s->segMan->getString(text);
}
sciw_set_status_bar(s, s->titlebar_port, s->_statusBarText, fgcolor, bgcolor);
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index dbbb10a4d1..dca123663d 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -180,53 +180,39 @@ reg_t kMemory(EngineState *s, int, int argc, reg_t *argv) {
break;
case K_MEMORY_MEMCPY : {
int size = argv[3].toUint16();
- byte *dest = s->segMan->derefBulkPtr(argv[1], size);
- byte *src = s->segMan->derefBulkPtr(argv[2], size);
-
- if (dest && src)
- memcpy(dest, src, size);
- else {
- warning("Could not execute kMemory:memcpy of %d bytes:", size);
- if (!dest) {
- warning(" dest ptr (%04x:%04x) invalid/memory region too small", PRINT_REG(argv[1]));
- }
- if (!src) {
- warning(" src ptr (%04x:%04x) invalid/memory region too small", PRINT_REG(argv[2]));
- }
- }
+ s->segMan->memcpy(argv[1], argv[2], size);
break;
}
case K_MEMORY_PEEK : {
- byte *ref = s->segMan->derefBulkPtr(argv[1], 2);
+ SegmentRef ref = s->segMan->dereference(argv[1]);
- if (!ref) {
+ if (!ref.isValid() || ref.maxSize < 2) {
// This occurs in KQ5CD when interacting with certain objects
warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
- if (s->segMan->getSegmentType(argv[1].segment) == SEG_TYPE_LOCALS)
- return *((reg_t *) ref);
+ if (ref.isRaw)
+ return make_reg(0, (int16)READ_LE_UINT16(ref.raw));
else
- return make_reg(0, (int16)READ_LE_UINT16(ref));
+ return *(ref.reg);
break;
}
case K_MEMORY_POKE : {
- byte *ref = s->segMan->derefBulkPtr(argv[1], 2);
+ SegmentRef ref = s->segMan->dereference(argv[1]);
- if (!ref) {
+ if (!ref.isValid() || ref.maxSize < 2) {
warning("Attempt to poke invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
- if (s->segMan->getSegmentType(argv[1].segment) == SEG_TYPE_LOCALS)
- *((reg_t *) ref) = argv[2];
- else {
+ if (ref.isRaw) {
if (argv[2].segment) {
error("Attempt to poke memory reference %04x:%04x to %04x:%04x", PRINT_REG(argv[2]), PRINT_REG(argv[1]));
return s->r_acc;
- WRITE_LE_UINT16(ref, argv[2].offset); // ?
}
- }
+ WRITE_LE_UINT16(ref.raw, argv[2].offset);
+ } else
+ *(ref.reg) = argv[2];
break;
}
}
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 6bc2a1086f..421974701e 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -257,27 +257,18 @@ struct PathfindingState {
static Vertex *s_vertex_cur; // FIXME: Avoid non-const global vars
-// FIXME: Temporary hack to deal with points in reg_ts
-static bool polygon_is_reg_t(const byte *list, int size) {
- // Check the first three reg_ts
- for (int i = 0; i < (size < 3 ? size : 3); i++)
- if ((((reg_t *) list) + i)->segment)
- // Non-zero segment, cannot be reg_ts
- return false;
-
- // First three segments were zero, assume reg_ts
- return true;
-}
-
-static Common::Point read_point(const byte *list, int is_reg_t, int offset) {
+static Common::Point read_point(SegManager *segMan, reg_t list, int offset) {
+ SegmentRef list_r = segMan->dereference(list);
+ if (!list_r.isValid()) {
+ warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(list));
+ }
Common::Point point;
- if (!is_reg_t) {
- POLY_GET_POINT(list, offset, point);
+ if (list_r.isRaw) {
+ POLY_GET_POINT(list_r.raw, offset, point);
} else {
- POLY_GET_POINT_REG_T((reg_t *)list, offset, point);
+ POLY_GET_POINT_REG_T(list_r.reg, offset, point);
}
-
return point;
}
@@ -295,14 +286,12 @@ static bool polygons_equal(SegManager *segMan, reg_t p1, reg_t p2) {
if (size != GET_SEL32(p2, size).toUint16())
return false;
- const byte *p1_points = segMan->derefBulkPtr(GET_SEL32(p1, points), size * POLY_POINT_SIZE);
- const byte *p2_points = segMan->derefBulkPtr(GET_SEL32(p2, points), size * POLY_POINT_SIZE);
- bool p1_is_reg_t = polygon_is_reg_t(p1_points, size);
- bool p2_is_reg_t = polygon_is_reg_t(p2_points, size);
+ reg_t p1_points = GET_SEL32(p1, points);
+ reg_t p2_points = GET_SEL32(p2, points);
// Check for the same points
for (int i = 0; i < size; i++) {
- if (read_point(p1_points, p1_is_reg_t, i) != read_point(p2_points, p2_is_reg_t, i))
+ if (read_point(segMan, p1_points, i) != read_point(segMan, p2_points, i))
return false;
}
@@ -360,14 +349,12 @@ static void draw_polygon(EngineState *s, reg_t polygon) {
int size = GET_SEL32(polygon, size).toUint16();
int type = GET_SEL32(polygon, type).toUint16();
Common::Point first, prev;
- const byte *list = s->segMan->derefBulkPtr(points, size * POLY_POINT_SIZE);
- int is_reg_t = polygon_is_reg_t(list, size);
int i;
- prev = first = read_point(list, is_reg_t, 0);
+ prev = first = read_point(segMan, points, 0);
for (i = 1; i < size; i++) {
- Common::Point point = read_point(list, is_reg_t, i);
+ Common::Point point = read_point(segMan, points, i);
draw_line(s, prev, point, type);
prev = point;
}
@@ -407,18 +394,16 @@ static void print_polygon(SegManager *segMan, reg_t polygon) {
int size = GET_SEL32(polygon, size).toUint16();
int type = GET_SEL32(polygon, type).toUint16();
int i;
- const byte *point_array = segMan->derefBulkPtr(points, size * POLY_POINT_SIZE);
- int is_reg_t = polygon_is_reg_t(point_array, size);
Common::Point point;
printf("%i:", type);
for (i = 0; i < size; i++) {
- point = read_point(point_array, is_reg_t, i);
+ point = read_point(segMan, points, i);
printf(" (%i, %i)", point.x, point.y);
}
- point = read_point(point_array, is_reg_t, 0);
+ point = read_point(segMan, points, 0);
printf(" (%i, %i);\n", point.x, point.y);
}
@@ -1231,15 +1216,15 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
int i;
reg_t points = GET_SEL32(polygon, points);
int size = GET_SEL32(polygon, size).toUint16();
- const byte *list = s->segMan->derefBulkPtr(points, size * POLY_POINT_SIZE);
Polygon *poly = new Polygon(GET_SEL32(polygon, type).toUint16());
- int is_reg_t = polygon_is_reg_t(list, size);
+
+ int skip = 0;
// WORKAROUND: broken polygon in lsl1sci, room 350, after opening elevator
// Polygon has 17 points but size is set to 19
if ((size == 19) && (s->_gameName == "lsl1sci")) {
if ((s->currentRoomNumber() == 350)
- && (read_point(list, is_reg_t, 18) == Common::Point(108, 137))) {
+ && (read_point(segMan, points, 18) == Common::Point(108, 137))) {
debug(1, "Applying fix for broken polygon in lsl1sci, room 350");
size = 17;
}
@@ -1248,33 +1233,31 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
// WORKAROUND: self-intersecting polygons in ECO, rooms 221, 280 and 300
if ((size == 11) && (s->_gameName == "ecoquest")) {
if ((s->currentRoomNumber() == 300)
- && (read_point(list, is_reg_t, 10) == Common::Point(221, 0))) {
+ && (read_point(segMan, points, 10) == Common::Point(221, 0))) {
debug(1, "Applying fix for self-intersecting polygon in ECO, room 300");
size = 10;
}
}
if ((size == 12) && (s->_gameName == "ecoquest")) {
if ((s->currentRoomNumber() == 280)
- && (read_point(list, is_reg_t, 11) == Common::Point(238, 189))) {
+ && (read_point(segMan, points, 11) == Common::Point(238, 189))) {
debug(1, "Applying fix for self-intersecting polygon in ECO, room 280");
size = 10;
}
}
if ((size == 16) && (s->_gameName == "ecoquest")) {
if ((s->currentRoomNumber() == 221)
- && (read_point(list, is_reg_t, 1) == Common::Point(419, 175))) {
+ && (read_point(segMan, points, 1) == Common::Point(419, 175))) {
debug(1, "Applying fix for self-intersecting polygon in ECO, room 221");
// Swap the first two points
- poly->vertices.insertHead(new Vertex(read_point(list, is_reg_t, 1)));
- poly->vertices.insertHead(new Vertex(read_point(list, is_reg_t, 0)));
- size = 14;
- assert(!is_reg_t);
- list += 2 * POLY_POINT_SIZE;
+ poly->vertices.insertHead(new Vertex(read_point(segMan, points, 1)));
+ poly->vertices.insertHead(new Vertex(read_point(segMan, points, 0)));
+ skip = 2;
}
}
- for (i = 0; i < size; i++) {
- Vertex *vertex = new Vertex(read_point(list, is_reg_t, i));
+ for (i = skip; i < size; i++) {
+ Vertex *vertex = new Vertex(read_point(segMan, points, i));
poly->vertices.insertHead(vertex);
}
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 3d22936680..84ac720a05 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -39,12 +39,12 @@ namespace Sci {
}
/* Returns the string the script intended to address */
-char *kernel_lookup_text(EngineState *s, reg_t address, int index) {
+Common::String kernel_lookup_text(EngineState *s, reg_t address, int index) {
char *seeker;
Resource *textres;
if (address.segment)
- return s->segMan->derefString(address);
+ return s->segMan->getString(address);
else {
int textlen;
int _index = index;
@@ -189,7 +189,7 @@ reg_t kSetSynonyms(EngineState *s, int, int argc, reg_t *argv) {
reg_t kParse(EngineState *s, int, int argc, reg_t *argv) {
SegManager *segMan = s->segMan;
reg_t stringpos = argv[0];
- char *string = s->segMan->derefString(stringpos);
+ Common::String string = s->segMan->getString(stringpos);
char *error;
ResultWordList words;
reg_t event = argv[1];
@@ -197,7 +197,7 @@ reg_t kParse(EngineState *s, int, int argc, reg_t *argv) {
s->parser_event = event;
- bool res = voc->tokenizeString(words, string, &error);
+ bool res = voc->tokenizeString(words, string.c_str(), &error);
s->parser_valid = 0; /* not valid */
if (res && !words.empty()) {
@@ -242,8 +242,7 @@ reg_t kParse(EngineState *s, int, int argc, reg_t *argv) {
s->r_acc = make_reg(0, 0);
PUT_SEL32V(event, claimed, 1);
if (error) {
- char *pbase_str = s->segMan->derefString(s->parser_base);
- strcpy(pbase_str, error);
+ s->segMan->strcpy(s->parser_base, error);
debugC(2, kDebugLevelParser, "Word unknown: %s\n", error);
/* Issue warning: */
@@ -259,129 +258,66 @@ reg_t kParse(EngineState *s, int, int argc, reg_t *argv) {
reg_t kStrEnd(EngineState *s, int, int argc, reg_t *argv) {
reg_t address = argv[0];
- char *seeker = s->segMan->derefString(address);
-
- while (*seeker++)
- ++address.offset;
+ address.offset += s->segMan->strlen(address);
return address;
}
reg_t kStrCat(EngineState *s, int, int argc, reg_t *argv) {
- char *s1 = s->segMan->derefString(argv[0]);
- char *s2 = s->segMan->derefString(argv[1]);
+ Common::String s1 = s->segMan->getString(argv[0]);
+ Common::String s2 = s->segMan->getString(argv[1]);
- strcat(s1, s2);
+ s1 += s2;
+ s->segMan->strcpy(argv[0], s1.c_str());
return argv[0];
}
reg_t kStrCmp(EngineState *s, int, int argc, reg_t *argv) {
- char *s1 = s->segMan->derefString(argv[0]);
- char *s2 = s->segMan->derefString(argv[1]);
+ Common::String s1 = s->segMan->getString(argv[0]);
+ Common::String s2 = s->segMan->getString(argv[1]);
if (argc > 2)
- return make_reg(0, strncmp(s1, s2, argv[2].toUint16()));
+ return make_reg(0, strncmp(s1.c_str(), s2.c_str(), argv[2].toUint16()));
else
- return make_reg(0, strcmp(s1, s2));
+ return make_reg(0, strcmp(s1.c_str(), s2.c_str()));
}
reg_t kStrCpy(EngineState *s, int, int argc, reg_t *argv) {
- char *dest = s->segMan->derefString(argv[0]);
- char *src = s->segMan->derefString(argv[1]);
-
- if (!dest) {
- warning("Attempt to strcpy TO invalid pointer %04x:%04x",
- PRINT_REG(argv[0]));
- return NULL_REG;
- }
- if (!src) {
- warning("Attempt to strcpy FROM invalid pointer %04x:%04x",
- PRINT_REG(argv[1]));
- *dest = 0;
- return argv[1];
- }
-
if (argc > 2) {
int length = argv[2].toSint16();
if (length >= 0)
- strncpy(dest, src, length);
- else {
- if (s->segMan->_heap[argv[0].segment]->getType() == SEG_TYPE_DYNMEM) {
- reg_t *srcp = (reg_t *) src;
-
- int i;
- warning("Performing reg_t to raw conversion for AvoidPath");
- for (i = 0; i < -length / 2; i++) {
- dest[2 * i] = srcp->offset & 0xff;
- dest[2 * i + 1] = srcp->offset >> 8;
- srcp++;
- }
- } else
- memcpy(dest, src, -length);
- }
+ s->segMan->strncpy(argv[0], argv[1], length);
+ else
+ s->segMan->memcpy(argv[0], argv[1], -length);
} else
- strcpy(dest, src);
+ s->segMan->strcpy(argv[0], argv[1]);
return argv[0];
}
-/* Simple heuristic to work around array handling peculiarity in SQ4:
-It uses StrAt() to read the individual elements, so we must determine
-whether a string is really a string or an array. */
-static int is_print_str(const char *str) {
- int printable = 0;
- int len = strlen(str);
-
- if (len == 0) return 1;
-
- while (*str) {
- // The parameter passed to isprint() needs to be in the range
- // 0 to 0xFF or EOF, according to MSDN, therefore we cast it
- // to an unsigned char. Values outside this range (in this
- // case, negative values) yield unpredictable results. Refer to:
- // http://msdn.microsoft.com/en-us/library/ewx8s4kw.aspx
- if (isprint((byte)*str))
- printable++;
- str++;
- }
-
- return ((float)printable / (float)len >= 0.5);
-}
-
reg_t kStrAt(EngineState *s, int, int argc, reg_t *argv) {
- byte *dest = (byte*)s->segMan->derefString(argv[0]);
- reg_t *dest2;
-
- if (!dest) {
+ SegmentRef dest_r = s->segMan->dereference(argv[0]);
+ if (!dest_r.raw) {
warning("Attempt to StrAt at invalid pointer %04x:%04x", PRINT_REG(argv[0]));
return NULL_REG;
}
- bool lsl5PasswordWorkaround = false;
- // LSL5 stores the password at the beginning in memory.drv, using XOR encryption,
- // which means that is_print_str() will fail. Therefore, do not use the heuristic to determine
- // if we're handling a string or an array for LSL5's password screen (room 155)
- if (s->_gameName.equalsIgnoreCase("lsl5") && s->currentRoomNumber() == 155)
- lsl5PasswordWorkaround = true;
-
- if ((argc == 2) &&
- /* Our pathfinder already works around the issue we're trying to fix */
- (strcmp(s->segMan->getDescription(argv[0]), AVOIDPATH_DYNMEM_STRING) != 0) &&
- ((strlen((const char*)dest) < 2) ||
- (!lsl5PasswordWorkaround && !is_print_str((const char*)dest)))) {
- // SQ4 array handling detected
+ byte* dest;
+
+ if (dest_r.isRaw) {
+ dest = (byte*)dest_r.raw + argv[1].toUint16();
+ } else {
#ifndef SCUMM_BIG_ENDIAN
int odd = argv[1].toUint16() & 1;
#else
int odd = !(argv[1].toUint16() & 1);
#endif
- dest2 = ((reg_t *) dest) + (argv[1].toUint16() / 2);
- dest = ((byte *)(&dest2->offset)) + odd;
- } else
- dest += argv[1].toUint16();
+ reg_t *tmp = dest_r.reg + (argv[1].toUint16() / 2);
+ dest = ((byte *)(&tmp->offset)) + odd;
+ }
s->r_acc = make_reg(0, *dest);
@@ -393,7 +329,8 @@ reg_t kStrAt(EngineState *s, int, int argc, reg_t *argv) {
reg_t kReadNumber(EngineState *s, int, int argc, reg_t *argv) {
- char *source = s->segMan->derefString(argv[0]);
+ Common::String source_str = s->segMan->getString(argv[0]);
+ const char *source = source_str.c_str();
while (isspace(*source))
source++; /* Skip whitespace */
@@ -419,10 +356,10 @@ reg_t kReadNumber(EngineState *s, int, int argc, reg_t *argv) {
reg_t kFormat(EngineState *s, int, int argc, reg_t *argv) {
int *arguments;
reg_t dest = argv[0];
- char *target = s->segMan->derefString(dest);
+ char targetbuf[512];
+ char *target = targetbuf;
reg_t position = argv[1]; /* source */
int index = argv[2].toUint16();
- char *source;
char *str_base = target;
int mode = 0;
int paramindex = 0; /* Next parameter to evaluate */
@@ -439,7 +376,8 @@ reg_t kFormat(EngineState *s, int, int argc, reg_t *argv) {
else
startarg = 3; /* First parameter to use for formatting */
- source = kernel_lookup_text(s, position, index);
+ Common::String source_str = kernel_lookup_text(s, position, index);
+ const char* source = source_str.c_str();
debugC(2, kDebugLevelStrings, "Formatting \"%s\"\n", source);
@@ -505,9 +443,9 @@ reg_t kFormat(EngineState *s, int, int argc, reg_t *argv) {
switch (xfer) {
case 's': { /* Copy string */
reg_t reg = argv[startarg + paramindex];
- char *tempsource = kernel_lookup_text(s, reg,
- arguments[paramindex + 1]);
- int slen = strlen(tempsource);
+ Common::String tempsource = kernel_lookup_text(s, reg,
+ arguments[paramindex + 1]);
+ int slen = strlen(tempsource.c_str());
int extralen = str_leng - slen;
CHECK_OVERFLOW1(target, extralen, NULL_REG);
if (extralen < 0)
@@ -538,7 +476,7 @@ reg_t kFormat(EngineState *s, int, int argc, reg_t *argv) {
}
- strcpy(target, tempsource);
+ strcpy(target, tempsource.c_str());
target += slen;
switch (align) {
@@ -627,19 +565,15 @@ reg_t kFormat(EngineState *s, int, int argc, reg_t *argv) {
free(arguments);
*target = 0; /* Terminate string */
+
+ s->segMan->strcpy(dest, targetbuf);
+
return dest; /* Return target addr */
}
reg_t kStrLen(EngineState *s, int, int argc, reg_t *argv) {
- char *str = s->segMan->derefString(argv[0]);
-
- if (!str) {
- warning("StrLen: invalid pointer %04x:%04x", PRINT_REG(argv[0]));
- return NULL_REG;
- }
-
- return make_reg(0, strlen(str));
+ return make_reg(0, s->segMan->strlen(argv[0]));
}
@@ -664,7 +598,7 @@ reg_t kGetFarText(EngineState *s, int, int argc, reg_t *argv) {
** resource.
*/
- strcpy(s->segMan->derefString(argv[2]), seeker); /* Copy the string and get return value */
+ s->segMan->strcpy(argv[2], seeker); /* Copy the string and get return value */
return argv[2];
}
@@ -710,7 +644,6 @@ reg_t kMessage(EngineState *s, int, int argc, reg_t *argv) {
case K_MESSAGE_GET:
case K_MESSAGE_NEXT: {
reg_t bufferReg;
- char *buffer = NULL;
Common::String str;
reg_t retval;
@@ -739,18 +672,15 @@ reg_t kMessage(EngineState *s, int, int argc, reg_t *argv) {
if (!bufferReg.isNull()) {
int len = str.size() + 1;
- buffer = s->segMan->derefString(bufferReg, len);
-
- if (buffer) {
- strcpy(buffer, str.c_str());
- } else {
+ SegmentRef buffer_r = s->segMan->dereference(bufferReg);
+ if (buffer_r.maxSize < len) {
warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str.c_str());
// Set buffer to empty string if possible
- buffer = s->segMan->derefString(bufferReg, 1);
- if (buffer)
- *buffer = 0;
- }
+ if (buffer_r.maxSize > 0)
+ s->segMan->strcpy(bufferReg, "");
+ } else
+ s->segMan->strcpy(bufferReg, str.c_str());
s->_msgState.gotoNext();
}
@@ -792,6 +722,8 @@ reg_t kMessage(EngineState *s, int, int argc, reg_t *argv) {
if (buffer) {
// FIXME: Is this correct? I.e., do we really write into a "raw" segment
// here? Or maybe we want to write 4 reg_t instead?
+ assert(s->segMan->dereference(argv[1]).isRaw);
+
WRITE_LE_UINT16(buffer, module);
WRITE_LE_UINT16(buffer + 2, msg.noun);
WRITE_LE_UINT16(buffer + 4, msg.verb);
@@ -811,26 +743,29 @@ reg_t kMessage(EngineState *s, int, int argc, reg_t *argv) {
}
reg_t kSetQuitStr(EngineState *s, int, int argc, reg_t *argv) {
- char *quitStr = s->segMan->derefString(argv[0]);
- debug("Setting quit string to '%s'", quitStr);
- return s->r_acc;
+ Common::String quitStr = s->segMan->getString(argv[0]);
+ debug("Setting quit string to '%s'", quitStr.c_str());
+ return s->r_acc;
}
reg_t kStrSplit(EngineState *s, int, int argc, reg_t *argv) {
- const char *format = s->segMan->derefString(argv[1]);
- const char *sep = !argv[2].isNull() ? s->segMan->derefString(argv[2]) : NULL;
- Common::String str = s->strSplit(format, sep);
+ Common::String format = s->segMan->getString(argv[1]);
+ Common::String sep_str;
+ const char *sep = NULL;
+ if (!argv[2].isNull()) {
+ sep_str = s->segMan->getString(argv[2]);
+ sep = sep_str.c_str();
+ }
+ Common::String str = s->strSplit(format.c_str(), sep);
// Make sure target buffer is large enough
- char *buf = s->segMan->derefString(argv[0], str.size() + 1);
-
- if (buf) {
- strcpy(buf, str.c_str());
- return argv[0];
- } else {
+ 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());
return NULL_REG;
}
+ s->segMan->strcpy(argv[0], str.c_str());
+ return argv[0];
}
} // End of namespace Sci
diff --git a/engines/sci/gfx/gfx_gui.cpp b/engines/sci/gfx/gfx_gui.cpp
index b4479b7341..6deb01b1c2 100644
--- a/engines/sci/gfx/gfx_gui.cpp
+++ b/engines/sci/gfx/gfx_gui.cpp
@@ -175,7 +175,7 @@ GfxPort *sciw_new_window(EngineState *s,
win = new GfxPort(visual, area, color, bgcolor);
win->_font = font;
- win->title_text = title;
+ win->_title_text = title;
win->port_flags = flags;
win->_flags |= GFXW_FLAG_IMMUNE_TO_SNAPSHOTS;
diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h
index 1bff83e713..aeb3b05cd4 100644
--- a/engines/sci/gfx/gfx_state_internal.h
+++ b/engines/sci/gfx/gfx_state_internal.h
@@ -382,7 +382,7 @@ struct GfxPort : public GfxContainer {
gfxw_snapshot_t *restore_snap; /**< Snapshot to be restored automagically,
experimental feature used in the PQ3 interpreter */
int port_flags; /**< interpreter-dependant flags */
- const char *title_text;
+ Common::String _title_text;
byte gray_text; /**< Whether text is 'grayed out' (dithered) */
public:
diff --git a/engines/sci/gfx/gfx_widgets.cpp b/engines/sci/gfx/gfx_widgets.cpp
index 3d94bf1342..1d737e9eb2 100644
--- a/engines/sci/gfx/gfx_widgets.cpp
+++ b/engines/sci/gfx/gfx_widgets.cpp
@@ -1581,7 +1581,6 @@ GfxPort::GfxPort(GfxVisual *visual_, rect_t area, gfx_color_t fgcolor, gfx_color
port_bg = NULL;
_parent = NULL;
_decorations = NULL;
- title_text = NULL;
draw_pos = Common::Point(0, 0);
gray_text = 0;
_color = fgcolor;
diff --git a/engines/sci/gfx/menubar.cpp b/engines/sci/gfx/menubar.cpp
index 1c04486d4d..283b233477 100644
--- a/engines/sci/gfx/menubar.cpp
+++ b/engines/sci/gfx/menubar.cpp
@@ -122,7 +122,7 @@ int Menu::addMenuItem(GfxState *state, MenuType type, const char *left, const ch
return total_left_size + width;
}
-void Menubar::addMenu(GfxState *state, const char *title, const char *entries, int font, reg_t entries_base) {
+void Menubar::addMenu(GfxState *state, const Common::String &title, const Common::String &entries, int font, reg_t entries_base) {
char tracker;
char *left = NULL;
reg_t left_origin = entries_base;
@@ -134,17 +134,19 @@ void Menubar::addMenu(GfxState *state, const char *title, const char *entries, i
menu._title = title;
- gfxop_get_text_params(state, font, title, SIZE_INF, &(menu._titleWidth), &height, 0, NULL, NULL, NULL);
+ gfxop_get_text_params(state, font, title.c_str(), SIZE_INF, &(menu._titleWidth), &height, 0, NULL, NULL, NULL);
+
+ const char *entries_p = entries.c_str();
do {
- tracker = *entries++;
+ tracker = *entries_p++;
entries_base.offset++;
if (!left) { // Left string not finished?
if (tracker == '=') { // Hit early-SCI tag assignment?
- left = sci_strndup(entries - string_len - 1, string_len);
- tag = atoi(entries++);
- tracker = *entries++;
+ left = sci_strndup(entries_p - string_len - 1, string_len);
+ tag = atoi(entries_p++);
+ tracker = *entries_p++;
}
if ((tracker == 0 && string_len > 0) || (tracker == '=') || (tracker == ':')) { // End of entry
MenuType entrytype = MENU_TYPE_NORMAL;
@@ -152,7 +154,7 @@ void Menubar::addMenu(GfxState *state, const char *title, const char *entries, i
reg_t beginning;
if (!left)
- left = sci_strndup(entries - string_len - 1, string_len);
+ left = sci_strndup(entries_p - string_len - 1, string_len);
inleft = left;
while (isspace(*inleft))
@@ -179,7 +181,7 @@ void Menubar::addMenu(GfxState *state, const char *title, const char *entries, i
if (!left) {
left_origin = entries_base;
left_origin.offset -= string_len + 1;
- left = sci_strndup(entries - string_len - 1, string_len);
+ left = sci_strndup(entries_p - string_len - 1, string_len);
}
string_len = 0; // Continue with the right string
} else
@@ -189,7 +191,7 @@ void Menubar::addMenu(GfxState *state, const char *title, const char *entries, i
if ((tracker == ':') || (tracker == 0)) { // End of entry
int key, modifiers = 0;
- char *right = sci_strndup(entries - string_len - 1, string_len);
+ char *right = sci_strndup(entries_p - string_len - 1, string_len);
if (right[0] == '#') {
right[0] = SCI_SPECIAL_CHAR_FUNCTION; // Function key
@@ -294,7 +296,7 @@ int Menubar::setAttribute(EngineState *s, int menu_nr, int item_nr, int attribut
case MENU_ATTRIBUTE_SAID:
if (value.segment) {
item->_saidPos = value;
- memcpy(item->_said, s->segMan->derefBulkPtr(value, 0), MENU_SAID_SPEC_SIZE); // Copy Said spec
+ s->segMan->memcpy(item->_said, value, MENU_SAID_SPEC_SIZE); // Copy Said spec
item->_flags |= MENU_ATTRIBUTE_FLAGS_SAID;
} else
@@ -304,7 +306,7 @@ int Menubar::setAttribute(EngineState *s, int menu_nr, int item_nr, int attribut
case MENU_ATTRIBUTE_TEXT:
assert(value.segment);
- item->_text = s->segMan->derefString(value);
+ item->_text = s->segMan->getString(value);
item->_textPos = value;
break;
diff --git a/engines/sci/gfx/menubar.h b/engines/sci/gfx/menubar.h
index 44ecd8f1bb..029af5923b 100644
--- a/engines/sci/gfx/menubar.h
+++ b/engines/sci/gfx/menubar.h
@@ -171,7 +171,7 @@ public:
* @param[in] font The font which is to be used for drawing
* @param[in] entries_base Segmented VM address of the entries string
*/
- void addMenu(GfxState *state, const char *title, const char *entries, int font, reg_t entries_base);
+ void addMenu(GfxState *state, const Common::String &title, const Common::String &entries, int font, reg_t entries_base);
/**