libmspack 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/README.md +75 -0
- data/Rakefile +22 -0
- data/UNLICENSE +24 -0
- data/ext/Rakefile +16 -0
- data/ext/i386-windows/libmspack.dll +0 -0
- data/ext/libmspack/AUTHORS +12 -0
- data/ext/libmspack/COPYING.LIB +504 -0
- data/ext/libmspack/ChangeLog +491 -0
- data/ext/libmspack/Makefile.am +100 -0
- data/ext/libmspack/NEWS +0 -0
- data/ext/libmspack/README +130 -0
- data/ext/libmspack/TODO +8 -0
- data/ext/libmspack/cleanup.sh +9 -0
- data/ext/libmspack/configure.ac +50 -0
- data/ext/libmspack/debian/changelog +6 -0
- data/ext/libmspack/debian/control +14 -0
- data/ext/libmspack/debian/rules +101 -0
- data/ext/libmspack/doc/Doxyfile.in +22 -0
- data/ext/libmspack/doc/Makefile.in +14 -0
- data/ext/libmspack/doc/szdd_kwaj_format.html +331 -0
- data/ext/libmspack/libmspack.pc.in +10 -0
- data/ext/libmspack/mspack/cab.h +127 -0
- data/ext/libmspack/mspack/cabc.c +24 -0
- data/ext/libmspack/mspack/cabd.c +1444 -0
- data/ext/libmspack/mspack/chm.h +122 -0
- data/ext/libmspack/mspack/chmc.c +24 -0
- data/ext/libmspack/mspack/chmd.c +1392 -0
- data/ext/libmspack/mspack/crc32.c +95 -0
- data/ext/libmspack/mspack/crc32.h +17 -0
- data/ext/libmspack/mspack/des.h +15 -0
- data/ext/libmspack/mspack/hlp.h +33 -0
- data/ext/libmspack/mspack/hlpc.c +24 -0
- data/ext/libmspack/mspack/hlpd.c +24 -0
- data/ext/libmspack/mspack/kwaj.h +118 -0
- data/ext/libmspack/mspack/kwajc.c +24 -0
- data/ext/libmspack/mspack/kwajd.c +561 -0
- data/ext/libmspack/mspack/lit.h +35 -0
- data/ext/libmspack/mspack/litc.c +24 -0
- data/ext/libmspack/mspack/litd.c +24 -0
- data/ext/libmspack/mspack/lzss.h +66 -0
- data/ext/libmspack/mspack/lzssd.c +93 -0
- data/ext/libmspack/mspack/lzx.h +221 -0
- data/ext/libmspack/mspack/lzxc.c +18 -0
- data/ext/libmspack/mspack/lzxd.c +895 -0
- data/ext/libmspack/mspack/mspack.def +28 -0
- data/ext/libmspack/mspack/mspack.h +2353 -0
- data/ext/libmspack/mspack/mszip.h +126 -0
- data/ext/libmspack/mspack/mszipc.c +18 -0
- data/ext/libmspack/mspack/mszipd.c +514 -0
- data/ext/libmspack/mspack/oab.h +60 -0
- data/ext/libmspack/mspack/oabc.c +24 -0
- data/ext/libmspack/mspack/oabd.c +408 -0
- data/ext/libmspack/mspack/qtm.h +128 -0
- data/ext/libmspack/mspack/qtmc.c +18 -0
- data/ext/libmspack/mspack/qtmd.c +489 -0
- data/ext/libmspack/mspack/readbits.h +207 -0
- data/ext/libmspack/mspack/readhuff.h +173 -0
- data/ext/libmspack/mspack/sha.h +15 -0
- data/ext/libmspack/mspack/system.c +239 -0
- data/ext/libmspack/mspack/system.h +124 -0
- data/ext/libmspack/mspack/szdd.h +39 -0
- data/ext/libmspack/mspack/szddc.c +24 -0
- data/ext/libmspack/mspack/szddd.c +247 -0
- data/ext/libmspack/rebuild.sh +8 -0
- data/ext/libmspack/test/cabd_c10 +19 -0
- data/ext/libmspack/test/cabd_compare +34 -0
- data/ext/libmspack/test/cabd_md5.c +161 -0
- data/ext/libmspack/test/cabd_memory.c +179 -0
- data/ext/libmspack/test/cabd_test.c +386 -0
- data/ext/libmspack/test/cabrip.c +81 -0
- data/ext/libmspack/test/chmd_compare +38 -0
- data/ext/libmspack/test/chmd_find.c +95 -0
- data/ext/libmspack/test/chmd_md5.c +67 -0
- data/ext/libmspack/test/chmd_order.c +144 -0
- data/ext/libmspack/test/chminfo.c +284 -0
- data/ext/libmspack/test/chmx.c +216 -0
- data/ext/libmspack/test/error.h +22 -0
- data/ext/libmspack/test/expand.c +79 -0
- data/ext/libmspack/test/md5.c +457 -0
- data/ext/libmspack/test/md5.h +165 -0
- data/ext/libmspack/test/md5_fh.h +123 -0
- data/ext/libmspack/test/msdecompile_md5 +24 -0
- data/ext/libmspack/test/msexpand_md5 +39 -0
- data/ext/libmspack/test/multifh.c +435 -0
- data/ext/libmspack/test/oabx.c +41 -0
- data/ext/libmspack/test/test_files/cabd/1.pl +84 -0
- data/ext/libmspack/test/test_files/cabd/2.pl +75 -0
- data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
- data/ext/libmspack/winbuild.sh +26 -0
- data/ext/x86_64-windows/libmspack.dll +0 -0
- data/lib/libmspack/constants.rb +9 -0
- data/lib/libmspack/exceptions.rb +12 -0
- data/lib/libmspack/mscab.rb +722 -0
- data/lib/libmspack/mschm.rb +301 -0
- data/lib/libmspack/mshlp.rb +15 -0
- data/lib/libmspack/mskwaj.rb +124 -0
- data/lib/libmspack/mslit.rb +18 -0
- data/lib/libmspack/msoab.rb +36 -0
- data/lib/libmspack/mspack.rb +208 -0
- data/lib/libmspack/msszdd.rb +81 -0
- data/lib/libmspack/system.rb +84 -0
- data/lib/libmspack/version.rb +4 -0
- data/lib/libmspack.rb +121 -0
- data/libmspack.gemspec +33 -0
- data/spec/libmspack_spec.rb +26 -0
- data/spec/spec_helper.rb +5 -0
- metadata +309 -0
@@ -0,0 +1,489 @@
|
|
1
|
+
/* This file is part of libmspack.
|
2
|
+
* (C) 2003-2004 Stuart Caie.
|
3
|
+
*
|
4
|
+
* The Quantum method was created by David Stafford, adapted by Microsoft
|
5
|
+
* Corporation.
|
6
|
+
*
|
7
|
+
* This decompressor is based on an implementation by Matthew Russotto, used
|
8
|
+
* with permission.
|
9
|
+
*
|
10
|
+
* libmspack is free software; you can redistribute it and/or modify it under
|
11
|
+
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
12
|
+
*
|
13
|
+
* For further details, see the file COPYING.LIB distributed with libmspack
|
14
|
+
*/
|
15
|
+
|
16
|
+
/* Quantum decompression implementation */
|
17
|
+
|
18
|
+
/* This decompressor was researched and implemented by Matthew Russotto. It
|
19
|
+
* has since been tidied up by Stuart Caie. More information can be found at
|
20
|
+
* http://www.speakeasy.org/~russotto/quantumcomp.html
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <system.h>
|
24
|
+
#include <qtm.h>
|
25
|
+
|
26
|
+
/* import bit-reading macros and code */
|
27
|
+
#define BITS_TYPE struct qtmd_stream
|
28
|
+
#define BITS_VAR qtm
|
29
|
+
#define BITS_ORDER_MSB
|
30
|
+
#define READ_BYTES do { \
|
31
|
+
unsigned char b0, b1; \
|
32
|
+
READ_IF_NEEDED; b0 = *i_ptr++; \
|
33
|
+
READ_IF_NEEDED; b1 = *i_ptr++; \
|
34
|
+
INJECT_BITS((b0 << 8) | b1, 16); \
|
35
|
+
} while (0)
|
36
|
+
#include <readbits.h>
|
37
|
+
|
38
|
+
/* Quantum static data tables:
|
39
|
+
*
|
40
|
+
* Quantum uses 'position slots' to represent match offsets. For every
|
41
|
+
* match, a small 'position slot' number and a small offset from that slot
|
42
|
+
* are encoded instead of one large offset.
|
43
|
+
*
|
44
|
+
* position_base[] is an index to the position slot bases
|
45
|
+
*
|
46
|
+
* extra_bits[] states how many bits of offset-from-base data is needed.
|
47
|
+
*
|
48
|
+
* length_base[] and length_extra[] are equivalent in function, but are
|
49
|
+
* used for encoding selector 6 (variable length match) match lengths,
|
50
|
+
* instead of match offsets.
|
51
|
+
*
|
52
|
+
* They are generated with the following code:
|
53
|
+
* unsigned int i, offset;
|
54
|
+
* for (i = 0, offset = 0; i < 42; i++) {
|
55
|
+
* position_base[i] = offset;
|
56
|
+
* extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
|
57
|
+
* offset += 1 << extra_bits[i];
|
58
|
+
* }
|
59
|
+
* for (i = 0, offset = 0; i < 26; i++) {
|
60
|
+
* length_base[i] = offset;
|
61
|
+
* length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
|
62
|
+
* offset += 1 << length_extra[i];
|
63
|
+
* }
|
64
|
+
* length_base[26] = 254; length_extra[26] = 0;
|
65
|
+
*/
|
66
|
+
static const unsigned int position_base[42] = {
|
67
|
+
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
68
|
+
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
|
69
|
+
65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
|
70
|
+
};
|
71
|
+
static const unsigned char extra_bits[42] = {
|
72
|
+
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
73
|
+
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
|
74
|
+
};
|
75
|
+
static const unsigned char length_base[27] = {
|
76
|
+
0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
|
77
|
+
30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
|
78
|
+
};
|
79
|
+
static const unsigned char length_extra[27] = {
|
80
|
+
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
81
|
+
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
82
|
+
};
|
83
|
+
|
84
|
+
|
85
|
+
/* Arithmetic decoder:
|
86
|
+
*
|
87
|
+
* GET_SYMBOL(model, var) fetches the next symbol from the stated model
|
88
|
+
* and puts it in var.
|
89
|
+
*
|
90
|
+
* If necessary, qtmd_update_model() is called.
|
91
|
+
*/
|
92
|
+
#define GET_SYMBOL(model, var) do { \
|
93
|
+
range = ((H - L) & 0xFFFF) + 1; \
|
94
|
+
symf = ((((C - L + 1) * model.syms[0].cumfreq)-1) / range) & 0xFFFF; \
|
95
|
+
\
|
96
|
+
for (i = 1; i < model.entries; i++) { \
|
97
|
+
if (model.syms[i].cumfreq <= symf) break; \
|
98
|
+
} \
|
99
|
+
(var) = model.syms[i-1].sym; \
|
100
|
+
\
|
101
|
+
range = (H - L) + 1; \
|
102
|
+
symf = model.syms[0].cumfreq; \
|
103
|
+
H = L + ((model.syms[i-1].cumfreq * range) / symf) - 1; \
|
104
|
+
L = L + ((model.syms[i].cumfreq * range) / symf); \
|
105
|
+
\
|
106
|
+
do { model.syms[--i].cumfreq += 8; } while (i > 0); \
|
107
|
+
if (model.syms[0].cumfreq > 3800) qtmd_update_model(&model); \
|
108
|
+
\
|
109
|
+
while (1) { \
|
110
|
+
if ((L & 0x8000) != (H & 0x8000)) { \
|
111
|
+
if ((L & 0x4000) && !(H & 0x4000)) { \
|
112
|
+
/* underflow case */ \
|
113
|
+
C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \
|
114
|
+
} \
|
115
|
+
else break; \
|
116
|
+
} \
|
117
|
+
L <<= 1; H = (H << 1) | 1; \
|
118
|
+
ENSURE_BITS(1); \
|
119
|
+
C = (C << 1) | PEEK_BITS(1); \
|
120
|
+
REMOVE_BITS(1); \
|
121
|
+
} \
|
122
|
+
} while (0)
|
123
|
+
|
124
|
+
static void qtmd_update_model(struct qtmd_model *model) {
|
125
|
+
struct qtmd_modelsym tmp;
|
126
|
+
int i, j;
|
127
|
+
|
128
|
+
if (--model->shiftsleft) {
|
129
|
+
for (i = model->entries - 1; i >= 0; i--) {
|
130
|
+
/* -1, not -2; the 0 entry saves this */
|
131
|
+
model->syms[i].cumfreq >>= 1;
|
132
|
+
if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
|
133
|
+
model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
}
|
137
|
+
else {
|
138
|
+
model->shiftsleft = 50;
|
139
|
+
for (i = 0; i < model->entries; i++) {
|
140
|
+
/* no -1, want to include the 0 entry */
|
141
|
+
/* this converts cumfreqs into frequencies, then shifts right */
|
142
|
+
model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
|
143
|
+
model->syms[i].cumfreq++; /* avoid losing things entirely */
|
144
|
+
model->syms[i].cumfreq >>= 1;
|
145
|
+
}
|
146
|
+
|
147
|
+
/* now sort by frequencies, decreasing order -- this must be an
|
148
|
+
* inplace selection sort, or a sort with the same (in)stability
|
149
|
+
* characteristics */
|
150
|
+
for (i = 0; i < model->entries - 1; i++) {
|
151
|
+
for (j = i + 1; j < model->entries; j++) {
|
152
|
+
if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
|
153
|
+
tmp = model->syms[i];
|
154
|
+
model->syms[i] = model->syms[j];
|
155
|
+
model->syms[j] = tmp;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
/* then convert frequencies back to cumfreq */
|
161
|
+
for (i = model->entries - 1; i >= 0; i--) {
|
162
|
+
model->syms[i].cumfreq += model->syms[i+1].cumfreq;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
|
168
|
+
static void qtmd_init_model(struct qtmd_model *model,
|
169
|
+
struct qtmd_modelsym *syms, int start, int len)
|
170
|
+
{
|
171
|
+
int i;
|
172
|
+
|
173
|
+
model->shiftsleft = 4;
|
174
|
+
model->entries = len;
|
175
|
+
model->syms = syms;
|
176
|
+
|
177
|
+
for (i = 0; i <= len; i++) {
|
178
|
+
syms[i].sym = start + i; /* actual symbol */
|
179
|
+
syms[i].cumfreq = len - i; /* current frequency of that symbol */
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
|
184
|
+
/*-------- main Quantum code --------*/
|
185
|
+
|
186
|
+
struct qtmd_stream *qtmd_init(struct mspack_system *system,
|
187
|
+
struct mspack_file *input,
|
188
|
+
struct mspack_file *output,
|
189
|
+
int window_bits, int input_buffer_size)
|
190
|
+
{
|
191
|
+
unsigned int window_size = 1 << window_bits;
|
192
|
+
struct qtmd_stream *qtm;
|
193
|
+
int i;
|
194
|
+
|
195
|
+
if (!system) return NULL;
|
196
|
+
|
197
|
+
/* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
|
198
|
+
if (window_bits < 10 || window_bits > 21) return NULL;
|
199
|
+
|
200
|
+
input_buffer_size = (input_buffer_size + 1) & -2;
|
201
|
+
if (input_buffer_size < 2) return NULL;
|
202
|
+
|
203
|
+
/* allocate decompression state */
|
204
|
+
if (!(qtm = (struct qtmd_stream *) system->alloc(system, sizeof(struct qtmd_stream)))) {
|
205
|
+
return NULL;
|
206
|
+
}
|
207
|
+
|
208
|
+
/* allocate decompression window and input buffer */
|
209
|
+
qtm->window = (unsigned char *) system->alloc(system, (size_t) window_size);
|
210
|
+
qtm->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
|
211
|
+
if (!qtm->window || !qtm->inbuf) {
|
212
|
+
system->free(qtm->window);
|
213
|
+
system->free(qtm->inbuf);
|
214
|
+
system->free(qtm);
|
215
|
+
return NULL;
|
216
|
+
}
|
217
|
+
|
218
|
+
/* initialise decompression state */
|
219
|
+
qtm->sys = system;
|
220
|
+
qtm->input = input;
|
221
|
+
qtm->output = output;
|
222
|
+
qtm->inbuf_size = input_buffer_size;
|
223
|
+
qtm->window_size = window_size;
|
224
|
+
qtm->window_posn = 0;
|
225
|
+
qtm->frame_todo = QTM_FRAME_SIZE;
|
226
|
+
qtm->header_read = 0;
|
227
|
+
qtm->error = MSPACK_ERR_OK;
|
228
|
+
|
229
|
+
qtm->i_ptr = qtm->i_end = &qtm->inbuf[0];
|
230
|
+
qtm->o_ptr = qtm->o_end = &qtm->window[0];
|
231
|
+
qtm->input_end = 0;
|
232
|
+
qtm->bits_left = 0;
|
233
|
+
qtm->bit_buffer = 0;
|
234
|
+
|
235
|
+
/* initialise arithmetic coding models
|
236
|
+
* - model 4 depends on window size, ranges from 20 to 24
|
237
|
+
* - model 5 depends on window size, ranges from 20 to 36
|
238
|
+
* - model 6pos depends on window size, ranges from 20 to 42
|
239
|
+
*/
|
240
|
+
i = window_bits * 2;
|
241
|
+
qtmd_init_model(&qtm->model0, &qtm->m0sym[0], 0, 64);
|
242
|
+
qtmd_init_model(&qtm->model1, &qtm->m1sym[0], 64, 64);
|
243
|
+
qtmd_init_model(&qtm->model2, &qtm->m2sym[0], 128, 64);
|
244
|
+
qtmd_init_model(&qtm->model3, &qtm->m3sym[0], 192, 64);
|
245
|
+
qtmd_init_model(&qtm->model4, &qtm->m4sym[0], 0, (i > 24) ? 24 : i);
|
246
|
+
qtmd_init_model(&qtm->model5, &qtm->m5sym[0], 0, (i > 36) ? 36 : i);
|
247
|
+
qtmd_init_model(&qtm->model6, &qtm->m6sym[0], 0, i);
|
248
|
+
qtmd_init_model(&qtm->model6len, &qtm->m6lsym[0], 0, 27);
|
249
|
+
qtmd_init_model(&qtm->model7, &qtm->m7sym[0], 0, 7);
|
250
|
+
|
251
|
+
/* all ok */
|
252
|
+
return qtm;
|
253
|
+
}
|
254
|
+
|
255
|
+
int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
|
256
|
+
unsigned int frame_todo, frame_end, window_posn, match_offset, range;
|
257
|
+
unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest;
|
258
|
+
int i, j, selector, extra, sym, match_length;
|
259
|
+
unsigned short H, L, C, symf;
|
260
|
+
|
261
|
+
register unsigned int bit_buffer;
|
262
|
+
register unsigned char bits_left;
|
263
|
+
|
264
|
+
/* easy answers */
|
265
|
+
if (!qtm || (out_bytes < 0)) return MSPACK_ERR_ARGS;
|
266
|
+
if (qtm->error) return qtm->error;
|
267
|
+
|
268
|
+
/* flush out any stored-up bytes before we begin */
|
269
|
+
i = qtm->o_end - qtm->o_ptr;
|
270
|
+
if ((off_t) i > out_bytes) i = (int) out_bytes;
|
271
|
+
if (i) {
|
272
|
+
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
273
|
+
return qtm->error = MSPACK_ERR_WRITE;
|
274
|
+
}
|
275
|
+
qtm->o_ptr += i;
|
276
|
+
out_bytes -= i;
|
277
|
+
}
|
278
|
+
if (out_bytes == 0) return MSPACK_ERR_OK;
|
279
|
+
|
280
|
+
/* restore local state */
|
281
|
+
RESTORE_BITS;
|
282
|
+
window = qtm->window;
|
283
|
+
window_posn = qtm->window_posn;
|
284
|
+
frame_todo = qtm->frame_todo;
|
285
|
+
H = qtm->H;
|
286
|
+
L = qtm->L;
|
287
|
+
C = qtm->C;
|
288
|
+
|
289
|
+
/* while we do not have enough decoded bytes in reserve: */
|
290
|
+
while ((qtm->o_end - qtm->o_ptr) < out_bytes) {
|
291
|
+
/* read header if necessary. Initialises H, L and C */
|
292
|
+
if (!qtm->header_read) {
|
293
|
+
H = 0xFFFF; L = 0; READ_BITS(C, 16);
|
294
|
+
qtm->header_read = 1;
|
295
|
+
}
|
296
|
+
|
297
|
+
/* decode more, up to the number of bytes needed, the frame boundary,
|
298
|
+
* or the window boundary, whichever comes first */
|
299
|
+
frame_end = window_posn + (out_bytes - (qtm->o_end - qtm->o_ptr));
|
300
|
+
if ((window_posn + frame_todo) < frame_end) {
|
301
|
+
frame_end = window_posn + frame_todo;
|
302
|
+
}
|
303
|
+
if (frame_end > qtm->window_size) {
|
304
|
+
frame_end = qtm->window_size;
|
305
|
+
}
|
306
|
+
|
307
|
+
while (window_posn < frame_end) {
|
308
|
+
GET_SYMBOL(qtm->model7, selector);
|
309
|
+
if (selector < 4) {
|
310
|
+
/* literal byte */
|
311
|
+
struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
|
312
|
+
((selector == 1) ? &qtm->model1 :
|
313
|
+
((selector == 2) ? &qtm->model2 :
|
314
|
+
&qtm->model3));
|
315
|
+
GET_SYMBOL((*mdl), sym);
|
316
|
+
window[window_posn++] = sym;
|
317
|
+
frame_todo--;
|
318
|
+
}
|
319
|
+
else {
|
320
|
+
/* match repeated string */
|
321
|
+
switch (selector) {
|
322
|
+
case 4: /* selector 4 = fixed length match (3 bytes) */
|
323
|
+
GET_SYMBOL(qtm->model4, sym);
|
324
|
+
READ_MANY_BITS(extra, extra_bits[sym]);
|
325
|
+
match_offset = position_base[sym] + extra + 1;
|
326
|
+
match_length = 3;
|
327
|
+
break;
|
328
|
+
|
329
|
+
case 5: /* selector 5 = fixed length match (4 bytes) */
|
330
|
+
GET_SYMBOL(qtm->model5, sym);
|
331
|
+
READ_MANY_BITS(extra, extra_bits[sym]);
|
332
|
+
match_offset = position_base[sym] + extra + 1;
|
333
|
+
match_length = 4;
|
334
|
+
break;
|
335
|
+
|
336
|
+
case 6: /* selector 6 = variable length match */
|
337
|
+
GET_SYMBOL(qtm->model6len, sym);
|
338
|
+
READ_MANY_BITS(extra, length_extra[sym]);
|
339
|
+
match_length = length_base[sym] + extra + 5;
|
340
|
+
|
341
|
+
GET_SYMBOL(qtm->model6, sym);
|
342
|
+
READ_MANY_BITS(extra, extra_bits[sym]);
|
343
|
+
match_offset = position_base[sym] + extra + 1;
|
344
|
+
break;
|
345
|
+
|
346
|
+
default:
|
347
|
+
/* should be impossible, model7 can only return 0-6 */
|
348
|
+
D(("got %d from selector", selector))
|
349
|
+
return qtm->error = MSPACK_ERR_DECRUNCH;
|
350
|
+
}
|
351
|
+
|
352
|
+
rundest = &window[window_posn];
|
353
|
+
frame_todo -= match_length;
|
354
|
+
|
355
|
+
/* does match destination wrap the window? This situation is possible
|
356
|
+
* where the window size is less than the 32k frame size, but matches
|
357
|
+
* must not go beyond a frame boundary */
|
358
|
+
if ((window_posn + match_length) > qtm->window_size) {
|
359
|
+
/* copy first part of match, before window end */
|
360
|
+
i = qtm->window_size - window_posn;
|
361
|
+
j = window_posn - match_offset;
|
362
|
+
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
363
|
+
|
364
|
+
/* flush currently stored data */
|
365
|
+
i = (&window[qtm->window_size] - qtm->o_ptr);
|
366
|
+
|
367
|
+
/* this should not happen, but if it does then this code
|
368
|
+
* can't handle the situation (can't flush up to the end of
|
369
|
+
* the window, but can't break out either because we haven't
|
370
|
+
* finished writing the match). bail out in this case */
|
371
|
+
if (i > out_bytes) {
|
372
|
+
D(("during window-wrap match; %d bytes to flush but only need %d",
|
373
|
+
i, (int) out_bytes))
|
374
|
+
return qtm->error = MSPACK_ERR_DECRUNCH;
|
375
|
+
}
|
376
|
+
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
377
|
+
return qtm->error = MSPACK_ERR_WRITE;
|
378
|
+
}
|
379
|
+
out_bytes -= i;
|
380
|
+
qtm->o_ptr = &window[0];
|
381
|
+
qtm->o_end = &window[0];
|
382
|
+
|
383
|
+
/* copy second part of match, after window wrap */
|
384
|
+
rundest = &window[0];
|
385
|
+
i = match_length - (qtm->window_size - window_posn);
|
386
|
+
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
387
|
+
window_posn = window_posn + match_length - qtm->window_size;
|
388
|
+
|
389
|
+
break; /* because "window_posn < frame_end" has now failed */
|
390
|
+
}
|
391
|
+
else {
|
392
|
+
/* normal match - output won't wrap window or frame end */
|
393
|
+
i = match_length;
|
394
|
+
|
395
|
+
/* does match _offset_ wrap the window? */
|
396
|
+
if (match_offset > window_posn) {
|
397
|
+
/* j = length from match offset to end of window */
|
398
|
+
j = match_offset - window_posn;
|
399
|
+
if (j > (int) qtm->window_size) {
|
400
|
+
D(("match offset beyond window boundaries"))
|
401
|
+
return qtm->error = MSPACK_ERR_DECRUNCH;
|
402
|
+
}
|
403
|
+
runsrc = &window[qtm->window_size - j];
|
404
|
+
if (j < i) {
|
405
|
+
/* if match goes over the window edge, do two copy runs */
|
406
|
+
i -= j; while (j-- > 0) *rundest++ = *runsrc++;
|
407
|
+
runsrc = window;
|
408
|
+
}
|
409
|
+
while (i-- > 0) *rundest++ = *runsrc++;
|
410
|
+
}
|
411
|
+
else {
|
412
|
+
runsrc = rundest - match_offset;
|
413
|
+
while (i-- > 0) *rundest++ = *runsrc++;
|
414
|
+
}
|
415
|
+
window_posn += match_length;
|
416
|
+
}
|
417
|
+
} /* if (window_posn+match_length > frame_end) */
|
418
|
+
} /* while (window_posn < frame_end) */
|
419
|
+
|
420
|
+
qtm->o_end = &window[window_posn];
|
421
|
+
|
422
|
+
/* if we subtracted too much from frame_todo, it will
|
423
|
+
* wrap around past zero and go above its max value */
|
424
|
+
if (frame_todo > QTM_FRAME_SIZE) {
|
425
|
+
D(("overshot frame alignment"))
|
426
|
+
return qtm->error = MSPACK_ERR_DECRUNCH;
|
427
|
+
}
|
428
|
+
|
429
|
+
/* another frame completed? */
|
430
|
+
if (frame_todo == 0) {
|
431
|
+
/* re-align input */
|
432
|
+
if (bits_left & 7) REMOVE_BITS(bits_left & 7);
|
433
|
+
|
434
|
+
/* special Quantum hack -- cabd.c injects a trailer byte to allow the
|
435
|
+
* decompressor to realign itself. CAB Quantum blocks, unlike LZX
|
436
|
+
* blocks, can have anything from 0 to 4 trailing null bytes. */
|
437
|
+
do { READ_BITS(i, 8); } while (i != 0xFF);
|
438
|
+
|
439
|
+
qtm->header_read = 0;
|
440
|
+
|
441
|
+
frame_todo = QTM_FRAME_SIZE;
|
442
|
+
}
|
443
|
+
|
444
|
+
/* window wrap? */
|
445
|
+
if (window_posn == qtm->window_size) {
|
446
|
+
/* flush all currently stored data */
|
447
|
+
i = (qtm->o_end - qtm->o_ptr);
|
448
|
+
/* break out if we have more than enough to finish this request */
|
449
|
+
if (i >= out_bytes) break;
|
450
|
+
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
451
|
+
return qtm->error = MSPACK_ERR_WRITE;
|
452
|
+
}
|
453
|
+
out_bytes -= i;
|
454
|
+
qtm->o_ptr = &window[0];
|
455
|
+
qtm->o_end = &window[0];
|
456
|
+
window_posn = 0;
|
457
|
+
}
|
458
|
+
|
459
|
+
} /* while (more bytes needed) */
|
460
|
+
|
461
|
+
if (out_bytes) {
|
462
|
+
i = (int) out_bytes;
|
463
|
+
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
464
|
+
return qtm->error = MSPACK_ERR_WRITE;
|
465
|
+
}
|
466
|
+
qtm->o_ptr += i;
|
467
|
+
}
|
468
|
+
|
469
|
+
/* store local state */
|
470
|
+
|
471
|
+
STORE_BITS;
|
472
|
+
qtm->window_posn = window_posn;
|
473
|
+
qtm->frame_todo = frame_todo;
|
474
|
+
qtm->H = H;
|
475
|
+
qtm->L = L;
|
476
|
+
qtm->C = C;
|
477
|
+
|
478
|
+
return MSPACK_ERR_OK;
|
479
|
+
}
|
480
|
+
|
481
|
+
void qtmd_free(struct qtmd_stream *qtm) {
|
482
|
+
struct mspack_system *sys;
|
483
|
+
if (qtm) {
|
484
|
+
sys = qtm->sys;
|
485
|
+
sys->free(qtm->window);
|
486
|
+
sys->free(qtm->inbuf);
|
487
|
+
sys->free(qtm);
|
488
|
+
}
|
489
|
+
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
/* This file is part of libmspack.
|
2
|
+
* (C) 2003-2010 Stuart Caie.
|
3
|
+
*
|
4
|
+
* libmspack is free software; you can redistribute it and/or modify it under
|
5
|
+
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
6
|
+
*
|
7
|
+
* For further details, see the file COPYING.LIB distributed with libmspack
|
8
|
+
*/
|
9
|
+
|
10
|
+
#ifndef MSPACK_READBITS_H
|
11
|
+
#define MSPACK_READBITS_H 1
|
12
|
+
|
13
|
+
/* this header defines macros that read data streams by
|
14
|
+
* the individual bits
|
15
|
+
*
|
16
|
+
* INIT_BITS initialises bitstream state in state structure
|
17
|
+
* STORE_BITS stores bitstream state in state structure
|
18
|
+
* RESTORE_BITS restores bitstream state from state structure
|
19
|
+
* ENSURE_BITS(n) ensure there are at least N bits in the bit buffer
|
20
|
+
* READ_BITS(var,n) takes N bits from the buffer and puts them in var
|
21
|
+
* PEEK_BITS(n) extracts without removing N bits from the bit buffer
|
22
|
+
* REMOVE_BITS(n) removes N bits from the bit buffer
|
23
|
+
*
|
24
|
+
* READ_BITS simply calls ENSURE_BITS, PEEK_BITS and REMOVE_BITS,
|
25
|
+
* which means it's limited to reading the number of bits you can
|
26
|
+
* ensure at any one time. It also fails if asked to read zero bits.
|
27
|
+
* If you need to read zero bits, or more bits than can be ensured in
|
28
|
+
* one go, use READ_MANY_BITS instead.
|
29
|
+
*
|
30
|
+
* These macros have variable names baked into them, so to use them
|
31
|
+
* you have to define some macros:
|
32
|
+
* - BITS_TYPE: the type name of your state structure
|
33
|
+
* - BITS_VAR: the variable that points to your state structure
|
34
|
+
* - define BITS_ORDER_MSB if bits are read from the MSB, or
|
35
|
+
* define BITS_ORDER_LSB if bits are read from the LSB
|
36
|
+
* - READ_BYTES: some code that reads more data into the bit buffer,
|
37
|
+
* it should use READ_IF_NEEDED (calls read_input if the byte buffer
|
38
|
+
* is empty), then INJECT_BITS(data,n) to put data from the byte
|
39
|
+
* buffer into the bit buffer.
|
40
|
+
*
|
41
|
+
* You also need to define some variables and structure members:
|
42
|
+
* - unsigned char *i_ptr; // current position in the byte buffer
|
43
|
+
* - unsigned char *i_end; // end of the byte buffer
|
44
|
+
* - unsigned int bit_buffer; // the bit buffer itself
|
45
|
+
* - unsigned int bits_left; // number of bits remaining
|
46
|
+
*
|
47
|
+
* If you use read_input() and READ_IF_NEEDED, they also expect these
|
48
|
+
* structure members:
|
49
|
+
* - struct mspack_system *sys; // to access sys->read()
|
50
|
+
* - unsigned int error; // to record/return read errors
|
51
|
+
* - unsigned char input_end; // to mark reaching the EOF
|
52
|
+
* - unsigned char *inbuf; // the input byte buffer
|
53
|
+
* - unsigned int inbuf_size; // the size of the input byte buffer
|
54
|
+
*
|
55
|
+
* Your READ_BYTES implementation should read data from *i_ptr and
|
56
|
+
* put them in the bit buffer. READ_IF_NEEDED will call read_input()
|
57
|
+
* if i_ptr reaches i_end, and will fill up inbuf and set i_ptr to
|
58
|
+
* the start of inbuf and i_end to the end of inbuf.
|
59
|
+
*
|
60
|
+
* If you're reading in MSB order, the routines work by using the area
|
61
|
+
* beyond the MSB and the LSB of the bit buffer as a free source of
|
62
|
+
* zeroes when shifting. This avoids having to mask any bits. So we
|
63
|
+
* have to know the bit width of the bit buffer variable. We use
|
64
|
+
* <limits.h> and CHAR_BIT to find the size of the bit buffer in bits.
|
65
|
+
*
|
66
|
+
* If you are reading in LSB order, bits need to be masked. Normally
|
67
|
+
* this is done by computing the mask: N bits are masked by the value
|
68
|
+
* (1<<N)-1). However, you can define BITS_LSB_TABLE to use a lookup
|
69
|
+
* table instead of computing this. This adds two new macros,
|
70
|
+
* PEEK_BITS_T and READ_BITS_T which work the same way as PEEK_BITS
|
71
|
+
* and READ_BITS, except they use this lookup table. This is useful if
|
72
|
+
* you need to look up a number of bits that are only known at
|
73
|
+
* runtime, so the bit mask can't be turned into a constant by the
|
74
|
+
* compiler.
|
75
|
+
|
76
|
+
* The bit buffer datatype should be at least 32 bits wide: it must be
|
77
|
+
* possible to ENSURE_BITS(17), so it must be possible to add 16 new bits
|
78
|
+
* to the bit buffer when the bit buffer already has 1 to 15 bits left.
|
79
|
+
*/
|
80
|
+
|
81
|
+
#ifndef BITS_VAR
|
82
|
+
# error "define BITS_VAR as the state structure poiner variable name"
|
83
|
+
#endif
|
84
|
+
#ifndef BITS_TYPE
|
85
|
+
# error "define BITS_TYPE as the state structure type"
|
86
|
+
#endif
|
87
|
+
#if defined(BITS_ORDER_MSB) && defined(BITS_ORDER_LSB)
|
88
|
+
# error "you must define either BITS_ORDER_MSB or BITS_ORDER_LSB"
|
89
|
+
#else
|
90
|
+
# if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
|
91
|
+
# error "you must define BITS_ORDER_MSB or BITS_ORDER_LSB"
|
92
|
+
# endif
|
93
|
+
#endif
|
94
|
+
|
95
|
+
#if HAVE_LIMITS_H
|
96
|
+
# include <limits.h>
|
97
|
+
#endif
|
98
|
+
#ifndef CHAR_BIT
|
99
|
+
# define CHAR_BIT (8)
|
100
|
+
#endif
|
101
|
+
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
|
102
|
+
|
103
|
+
#define INIT_BITS do { \
|
104
|
+
BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
|
105
|
+
BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
|
106
|
+
BITS_VAR->bit_buffer = 0; \
|
107
|
+
BITS_VAR->bits_left = 0; \
|
108
|
+
BITS_VAR->input_end = 0; \
|
109
|
+
} while (0)
|
110
|
+
|
111
|
+
#define STORE_BITS do { \
|
112
|
+
BITS_VAR->i_ptr = i_ptr; \
|
113
|
+
BITS_VAR->i_end = i_end; \
|
114
|
+
BITS_VAR->bit_buffer = bit_buffer; \
|
115
|
+
BITS_VAR->bits_left = bits_left; \
|
116
|
+
} while (0)
|
117
|
+
|
118
|
+
#define RESTORE_BITS do { \
|
119
|
+
i_ptr = BITS_VAR->i_ptr; \
|
120
|
+
i_end = BITS_VAR->i_end; \
|
121
|
+
bit_buffer = BITS_VAR->bit_buffer; \
|
122
|
+
bits_left = BITS_VAR->bits_left; \
|
123
|
+
} while (0)
|
124
|
+
|
125
|
+
#define ENSURE_BITS(nbits) do { \
|
126
|
+
while (bits_left < (nbits)) READ_BYTES; \
|
127
|
+
} while (0)
|
128
|
+
|
129
|
+
#define READ_BITS(val, nbits) do { \
|
130
|
+
ENSURE_BITS(nbits); \
|
131
|
+
(val) = PEEK_BITS(nbits); \
|
132
|
+
REMOVE_BITS(nbits); \
|
133
|
+
} while (0)
|
134
|
+
|
135
|
+
#define READ_MANY_BITS(val, bits) do { \
|
136
|
+
unsigned char needed = (bits), bitrun; \
|
137
|
+
(val) = 0; \
|
138
|
+
while (needed > 0) { \
|
139
|
+
if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
|
140
|
+
bitrun = (bits_left < needed) ? bits_left : needed; \
|
141
|
+
(val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
|
142
|
+
REMOVE_BITS(bitrun); \
|
143
|
+
needed -= bitrun; \
|
144
|
+
} \
|
145
|
+
} while (0)
|
146
|
+
|
147
|
+
#ifdef BITS_ORDER_MSB
|
148
|
+
# define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
|
149
|
+
# define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
|
150
|
+
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
|
151
|
+
(bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), (bits_left += (nbits)))
|
152
|
+
#else /* BITS_ORDER_LSB */
|
153
|
+
# define PEEK_BITS(nbits) (bit_buffer & ((1 << (nbits))-1))
|
154
|
+
# define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits)))
|
155
|
+
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
|
156
|
+
(bitdata) << bits_left), (bits_left += (nbits)))
|
157
|
+
#endif
|
158
|
+
|
159
|
+
#ifdef BITS_LSB_TABLE
|
160
|
+
/* lsb_bit_mask[n] = (1 << n) - 1 */
|
161
|
+
static const unsigned short lsb_bit_mask[17] = {
|
162
|
+
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
|
163
|
+
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
164
|
+
};
|
165
|
+
# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
|
166
|
+
# define READ_BITS_T(val, nbits) do { \
|
167
|
+
ENSURE_BITS(nbits); \
|
168
|
+
(val) = PEEK_BITS_T(nbits); \
|
169
|
+
REMOVE_BITS(nbits); \
|
170
|
+
} while (0)
|
171
|
+
#endif
|
172
|
+
|
173
|
+
#ifndef BITS_NO_READ_INPUT
|
174
|
+
# define READ_IF_NEEDED do { \
|
175
|
+
if (i_ptr >= i_end) { \
|
176
|
+
if (read_input(BITS_VAR)) \
|
177
|
+
return BITS_VAR->error; \
|
178
|
+
i_ptr = BITS_VAR->i_ptr; \
|
179
|
+
i_end = BITS_VAR->i_end; \
|
180
|
+
} \
|
181
|
+
} while (0)
|
182
|
+
|
183
|
+
static int read_input(BITS_TYPE *p) {
|
184
|
+
int read = p->sys->read(p->input, &p->inbuf[0], (int)p->inbuf_size);
|
185
|
+
if (read < 0) return p->error = MSPACK_ERR_READ;
|
186
|
+
|
187
|
+
/* we might overrun the input stream by asking for bits we don't use,
|
188
|
+
* so fake 2 more bytes at the end of input */
|
189
|
+
if (read == 0) {
|
190
|
+
if (p->input_end) {
|
191
|
+
D(("out of input bytes"))
|
192
|
+
return p->error = MSPACK_ERR_READ;
|
193
|
+
}
|
194
|
+
else {
|
195
|
+
read = 2;
|
196
|
+
p->inbuf[0] = p->inbuf[1] = 0;
|
197
|
+
p->input_end = 1;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
/* update i_ptr and i_end */
|
202
|
+
p->i_ptr = &p->inbuf[0];
|
203
|
+
p->i_end = &p->inbuf[read];
|
204
|
+
return MSPACK_ERR_OK;
|
205
|
+
}
|
206
|
+
#endif
|
207
|
+
#endif
|