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 // Resource file routines for Simon1/Simon2
24 
25 
26 #include "common/archive.h"
27 #include "common/file.h"
28 #include "common/memstream.h"
29 #include "common/textconsole.h"
30 #include "common/util.h"
31 
32 #include "agos/agos.h"
33 #include "agos/intern.h"
34 
35 #include "common/zlib.h"
36 
37 namespace AGOS {
38 
39 #ifdef ENABLE_AGOS2
to16Wrapper(uint value)40 uint16 AGOSEngine_Feeble::to16Wrapper(uint value) {
41 	return TO_LE_16(value);
42 }
43 
readUint16Wrapper(const void * src)44 uint16 AGOSEngine_Feeble::readUint16Wrapper(const void *src) {
45 	return READ_LE_UINT16(src);
46 }
47 
readUint32Wrapper(const void * src)48 uint32 AGOSEngine_Feeble::readUint32Wrapper(const void *src) {
49 	return READ_LE_UINT32(src);
50 }
51 #endif
52 
to16Wrapper(uint value)53 uint16 AGOSEngine::to16Wrapper(uint value) {
54 	return TO_BE_16(value);
55 }
56 
readUint16Wrapper(const void * src)57 uint16 AGOSEngine::readUint16Wrapper(const void *src) {
58 	return READ_BE_UINT16(src);
59 }
60 
readUint32Wrapper(const void * src)61 uint32 AGOSEngine::readUint32Wrapper(const void *src) {
62 	return READ_BE_UINT32(src);
63 }
64 
decompressData(const char * srcName,byte * dst,uint32 offset,uint32 srcSize,uint32 dstSize)65 void AGOSEngine::decompressData(const char *srcName, byte *dst, uint32 offset, uint32 srcSize, uint32 dstSize) {
66 #ifdef USE_ZLIB
67 		Common::File in;
68 		in.open(srcName);
69 		if (in.isOpen() == false)
70 			error("decompressData: Can't load %s", srcName);
71 
72 		in.seek(offset, SEEK_SET);
73 		if (srcSize != dstSize) {
74 			byte *srcBuffer = (byte *)malloc(srcSize);
75 
76 			if (in.read(srcBuffer, srcSize) != srcSize)
77 				error("decompressData: Read failed");
78 
79 			unsigned long decompressedSize = dstSize;
80 			if (!Common::uncompress(dst, &decompressedSize, srcBuffer, srcSize))
81 				error("decompressData: Zlib uncompress error");
82 			free(srcBuffer);
83 		} else {
84 			if (in.read(dst, dstSize) != dstSize)
85 				error("decompressData: Read failed");
86 		}
87 		in.close();
88 #else
89 	error("Zlib support is required for Amiga and Macintosh versions");
90 #endif
91 }
92 
loadOffsets(const char * filename,int number,uint32 & file,uint32 & offset,uint32 & srcSize,uint32 & dstSize)93 void AGOSEngine::loadOffsets(const char *filename, int number, uint32 &file, uint32 &offset, uint32 &srcSize, uint32 &dstSize) {
94 	Common::File in;
95 
96 	int offsSize = (getPlatform() == Common::kPlatformAmiga) ? 16 : 12;
97 
98 	/* read offsets from index */
99 	in.open(filename);
100 	if (in.isOpen() == false) {
101 		error("loadOffsets: Can't load index file '%s'", filename);
102 	}
103 
104 	in.seek(number * offsSize, SEEK_SET);
105 	offset = in.readUint32LE();
106 	dstSize = in.readUint32LE();
107 	srcSize = in.readUint32LE();
108 	file = in.readUint32LE();
109 	in.close();
110 }
111 
allocGamePcVars(Common::SeekableReadStream * in)112 int AGOSEngine::allocGamePcVars(Common::SeekableReadStream *in) {
113 	uint32 itemArraySize, itemArrayInited, stringTableNum;
114 	uint32 version;
115 	uint32 i;
116 
117 	itemArraySize = in->readUint32BE();
118 	version = in->readUint32BE();
119 	itemArrayInited = in->readUint32BE();
120 	stringTableNum = in->readUint32BE();
121 
122 	// First two items are predefined
123 	if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
124 		itemArraySize += 2;
125 		itemArrayInited = itemArraySize;
126 	} else {
127 		itemArrayInited += 2;
128 		itemArraySize += 2;
129 	}
130 
131 	if (version != 0x80)
132 		error("allocGamePcVars: Not a runtime database");
133 
134 	_itemArrayPtr = (Item **)calloc(itemArraySize, sizeof(Item *));
135 	if (_itemArrayPtr == NULL)
136 		error("allocGamePcVars: Out of memory for Item array");
137 
138 	_itemArraySize = itemArraySize;
139 	_itemArrayInited = itemArrayInited;
140 
141 	for (i = 1; i < itemArrayInited; i++) {
142 		_itemArrayPtr[i] = (Item *)allocateItem(sizeof(Item));
143 	}
144 
145 	// The rest is cleared automatically by calloc
146 	allocateStringTable(stringTableNum + 10);
147 	_stringTabNum = stringTableNum;
148 
149 	return itemArrayInited;
150 }
151 
loadGamePcFile()152 void AGOSEngine_PN::loadGamePcFile() {
153 	if (getFileName(GAME_BASEFILE) != NULL) {
154 		Common::File in;
155 		// Read dataBase
156 		if (!in.open(getFileName(GAME_BASEFILE))) {
157 			error("loadGamePcFile: Can't load database file '%s'", getFileName(GAME_BASEFILE));
158 		}
159 
160 		_dataBaseSize = in.size();
161 		_dataBase = (byte *)malloc(_dataBaseSize);
162 		if (_dataBase == NULL)
163 			error("loadGamePcFile: Out of memory for dataBase");
164 		in.read(_dataBase, _dataBaseSize);
165 
166 		if (_dataBase[31] != 0)
167 			error("Later version of system requested");
168 	}
169 
170 	if (getFileName(GAME_TEXTFILE) != NULL) {
171 		Common::File in;
172 		// Read textBase
173 		if (!in.open(getFileName(GAME_TEXTFILE))) {
174 			error("loadGamePcFile: Can't load textbase file '%s'", getFileName(GAME_TEXTFILE));
175 		}
176 
177 		_textBaseSize = in.size();
178 		_textBase = (byte *)malloc(_textBaseSize);
179 		if (_textBase == NULL)
180 			error("loadGamePcFile: Out of memory for textBase");
181 		in.read(_textBase, _textBaseSize);
182 
183 		if (_textBase[getlong(30L)] != 128)
184 			error("Unknown compression format");
185 	}
186 }
187 
loadGamePcFile()188 void AGOSEngine::loadGamePcFile() {
189 	int fileSize;
190 
191 	if (getFileName(GAME_BASEFILE) != NULL) {
192 		/* Read main gamexx file */
193 		Common::File in;
194 		if (!in.open(getFileName(GAME_BASEFILE))) {
195 			error("loadGamePcFile: Can't load gamexx file '%s'", getFileName(GAME_BASEFILE));
196 		}
197 
198 		if (getFeatures() & GF_CRUNCHED_GAMEPC) {
199 			uint srcSize = in.size();
200 			byte *srcBuf = (byte *)malloc(srcSize);
201 			in.read(srcBuf, srcSize);
202 
203 			uint dstSize = READ_BE_UINT32(srcBuf + srcSize - 4);
204 			byte *dstBuf = (byte *)malloc(dstSize);
205 			decrunchFile(srcBuf, dstBuf, srcSize);
206 			free(srcBuf);
207 
208 			Common::MemoryReadStream stream(dstBuf, dstSize);
209 			readGamePcFile(&stream);
210 			free(dstBuf);
211 		} else {
212 			readGamePcFile(&in);
213 		}
214 	}
215 
216 	if (getFileName(GAME_TBLFILE) != NULL) {
217 		/* Read list of TABLE resources */
218 		Common::File in;
219 		if (!in.open(getFileName(GAME_TBLFILE))) {
220 			error("loadGamePcFile: Can't load table resources file '%s'", getFileName(GAME_TBLFILE));
221 		}
222 
223 		fileSize = in.size();
224 
225 		_tblList = (byte *)malloc(fileSize);
226 		if (_tblList == NULL)
227 			error("loadGamePcFile: Out of memory for strip table list");
228 		in.read(_tblList, fileSize);
229 
230 		/* Remember the current state */
231 		_subroutineListOrg = _subroutineList;
232 		_tablesHeapPtrOrg = _tablesHeapPtr;
233 		_tablesHeapCurPosOrg = _tablesHeapCurPos;
234 	}
235 
236 	if (getFileName(GAME_STRFILE) != NULL) {
237 		/* Read list of TEXT resources */
238 		Common::File in;
239 		if (!in.open(getFileName(GAME_STRFILE)))
240 			error("loadGamePcFile: Can't load text resources file '%s'", getFileName(GAME_STRFILE));
241 
242 		fileSize = in.size();
243 		_strippedTxtMem = (byte *)malloc(fileSize);
244 		if (_strippedTxtMem == NULL)
245 			error("loadGamePcFile: Out of memory for strip text list");
246 		in.read(_strippedTxtMem, fileSize);
247 	}
248 
249 	if (getFileName(GAME_STATFILE) != NULL) {
250 		/* Read list of ROOM STATE resources */
251 		Common::File in;
252 		if (!in.open(getFileName(GAME_STATFILE))) {
253 			error("loadGamePcFile: Can't load state resources file '%s'", getFileName(GAME_STATFILE));
254 		}
255 
256 		_numRoomStates = in.size() / 8;
257 
258 		_roomStates = (RoomState *)calloc(_numRoomStates, sizeof(RoomState));
259 		if (_roomStates == NULL)
260 			error("loadGamePcFile: Out of memory for room state list");
261 
262 		for (uint s = 0; s < _numRoomStates; s++) {
263 			uint16 num = in.readUint16BE() - (_itemArrayInited - 2);
264 
265 			_roomStates[num].state = in.readUint16BE();
266 			_roomStates[num].classFlags = in.readUint16BE();
267 			_roomStates[num].roomExitStates = in.readUint16BE();
268 		}
269 	}
270 
271 	if (getFileName(GAME_RMSLFILE) != NULL) {
272 		/* Read list of ROOM ITEMS resources */
273 		Common::File in;
274 		if (!in.open(getFileName(GAME_RMSLFILE))) {
275 			error("loadGamePcFile: Can't load room resources file '%s'", getFileName(GAME_RMSLFILE));
276 		}
277 
278 		fileSize = in.size();
279 
280 		_roomsList = (byte *)malloc(fileSize);
281 		if (_roomsList == NULL)
282 			error("loadGamePcFile: Out of memory for room items list");
283 		in.read(_roomsList, fileSize);
284 	}
285 
286 	if (getFileName(GAME_XTBLFILE) != NULL) {
287 		/* Read list of XTABLE resources */
288 		Common::File in;
289 		if (!in.open(getFileName(GAME_XTBLFILE))) {
290 			error("loadGamePcFile: Can't load xtable resources file '%s'", getFileName(GAME_XTBLFILE));
291 		}
292 
293 		fileSize = in.size();
294 
295 		_xtblList = (byte *)malloc(fileSize);
296 		if (_xtblList == NULL)
297 			error("loadGamePcFile: Out of memory for strip xtable list");
298 		in.read(_xtblList, fileSize);
299 
300 		/* Remember the current state */
301 		_xsubroutineListOrg = _subroutineList;
302 		_xtablesHeapPtrOrg = _tablesHeapPtr;
303 		_xtablesHeapCurPosOrg = _tablesHeapCurPos;
304 	}
305 }
306 
readGamePcFile(Common::SeekableReadStream * in)307 void AGOSEngine::readGamePcFile(Common::SeekableReadStream *in) {
308 	int num_inited_objects;
309 	int i;
310 
311 	num_inited_objects = allocGamePcVars(in);
312 
313 	createPlayer();
314 	readGamePcText(in);
315 
316 	for (i = 2; i < num_inited_objects; i++) {
317 		readItemFromGamePc(in, _itemArrayPtr[i]);
318 	}
319 
320 	readSubroutineBlock(in);
321 }
322 
readGamePcText(Common::SeekableReadStream * in)323 void AGOSEngine::readGamePcText(Common::SeekableReadStream *in) {
324 	_textSize = in->readUint32BE();
325 	_textMem = (byte *)malloc(_textSize);
326 	if (_textMem == NULL)
327 		error("readGamePcText: Out of text memory");
328 
329 	in->read(_textMem, _textSize);
330 
331 	setupStringTable(_textMem, _stringTabNum);
332 }
333 
readItemFromGamePc(Common::SeekableReadStream * in,Item * item)334 void AGOSEngine::readItemFromGamePc(Common::SeekableReadStream *in, Item *item) {
335 	uint32 type;
336 
337 	if (getGameType() == GType_ELVIRA1) {
338 		item->itemName = (uint16)in->readUint32BE();
339 		item->adjective = in->readUint16BE();
340 		item->noun = in->readUint16BE();
341 		item->state = in->readUint16BE();
342 		in->readUint16BE();
343 		item->next = (uint16)fileReadItemID(in);
344 		item->child = (uint16)fileReadItemID(in);
345 		item->parent = (uint16)fileReadItemID(in);
346 		in->readUint16BE();
347 		in->readUint16BE();
348 		in->readUint16BE();
349 		item->classFlags = in->readUint16BE();
350 		item->children = NULL;
351 	} else if (getGameType() == GType_ELVIRA2) {
352 		item->itemName = (uint16)in->readUint32BE();
353 		item->adjective = in->readUint16BE();
354 		item->noun = in->readUint16BE();
355 		item->state = in->readUint16BE();
356 		item->next = (uint16)fileReadItemID(in);
357 		item->child = (uint16)fileReadItemID(in);
358 		item->parent = (uint16)fileReadItemID(in);
359 		in->readUint16BE();
360 		item->classFlags = in->readUint16BE();
361 		item->children = NULL;
362 	} else {
363 		item->adjective = in->readUint16BE();
364 		item->noun = in->readUint16BE();
365 		item->state = in->readUint16BE();
366 		item->next = (uint16)fileReadItemID(in);
367 		item->child = (uint16)fileReadItemID(in);
368 		item->parent = (uint16)fileReadItemID(in);
369 		in->readUint16BE();
370 		item->classFlags = in->readUint16BE();
371 		item->children = NULL;
372 	}
373 
374 
375 	type = in->readUint32BE();
376 	while (type) {
377 		type = in->readUint16BE();
378 		if (type != 0)
379 			readItemChildren(in, item, type);
380 	}
381 }
382 
readItemChildren(Common::SeekableReadStream * in,Item * item,uint type)383 void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, uint type) {
384 	if (type == kRoomType) {
385 		SubRoom *subRoom = (SubRoom *)allocateChildBlock(item, kRoomType, sizeof(SubRoom));
386 		subRoom->roomShort = in->readUint32BE();
387 		subRoom->roomLong = in->readUint32BE();
388 		subRoom->flags = in->readUint16BE();
389 	} else if (type == kObjectType) {
390 		SubObject *subObject = (SubObject *)allocateChildBlock(item, kObjectType, sizeof(SubObject));
391 		in->readUint32BE();
392 		in->readUint32BE();
393 		in->readUint32BE();
394 		subObject->objectName = in->readUint32BE();
395 		subObject->objectSize = in->readUint16BE();
396 		subObject->objectWeight = in->readUint16BE();
397 		subObject->objectFlags = in->readUint16BE();
398 	} else if (type == kGenExitType) {
399 		SubGenExit *genExit = (SubGenExit *)allocateChildBlock(item, kGenExitType, sizeof(SubGenExit));
400 		genExit->dest[0] = (uint16)fileReadItemID(in);
401 		genExit->dest[1] = (uint16)fileReadItemID(in);
402 		genExit->dest[2] = (uint16)fileReadItemID(in);
403 		genExit->dest[3] = (uint16)fileReadItemID(in);
404 		genExit->dest[4] = (uint16)fileReadItemID(in);
405 		genExit->dest[5] = (uint16)fileReadItemID(in);
406 		fileReadItemID(in);
407 		fileReadItemID(in);
408 		fileReadItemID(in);
409 		fileReadItemID(in);
410 		fileReadItemID(in);
411 		fileReadItemID(in);
412 	} else if (type == kContainerType) {
413 		SubContainer *container = (SubContainer *)allocateChildBlock(item, kContainerType, sizeof(SubContainer));
414 		container->volume = in->readUint16BE();
415 		container->flags = in->readUint16BE();
416 	} else if (type == kChainType) {
417 		SubChain *chain = (SubChain *)allocateChildBlock(item, kChainType, sizeof(SubChain));
418 		chain->chChained = (uint16)fileReadItemID(in);
419 	} else if (type == kUserFlagType) {
420 		setUserFlag(item, 0, in->readUint16BE());
421 		setUserFlag(item, 1, in->readUint16BE());
422 		setUserFlag(item, 2, in->readUint16BE());
423 		setUserFlag(item, 3, in->readUint16BE());
424 		setUserFlag(item, 4, in->readUint16BE());
425 		setUserFlag(item, 5, in->readUint16BE());
426 		setUserFlag(item, 6, in->readUint16BE());
427 		setUserFlag(item, 7, in->readUint16BE());
428 		SubUserFlag *subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType);
429 		subUserFlag->userItems[0] = (uint16)fileReadItemID(in);
430 		fileReadItemID(in);
431 		fileReadItemID(in);
432 		fileReadItemID(in);
433 	} else if (type == kInheritType) {
434 		SubInherit *inherit = (SubInherit *)allocateChildBlock(item, kInheritType, sizeof(SubInherit));
435 		inherit->inMaster = (uint16)fileReadItemID(in);
436 	} else {
437 		error("readItemChildren: invalid type %d", type);
438 	}
439 }
440 
readItemChildren(Common::SeekableReadStream * in,Item * item,uint type)441 void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item *item, uint type) {
442 	if (type == kRoomType) {
443 		uint fr1 = in->readUint16BE();
444 		uint fr2 = in->readUint16BE();
445 		uint i, size;
446 		uint j, k;
447 		SubRoom *subRoom;
448 
449 		size = SubRoom_SIZE;
450 		for (i = 0, j = fr2; i != 6; i++, j >>= 2)
451 			if (j & 3)
452 				size += sizeof(subRoom->roomExit[0]);
453 
454 		subRoom = (SubRoom *)allocateChildBlock(item, kRoomType, size);
455 		subRoom->subroutine_id = fr1;
456 		subRoom->roomExitStates = fr2;
457 
458 		for (i = k = 0, j = fr2; i != 6; i++, j >>= 2)
459 			if (j & 3)
460 				subRoom->roomExit[k++] = (uint16)fileReadItemID(in);
461 	} else if (type == kObjectType) {
462 		uint32 fr = in->readUint32BE();
463 		uint i, k, size;
464 		SubObject *subObject;
465 
466 		size = SubObject_SIZE;
467 		for (i = 0; i != 16; i++)
468 			if (fr & (1 << i))
469 				size += sizeof(subObject->objectFlagValue[0]);
470 
471 		subObject = (SubObject *)allocateChildBlock(item, kObjectType, size);
472 		subObject->objectFlags = fr;
473 
474 		k = 0;
475 		if (fr & 1) {
476 			subObject->objectFlagValue[k++] = (uint16)in->readUint32BE();
477 		}
478 		for (i = 1; i != 16; i++)
479 			if (fr & (1 << i))
480 				subObject->objectFlagValue[k++] = in->readUint16BE();
481 
482 		if (getGameType() != GType_ELVIRA2)
483 			subObject->objectName = (uint16)in->readUint32BE();
484 	} else if (type == kSuperRoomType) {
485 		assert(getGameType() == GType_ELVIRA2);
486 
487 		uint i, j, k, size;
488 		uint id, x, y, z;
489 		SubSuperRoom *subSuperRoom;
490 
491 		id = in->readUint16BE();
492 		x = in->readUint16BE();
493 		y = in->readUint16BE();
494 		z = in->readUint16BE();
495 
496 		j = x * y * z;
497 		size = SubSuperRoom_SIZE;
498 		for (i = 0; i != j; i++)
499 			size += sizeof(subSuperRoom->roomExitStates[0]);
500 
501 		subSuperRoom = (SubSuperRoom *)allocateChildBlock(item, kSuperRoomType, size);
502 		subSuperRoom->subroutine_id = id;
503 		subSuperRoom->roomX = x;
504 		subSuperRoom->roomY = y;
505 		subSuperRoom->roomZ = z;
506 
507 		for (i = k = 0; i != j; i++)
508 			subSuperRoom->roomExitStates[k++] = in->readUint16BE();
509 	} else if (type == kContainerType) {
510 		SubContainer *container = (SubContainer *)allocateChildBlock(item, kContainerType, sizeof(SubContainer));
511 		container->volume = in->readUint16BE();
512 		container->flags = in->readUint16BE();
513 	} else if (type == kChainType) {
514 		SubChain *chain = (SubChain *)allocateChildBlock(item, kChainType, sizeof(SubChain));
515 		chain->chChained = (uint16)fileReadItemID(in);
516 	} else if (type == kUserFlagType) {
517 		setUserFlag(item, 0, in->readUint16BE());
518 		setUserFlag(item, 1, in->readUint16BE());
519 		setUserFlag(item, 2, in->readUint16BE());
520 		setUserFlag(item, 3, in->readUint16BE());
521 	} else if (type == kInheritType) {
522 		SubInherit *inherit = (SubInherit *)allocateChildBlock(item, kInheritType, sizeof(SubInherit));
523 		inherit->inMaster = (uint16)fileReadItemID(in);
524 	} else {
525 		error("readItemChildren: invalid type %d", type);
526 	}
527 }
528 
fileReadItemID(Common::SeekableReadStream * in)529 uint fileReadItemID(Common::SeekableReadStream *in) {
530 	uint32 val = in->readUint32BE();
531 	if (val == 0xFFFFFFFF)
532 		return 0;
533 	return val + 2;
534 }
535 
openGameFile()536 void AGOSEngine::openGameFile() {
537 	_gameFile = new Common::File();
538 	_gameFile->open(getFileName(GAME_GMEFILE));
539 
540 	if (!_gameFile->isOpen())
541 		error("openGameFile: Can't load game file '%s'", getFileName(GAME_GMEFILE));
542 
543 	uint32 size = _gameFile->readUint32LE();
544 
545 	_gameOffsetsPtr = (uint32 *)malloc(size);
546 	if (_gameOffsetsPtr == NULL)
547 		error("openGameFile: Out of memory, game offsets");
548 
549 	_gameFile->seek(0, SEEK_SET);
550 
551 	for (uint r = 0; r < size / 4; r++)
552 		_gameOffsetsPtr[r] = _gameFile->readUint32LE();
553 }
554 
readGameFile(void * dst,uint32 offs,uint32 size)555 void AGOSEngine::readGameFile(void *dst, uint32 offs, uint32 size) {
556 	_gameFile->seek(offs, SEEK_SET);
557 	if (_gameFile->read(dst, size) != size)
558 		error("readGameFile: Read failed (%d,%d)", offs, size);
559 }
560 
561 // Thanks to Stuart Caie for providing the original
562 // C conversion upon which this decruncher is based.
563 
564 #define SD_GETBIT(var) do {     \
565 	if (!bits--) {              \
566 		s -= 4;                 \
567 		if (s < src)            \
568 			return false;       \
569 		bb = READ_BE_UINT32(s); \
570 		bits = 31;              \
571 	}                           \
572 	(var) = bb & 1;             \
573 	bb >>= 1;                   \
574 }while (0)
575 
576 #define SD_GETBITS(var, nbits) do { \
577 	bc = (nbits);                   \
578 	(var) = 0;                      \
579 	while (bc--) {                   \
580 		(var) <<= 1;                \
581 		SD_GETBIT(bit);             \
582 		(var) |= bit;               \
583 	}                               \
584 }while (0)
585 
586 #define SD_TYPE_LITERAL (0)
587 #define SD_TYPE_MATCH   (1)
588 
decrunchFile(byte * src,byte * dst,uint32 size)589 bool AGOSEngine::decrunchFile(byte *src, byte *dst, uint32 size) {
590 	byte *s = src + size - 4;
591 	uint32 destlen = READ_BE_UINT32 (s);
592 	uint32 bb, x, y;
593 	byte *d = dst + destlen;
594 	byte bc, bit, bits, type;
595 
596 	// Initialize bit buffer.
597 	s -= 4;
598 	bb = x = READ_BE_UINT32 (s);
599 	bits = 0;
600 	do {
601 		x >>= 1;
602 		bits++;
603 	} while (x);
604 	bits--;
605 
606 	while (d > dst) {
607 		SD_GETBIT(x);
608 		if (x) {
609 			SD_GETBITS(x, 2);
610 			switch (x) {
611 			case 0:
612 				type = SD_TYPE_MATCH;
613 				x = 9;
614 				y = 2;
615 				break;
616 
617 			case 1:
618 				type = SD_TYPE_MATCH;
619 				x = 10;
620 				y = 3;
621 				break;
622 
623 			case 2:
624 				type = SD_TYPE_MATCH;
625 				x = 12;
626 				SD_GETBITS(y, 8);
627 				break;
628 
629 			default:
630 				type = SD_TYPE_LITERAL;
631 				x = 8;
632 				y = 8;
633 			}
634 		} else {
635 			SD_GETBIT(x);
636 			if (x) {
637 				type = SD_TYPE_MATCH;
638 				x = 8;
639 				y = 1;
640 			} else {
641 				type = SD_TYPE_LITERAL;
642 				x = 3;
643 				y = 0;
644 			}
645 		}
646 
647 		if (type == SD_TYPE_LITERAL) {
648 			SD_GETBITS(x, x);
649 			y += x;
650 			if ((int)(y + 1) > (d - dst))
651 				return false; // Overflow?
652 			do {
653 				SD_GETBITS(x, 8);
654 				*--d = x;
655 			} while (y-- > 0);
656 		} else {
657 			if ((int)(y + 1) > (d - dst))
658 				return false; // Overflow?
659 			SD_GETBITS(x, x);
660 			if ((d + x) > (dst + destlen))
661 				return false; // Offset overflow?
662 			do {
663 				d--;
664 				*d = d[x];
665 			} while (y-- > 0);
666 		}
667 	}
668 
669 	// Successful decrunch.
670 	return true;
671 }
672 
673 #undef SD_GETBIT
674 #undef SD_GETBITS
675 #undef SD_TYPE_LITERAL
676 #undef SD_TYPE_MATCH
677 
getBit(Common::Stack<uint32> & dataList,uint32 & srcVal)678 static bool getBit(Common::Stack<uint32> &dataList, uint32 &srcVal) {
679 	bool result = srcVal & 1;
680 	srcVal >>= 1;
681 	if (srcVal == 0) {
682 		srcVal = dataList.pop();
683 
684 		result = srcVal & 1;
685 		srcVal = (srcVal >> 1) | 0x80000000L;
686 	}
687 
688 	return result;
689 }
690 
copyBits(Common::Stack<uint32> & dataList,uint32 & srcVal,int numBits)691 static uint32 copyBits(Common::Stack<uint32> &dataList, uint32 &srcVal, int numBits) {
692 	uint32 destVal = 0;
693 
694 	for (int i = 0; i < numBits; ++i) {
695 		bool f = getBit(dataList, srcVal);
696 		destVal = (destVal << 1) | (f ? 1 : 0);
697 	}
698 
699 	return destVal;
700 }
701 
transferLoop(uint8 * dataOut,int & outIndex,uint32 destVal,int max)702 static void transferLoop(uint8 *dataOut, int &outIndex, uint32 destVal, int max) {
703 	assert(outIndex > max - 1);
704 	byte *pDest = dataOut + outIndex;
705 
706 	 for (int i = 0; (i <= max) && (outIndex > 0); ++i) {
707 		pDest = dataOut + --outIndex;
708 		*pDest = pDest[destVal];
709 	 }
710 }
711 
decompressPN(Common::Stack<uint32> & dataList,uint8 * & dataOut,int & dataOutSize)712 void AGOSEngine::decompressPN(Common::Stack<uint32> &dataList, uint8 *&dataOut, int &dataOutSize) {
713 	// Set up the output data area
714 	dataOutSize = dataList.pop();
715 	dataOut = new uint8[dataOutSize];
716 	int outIndex = dataOutSize;
717 
718 	// Decompression routine
719 	uint32 srcVal = dataList.pop();
720 	uint32 destVal;
721 
722 	while (outIndex > 0) {
723 		uint32 numBits = 0;
724 		int count = 0;
725 
726 		if (getBit(dataList, srcVal)) {
727 			destVal = copyBits(dataList, srcVal, 2);
728 
729 			if (destVal < 2) {
730 				count = destVal + 2;
731 				destVal = copyBits(dataList, srcVal, destVal + 9);
732 				transferLoop(dataOut, outIndex, destVal, count);
733 				continue;
734 			} else if (destVal != 3) {
735 				count = copyBits(dataList, srcVal, 8);
736 				destVal = copyBits(dataList, srcVal, 8);
737 				transferLoop(dataOut, outIndex, destVal, count);
738 				continue;
739 			} else {
740 				numBits = 8;
741 				count = 8;
742 			}
743 		} else if (getBit(dataList, srcVal)) {
744 			destVal = copyBits(dataList, srcVal, 8);
745 			transferLoop(dataOut, outIndex, destVal, 1);
746 			continue;
747 		} else {
748 			numBits = 3;
749 			count = 0;
750 		}
751 
752 		destVal = copyBits(dataList, srcVal, numBits);
753 		count += destVal;
754 
755 		// Loop through extracting specified number of bytes
756 		for (int i = 0; i <= count; ++i) {
757 			// Shift 8 bits from the source to the destination
758 			for (int bitCtr = 0; bitCtr < 8; ++bitCtr) {
759 				bool flag = getBit(dataList, srcVal);
760 				destVal = (destVal << 1) | (flag ? 1 : 0);
761 			}
762 
763 			dataOut[--outIndex] = destVal & 0xff;
764 		}
765 	}
766 }
767 
loadVGABeardFile(uint16 id)768 void AGOSEngine::loadVGABeardFile(uint16 id) {
769 	uint32 offs, size;
770 
771 	if (getFeatures() & GF_OLD_BUNDLE) {
772 		Common::File in;
773 		char filename[15];
774 		if (id == 23)
775 			id = 112;
776 		else if (id == 328)
777 			id = 119;
778 
779 		if (getPlatform() == Common::kPlatformAmiga) {
780 			if (getFeatures() & GF_TALKIE)
781 				sprintf(filename, "0%d.out", id);
782 			else
783 				sprintf(filename, "0%d.pkd", id);
784 		} else {
785 			sprintf(filename, "0%d.VGA", id);
786 		}
787 
788 		if (!in.open(filename))
789 			error("loadSimonVGAFile: Can't load %s", filename);
790 
791 		size = in.size();
792 		if (getFeatures() & GF_CRUNCHED) {
793 			byte *srcBuffer = (byte *)malloc(size);
794 			if (in.read(srcBuffer, size) != size)
795 				error("loadSimonVGAFile: Read failed");
796 			decrunchFile(srcBuffer, _vgaBufferPointers[11].vgaFile2, size);
797 			free(srcBuffer);
798 		} else {
799 			if (in.read(_vgaBufferPointers[11].vgaFile2, size) != size)
800 				error("loadSimonVGAFile: Read failed");
801 		}
802 	} else {
803 		offs = _gameOffsetsPtr[id];
804 		size = _gameOffsetsPtr[id + 1] - offs;
805 		readGameFile(_vgaBufferPointers[11].vgaFile2, offs, size);
806 	}
807 }
808 
safeReadByte(const uint8 * & src,const uint8 * end)809 uint8 safeReadByte(const uint8 *&src, const uint8 *end) {
810 	if (src < end)
811 		return (*src++);
812 	error("decodePak98(): invalid data");
813 	return 0;
814 }
815 
safeReadWord(const uint8 * & src,const uint8 * end)816 uint16 safeReadWord(const uint8 *&src, const uint8 *end) {
817 	uint8 lo = safeReadByte(src, end);
818 	return (safeReadByte(src, end) << 8) | lo;
819 }
820 
821 #define S_NEXTBYTE safeReadByte(src, endSrc)
822 #define S_NEXTWORD safeReadWord(src, endSrc)
823 
decodePak98(uint8 * dst,uint32 outSize,const uint8 * src,uint32 inSize)824 void decodePak98(uint8 *dst, uint32 outSize, const uint8 *src, uint32 inSize) {
825 	const uint8 *end = dst + outSize;
826 	const uint8 *endSrc = src + inSize;
827 	uint8 state = 0x80;
828 	uint8 flg = S_NEXTBYTE;
829 
830 	for (uint32 srcBytesLeft = inSize - 1; srcBytesLeft; ) {
831 		if (state & flg) {
832 			if (dst < end)
833 				*dst++ = S_NEXTBYTE;
834 			--srcBytesLeft;
835 		} else {
836 			srcBytesLeft -= 2;
837 			uint16 cmd2 = S_NEXTWORD;
838 			uint8 cmd3 = cmd2 & 0x0F;
839 			cmd2 >>= 4;
840 
841 			if (cmd2 == 0) {
842 				uint16 count = cmd3 + 4;
843 				--srcBytesLeft;
844 				if (cmd3 == 0x0F) {
845 					count = S_NEXTWORD;
846 					srcBytesLeft -= 2;
847 				} else if (cmd3 == 0x0E) {
848 					count = 18 + (S_NEXTBYTE);
849 					--srcBytesLeft;
850 				}
851 
852 				uint8 destVal = S_NEXTBYTE;
853 				while (count-- && dst < end)
854 					*dst++ = destVal;
855 
856 			} else if (cmd2 == 1) {
857 				uint16 count = cmd3 + 3;
858 				if (cmd3 == 0x0F) {
859 					count = S_NEXTWORD;
860 					srcBytesLeft -= 2;
861 				} else if (cmd3 == 0x0E) {
862 					count = 17 + (S_NEXTBYTE);
863 					--srcBytesLeft;
864 				}
865 
866 				dst += count;
867 
868 			} else if (cmd2 == 2) {
869 				uint16 count = cmd3 + 16;
870 				if (cmd3 == 0x0F) {
871 					count = S_NEXTWORD;
872 					srcBytesLeft -= 2;
873 				} else if (cmd3 == 0x0E) {
874 					count = 30 + (S_NEXTBYTE);
875 					--srcBytesLeft;
876 				}
877 
878 				srcBytesLeft -= count;
879 				while (count-- && dst < end)
880 					*dst++ = S_NEXTBYTE;
881 
882 			} else {
883 				uint16 count = cmd3 + 3;
884 				if (cmd3 == 0x0F) {
885 					count = 18 + (S_NEXTBYTE);
886 					--srcBytesLeft;
887 				}
888 
889 				const uint8 *src2 = dst - cmd2;
890 				while (count-- && dst < end)
891 					*dst++ = *src2++;
892 			}
893 		}
894 
895 		if (!(state >>= 1)) {
896 			state = 0x80;
897 			if (srcBytesLeft) {
898 				flg = S_NEXTBYTE;
899 				srcBytesLeft--;
900 			}
901 		}
902 	}
903 }
904 
905 #undef S_NEXTBYTE
906 #undef S_NEXTWORD
907 
loadVGAVideoFile(uint16 id,uint8 type,bool useError)908 void AGOSEngine::loadVGAVideoFile(uint16 id, uint8 type, bool useError) {
909 	Common::File in;
910 	char filename[15];
911 	byte *dst;
912 	uint32 file, offs, srcSize, dstSize;
913 	uint extraBuffer = 0;
914 
915 	if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) &&
916 		id == 2 && type == 2) {
917 		// WORKAROUND: For the extra long strings in foreign languages
918 		// Allocate more space for text to cope with foreign languages that use
919 		// up more space than English. I hope 6400 bytes are enough. This number
920 		// is base on: 2 (lines) * 320 (screen width) * 10 (textheight) -- olki
921 		extraBuffer += 6400;
922 	}
923 
924 	if (getFeatures() & GF_ZLIBCOMP) {
925 		loadOffsets(getFileName(GAME_GFXIDXFILE), id * 3 + type, file, offs, srcSize, dstSize);
926 
927 		if (getPlatform() == Common::kPlatformAmiga)
928 			sprintf(filename, "GFX%d.VGA", file);
929 		else
930 			sprintf(filename, "graphics.vga");
931 
932 		dst = allocBlock(dstSize + extraBuffer);
933 		decompressData(filename, dst, offs, srcSize, dstSize);
934 	} else if (getFeatures() & GF_OLD_BUNDLE) {
935 		if (getPlatform() == Common::kPlatformAcorn) {
936 			sprintf(filename, "%.3d%d.DAT", id, type);
937 		} else if (getPlatform() == Common::kPlatformAmiga || getPlatform() == Common::kPlatformAtariST) {
938 			if (getFeatures() & GF_TALKIE) {
939 				sprintf(filename, "%.3d%d.out", id, type);
940 			} else if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) {
941 				if (getPlatform() == Common::kPlatformAtariST)
942 					sprintf(filename, "%.2d%d.out", id, type);
943 				else
944 					sprintf(filename, "%c%d.out", 48 + id, type);
945 			} else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
946 				sprintf(filename, "%.2d%d.pkd", id, type);
947 			} else if (getGameType() == GType_PN) {
948 				sprintf(filename, "%c%d.in", id + 48, type);
949 			} else {
950 				sprintf(filename, "%.3d%d.pkd", id, type);
951 			}
952 		} else {
953 			if (getGameType() == GType_ELVIRA1 && getPlatform() == Common::kPlatformPC98) {
954 				sprintf(filename, "%.2d.GR2", id);
955 			} else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
956 				sprintf(filename, "%.2d%d.VGA", id, type);
957 			} else if (getGameType() == GType_PN) {
958 				sprintf(filename, "%c%d.out", id + 48, type);
959 			} else {
960 				sprintf(filename, "%.3d%d.VGA", id, type);
961 			}
962 		}
963 
964 		if (!in.open(filename)) {
965 			if (useError)
966 				error("loadVGAVideoFile: Can't load %s", filename);
967 
968 			_block = _blockEnd = NULL;
969 			return;
970 		}
971 
972 		dstSize = srcSize = in.size();
973 		if (getGameType() == GType_PN && getPlatform() == Common::kPlatformDOS && id == 17 && type == 2) {
974 			// The A2.out file isn't compressed in PC version of Personal Nightmare
975 			dst = allocBlock(dstSize + extraBuffer);
976 			if (in.read(dst, dstSize) != dstSize)
977 				error("loadVGAVideoFile: Read failed");
978 		} else if (getGameType() == GType_PN && (getFeatures() & GF_CRUNCHED)) {
979 			Common::Stack<uint32> data;
980 			byte *dataOut = 0;
981 			int dataOutSize = 0;
982 
983 			for (uint i = 0; i < srcSize / 4; ++i) {
984 				uint32 dataVal = in.readUint32BE();
985 				// Correct incorrect byte, in corrupt 72.out file, included in some PC versions.
986 				if (dataVal == 168042714)
987 					data.push(168050906);
988 				else
989 					data.push(dataVal);
990 			}
991 
992 			decompressPN(data, dataOut, dataOutSize);
993 			dst = allocBlock (dataOutSize + extraBuffer);
994 			memcpy(dst, dataOut, dataOutSize);
995 			delete[] dataOut;
996 		} else if (getFeatures() & GF_CRUNCHED) {
997 			byte *srcBuffer = (byte *)malloc(srcSize);
998 			if (in.read(srcBuffer, srcSize) != srcSize)
999 				error("loadVGAVideoFile: Read failed");
1000 
1001 			dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
1002 			dst = allocBlock (dstSize + extraBuffer);
1003 			decrunchFile(srcBuffer, dst, srcSize);
1004 			free(srcBuffer);
1005 		} else if (getPlatform() == Common::kPlatformPC98) {
1006 			bool compressed = (in.readUint16LE() == 1);
1007 			srcSize = in.readUint32LE();
1008 			if (type == 1) {
1009 				if (compressed)
1010 					srcSize = in.readUint32LE() + 2;
1011 				in.seek(srcSize, SEEK_CUR);
1012 				compressed = (in.readUint16LE() == 1);
1013 				srcSize = in.readUint32LE();
1014 			}
1015 
1016 			if (compressed) {
1017 				dstSize = srcSize;
1018 				srcSize = in.readUint32LE();
1019 				uint16 fill = in.readUint16LE();
1020 				dst = allocBlock(dstSize);
1021 
1022 				Common::fill<uint16*, uint16>((uint16*)dst, (uint16*)(dst + (dstSize & ~1)), TO_LE_16(fill));
1023 				if (dstSize & 1)
1024 					*(dst + dstSize - 1) = fill & 0xff;
1025 
1026 				if (srcSize) {
1027 					uint8 *srcBuffer = new uint8[srcSize];
1028 					if (in.read(srcBuffer, srcSize) != srcSize)
1029 						error("loadVGAVideoFile: Read failed");
1030 					decodePak98(dst, dstSize, srcBuffer, srcSize);
1031 					delete[] srcBuffer;
1032 				}
1033 			} else {
1034 				dstSize = srcSize;
1035 				dst = allocBlock(dstSize + extraBuffer);
1036 				if (in.read(dst, dstSize) != dstSize)
1037 					error("loadVGAVideoFile: Read failed");
1038 			}
1039 		} else {
1040 			dst = allocBlock(dstSize + extraBuffer);
1041 			if (in.read(dst, dstSize) != dstSize)
1042 				error("loadVGAVideoFile: Read failed");
1043 		}
1044 	} else {
1045 		id = id * 2 + (type - 1);
1046 		offs = _gameOffsetsPtr[id];
1047 		dstSize = _gameOffsetsPtr[id + 1] - offs;
1048 
1049 		if (!dstSize) {
1050 			if (useError)
1051 				error("loadVGAVideoFile: Can't load id %d type %d", id, type);
1052 
1053 			_block = _blockEnd = NULL;
1054 			return;
1055 		}
1056 
1057 		dst = allocBlock(dstSize + extraBuffer);
1058 		readGameFile(dst, offs, dstSize);
1059 	}
1060 }
1061 
createPak98FileStream(const char * filename)1062 Common::SeekableReadStream *AGOSEngine::createPak98FileStream(const char *filename) {
1063 	Common::File in;
1064 	if (!in.open(filename))
1065 		return 0;
1066 
1067 	/*uint16 cmpType = */in.readUint16LE();
1068 	uint32 outSize = in.readUint32LE();
1069 	uint32 inSize = in.readUint32LE();
1070 	uint16 fill = in.readUint16LE();
1071 
1072 	uint8 *decBuffer = (uint8*)malloc(outSize);
1073 	Common::fill<uint16*, uint16>((uint16*)decBuffer, (uint16*)(decBuffer + (outSize & ~1)), TO_LE_16(fill));
1074 	if (outSize & 1)
1075 		*(decBuffer + outSize - 1) = fill & 0xff;
1076 
1077 	if (inSize) {
1078 		uint8 *tempBuffer = new uint8[inSize];
1079 		in.read(tempBuffer, inSize);
1080 		decodePak98(decBuffer, outSize, tempBuffer, inSize);
1081 		delete[] tempBuffer;
1082 	}
1083 
1084 	return new Common::MemoryReadStream(decBuffer, outSize, DisposeAfterUse::YES);
1085 }
1086 
convertPC98Image(VC10_state & state)1087 void AGOSEngine::convertPC98Image(VC10_state &state) {
1088 	if (state.flags & (kDFCompressedFlip | kDFCompressed)) {
1089 		const byte *src = state.srcPtr;
1090 		uint32 outSize = READ_LE_UINT32(src + 2);
1091 		assert(outSize >= (uint32)((state.width << 3) * state.height));
1092 		uint32 inSize = READ_LE_UINT32(src + 6);
1093 		uint16 fill = READ_LE_UINT16(src + 10);
1094 		delete[] _pak98Buf;
1095 		byte *decBuffer = new uint8[outSize];
1096 		Common::fill<uint16*, uint16>((uint16*)decBuffer, (uint16*)(decBuffer + (outSize & ~1)), TO_LE_16(fill));
1097 		if (outSize & 1)
1098 			*(decBuffer + outSize - 1) = fill & 0xff;
1099 		if (inSize)
1100 			decodePak98(decBuffer, outSize, src + 12, inSize);
1101 		_pak98Buf = state.srcPtr = decBuffer;
1102 		_paletteModNext = 0;
1103 	}
1104 
1105 	// The PC-98 images are in a planar format, but slightly different from the Amiga format. It does
1106 	// not make much sense to set the GF_PLANAR flag, since the Amiga code can't be used anyway.
1107 	free(_planarBuf);
1108 	uint16 planeLW = state.width << 1;
1109 	uint16 planePitch = planeLW * 3;
1110 
1111 	_planarBuf = (byte*)malloc((state.width << 3) * state.height);
1112 
1113 	const byte *src[4];
1114 	memset(src, 0, sizeof(src));
1115 	for (int i = 0; i < 4; ++i)
1116 		src[i] = state.srcPtr + i * planeLW;
1117 	byte *dst = _planarBuf;
1118 
1119 	for (int y = 0; y < state.height; ++y) {
1120 		for (int x = 0; x < planeLW; ++x) {
1121 			for (int i = 0; i <= 6; i += 2) {
1122 				byte col = 0;
1123 				for (int ii = 0; ii < 4; ++ii) {
1124 					col |= ((*src[ii] >> (7 - i)) & 1) << (ii + 4);
1125 					col |= ((*src[ii] >> (6 - i)) & 1) << ii;
1126 				}
1127 				*dst++ = col;
1128 			}
1129 			for (int ii = 0; ii < 4; ++ii)
1130 				++src[ii];
1131 		}
1132 		for (int ii = 0; ii < 4; ++ii)
1133 			src[ii] += planePitch;
1134 	}
1135 
1136 	state.srcPtr = _planarBuf;
1137 	if (state.flags & kDFCompressedFlip)
1138 		state.flags |= kDFFlip;
1139 	state.flags &= ~(kDFCompressedFlip | kDFCompressed);
1140 }
1141 
1142 } // End of namespace AGOS
1143