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