[Scummvm-git-logs] scummvm master -> 5a95bb2eadd19294b2719a17acd621546f5ad3d1
sev-
noreply at scummvm.org
Sun Jul 24 21:38:13 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
5a95bb2ead DIRECTOR: Fix b_installMenu string decoding
Commit: 5a95bb2eadd19294b2719a17acd621546f5ad3d1
https://github.com/scummvm/scummvm/commit/5a95bb2eadd19294b2719a17acd621546f5ad3d1
Author: Scott Percival (code at moral.net.au)
Date: 2022-07-24T23:38:10+02:00
Commit Message:
DIRECTOR: Fix b_installMenu string decoding
installMenu loads a menu definition from a text cast member. In our
implementation, at load time we coerce the contents to Unicode based on
the platform encoding. Unfortunately for us, Macromedia decided to use
two non-ASCII codepoints for indicating checkmarks and code separators,
which are evaluated as the byte value instead of whatever physical
character they correspond to.
Amending this is slightly hacky, as the UTF-8 equivalent of these
codepoints is two bytes long. The text is first normalised to remove the
platform transformation. The checkmark UTF-8 sequence is replaced with
the single byte equivalent, to maintain compatibility with MacMenu.
Finally, the code separator UTF-8 sequence is used to split the line
between menu definition and script definition.
Fixes the menu system in Eastern Mind.
Changed paths:
engines/director/lingo/lingo-builtins.cpp
engines/director/stxt.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index d9b1e6c140b..171908efe2f 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1958,9 +1958,7 @@ void LB::b_installMenu(int nargs) {
}
TextCastMember *field = static_cast<TextCastMember *>(member);
- // TODO: We should process the U32String instead of encoding it to Mac Roman first
- Common::String menuStxt = g_lingo->_compiler->codePreprocessor(field->getText(), field->getCast()->_lingoArchive, kNoneScript, memberID, true).encode(Common::kMacRoman);
- Common::String line;
+ Common::U32String menuStxt = g_lingo->_compiler->codePreprocessor(field->getText(), field->getCast()->_lingoArchive, kNoneScript, memberID, true);
int linenum = -1; // We increment it before processing
Graphics::MacMenu *menu = g_director->_wm->addMenu();
@@ -1971,27 +1969,50 @@ void LB::b_installMenu(int nargs) {
menu->setCommandsCallback(menuCommandsCallback, g_director);
- debugC(3, kDebugLingoExec, "installMenu: '%s'", Common::toPrintable(menuStxt).c_str());
+ debugC(3, kDebugLingoExec, "installMenu: '%s'", Common::toPrintable(menuStxt).encode().c_str());
LingoArchive *mainArchive = g_director->getCurrentMovie()->getMainLingoArch();
- for (const byte *s = (const byte *)menuStxt.c_str(); *s; s++) {
- // Get next line
- line.clear();
- while (*s && *s != '\n') { // If we see a whitespace
- if (*s == (byte)'\xc2') {
+ // Since loading the STXT converts the text to Unicode based on the platform
+ // encoding, we need to fetch the correct Unicode character for the platform.
+
+ // STXT sections use Mac-style carriage returns for line breaks.
+ // The code preprocessor converts carriage returns to line feeds.
+ const uint32 LINE_BREAK = 0x0a;
+ // Menu definitions use the character 0xc3 to denote a checkmark.
+ // For Mac, this is â. For Windows, this is Ã.
+ const uint8 CHECKMARK_CHAR = 0xc3;
+ const uint32 CHECKMARK_U32 = numToChar(CHECKMARK_CHAR);
+ const char *CHECKMARK_STR = "\xc3\x83";
+ // Menu definitions use the character 0xc5 to denote a code separator.
+ // For Mac, this is â. For Windows, this is Ã
.
+ const uint8 CODE_SEPARATOR_CHAR = 0xc5;
+ const uint32 CODE_SEPARATOR_U32 = numToChar(CODE_SEPARATOR_CHAR);
+ const char *CODE_SEPARATOR_STR = "\xc3\x85";
+
+ Common::U32String lineBuffer;
+
+ for (const Common::u32char_type_t *s = menuStxt.c_str(); *s; s++) {
+ lineBuffer.clear();
+ while (*s && *s != LINE_BREAK) {
+ if (*s == CHECKMARK_U32) {
+ lineBuffer += CHECKMARK_CHAR;
s++;
- if (*s == '\n') {
- line += ' ';
-
+ } else if (*s == CODE_SEPARATOR_U32) {
+ lineBuffer += CODE_SEPARATOR_CHAR;
+ s++;
+ } else if (*s == CONTINUATION) { // fast forward to the next line
+ s++;
+ if (*s == LINE_BREAK) {
+ lineBuffer += ' ';
s++;
}
} else {
- line += *s++;
+ lineBuffer += *s++;
}
}
-
linenum++;
+ Common::String line = lineBuffer.encode();
if (line.empty())
continue;
@@ -2016,14 +2037,22 @@ void LB::b_installMenu(int nargs) {
continue;
}
- // We have \xc5 as a separator
- const char *p = strchr(line.c_str(), '\xc5');
+ // If the line has a UTF8 checkmark, replace it with a byte character
+ // as expected by MacMenu.
+ size_t checkOffset = line.find(CHECKMARK_STR);
+ if (checkOffset != Common::String::npos) {
+ line.erase(checkOffset, strlen(CHECKMARK_STR));
+ line.insertChar((const char)CHECKMARK_CHAR, checkOffset);
+ }
+
+ // Split the line at the code separator
+ size_t sepOffset = line.find(CODE_SEPARATOR_STR);
Common::String text;
- if (p) {
- text = Common::String(line.c_str(), p);
- command = Common::String(p + 1);
+ if (sepOffset != Common::String::npos) {
+ text = Common::String(line.c_str(), line.c_str() + sepOffset);
+ command = Common::String(line.c_str() + sepOffset + strlen(CODE_SEPARATOR_STR));
} else {
text = line;
command = "";
diff --git a/engines/director/stxt.cpp b/engines/director/stxt.cpp
index 8b550623073..1db2ecf26ad 100644
--- a/engines/director/stxt.cpp
+++ b/engines/director/stxt.cpp
@@ -43,7 +43,7 @@ Stxt::Stxt(Cast *cast, Common::SeekableReadStreamEndian &textStream) : _cast(cas
uint32 offset = textStream.readUint32();
if (offset != 12) {
- error("Stxt init: unhandlef offset");
+ error("Stxt init: unhandled offset");
return;
}
uint32 strLen = textStream.readUint32();
@@ -51,6 +51,18 @@ Stxt::Stxt(Cast *cast, Common::SeekableReadStreamEndian &textStream) : _cast(cas
Common::String text = textStream.readString(0, strLen);
debugC(3, kDebugText, "Stxt init: offset: %d strLen: %d dataLen: %d textlen: %u", offset, strLen, dataLen, text.size());
+ // TODO: Before applying formatting and decoding the text to a U32String,
+ // check if the following hold true:
+ // - The engine platform doesn't match the file platform
+ // - The movie has a valid font table (FXmp)
+ // - The font table has a mapping between the two platforms
+ // - The text has sections written in a font without a Map None qualifier
+ // If yes, then just those sections should be preprocessed by churning the
+ // bytes through the appropriate mapping (e.g. if running a Mac file on
+ // Windows, use the "Mac: => Win:" rules).
+ // Confirmed in real Director 4 that these sections are preprocessed in
+ // the cast member on startup and not faked at text render time.
+
uint16 formattingCount = textStream.readUint16();
uint32 prevPos = 0;
More information about the Scummvm-git-logs
mailing list