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/scummsys.h"
24 #include "common/endian.h"
25 #include "common/file.h"
26 #include "common/stack.h"
27 #include "common/util.h"
28 #include "tsage/resources.h"
29 #include "tsage/tsage.h"
30
31 namespace TsAGE {
32
33
MemoryManager()34 MemoryManager::MemoryManager() {
35 _memoryPool = new MemoryHeader*[MEMORY_POOL_SIZE];
36 Common::fill(&_memoryPool[0], &_memoryPool[MEMORY_POOL_SIZE], (MemoryHeader *)NULL);
37 }
38
~MemoryManager()39 MemoryManager::~MemoryManager() {
40 for (int i = 0; i < MEMORY_POOL_SIZE; ++i) {
41 if (_memoryPool[i] != NULL)
42 free(_memoryPool[i]);
43 }
44 delete[] _memoryPool;
45 }
46
allocate(uint32 size)47 uint16 MemoryManager::allocate(uint32 size) {
48 int idx = 0;
49 while ((idx < MEMORY_POOL_SIZE) && (_memoryPool[idx] != NULL))
50 ++idx;
51 if (idx == MEMORY_POOL_SIZE)
52 error("Out of memory handles");
53
54 // Create the new entry
55 _memoryPool[idx] = (MemoryHeader *)malloc(sizeof(MemoryHeader) + size);
56 _memoryPool[idx]->id = MEMORY_ENTRY_ID;
57 _memoryPool[idx]->index = idx;
58 _memoryPool[idx]->lockCtr = 0;
59 _memoryPool[idx]->criticalCtr = 0;
60 _memoryPool[idx]->tag = 0;
61 _memoryPool[idx]->size = size;
62
63 // Return it's index
64 return idx;
65 }
66
allocate2(uint32 size)67 byte *MemoryManager::allocate2(uint32 size) {
68 uint32 idx = allocate(size);
69 byte *result = lock(idx);
70 Common::fill(result, result + size, 0);
71 return result;
72 }
73
lock(uint32 handle)74 byte *MemoryManager::lock(uint32 handle) {
75 assert((int)handle < MEMORY_POOL_SIZE);
76 return (byte *)_memoryPool[handle] + sizeof(MemoryHeader);
77 }
78
indexOf(const byte * p)79 int MemoryManager::indexOf(const byte *p) {
80 for (int idx = 0; idx < MEMORY_POOL_SIZE; ++idx) {
81 if (((byte *)_memoryPool[idx] + sizeof(MemoryHeader)) == p)
82 return idx;
83 }
84
85 return -1;
86 }
87
deallocate(const byte * p)88 void MemoryManager::deallocate(const byte *p) {
89 if (!p)
90 return;
91
92 int idx = indexOf(p);
93 assert(idx != -1);
94 if (_memoryPool[idx]->lockCtr-- == 0) {
95 free(_memoryPool[idx]);
96 _memoryPool[idx] = NULL;
97 }
98 }
99
getSize(const byte * p)100 uint32 MemoryManager::getSize(const byte *p) {
101 int idx = indexOf(p);
102 assert(idx >= 0);
103 return _memoryPool[idx]->size;
104 }
105
incLocks(const byte * p)106 void MemoryManager::incLocks(const byte *p) {
107 int idx = indexOf(p);
108 assert(idx >= 0);
109 _memoryPool[idx]->lockCtr++;
110 }
111
112 /*-------------------------------------------------------------------------*/
113
114 static uint16 bitMasks[4] = {0x1ff, 0x3ff, 0x7ff, 0xfff};
115
readToken()116 uint16 BitReader::readToken() {
117 assert((numBits >= 9) && (numBits <= 12));
118 uint16 result = _remainder;
119 int bitsLeft = numBits - _bitsLeft;
120 int bitOffset = _bitsLeft;
121 _bitsLeft = 0;
122
123 while (bitsLeft >= 0) {
124 _remainder = readByte();
125 result |= _remainder << bitOffset;
126 bitsLeft -= 8;
127 bitOffset += 8;
128 }
129
130 _bitsLeft = -bitsLeft;
131 _remainder >>= 8 - _bitsLeft;
132 return result & bitMasks[numBits - 9];
133 }
134
135 /*-------------------------------------------------------------------------*/
136
TLib(MemoryManager & memManager,const Common::String & filename)137 TLib::TLib(MemoryManager &memManager, const Common::String &filename) :
138 _filename(filename), _memoryManager(memManager) {
139
140 // If the resource strings list isn't yet loaded, load them
141 if (_resStrings.size() == 0) {
142 Common::File f;
143 if (f.open("tsage.cfg")) {
144 while (!f.eos()) {
145 _resStrings.push_back(f.readLine());
146 }
147 f.close();
148 }
149 }
150
151 if (!_file.open(filename))
152 error("Missing file %s", filename.c_str());
153
154 loadIndex();
155 }
156
~TLib()157 TLib::~TLib() {
158 _resStrings.clear();
159 }
160
161 /**
162 * Load a section index from the given position in the file
163 */
loadSection(uint32 fileOffset)164 void TLib::loadSection(uint32 fileOffset) {
165 _resources.clear();
166 _file.seek(fileOffset);
167 _sections.fileOffset = fileOffset;
168
169 ResourceManager::loadSection(_file, _resources);
170 }
171
172 struct DecodeReference {
173 uint16 vWord;
174 uint8 vByte;
175 };
176
177 /**
178 * Gets a resource from the currently loaded section
179 */
getResource(uint16 id,bool suppressErrors)180 byte *TLib::getResource(uint16 id, bool suppressErrors) {
181 // Scan for an entry for the given Id
182 ResourceEntry *re = NULL;
183 ResourceList::iterator iter;
184 for (iter = _resources.begin(); iter != _resources.end(); ++iter) {
185 if ((*iter).id == id) {
186 re = &(*iter);
187 break;
188 }
189 }
190 if (!re) {
191 if (suppressErrors)
192 return NULL;
193 error("Could not find resource Id #%d", id);
194 }
195
196 if (!re->isCompressed) {
197 // Read in the resource data and return it
198 byte *dataP = _memoryManager.allocate2(re->size);
199 _file.seek(_sections.fileOffset + re->fileOffset);
200 _file.read(dataP, re->size);
201
202 return dataP;
203 }
204
205 /*
206 * Decompress the data block
207 */
208
209 _file.seek(_sections.fileOffset + re->fileOffset);
210 Common::ReadStream *compStream = _file.readStream(re->size);
211 BitReader bitReader(*compStream);
212
213 byte *dataOut = _memoryManager.allocate2(re->uncompressedSize);
214 byte *destP = dataOut;
215 uint bytesWritten = 0;
216
217 uint16 ctrCurrent = 0x102, ctrMax = 0x200;
218 uint16 word_48050 = 0, currentToken = 0, word_48054 =0;
219 byte byte_49068 = 0, byte_49069 = 0;
220
221 const uint tableSize = 0x1000;
222 DecodeReference *table = (DecodeReference *)malloc(tableSize * sizeof(DecodeReference));
223 if (!table)
224 error("[TLib::getResource] Cannot allocate table buffer");
225
226 for (uint i = 0; i < tableSize; ++i) {
227 table[i].vByte = table[i].vWord = 0;
228 }
229 Common::Stack<uint16> tokenList;
230
231 for (;;) {
232 // Get the next decode token
233 uint16 token = bitReader.readToken();
234
235 // Handle the token
236 if (token == 0x101) {
237 // End of compressed stream
238 break;
239 } else if (token == 0x100) {
240 // Reset bit-rate
241 bitReader.numBits = 9;
242 ctrMax = 0x200;
243 ctrCurrent = 0x102;
244
245 // Set variables with next token
246 currentToken = word_48050 = bitReader.readToken();
247 byte_49069 = byte_49068 = (byte)currentToken;
248
249 ++bytesWritten;
250 assert(bytesWritten <= re->uncompressedSize);
251 *destP++ = byte_49069;
252 } else {
253 word_48054 = word_48050 = token;
254
255 if (token >= ctrCurrent) {
256 word_48050 = currentToken;
257 tokenList.push(byte_49068);
258 }
259
260 while (word_48050 >= 0x100) {
261 assert(word_48050 < 0x1000);
262 tokenList.push(table[word_48050].vByte);
263 word_48050 = table[word_48050].vWord;
264 }
265
266 byte_49069 = byte_49068 = (byte)word_48050;
267 tokenList.push(word_48050);
268
269 // Write out any cached tokens
270 while (!tokenList.empty()) {
271 ++bytesWritten;
272 assert(bytesWritten <= re->uncompressedSize);
273 *destP++ = tokenList.pop();
274 }
275
276 assert(ctrCurrent < 0x1000);
277 table[ctrCurrent].vByte = byte_49069;
278 table[ctrCurrent].vWord = currentToken;
279 ++ctrCurrent;
280
281 currentToken = word_48054;
282 if ((ctrCurrent >= ctrMax) && (bitReader.numBits != 12)) {
283 // Move to the next higher bit-rate
284 ++bitReader.numBits;
285 ctrMax <<= 1;
286 }
287 }
288 }
289
290 free(table);
291
292 assert(bytesWritten == re->uncompressedSize);
293 delete compStream;
294 return dataOut;
295 }
296
297 /**
298 * Finds the correct section and loads the specified resource within it
299 */
getResource(ResourceType resType,uint16 resNum,uint16 rlbNum,bool suppressErrors)300 byte *TLib::getResource(ResourceType resType, uint16 resNum, uint16 rlbNum, bool suppressErrors) {
301 SectionList::iterator i = _sections.begin();
302 while ((i != _sections.end()) && ((*i).resType != resType || (*i).resNum != resNum))
303 ++i;
304 if (i == _sections.end()) {
305 if (suppressErrors)
306 return NULL;
307 error("Unknown resource type %d num %d", resType, resNum);
308 }
309
310 loadSection((*i).fileOffset);
311
312 return getResource(rlbNum, suppressErrors);
313 }
314
315 /**
316 * Gets the offset of the start of a resource in the resource file
317 */
getResourceStart(ResourceType resType,uint16 resNum,uint16 rlbNum,ResourceEntry & entry)318 uint32 TLib::getResourceStart(ResourceType resType, uint16 resNum, uint16 rlbNum, ResourceEntry &entry) {
319 // Find the correct section
320 SectionList::iterator i = _sections.begin();
321 while ((i != _sections.end()) && ((*i).resType != resType || (*i).resNum != resNum))
322 ++i;
323 if (i == _sections.end()) {
324 error("Unknown resource type %d num %d", resType, resNum);
325 }
326
327 // Load in the section index
328 loadSection((*i).fileOffset);
329
330 // Scan for an entry for the given Id
331 ResourceEntry *re = NULL;
332 ResourceList::iterator iter;
333 for (iter = _resources.begin(); iter != _resources.end(); ++iter) {
334 if ((*iter).id == rlbNum) {
335 re = &(*iter);
336 break;
337 }
338 }
339
340 // Throw an error if no resource was found, or the resource is compressed
341 if (!re || re->isCompressed)
342 error("Invalid resource Id #%d", rlbNum);
343
344 // Return the resource entry as well as the file offset
345 entry = *re;
346 return _sections.fileOffset + entry.fileOffset;
347 }
348
loadIndex()349 void TLib::loadIndex() {
350 uint16 resNum, configId, fileOffset;
351
352 // Load the root resources section
353 loadSection(0);
354
355 // Get the single resource from it
356 const byte *pData = getResource(0);
357 const byte *p = pData;
358
359 _sections.clear();
360
361 // Loop through reading the entries
362 while ((resNum = READ_LE_UINT16(p)) != 0xffff) {
363 configId = READ_LE_UINT16(p + 2);
364 fileOffset = READ_LE_UINT16(p + 4);
365 p += 6;
366
367 SectionEntry se;
368 se.resNum = resNum;
369 se.resType = (ResourceType)(configId & 0x1f);
370 se.fileOffset = (((configId >> 5) & 0x7ff) << 16) | fileOffset;
371 if (g_vm->getGameID() == GType_Ringworld2)
372 se.fileOffset <<= 4;
373
374 _sections.push_back(se);
375 }
376
377 _memoryManager.deallocate(pData);
378 }
379
380 /**
381 * Retrieves the specified palette resource and returns it's data
382 *
383 * @paletteNum Specefies the palette number
384 */
getPalette(int paletteNum,byte * palData,uint * startNum,uint * numEntries)385 bool TLib::getPalette(int paletteNum, byte *palData, uint *startNum, uint *numEntries) {
386 // Get the specified palette
387 byte *dataIn = getResource(RES_PALETTE, 0, paletteNum, true);
388 if (!dataIn)
389 return false;
390
391 *startNum = READ_LE_UINT16(dataIn);
392 *numEntries = READ_LE_UINT16(dataIn + 2);
393 assert((*startNum < 256) && ((*startNum + *numEntries) <= 256));
394
395 // Copy over the data
396 Common::copy(&dataIn[6], &dataIn[6 + *numEntries * 3], palData);
397
398 _memoryManager.deallocate(dataIn);
399 return true;
400 }
401
getSubResource(int resNum,int rlbNum,int index,uint * size,bool suppressErrors)402 byte *TLib::getSubResource(int resNum, int rlbNum, int index, uint *size, bool suppressErrors) {
403 // Get the specified image set
404 byte *dataIn = getResource(RES_VISAGE, resNum, rlbNum);
405 if (!dataIn) {
406 if (suppressErrors)
407 return NULL;
408
409 error("Unknown sub resource %d/%d index %d", resNum, rlbNum, index);
410 }
411
412 int numEntries = READ_LE_UINT16(dataIn);
413 uint32 entryOffset = READ_LE_UINT32(dataIn + 2 + (index - 1) * 4);
414 uint32 nextOffset = (index == numEntries) ?
415 _memoryManager.getSize(dataIn) : READ_LE_UINT32(dataIn + 2 + index * 4);
416 *size = nextOffset - entryOffset;
417 assert(*size < (1024 * 1024));
418
419 byte *entry = _memoryManager.allocate2(*size);
420 Common::copy(&dataIn[entryOffset], &dataIn[nextOffset], entry);
421
422 _memoryManager.deallocate(dataIn);
423 return entry;
424 }
425
426 /**
427 * Retrieves a given message resource, and returns the specified message number
428 */
getMessage(int resNum,int lineNum,Common::String & result,bool suppressErrors)429 bool TLib::getMessage(int resNum, int lineNum, Common::String &result, bool suppressErrors) {
430 byte *msgData = getResource(RES_MESSAGE, resNum, 0, true);
431 if (!msgData || (lineNum < 0)) {
432 if (suppressErrors)
433 return false;
434
435 error("Unknown message %d line %d", resNum, lineNum);
436 }
437
438 int msgSize = _memoryManager.getSize(msgData);
439 const char *srcP = (const char *)msgData;
440 const char *endP = srcP + msgSize;
441
442 while (lineNum-- > 0) {
443 srcP += strlen(srcP) + 1;
444
445 if (srcP >= endP) {
446 if (suppressErrors)
447 return false;
448
449 error("Unknown message %d line %d", resNum, lineNum);
450 }
451 }
452
453 result = Common::String(srcP);
454 _memoryManager.deallocate(msgData);
455 return true;
456 }
457
458 /*--------------------------------------------------------------------------*/
459
~ResourceManager()460 ResourceManager::~ResourceManager() {
461 for (uint idx = 0; idx < _libList.size(); ++idx)
462 delete _libList[idx];
463 }
464
addLib(const Common::String & libName)465 void ResourceManager::addLib(const Common::String &libName) {
466 assert(_libList.size() < 5);
467
468 _libList.push_back(new TLib(g_vm->_memoryManager, libName));
469 }
470
getResource(uint16 id,bool suppressErrors)471 byte *ResourceManager::getResource(uint16 id, bool suppressErrors) {
472 byte *result = NULL;
473 for (uint idx = 0; idx < _libList.size(); ++idx) {
474 result = _libList[idx]->getResource(id, true);
475 if (result)
476 return result;
477 }
478
479 if (!result && !suppressErrors)
480 error("Could not find resource Id #%d", id);
481 return NULL;
482 }
483
getResource(ResourceType resType,uint16 resNum,uint16 rlbNum,bool suppressErrors)484 byte *ResourceManager::getResource(ResourceType resType, uint16 resNum, uint16 rlbNum, bool suppressErrors) {
485 byte *result = NULL;
486 for (uint idx = 0; idx < _libList.size(); ++idx) {
487 result = _libList[idx]->getResource(resType, resNum, rlbNum, true);
488 if (result)
489 return result;
490 }
491
492 if (!result && !suppressErrors)
493 error("Unknown resource type %d num %d", resType, resNum);
494 return NULL;
495 }
496
getPalette(int paletteNum,byte * palData,uint * startNum,uint * numEntries,bool suppressErrors)497 void ResourceManager::getPalette(int paletteNum, byte *palData, uint *startNum, uint *numEntries, bool suppressErrors) {
498 for (uint idx = 0; idx < _libList.size(); ++idx) {
499 if (_libList[idx]->getPalette(paletteNum, palData, startNum, numEntries))
500 return;
501 }
502
503 if (!suppressErrors)
504 error("Unknown palette resource %d", paletteNum);
505 *numEntries = 0;
506 }
507
getSubResource(int resNum,int rlbNum,int index,uint * size,bool suppressErrors)508 byte *ResourceManager::getSubResource(int resNum, int rlbNum, int index, uint *size, bool suppressErrors) {
509 byte *result = NULL;
510 for (uint idx = 0; idx < _libList.size(); ++idx) {
511 result = _libList[idx]->getSubResource(resNum, rlbNum, index, size, true);
512 if (result)
513 return result;
514 }
515
516 if (!result && !suppressErrors)
517 error("Unknown resource %d/%d index %d", resNum, rlbNum, index);
518 return NULL;
519 }
520
getMessage(int resNum,int lineNum,bool suppressErrors)521 Common::String ResourceManager::getMessage(int resNum, int lineNum, bool suppressErrors) {
522 Common::String result;
523
524 for (uint idx = 0; idx < _libList.size(); ++idx) {
525 if (_libList[idx]->getMessage(resNum, lineNum, result, true))
526 return result;
527 }
528
529 if (!suppressErrors)
530 error("Unknown message %d line %d", resNum, lineNum);
531 return Common::String();
532 }
533
534 /*--------------------------------------------------------------------------*/
535
536 /**
537 * Open up the given resource file using a passed file object. If the desired entry is found
538 * in the index, return the index entry for it, and move the file to the start of the resource
539 */
scanIndex(Common::File & f,ResourceType resType,int rlbNum,int resNum,ResourceEntry & resEntry)540 bool ResourceManager::scanIndex(Common::File &f, ResourceType resType, int rlbNum, int resNum,
541 ResourceEntry &resEntry) {
542 // Load the root section index
543 ResourceList resList;
544 loadSection(f, resList);
545
546 // Loop through the index for the desired entry
547 ResourceList::iterator iter;
548 for (iter = resList.begin(); iter != resList.end(); ++iter) {
549 ResourceEntry &re = *iter;
550 if (re.id == resNum) {
551 // Found it, so exit
552 resEntry = re;
553 f.seek(re.fileOffset);
554 return true;
555 }
556 }
557
558 // No matching entry found
559 return false;
560 }
561
562 /**
563 * Inner logic for decoding a section index into a passed resource list object
564 */
loadSection(Common::File & f,ResourceList & resources)565 void ResourceManager::loadSection(Common::File &f, ResourceList &resources) {
566 if (f.readUint32BE() != 0x544D492D)
567 error("Data block is not valid Rlb data");
568
569 /*uint8 unknown1 = */f.readByte();
570 uint16 numEntries = f.readByte();
571
572 for (uint i = 0; i < numEntries; ++i) {
573 uint16 id = f.readUint16LE();
574 uint16 size = f.readUint16LE();
575 uint16 uncSize = f.readUint16LE();
576 uint8 sizeHi = f.readByte();
577 uint8 type = f.readByte() >> 5;
578 assert(type <= 1);
579 uint32 offset = f.readUint32LE();
580
581 ResourceEntry re;
582 re.id = id;
583 re.fileOffset = offset;
584 re.isCompressed = type != 0;
585 re.size = ((sizeHi & 0xF) << 16) | size;
586 re.uncompressedSize = ((sizeHi & 0xF0) << 12) | uncSize;
587
588 resources.push_back(re);
589 }
590 }
591
592 } // end of namespace TsAGE
593