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 "groovie/lzss.h"
24 
25 namespace Groovie {
26 
27 #define OUT_BUFF_SIZE 131072
28 #define COMP_THRESH 3 // Compression not attempted if string to be compressed is less than 3 long
29 
LzssReadStream(Common::ReadStream * indata,uint8 lengthmask,uint8 lengthbits)30 LzssReadStream::LzssReadStream(Common::ReadStream *indata, uint8 lengthmask, uint8 lengthbits) {
31 	/*
32 	TODO: Nasty hack. Make a buffer bigger than I'll ever need... probably.
33 	What should *really* happen is I should define a whole new type of stream
34 	that gets lzss decompressed on the fly
35 	*/
36 	_outLzssBufData = (uint8 *)malloc(OUT_BUFF_SIZE);
37 	_size = decodeLZSS(indata, lengthmask, lengthbits);
38 	_pos = 0;
39 }
40 
~LzssReadStream()41 LzssReadStream::~LzssReadStream() {
42 	free(_outLzssBufData);
43 }
44 
decodeLZSS(Common::ReadStream * in,uint8 lengthmask,uint8 lengthbits)45 uint32 LzssReadStream::decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits) {
46 	uint32 N = 1 << (16 - lengthbits); /* History buffer size */
47 	byte *histbuff = new byte[N]; /* History buffer */
48 	memset(histbuff, 0, N);
49 	uint32 outstreampos = 0;
50 	uint32 bufpos = 0;
51 
52 	while (!in->eos()) {
53 		byte flagbyte = in->readByte();
54 		for (uint32 i = 1; i <= 8; i++) {
55 			if (!in->eos()) {
56 				if ((flagbyte & 1) == 0) {
57 					uint32 offsetlen = in->readUint16LE();
58 					if (offsetlen == 0) {
59 						break;
60 					}
61 					uint32 length = (offsetlen & lengthmask) + COMP_THRESH;
62 					uint32 offset = (bufpos - (offsetlen >> lengthbits)) & (N - 1);
63 					for (uint32 j = 0; j < length; j++) {
64 						byte tempa = histbuff[(offset + j) & (N - 1)];
65 						_outLzssBufData[outstreampos++] = tempa;
66 						histbuff[bufpos] = tempa;
67 						bufpos = (bufpos + 1) & (N - 1);
68 					}
69 				} else {
70 					byte tempa = in->readByte();
71 					if (in->eos()) {
72 						break;
73 					}
74 					_outLzssBufData[outstreampos++] = tempa;
75 					histbuff[bufpos] = tempa;
76 					bufpos = (bufpos + 1) & (N - 1);
77 				}
78 				flagbyte = flagbyte >> 1;
79 			}
80 		}
81 	}
82 	delete[] histbuff;
83 	return outstreampos;
84 }
85 
eos() const86 bool LzssReadStream::eos() const {
87 	return _pos >= _size;
88 }
89 
read(void * buf,uint32 size)90 uint32 LzssReadStream::read(void *buf, uint32 size) {
91 	if (size > _size - _pos)
92 		size = _size - _pos;
93 
94 	memcpy(buf, &_outLzssBufData[_pos], size);
95 	_pos += size;
96 
97 	return size;
98 }
99 
100 } // End of Groovie namespace
101