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/file.h"
24 #include "common/debug.h"
25 #include "common/ustr.h"
26
27 #include "sludge/allfiles.h"
28 #include "sludge/moreio.h"
29 #include "sludge/newfatal.h"
30 #include "sludge/sludge.h"
31 #include "sludge/version.h"
32
33 namespace Sludge {
34
ResourceManager()35 ResourceManager::ResourceManager() {
36 init();
37 }
38
~ResourceManager()39 ResourceManager::~ResourceManager() {
40 kill();
41 }
42
init()43 void ResourceManager::init() {
44 _sliceBusy = true;
45 _bigDataFile = nullptr;
46 _startOfDataIndex = 0;
47 _startOfTextIndex = 0;
48 _startOfSubIndex = 0;
49 _startOfObjectIndex = 0;
50 _startIndex = 0;
51 _allResourceNames.clear();
52 }
kill()53 void ResourceManager::kill() {
54 if (_bigDataFile) {
55 delete _bigDataFile;
56 _bigDataFile = nullptr;
57 }
58 _allResourceNames.clear();
59 }
60
openSubSlice(int num)61 bool ResourceManager::openSubSlice(int num) {
62 if (_sliceBusy) {
63 fatal("Can't read from data file", "I'm already reading something");
64 return false;
65 }
66 _bigDataFile->seek(_startOfSubIndex + (num << 2), 0);
67 _bigDataFile->seek(_bigDataFile->readUint32LE(), 0);
68
69 return _sliceBusy = true;
70 }
71
openObjectSlice(int num)72 bool ResourceManager::openObjectSlice(int num) {
73 if (_sliceBusy) {
74 fatal("Can't read from data file", "I'm already reading something");
75 return false;
76 }
77
78 _bigDataFile->seek(_startOfObjectIndex + (num << 2), 0);
79 _bigDataFile->seek(_bigDataFile->readUint32LE(), 0);
80 return _sliceBusy = true;
81 }
82
openFileFromNum(int num)83 uint ResourceManager::openFileFromNum(int num) {
84 if (_sliceBusy) {
85 fatal("Can't read from data file", "I'm already reading something");
86 return 0;
87 }
88
89 _bigDataFile->seek(_startOfDataIndex + (num << 2), 0);
90 _bigDataFile->seek(_bigDataFile->readUint32LE(), 1);
91 _sliceBusy = true;
92
93 return _bigDataFile->readUint32LE();
94 }
95
96 uint32 ResourceManager::_cp1250ToUTF32[128] = {
97 /* 0x80 */
98 0x20ac, 0xfffd, 0x201a, 0xfffd, 0x201e, 0x2026, 0x2020, 0x2021,
99 0xfffd, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
100 /* 0x90 */
101 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
102 0xfffd, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
103 /* 0xa0 */
104 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
105 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
106 /* 0xb0 */
107 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
108 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
109 /* 0xc0 */
110 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
111 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
112 /* 0xd0 */
113 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
114 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
115 /* 0xe0 */
116 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
117 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
118 /* 0xf0 */
119 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
120 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
121 };
122
123 // Converts a string from ISO8859-2 or CP1250 to UTF8.
124 // This is needed for old games.
convertString(const Common::String & s)125 Common::String ResourceManager::convertString(const Common::String &s) {
126 Common::String res;
127 Common::U32String tmp;
128
129 // Convert CP1250 to UTF32
130 for (uint i = 0; i < s.size(); ++i) {
131 const byte c = s[i];
132 if (c < 0x80) {
133 tmp += c;
134 } else {
135 uint32 utf32 = _cp1250ToUTF32[c - 0x80];
136 if (utf32) {
137 tmp += utf32;
138 } else {
139 // It's an invalid CP1250 character...
140 return s;
141 }
142 }
143 }
144
145 // Convert UTF32 to UTF8
146 for (uint i = 0; i < tmp.size(); ++i) {
147 uint32 wc = tmp[i];
148 int count;
149 if (wc < 0x80)
150 count = 1;
151 else if (wc < 0x800)
152 count = 2;
153 else if (wc < 0x10000) {
154 if (wc < 0xd800 || wc >= 0xe000) {
155 count = 3;
156 } else {
157 // It's an invalid UTF32 character...
158 return s;
159 }
160 } else if (wc < 0x110000) {
161 count = 4;
162 } else {
163 // It's an invalid UTF32 character...
164 return s;
165 }
166 Common::String r = "";
167 switch (count) {
168 case 4:
169 r = (char)(0x80 | (wc & 0x3f)) + r;
170 wc = wc >> 6;
171 wc |= 0x10000;
172 // falls through
173 case 3:
174 r = (char)(0x80 | (wc & 0x3f)) + r;
175 wc = wc >> 6;
176 wc |= 0x800;
177 // falls through
178 case 2:
179 r = (char)(0x80 | (wc & 0x3f)) + r;
180 wc = wc >> 6;
181 wc |= 0xc0;
182 // falls through
183 case 1:
184 r = wc + r;
185 }
186 res += r;
187 }
188
189 return res;
190 }
191
getNumberedString(int value)192 Common::String ResourceManager::getNumberedString(int value) {
193 if (_sliceBusy) {
194 fatal("Can't read from data file", "I'm already reading something");
195 return NULL;
196 }
197
198 _bigDataFile->seek((value << 2) + _startOfTextIndex, 0);
199 value = _bigDataFile->readUint32LE();
200 _bigDataFile->seek(value, 0);
201
202 Common::String s = readString(_bigDataFile);
203
204 if (gameVersion < VERSION(2, 2)) {
205 // This is an older game - We need to convert the string to UTF-8
206 s = convertString(s);
207 }
208
209 return s;
210 }
211
startAccess()212 bool ResourceManager::startAccess() {
213 int wasBusy = _sliceBusy;
214 _sliceBusy = true;
215 return wasBusy;
216 }
finishAccess()217 void ResourceManager::finishAccess() {
218 _sliceBusy = false;
219 }
220
readResourceNames(Common::SeekableReadStream * readStream)221 void ResourceManager::readResourceNames(Common::SeekableReadStream *readStream) {
222 int numResourceNames = readStream->readUint16BE();
223 debugC(2, kSludgeDebugDataLoad, "numResourceNames %i", numResourceNames);
224 _allResourceNames.reserve(numResourceNames);
225
226 for (int fn = 0; fn < numResourceNames; fn++) {
227 _allResourceNames.push_back(readString(readStream));
228 debugC(2, kSludgeDebugDataLoad, "Resource %i: %s", fn, _allResourceNames[fn].c_str());
229 }
230 }
231
resourceNameFromNum(int i)232 const Common::String ResourceManager::resourceNameFromNum(int i) {
233 if (i == -1)
234 return "";
235
236 if (_allResourceNames.empty())
237 return "RESOURCE";
238
239 if (i < (int)_allResourceNames.size())
240 return _allResourceNames[i];
241
242 return "Unknown resource";
243 }
244
setData(Common::File * fp)245 void ResourceManager::setData(Common::File *fp) {
246 _bigDataFile = fp;
247 _startIndex = fp->pos();
248 }
249
setFileIndices(uint numLanguages,uint skipBefore)250 void ResourceManager::setFileIndices(uint numLanguages, uint skipBefore) {
251 _bigDataFile->seek(_startIndex, SEEK_SET);
252 _sliceBusy = false;
253
254 if (skipBefore > numLanguages) {
255 warning("Not a valid language ID! Using default instead.");
256 skipBefore = 0;
257 }
258
259 // STRINGS
260 int skipAfter = numLanguages - skipBefore;
261 while (skipBefore) {
262 _bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
263 skipBefore--;
264 }
265 _startOfTextIndex = _bigDataFile->pos() + 4;
266 debugC(2, kSludgeDebugDataLoad, "startOfTextIndex: %i", _startOfTextIndex);
267
268 _bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
269
270 while (skipAfter) {
271 _bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
272 skipAfter--;
273 }
274
275 _startOfSubIndex = _bigDataFile->pos() + 4;
276 _bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_CUR);
277 debugC(2, kSludgeDebugDataLoad, "startOfSubIndex: %i", _startOfSubIndex);
278
279 _startOfObjectIndex = _bigDataFile->pos() + 4;
280 _bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_CUR);
281 debugC(2, kSludgeDebugDataLoad, "startOfObjectIndex: %i", _startOfObjectIndex);
282
283 // Remember that the data section starts here
284 _startOfDataIndex = _bigDataFile->pos();
285 debugC(2, kSludgeDebugDataLoad, "startOfDataIndex: %i", _startOfDataIndex);
286 }
287
288 } // End of namespace Sludge
289