libmspack 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|