libmspack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +5 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +4 -0
  6. data/README.md +75 -0
  7. data/Rakefile +22 -0
  8. data/UNLICENSE +24 -0
  9. data/ext/Rakefile +16 -0
  10. data/ext/i386-windows/libmspack.dll +0 -0
  11. data/ext/libmspack/AUTHORS +12 -0
  12. data/ext/libmspack/COPYING.LIB +504 -0
  13. data/ext/libmspack/ChangeLog +491 -0
  14. data/ext/libmspack/Makefile.am +100 -0
  15. data/ext/libmspack/NEWS +0 -0
  16. data/ext/libmspack/README +130 -0
  17. data/ext/libmspack/TODO +8 -0
  18. data/ext/libmspack/cleanup.sh +9 -0
  19. data/ext/libmspack/configure.ac +50 -0
  20. data/ext/libmspack/debian/changelog +6 -0
  21. data/ext/libmspack/debian/control +14 -0
  22. data/ext/libmspack/debian/rules +101 -0
  23. data/ext/libmspack/doc/Doxyfile.in +22 -0
  24. data/ext/libmspack/doc/Makefile.in +14 -0
  25. data/ext/libmspack/doc/szdd_kwaj_format.html +331 -0
  26. data/ext/libmspack/libmspack.pc.in +10 -0
  27. data/ext/libmspack/mspack/cab.h +127 -0
  28. data/ext/libmspack/mspack/cabc.c +24 -0
  29. data/ext/libmspack/mspack/cabd.c +1444 -0
  30. data/ext/libmspack/mspack/chm.h +122 -0
  31. data/ext/libmspack/mspack/chmc.c +24 -0
  32. data/ext/libmspack/mspack/chmd.c +1392 -0
  33. data/ext/libmspack/mspack/crc32.c +95 -0
  34. data/ext/libmspack/mspack/crc32.h +17 -0
  35. data/ext/libmspack/mspack/des.h +15 -0
  36. data/ext/libmspack/mspack/hlp.h +33 -0
  37. data/ext/libmspack/mspack/hlpc.c +24 -0
  38. data/ext/libmspack/mspack/hlpd.c +24 -0
  39. data/ext/libmspack/mspack/kwaj.h +118 -0
  40. data/ext/libmspack/mspack/kwajc.c +24 -0
  41. data/ext/libmspack/mspack/kwajd.c +561 -0
  42. data/ext/libmspack/mspack/lit.h +35 -0
  43. data/ext/libmspack/mspack/litc.c +24 -0
  44. data/ext/libmspack/mspack/litd.c +24 -0
  45. data/ext/libmspack/mspack/lzss.h +66 -0
  46. data/ext/libmspack/mspack/lzssd.c +93 -0
  47. data/ext/libmspack/mspack/lzx.h +221 -0
  48. data/ext/libmspack/mspack/lzxc.c +18 -0
  49. data/ext/libmspack/mspack/lzxd.c +895 -0
  50. data/ext/libmspack/mspack/mspack.def +28 -0
  51. data/ext/libmspack/mspack/mspack.h +2353 -0
  52. data/ext/libmspack/mspack/mszip.h +126 -0
  53. data/ext/libmspack/mspack/mszipc.c +18 -0
  54. data/ext/libmspack/mspack/mszipd.c +514 -0
  55. data/ext/libmspack/mspack/oab.h +60 -0
  56. data/ext/libmspack/mspack/oabc.c +24 -0
  57. data/ext/libmspack/mspack/oabd.c +408 -0
  58. data/ext/libmspack/mspack/qtm.h +128 -0
  59. data/ext/libmspack/mspack/qtmc.c +18 -0
  60. data/ext/libmspack/mspack/qtmd.c +489 -0
  61. data/ext/libmspack/mspack/readbits.h +207 -0
  62. data/ext/libmspack/mspack/readhuff.h +173 -0
  63. data/ext/libmspack/mspack/sha.h +15 -0
  64. data/ext/libmspack/mspack/system.c +239 -0
  65. data/ext/libmspack/mspack/system.h +124 -0
  66. data/ext/libmspack/mspack/szdd.h +39 -0
  67. data/ext/libmspack/mspack/szddc.c +24 -0
  68. data/ext/libmspack/mspack/szddd.c +247 -0
  69. data/ext/libmspack/rebuild.sh +8 -0
  70. data/ext/libmspack/test/cabd_c10 +19 -0
  71. data/ext/libmspack/test/cabd_compare +34 -0
  72. data/ext/libmspack/test/cabd_md5.c +161 -0
  73. data/ext/libmspack/test/cabd_memory.c +179 -0
  74. data/ext/libmspack/test/cabd_test.c +386 -0
  75. data/ext/libmspack/test/cabrip.c +81 -0
  76. data/ext/libmspack/test/chmd_compare +38 -0
  77. data/ext/libmspack/test/chmd_find.c +95 -0
  78. data/ext/libmspack/test/chmd_md5.c +67 -0
  79. data/ext/libmspack/test/chmd_order.c +144 -0
  80. data/ext/libmspack/test/chminfo.c +284 -0
  81. data/ext/libmspack/test/chmx.c +216 -0
  82. data/ext/libmspack/test/error.h +22 -0
  83. data/ext/libmspack/test/expand.c +79 -0
  84. data/ext/libmspack/test/md5.c +457 -0
  85. data/ext/libmspack/test/md5.h +165 -0
  86. data/ext/libmspack/test/md5_fh.h +123 -0
  87. data/ext/libmspack/test/msdecompile_md5 +24 -0
  88. data/ext/libmspack/test/msexpand_md5 +39 -0
  89. data/ext/libmspack/test/multifh.c +435 -0
  90. data/ext/libmspack/test/oabx.c +41 -0
  91. data/ext/libmspack/test/test_files/cabd/1.pl +84 -0
  92. data/ext/libmspack/test/test_files/cabd/2.pl +75 -0
  93. data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
  94. data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
  95. data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
  96. data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
  97. data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
  98. data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
  99. data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
  100. data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
  101. data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
  102. data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
  103. data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
  104. data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
  105. data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
  106. data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
  107. data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
  108. data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
  109. data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
  110. data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
  111. data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
  112. data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
  113. data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
  114. data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
  115. data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
  116. data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
  117. data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
  118. data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
  119. data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
  120. data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
  121. data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
  122. data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
  123. data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
  124. data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
  125. data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
  126. data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
  127. data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
  128. data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
  129. data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
  130. data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
  131. data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
  132. data/ext/libmspack/winbuild.sh +26 -0
  133. data/ext/x86_64-windows/libmspack.dll +0 -0
  134. data/lib/libmspack/constants.rb +9 -0
  135. data/lib/libmspack/exceptions.rb +12 -0
  136. data/lib/libmspack/mscab.rb +722 -0
  137. data/lib/libmspack/mschm.rb +301 -0
  138. data/lib/libmspack/mshlp.rb +15 -0
  139. data/lib/libmspack/mskwaj.rb +124 -0
  140. data/lib/libmspack/mslit.rb +18 -0
  141. data/lib/libmspack/msoab.rb +36 -0
  142. data/lib/libmspack/mspack.rb +208 -0
  143. data/lib/libmspack/msszdd.rb +81 -0
  144. data/lib/libmspack/system.rb +84 -0
  145. data/lib/libmspack/version.rb +4 -0
  146. data/lib/libmspack.rb +121 -0
  147. data/libmspack.gemspec +33 -0
  148. data/spec/libmspack_spec.rb +26 -0
  149. data/spec/spec_helper.rb +5 -0
  150. 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