aboutsummaryrefslogtreecommitdiff
path: root/engines/cryo/LempelZiv.h
blob: fa683978de576f9ffeb4def9d4fe0e1a332258c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#pragma once

namespace Cryo {

class BitReaderBase {
public:
	unsigned char *_data;   //NB! never override this - used by decompressor
	unsigned int _queue;
	unsigned int _queueLeft;
public:
	BitReaderBase(void *data, unsigned int dataSize = 0) {
		_data = static_cast<unsigned char *>(data);
		_queue = _queueLeft = 0;
	}

	unsigned char GetBit() {
		return 0;   // to be overriden
	}
};

// used to decompress HSQ files
class BitReader16 : BitReaderBase {
public:
	unsigned char GetBit() {
		if (!_queueLeft) {
			_queue = (_data[1] << 8) | _data[0];
			_data += 2;
			_queueLeft += 16;
		}
		unsigned char bit = _queue & 1;
		_queue >>= 1;
		_queueLeft--;
		return bit;
	}
};

// used by HNM decoder
class BitReader32 : BitReaderBase {
public:
	unsigned char GetBit() {
		if (!_queueLeft) {
			_queue = (_data[3] << 24) | (_data[2] << 16) | (_data[1] << 8) | _data[0];
			_data += 4;
			_queueLeft += 32;
		}
		unsigned char bit = (_queue >> (_queueLeft - 1)) & 1;
		_queueLeft--;
		return bit;
	}
};

template <class BitReader>
class LempelZivBase : BitReader {
public:
	LempelZivBase(void *input, unsigned int inputSize) : BitReader(input, inputSize)

		unsigned int UnpackBuffer(void *output, unsigned int maxOutputSize) {
		unsigned char *out = static_cast<unsigned char *>(output);
		for (;;) {
			if (GetBit()) {
				*out++ = *_data++;
			} else {
				int length, offset;
				if (GetBit()) {
					length = *_data & 7;
					offset = ((_data[1] << 8) | _data[0]) >> 3;
					_data += 2;
					offset -= 8192;
					if (!length)
						length = *_data++;
					if (!length)
						break;
				} else {
					length = GetBit() * 2 + GetBit();
					offset = *(_data++) - 256;
				}
				length += 2;
				while (length--) {
					*out = *(out + offset);
					out++;
				}
			}
		}
		return out - static_cast<unsigned char *>(output);
	}
};

}