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 "mads/compression.h"
24 
25 namespace MADS {
26 
27 const char *const madsPackString = "MADSPACK";
28 const char *const FabInputExceededError = "FabDecompressor - Passed end of input buffer during decompression";
29 const char *const FabOutputExceededError = "FabDecompressor - Decompressed data exceeded specified size";
30 
isCompressed(Common::SeekableReadStream * stream)31 bool MadsPack::isCompressed(Common::SeekableReadStream *stream) {
32 	// Check whether the passed stream is packed
33 
34 	char tempBuffer[8];
35 	stream->seek(0);
36 	if (stream->read(tempBuffer, 8) == 8) {
37 		if (!strncmp(tempBuffer, madsPackString, 8))
38 			return true;
39 	}
40 
41 	return false;
42 }
43 
MadsPack(Common::SeekableReadStream * stream)44 MadsPack::MadsPack(Common::SeekableReadStream *stream) {
45 	initialize(stream);
46 }
47 
MadsPack(const Common::String & resourceName,MADSEngine * vm)48 MadsPack::MadsPack(const Common::String &resourceName, MADSEngine *vm) {
49 	File file(resourceName);
50 	initialize(&file);
51 	file.close();
52 }
53 
initialize(Common::SeekableReadStream * stream)54 void MadsPack::initialize(Common::SeekableReadStream *stream) {
55 	if (!MadsPack::isCompressed(stream))
56 		error("Attempted to decompress a resource that was not MadsPacked");
57 
58 	stream->seek(14);
59 	_count = stream->readUint16LE();
60 	_items = new MadsPackEntry[_count];
61 
62 	byte *headerData = new byte[0xA0];
63 	byte *header = headerData;
64 	stream->read(headerData, 0xA0);
65 
66 	for (int i = 0; i < _count; ++i, header += 10) {
67 		// Get header data
68 		_items[i]._type = (CompressionType)*header;
69 		_items[i]._priority = *(header + 1);
70 		_items[i]._size = READ_LE_UINT32(header + 2);
71 		_items[i]._compressedSize = READ_LE_UINT32(header + 6);
72 
73 		byte *sourceData = new byte[_items[i]._compressedSize];
74 		stream->read(sourceData, _items[i]._compressedSize);
75 
76 		switch (_items[i]._type) {
77 		case COMPRESS_NONE:
78 			// Entry isn't compressed
79 			_items[i]._data = sourceData;
80 			break;
81 
82 		case COMPRESS_FAB: {
83 				// Decompress the entry
84 				_items[i]._data = new byte[_items[i]._size];
85 
86 				FabDecompressor fab;
87 				fab.decompress(sourceData, _items[i]._compressedSize, _items[i]._data, _items[i]._size);
88 				delete[] sourceData;
89 				break;
90 			}
91 
92 		default:
93 			error("Unknown compression type encountered");
94 		}
95 	}
96 
97 	delete[] headerData;
98 	_dataOffset = stream->pos();
99 }
100 
~MadsPack()101 MadsPack::~MadsPack() {
102 	for (int i = 0; i < _count; ++i)
103 		delete[] _items[i]._data;
104 	delete[] _items;
105 }
106 
107 //--------------------------------------------------------------------------
108 
decompress(const byte * srcData,int srcSize,byte * destData,int destSize)109 void FabDecompressor::decompress(const byte *srcData, int srcSize, byte *destData, int destSize) {
110 	byte copyLen, copyOfsShift, copyOfsMask, copyLenMask;
111 	unsigned long copyOfs;
112 	byte *destP;
113 
114 	// Validate that the data starts with the FAB header
115 	if (strncmp((const char *)srcData, "FAB", 3) != 0)
116 		error("FabDecompressor - Invalid compressed data");
117 
118 	int shiftVal = srcData[3];
119 	if ((shiftVal < 10) || (shiftVal > 13))
120 		error("FabDecompressor - Invalid shift start");
121 
122 	copyOfsShift = 16 - shiftVal;
123 	copyOfsMask = 0xFF << (shiftVal - 8);
124 	copyLenMask = (1 << copyOfsShift) - 1;
125 	copyOfs = 0xFFFF0000;
126 	destP = destData;
127 
128 	// Initialize data fields
129 	_srcData = srcData;
130 	_srcP = _srcData + 6;
131 	_srcSize = srcSize;
132 	_bitsLeft = 16;
133 	_bitBuffer = READ_LE_UINT16(srcData + 4);
134 
135 	for (;;) {
136 		if (getBit() == 0) {
137 			if (getBit() == 0) {
138 				copyLen = ((getBit() << 1) | getBit()) + 2;
139 				copyOfs = *_srcP++ | 0xFFFFFF00;
140 			} else {
141 				copyOfs = (((_srcP[1] >> copyOfsShift) | copyOfsMask) << 8) | _srcP[0];
142 				copyLen = _srcP[1] & copyLenMask;
143 				_srcP += 2;
144 				if (copyLen == 0) {
145 					copyLen = *_srcP++;
146 					if (copyLen == 0)
147 						break;
148 					else if (copyLen == 1)
149 						continue;
150 					else
151 						copyLen++;
152 				} else {
153 					copyLen += 2;
154 				}
155 				copyOfs |= 0xFFFF0000;
156 			}
157 			while (copyLen-- > 0) {
158 				if (destP - destData == destSize)
159 					error(FabOutputExceededError);
160 
161 				*destP = destP[(signed int)copyOfs];
162 				destP++;
163 			}
164 		} else {
165 			if (_srcP - srcData == srcSize)
166 				error(FabInputExceededError);
167 			if (destP - destData == destSize)
168 				error(FabOutputExceededError);
169 
170 			*destP++ = *_srcP++;
171 		}
172 	}
173 
174 	if (destP - destData != destSize)
175 		error("FabDecompressor - Decompressed data does not match header decompressed size");
176 }
177 
getBit()178 int FabDecompressor::getBit() {
179 	_bitsLeft--;
180 	if (_bitsLeft == 0) {
181 		if (_srcP - _srcData == _srcSize)
182 			error(FabInputExceededError);
183 
184 		_bitBuffer = (READ_LE_UINT16(_srcP) << 1) | (_bitBuffer & 1);
185 		_srcP += 2;
186 		_bitsLeft = 16;
187 	}
188 
189 	int bit = _bitBuffer & 1;
190 	_bitBuffer >>= 1;
191 	return bit;
192 }
193 
194 } // End of namespace MADS
195