/* 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 . * */ #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(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(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