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.
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