1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/endian.h"
24 #include "scumm/he/localizer.h"
25 #include "common/file.h"
26 #include "common/debug.h"
27
28 namespace Scumm {
29
Localizer()30 Localizer::Localizer() {
31 Common::File _file;
32
33 _isValid = false;
34
35 if (!_file.open("lokalizator.big"))
36 return;
37
38 uint _fileSize = _file.size();
39 if (_fileSize < 0x18)
40 return;
41 byte *lkBig = new byte[_fileSize];
42 _file.read(lkBig, _fileSize);
43 // Obfuscation round 1
44 for (uint i = 0; i < _fileSize; i++)
45 lkBig[i] ^= (214013 * i + 2531011) >> 16;
46
47 uint32 numFiles = READ_LE_UINT32(lkBig + 0x14);
48 uint32 localeMsgOffset = 0, localeMsgSize = 0;
49 uint32 talkieDatOffset = 0, talkieDatSize = 0;
50
51 for (uint i = 0; i < numFiles; i++) {
52 byte *fileHdr = lkBig + 0x18 + 0x4c * i;
53 if (strcmp((char *) fileHdr, "locale.msg") == 0) {
54 localeMsgOffset = READ_LE_UINT32(fileHdr + 0x48);
55 localeMsgSize = READ_LE_UINT32(fileHdr + 0x44);
56 continue;
57 }
58 if (strcmp((char *) fileHdr, "talkie.dat") == 0) {
59 talkieDatOffset = READ_LE_UINT32(fileHdr + 0x48);
60 talkieDatSize = READ_LE_UINT32(fileHdr + 0x44);
61 continue;
62 }
63 }
64
65 _isValid = true;
66
67 if (localeMsgSize > 4) {
68 uint32 msgCount = READ_LE_UINT32(lkBig + localeMsgOffset);
69 // Obfuscation round 2
70 uint32 st = 0x12345678;
71 for (uint i = 0; i < localeMsgSize - 4; i++) {
72 byte x = 0;
73 switch (i & 3) {
74 case 0:
75 x = st;
76 break;
77 case 1:
78 x = st + 35;
79 break;
80 case 2:
81 x = st + 70;
82 break;
83 case 3:
84 x = st + 105;
85 st += 45707404;
86 break;
87 }
88 lkBig[i + localeMsgOffset + 4] ^= x;
89 }
90
91 uint32 cur = localeMsgOffset + 4;
92
93 for (uint i = 0; i < msgCount && cur < localeMsgOffset + localeMsgSize; i++) {
94 cur += 4; // Domain id or something like this, always zero
95 uint32 lenOrig = READ_LE_UINT32(lkBig + cur); cur += 4;
96 Common::String orig((char *) lkBig + cur, (char *) lkBig + cur + lenOrig);
97 cur += lenOrig;
98 uint32 lenTrans = READ_LE_UINT32(lkBig + cur); cur += 4;
99 Common::String trans((char *) lkBig + cur, (char *) lkBig + cur + lenTrans);
100 cur += lenTrans;
101 _translationMap[orig] = trans;
102 }
103 }
104
105 for (uint32 cur = talkieDatOffset; cur < talkieDatOffset + talkieDatSize; cur += 16) {
106 _talkMap[READ_LE_UINT32(lkBig+cur+4)] = READ_LE_UINT32(lkBig+cur+12);
107 }
108 }
109
translate(const Common::String & orig)110 Common::String Localizer::translate(const Common::String &orig) {
111 if (_translationMap.contains(orig)) {
112 return _translationMap[orig];
113 }
114 return orig;
115 }
116
mapTalk(uint32 orig)117 uint32 Localizer::mapTalk(uint32 orig) {
118 if (_talkMap.contains(orig)) {
119 return _talkMap[orig];
120 }
121 return orig;
122 }
123
124 }
125