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