Files
2026-02-02 04:50:13 +01:00

343 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/endian.h"
#include "common/macresman.h"
#include "common/punycode.h"
#include "kyra/engine/util.h"
namespace Kyra {
int Util::decodeString1(const char *src, char *dst) {
static const uint8 decodeTable1[] = {
0x20, 0x65, 0x74, 0x61, 0x69, 0x6E, 0x6F, 0x73, 0x72, 0x6C, 0x68,
0x63, 0x64, 0x75, 0x70, 0x6D
};
static const uint8 decodeTable2[] = {
0x74, 0x61, 0x73, 0x69, 0x6F, 0x20, 0x77, 0x62, 0x20, 0x72, 0x6E,
0x73, 0x64, 0x61, 0x6C, 0x6D, 0x68, 0x20, 0x69, 0x65, 0x6F, 0x72,
0x61, 0x73, 0x6E, 0x72, 0x74, 0x6C, 0x63, 0x20, 0x73, 0x79, 0x6E,
0x73, 0x74, 0x63, 0x6C, 0x6F, 0x65, 0x72, 0x20, 0x64, 0x74, 0x67,
0x65, 0x73, 0x69, 0x6F, 0x6E, 0x72, 0x20, 0x75, 0x66, 0x6D, 0x73,
0x77, 0x20, 0x74, 0x65, 0x70, 0x2E, 0x69, 0x63, 0x61, 0x65, 0x20,
0x6F, 0x69, 0x61, 0x64, 0x75, 0x72, 0x20, 0x6C, 0x61, 0x65, 0x69,
0x79, 0x6F, 0x64, 0x65, 0x69, 0x61, 0x20, 0x6F, 0x74, 0x72, 0x75,
0x65, 0x74, 0x6F, 0x61, 0x6B, 0x68, 0x6C, 0x72, 0x20, 0x65, 0x69,
0x75, 0x2C, 0x2E, 0x6F, 0x61, 0x6E, 0x73, 0x72, 0x63, 0x74, 0x6C,
0x61, 0x69, 0x6C, 0x65, 0x6F, 0x69, 0x72, 0x61, 0x74, 0x70, 0x65,
0x61, 0x6F, 0x69, 0x70, 0x20, 0x62, 0x6D
};
int size = 0;
uint cChar = 0;
while ((cChar = *src++) != 0) {
if (cChar & 0x80) {
cChar &= 0x7F;
int index = (cChar & 0x78) >> 3;
*dst++ = decodeTable1[index];
++size;
assert(cChar < sizeof(decodeTable2));
cChar = decodeTable2[cChar];
}
*dst++ = cChar;
++size;
}
*dst++ = 0;
return size;
}
void Util::decodeString2(const char *src, char *dst) {
if (!src || !dst)
return;
char out = 0;
while ((out = *src) != 0) {
if (*src == 0x1B) {
++src;
out = *src + 0x7F;
}
*dst++ = out;
++src;
}
*dst = 0;
}
void Util::convertString_KYRAtoGUI(char *str, int bufferSize, Common::CodePage srcCP) {
Common::U32String in(str, srcCP);
memset(str, 0, bufferSize);
Common::strlcpy(str, in.encode(Common::kUtf8).c_str(), bufferSize - 1);
}
void Util::convertString_GUItoKYRA(char *str, int bufferSize, Common::CodePage dstCP) {
Common::U32String in(str, Common::kUtf8);
memset(str, 0, bufferSize);
Common::strlcpy(str, in.encode(dstCP).c_str(), bufferSize);
}
Common::String Util::convertString_GUItoKYRA(Common::String &str, Common::CodePage dstCP) {
return Common::U32String(str.c_str(), Common::kUtf8).encode(dstCP);
}
Common::String Util::convertISOToUTF8(Common::String &str) {
return Common::U32String(str.c_str(), Common::kISO8859_1).encode(Common::kUtf8);
}
void Util::convertISOToDOS(char &c) {
if (c)
c = Common::U32String(Common::String::format("%c", c), Common::kISO8859_1).encode(Common::kDos850).firstChar();
}
uint16 Util::convertDOSToJohab(char c, uint8 *mergeFlags) {
uint16 dest = 0;
if (!((c >= (uint8)'A' && c <= (uint8)'Z') || (c >= (uint8)'a' && c <= (uint8)'z')))
return 0;
uint16 res = 0;
for (int16 lml = 0, lmu = ARRAYSIZE(_johabConvTable) - 1; lml <= lmu; ) {
res = MAX<int>(0, (lml + lmu)) >> 1;
if (_johabConvTable[res].key > c)
lmu = res - 1;
else
lml = res + 1;
if (_johabConvTable[res].key == c)
break;
}
if (_johabConvTable[res].key == c) {
dest = _johabConvTable[res].johabChar | 0x8000;
if (mergeFlags)
*mergeFlags = _johabConvTable[res].flags;
}
return dest;
}
struct JohabMergeTableEntry {
const char *s;
uint8 val;
};
const JohabMergeTableEntry _johabMergeTable[35] = {
{ "R", 0x03 }, { "T", 0x16 }, { "a", 0x11 }, { "c", 0x19 }, { "d", 0x17 },
{ "e", 0x08 }, { "f", 0x09 }, { "fa", 0x0B }, { "fg", 0x10 }, { "fq", 0x0C },
{ "fr", 0x0A }, { "ft", 0x0D }, { "fv", 0x0F }, { "fx", 0x0E }, { "g", 0x1D },
{ "hk", 0x20 }, { "hl", 0xA0 }, { "ho", 0x40 }, { "ml", 0x20 }, { "nj", 0x20 },
{ "nl", 0x60 }, { "np", 0x60 }, { "q", 0x13 }, { "qt", 0x14 }, { "r", 0x02 },
{ "rt", 0x04 }, { "s", 0x05 }, { "sg", 0x07 }, { "sw", 0x06 }, { "t", 0x15 },
{ "u", 0x00 }, { "v", 0x1C }, { "w", 0x18 }, { "x", 0x1B }, { "z", 0x1A }
};
uint16 johabMergeGetOffs(const char *srch) {
uint16 res = 0;
int find = 1;
for (int16 lml = 0, lmu = ARRAYSIZE(_johabMergeTable) - 1; lml <= lmu && find; ) {
res = MAX<int>(0, (lml + lmu)) >> 1;
find = strcmp(srch, _johabMergeTable[res].s);
if (find < 0)
lmu = res - 1;
else
lml = res + 1;
}
return find ? 0 : _johabMergeTable[res].val;
}
uint8 _hanMergeState = 0;
uint16 _2byteBackup = 0;
char _asciiPrev = '\0';
void Util::mergeUpdateJohabChars(uint16 &destJohabChar0, uint16 &destJohabChar1, char asciiInput, bool reset) {
if (reset) {
_hanMergeState = 0;
_asciiPrev = '\0';
_2byteBackup = 0;
}
if (!asciiInput)
return;
for (int loops = 1; loops; --loops) {
uint8 flags = 0;
uint8 offs = 0;
destJohabChar0 &= 0x7fff;
destJohabChar1 = convertDOSToJohab(asciiInput, &flags) & 0x7fff;
char in[3];
in[0] = in[1] = in[2] = '\0';
switch (_hanMergeState) {
case 0x01:
if (flags & 6) {
_2byteBackup = destJohabChar0;
destJohabChar0 = (destJohabChar0 & 0xFC1F) | (convertDOSToJohab(asciiInput) & 0x3E0);
destJohabChar1 = 0;
_hanMergeState = flags;
} else {
++loops;
}
break;
case 0x02:
if (flags & 0x10) {
in[0] = asciiInput;
in[1] = '\0';
offs = johabMergeGetOffs(in);
}
if (offs) {
_2byteBackup = destJohabChar0;
destJohabChar0 = (destJohabChar0 & 0xFFE0) | offs;
destJohabChar1 = 0;
_hanMergeState = flags;
} else {
++loops;
}
break;
case 0x04:
if (flags & 0x12) {
in[0] = (flags & 2) ? _asciiPrev : asciiInput;
in[1] = (flags & 2) ? asciiInput : '\0';
offs = johabMergeGetOffs(in);
}
if (offs) {
_2byteBackup = destJohabChar0;
destJohabChar0 = (flags & 2) ? (destJohabChar0 + offs) : ((destJohabChar0 & 0xFFE0) | offs);
destJohabChar1 = 0;
_hanMergeState = flags;
} else {
++loops;
}
break;
case 0x11:
if (flags & 6) {
destJohabChar1 = (convertDOSToJohab(_asciiPrev) & 0xFC1F) | (convertDOSToJohab(asciiInput, &flags) & 0x3E0);
destJohabChar0 = _2byteBackup;
_hanMergeState = flags;
} else if (flags & 0x10) {
in[0] = _asciiPrev;
in[1] = asciiInput;
in[2] = '\0';
offs = johabMergeGetOffs(in);
}
if (offs) {
_2byteBackup = destJohabChar0;
destJohabChar0 = (destJohabChar0 & 0xFFE0) | offs;
destJohabChar1 = 0;
_hanMergeState = flags;
} else if (!(flags & 6)) {
++loops;
}
break;
default:
_hanMergeState = flags & 7;
_2byteBackup = destJohabChar0;
destJohabChar0 = 0;
break;
}
_asciiPrev = asciiInput;
if (loops == 2) {
destJohabChar0 = 0;
_hanMergeState = 0;
}
}
if (destJohabChar0)
destJohabChar0 |= 0x8000;
if (destJohabChar1)
destJohabChar1 |= 0x8000;
}
Common::String Util::decodeString1(const Common::String &src) {
char *tmp = new char[src.size() * 2 + 2];
Util::decodeString1(src.c_str(), tmp);
Common::String reslt(tmp);
delete[] tmp;
return reslt;
}
Common::String Util::decodeString2(const Common::String &src) {
char *tmp = new char[src.size() * 2 + 2];
Util::decodeString2(src.c_str(), tmp);
Common::String reslt(tmp);
delete[] tmp;
return reslt;
}
Common::Path Util::findMacResourceFile(const char *baseName, const char *suffix) {
// The original executable has a TM char as its last character (character
// 0xAA from Mac code page). Depending on the emulator or platform used to
// copy the file it might have been reencoded to something else. So I look
// for multiple versions, also for punycode encoded files and also for the
// case where the user might have just removed the last character by
// renaming the file.
const Common::CodePage tryCodePages[] = {
Common::kMacRoman,
Common::kISO8859_1
};
Common::MacResManager resource;
Common::String tryName(baseName);
Common::Path fileName;
for (int i = 0; i < 2; ++i) {
for (int ii = 0; ii < ARRAYSIZE(tryCodePages); ++ii) {
Common::U32String fn(tryName + suffix, tryCodePages[ii]);
fileName = Common::Path(fn.encode(Common::kUtf8));
if (resource.exists(fileName))
return fileName;
fileName = Common::Path(Common::punycode_encodefilename(fn));
if (resource.exists(fileName))
return fileName;
}
tryName += "\xAA";
}
fileName.clear();
return fileName;
}
const Util::DOS2JOHABEntry Util::_johabConvTable[52] = {
{ 'A', 0x2041, 0x11 }, { 'B', 0x0741, 0x04 }, { 'C', 0x4041, 0x11 }, { 'D', 0x3441, 0x11 },
{ 'E', 0x1841, 0x01 }, { 'F', 0x1c41, 0x11 }, { 'G', 0x5041, 0x11 }, { 'H', 0x05a1, 0x04 },
{ 'I', 0x04a1, 0x02 }, { 'J', 0x04e1, 0x02 }, { 'K', 0x0461, 0x02 }, { 'L', 0x07a1, 0x02 },
{ 'M', 0x0761, 0x04 }, { 'N', 0x0681, 0x04 }, { 'O', 0x04c1, 0x02 }, { 'P', 0x0581, 0x02 },
{ 'Q', 0x2841, 0x01 }, { 'R', 0x0c41, 0x11 }, { 'S', 0x1041, 0x11 }, { 'T', 0x3041, 0x11 },
{ 'U', 0x0561, 0x02 }, { 'V', 0x4c41, 0x01 }, { 'W', 0x3c41, 0x01 }, { 'X', 0x4841, 0x11 },
{ 'Y', 0x0661, 0x04 }, { 'Z', 0x4441, 0x11 }, { 'a', 0x2041, 0x11 }, { 'b', 0x0741, 0x04 },
{ 'c', 0x4041, 0x11 }, { 'd', 0x3441, 0x11 }, { 'e', 0x1441, 0x11 }, { 'f', 0x1c41, 0x11 },
{ 'g', 0x5041, 0x11 }, { 'h', 0x05a1, 0x04 }, { 'i', 0x04a1, 0x02 }, { 'j', 0x04e1, 0x02 },
{ 'k', 0x0461, 0x02 }, { 'l', 0x07a1, 0x02 }, { 'm', 0x0761, 0x04 }, { 'n', 0x0681, 0x04 },
{ 'o', 0x0481, 0x02 }, { 'p', 0x0541, 0x02 }, { 'q', 0x2441, 0x11 }, { 'r', 0x0841, 0x11 },
{ 's', 0x1041, 0x11 }, { 't', 0x2c41, 0x11 }, { 'u', 0x0561, 0x02 }, { 'v', 0x4c41, 0x11 },
{ 'w', 0x3841, 0x11 }, { 'x', 0x4841, 0x11 }, { 'y', 0x0661, 0x04 }, { 'z', 0x4441, 0x11 }
};
} // End of namespace Kyra