diff options
Diffstat (limited to 'recipes-security/clamav/clamav-0.98.5/0007-libclamav-use-libmspack.patch')
-rw-r--r-- | recipes-security/clamav/clamav-0.98.5/0007-libclamav-use-libmspack.patch | 4042 |
1 files changed, 0 insertions, 4042 deletions
diff --git a/recipes-security/clamav/clamav-0.98.5/0007-libclamav-use-libmspack.patch b/recipes-security/clamav/clamav-0.98.5/0007-libclamav-use-libmspack.patch deleted file mode 100644 index 83f30fb..0000000 --- a/recipes-security/clamav/clamav-0.98.5/0007-libclamav-use-libmspack.patch +++ /dev/null | |||
@@ -1,4042 +0,0 @@ | |||
1 | From bffbaabfbb139ef1596d8b20f0275293cecd9297 Mon Sep 17 00:00:00 2001 | ||
2 | From: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> | ||
3 | Date: Wed, 30 Jul 2014 08:35:16 +0200 | ||
4 | Subject: libclamav: use libmspack | ||
5 | |||
6 | This patch provides support for upstream / external libmspack version | ||
7 | libmspack 0.4 (current). The old in-tree version of libmspack is removed | ||
8 | while no loner used. | ||
9 | |||
10 | BTS: #675558 | ||
11 | clamav: https://bugzilla.clamav.net/show_bug.cgi?id=11062 | ||
12 | |||
13 | Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> | ||
14 | --- | ||
15 | configure.ac | 3 + | ||
16 | libclamav/Makefile.am | 11 +- | ||
17 | libclamav/cab.c | 684 ----------------- | ||
18 | libclamav/cab.h | 81 -- | ||
19 | libclamav/chmunpack.h | 122 --- | ||
20 | libclamav/libmspack.c | 525 +++++++++++++ | ||
21 | libclamav/libmspack.h | 7 + | ||
22 | libclamav/mspack.c | 2026 ------------------------------------------------- | ||
23 | libclamav/mspack.h | 294 ------- | ||
24 | libclamav/scanners.c | 146 +--- | ||
25 | 10 files changed, 541 insertions(+), 3358 deletions(-) | ||
26 | delete mode 100644 libclamav/cab.c | ||
27 | delete mode 100644 libclamav/cab.h | ||
28 | delete mode 100644 libclamav/chmunpack.h | ||
29 | create mode 100644 libclamav/libmspack.c | ||
30 | create mode 100644 libclamav/libmspack.h | ||
31 | delete mode 100644 libclamav/mspack.c | ||
32 | delete mode 100644 libclamav/mspack.h | ||
33 | |||
34 | diff --git a/configure.ac b/configure.ac | ||
35 | index e230f939c2d3..41043753fc92 100644 | ||
36 | --- a/configure.ac | ||
37 | +++ b/configure.ac | ||
38 | @@ -174,6 +174,9 @@ if test "$enable_llvm" = "yes" && test "$subdirfailed" != "no"; then | ||
39 | fi | ||
40 | AM_CONDITIONAL([ENABLE_LLVM], | ||
41 | [test "$subdirfailed" != "yes" && test "$enable_llvm" != "no"]) | ||
42 | + | ||
43 | +PKG_CHECK_MODULES([LIBMSPACK], [libmspack]) | ||
44 | + | ||
45 | no_recursion="yes"; | ||
46 | AC_OUTPUT([libclamav/Makefile]) | ||
47 | |||
48 | diff --git a/libclamav/Makefile.am b/libclamav/Makefile.am | ||
49 | index 1aab51bd6ccc..538e83dcdd03 100644 | ||
50 | --- a/libclamav/Makefile.am | ||
51 | +++ b/libclamav/Makefile.am | ||
52 | @@ -147,6 +147,9 @@ if VERSIONSCRIPT | ||
53 | libclamav_la_LDFLAGS += -Wl,@VERSIONSCRIPTFLAG@,@top_srcdir@/libclamav/libclamav.map | ||
54 | endif | ||
55 | |||
56 | +libclamav_la_CFLAGS += $(LIBMSPACK_CFLAGS) | ||
57 | +libclamav_la_LDFLAGS += $(LIBMSPACK_LIBS) | ||
58 | + | ||
59 | include_HEADERS = clamav.h | ||
60 | |||
61 | libclamav_la_SOURCES = \ | ||
62 | @@ -204,8 +207,8 @@ libclamav_la_SOURCES = \ | ||
63 | upx.h \ | ||
64 | htmlnorm.c \ | ||
65 | htmlnorm.h \ | ||
66 | - chmunpack.c \ | ||
67 | - chmunpack.h \ | ||
68 | + libmspack.c \ | ||
69 | + libmspack.h \ | ||
70 | rebuildpe.c \ | ||
71 | rebuildpe.h \ | ||
72 | petite.c \ | ||
73 | @@ -283,10 +286,6 @@ libclamav_la_SOURCES = \ | ||
74 | regex_list.h \ | ||
75 | regex_suffix.c \ | ||
76 | regex_suffix.h \ | ||
77 | - mspack.c \ | ||
78 | - mspack.h \ | ||
79 | - cab.c \ | ||
80 | - cab.h \ | ||
81 | entconv.c \ | ||
82 | entconv.h \ | ||
83 | entitylist.h \ | ||
84 | diff --git a/libclamav/cab.c b/libclamav/cab.c | ||
85 | deleted file mode 100644 | ||
86 | index 6d2eade7d4ea..000000000000 | ||
87 | --- a/libclamav/cab.c | ||
88 | +++ /dev/null | ||
89 | @@ -1,684 +0,0 @@ | ||
90 | -/* | ||
91 | - * Copyright (C) 2007-2008 Sourcefire, Inc. | ||
92 | - * | ||
93 | - * Authors: Tomasz Kojm | ||
94 | - * | ||
95 | - * This program is free software; you can redistribute it and/or modify | ||
96 | - * it under the terms of the GNU General Public License version 2 as | ||
97 | - * published by the Free Software Foundation. | ||
98 | - * | ||
99 | - * This program is distributed in the hope that it will be useful, | ||
100 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
101 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
102 | - * GNU General Public License for more details. | ||
103 | - * | ||
104 | - * You should have received a copy of the GNU General Public License | ||
105 | - * along with this program; if not, write to the Free Software | ||
106 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
107 | - * MA 02110-1301, USA. | ||
108 | - */ | ||
109 | - | ||
110 | -#if HAVE_CONFIG_H | ||
111 | -#include "clamav-config.h" | ||
112 | -#endif | ||
113 | - | ||
114 | -#include <stdio.h> | ||
115 | -#include <string.h> | ||
116 | -#include <ctype.h> | ||
117 | -#include <sys/types.h> | ||
118 | -#include <sys/stat.h> | ||
119 | -#ifdef HAVE_UNISTD_H | ||
120 | -#include <unistd.h> | ||
121 | -#endif | ||
122 | -#include <fcntl.h> | ||
123 | - | ||
124 | -#include "clamav.h" | ||
125 | -#include "cltypes.h" | ||
126 | -#include "others.h" | ||
127 | -#include "mspack.h" | ||
128 | -#include "cab.h" | ||
129 | - | ||
130 | -#define EC32(x) cli_readint32(&x) /* Convert little endian to host */ | ||
131 | -#define EC16(x) cli_readint16(&x) | ||
132 | - | ||
133 | -/* hard limits */ | ||
134 | -#define CAB_FOLDER_LIMIT 5000 | ||
135 | -#define CAB_FILE_LIMIT 5000 | ||
136 | - | ||
137 | -/* Cabinet format data structures */ | ||
138 | - | ||
139 | -struct cab_hdr { | ||
140 | - uint32_t signature; /* file signature */ | ||
141 | - uint32_t res1; /* reserved */ | ||
142 | - uint32_t cbCabinet; /* size of cabinet file */ | ||
143 | - uint32_t res2; /* reserved */ | ||
144 | - uint32_t coffFiles; /* offset of the first file entry */ | ||
145 | - uint32_t res3; /* reserved */ | ||
146 | - uint8_t versionMinor; /* file format version, minor */ | ||
147 | - uint8_t versionMajor; /* file format version, major */ | ||
148 | - uint16_t cFolders; /* number of folder entries */ | ||
149 | - uint16_t cFiles; /* number of file entries */ | ||
150 | - uint16_t flags; /* option flags */ | ||
151 | - uint16_t setID; /* multiple cabs related */ | ||
152 | - uint16_t iCabinet; /* multiple cabs related */ | ||
153 | -}; | ||
154 | - | ||
155 | -struct cab_hdr_opt { | ||
156 | - uint16_t cbCFHeader; /* size of reserved header area */ | ||
157 | - uint8_t cbCFFolder; /* size of reserved folder area */ | ||
158 | - uint8_t cbCFData; /* size of reserved block area */ | ||
159 | -}; | ||
160 | - | ||
161 | -struct cab_folder_hdr | ||
162 | -{ | ||
163 | - uint32_t coffCabStart; /* offset of the first data block */ | ||
164 | - uint16_t cCFData; /* number of data blocks */ | ||
165 | - uint16_t typeCompress; /* compression type */ | ||
166 | -}; | ||
167 | - | ||
168 | -struct cab_file_hdr | ||
169 | -{ | ||
170 | - uint32_t cbFile; /* uncompressed size */ | ||
171 | - uint32_t uoffFolderStart; /* uncompressed offset of file in folder */ | ||
172 | - uint16_t iFolder; /* folder index */ | ||
173 | - uint16_t date; /* date stamp */ | ||
174 | - uint16_t time; /* time stamp */ | ||
175 | - uint16_t attribs; /* attribute flags */ | ||
176 | -}; | ||
177 | - | ||
178 | -struct cab_block_hdr | ||
179 | -{ | ||
180 | - uint32_t csum; /* data block checksum */ | ||
181 | - uint16_t cbData; /* number of compressed bytes */ | ||
182 | - uint16_t cbUncomp; /* number of uncompressed bytes */ | ||
183 | -}; | ||
184 | - | ||
185 | -static char *cab_readstr(fmap_t *map, off_t *offset, int *ret) | ||
186 | -{ | ||
187 | - int i; | ||
188 | - const char *str; | ||
189 | - char *retstr; | ||
190 | - | ||
191 | - if(!(str = fmap_need_offstr(map, *offset, 256))) { | ||
192 | - *ret = CL_EFORMAT; | ||
193 | - return NULL; | ||
194 | - } | ||
195 | - | ||
196 | - i = strlen(str) + 1; | ||
197 | - if(i>=255) { | ||
198 | - fmap_unneed_ptr(map, str, i); | ||
199 | - *ret = CL_EFORMAT; | ||
200 | - return NULL; | ||
201 | - } | ||
202 | - | ||
203 | - *offset += i; | ||
204 | - if((retstr = cli_malloc(i))) | ||
205 | - memcpy(retstr, str, i); | ||
206 | - fmap_unneed_ptr(map, str, i); | ||
207 | - | ||
208 | - if(!retstr) { | ||
209 | - *ret = CL_EMEM; | ||
210 | - return NULL; | ||
211 | - } | ||
212 | - | ||
213 | - *ret = CL_SUCCESS; | ||
214 | - return retstr; | ||
215 | -} | ||
216 | - | ||
217 | -static int cab_chkname(char *name, int san) | ||
218 | -{ | ||
219 | - size_t i, len = strlen(name); | ||
220 | - | ||
221 | - | ||
222 | - for(i = 0; i < len; i++) { | ||
223 | - if(!san && (strchr("%/*?|\\\"+=<>;:\t ", name[i]) || !isascii(name[i]))) { | ||
224 | - cli_dbgmsg("cab_chkname: File name contains disallowed characters\n"); | ||
225 | - return 1; | ||
226 | - } else if(san && !isalnum(name[i])) { | ||
227 | - name[i] = '*'; | ||
228 | - } | ||
229 | - } | ||
230 | - | ||
231 | - return 0; | ||
232 | -} | ||
233 | - | ||
234 | -void cab_free(struct cab_archive *cab) | ||
235 | -{ | ||
236 | - struct cab_folder *folder; | ||
237 | - struct cab_file *file; | ||
238 | - | ||
239 | - | ||
240 | - if(cab->state) { | ||
241 | - if(cab->state->stream) { | ||
242 | - switch(cab->state->cmethod & 0x000f) { | ||
243 | - case 0x0001: | ||
244 | - mszip_free(cab->state->stream); | ||
245 | - break; | ||
246 | - case 0x0002: | ||
247 | - qtm_free(cab->state->stream); | ||
248 | - break; | ||
249 | - case 0x0003: | ||
250 | - lzx_free(cab->state->stream); | ||
251 | - } | ||
252 | - } | ||
253 | - free(cab->state); | ||
254 | - } | ||
255 | - | ||
256 | - while(cab->folders) { | ||
257 | - folder = cab->folders; | ||
258 | - cab->folders = cab->folders->next; | ||
259 | - free(folder); | ||
260 | - } | ||
261 | - | ||
262 | - while(cab->files) { | ||
263 | - file = cab->files; | ||
264 | - cab->files = cab->files->next; | ||
265 | - free(file->name); | ||
266 | - free(file); | ||
267 | - } | ||
268 | -} | ||
269 | - | ||
270 | -int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) | ||
271 | -{ | ||
272 | - unsigned int i, folders = 0; | ||
273 | - struct cab_file *file, *lfile = NULL; | ||
274 | - struct cab_folder *folder, *lfolder = NULL; | ||
275 | - const struct cab_hdr *hdr; | ||
276 | - const struct cab_hdr_opt *hdr_opt; | ||
277 | - uint16_t fidx; | ||
278 | - uint32_t coffFiles; | ||
279 | - char *pt; | ||
280 | - int ret; | ||
281 | - off_t resfold = 0, rsize, cur_offset = offset; | ||
282 | - | ||
283 | - if(!(hdr=fmap_need_off_once(map, cur_offset, sizeof(*hdr)))) { | ||
284 | - cli_dbgmsg("cab_open: Can't read cabinet header\n"); | ||
285 | - return CL_EFORMAT; /* most likely a corrupted file */ | ||
286 | - } | ||
287 | - cur_offset += sizeof(*hdr); | ||
288 | - | ||
289 | - if(EC32(hdr->signature) != 0x4643534d) { | ||
290 | - cli_dbgmsg("cab_open: Incorrect CAB signature\n"); | ||
291 | - return CL_EFORMAT; | ||
292 | - } else { | ||
293 | - cli_dbgmsg("CAB: -------------- Cabinet file ----------------\n"); | ||
294 | - } | ||
295 | - | ||
296 | - rsize = map->len; | ||
297 | - | ||
298 | - memset(cab, 0, sizeof(struct cab_archive)); | ||
299 | - | ||
300 | - cab->length = EC32(hdr->cbCabinet); | ||
301 | - cli_dbgmsg("CAB: Cabinet length: %u\n", cab->length); | ||
302 | - if((off_t) cab->length > rsize) { | ||
303 | - cli_dbgmsg("CAB: Truncating file size from %lu to %lu\n", (unsigned long int) cab->length, (unsigned long int) rsize); | ||
304 | - cab->length = (uint32_t) rsize; | ||
305 | - } | ||
306 | - | ||
307 | - cab->nfolders = EC16(hdr->cFolders); | ||
308 | - if(!cab->nfolders) { | ||
309 | - cli_dbgmsg("cab_open: No folders in cabinet (fake cab?)\n"); | ||
310 | - return CL_EFORMAT; | ||
311 | - } else { | ||
312 | - cli_dbgmsg("CAB: Folders: %u\n", cab->nfolders); | ||
313 | - if(cab->nfolders > CAB_FOLDER_LIMIT) { | ||
314 | - cab->nfolders = CAB_FOLDER_LIMIT; | ||
315 | - cli_dbgmsg("CAB: *** Number of folders limited to %u ***\n", cab->nfolders); | ||
316 | - } | ||
317 | - } | ||
318 | - | ||
319 | - cab->nfiles = EC16(hdr->cFiles); | ||
320 | - if(!cab->nfiles) { | ||
321 | - cli_dbgmsg("cab_open: No files in cabinet (fake cab?)\n"); | ||
322 | - return CL_EFORMAT; | ||
323 | - } else { | ||
324 | - cli_dbgmsg("CAB: Files: %u\n", cab->nfiles); | ||
325 | - if(cab->nfiles > CAB_FILE_LIMIT) { | ||
326 | - cab->nfiles = CAB_FILE_LIMIT; | ||
327 | - cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles); | ||
328 | - } | ||
329 | - } | ||
330 | - | ||
331 | - cli_dbgmsg("CAB: File format version: %u.%u\n", hdr->versionMajor, hdr->versionMinor); | ||
332 | - | ||
333 | - cab->flags = EC16(hdr->flags); | ||
334 | - coffFiles = EC16(hdr->coffFiles); | ||
335 | - | ||
336 | - if(cab->flags & 0x0004) { | ||
337 | - if(!(hdr_opt = fmap_need_off_once(map, cur_offset, sizeof(*hdr_opt)))) { | ||
338 | - cli_dbgmsg("cab_open: Can't read file header (fake cab?)\n"); | ||
339 | - return CL_EFORMAT; /* most likely a corrupted file */ | ||
340 | - } | ||
341 | - | ||
342 | - cab->reshdr = EC16(hdr_opt->cbCFHeader); | ||
343 | - resfold = hdr_opt->cbCFFolder; | ||
344 | - cab->resdata = hdr_opt->cbCFData; | ||
345 | - | ||
346 | - cur_offset += sizeof(*hdr_opt) + cab->reshdr; | ||
347 | - if(cab->reshdr) { | ||
348 | - if(cab->reshdr >= rsize) { | ||
349 | - cli_dbgmsg("cab_open: Can't lseek to %u (fake cab?)\n", cab->reshdr); | ||
350 | - return CL_EFORMAT; /* most likely a corrupted file */ | ||
351 | - } | ||
352 | - } | ||
353 | - } | ||
354 | - | ||
355 | - if(cab->flags & 0x0001) { /* preceding cabinet */ | ||
356 | - /* name */ | ||
357 | - pt = cab_readstr(map, &cur_offset, &ret); | ||
358 | - if(ret) | ||
359 | - return ret; | ||
360 | - if(cab_chkname(pt, 0)) | ||
361 | - cli_dbgmsg("CAB: Invalid name of preceding cabinet\n"); | ||
362 | - else | ||
363 | - cli_dbgmsg("CAB: Preceding cabinet name: %s\n", pt); | ||
364 | - free(pt); | ||
365 | - /* info */ | ||
366 | - pt = cab_readstr(map, &cur_offset, &ret); | ||
367 | - if(ret) | ||
368 | - return ret; | ||
369 | - if(cab_chkname(pt, 0)) | ||
370 | - cli_dbgmsg("CAB: Invalid info for preceding cabinet\n"); | ||
371 | - else | ||
372 | - cli_dbgmsg("CAB: Preceding cabinet info: %s\n", pt); | ||
373 | - free(pt); | ||
374 | - } | ||
375 | - | ||
376 | - if(cab->flags & 0x0002) { /* next cabinet */ | ||
377 | - /* name */ | ||
378 | - pt = cab_readstr(map, &cur_offset, &ret); | ||
379 | - if(ret) | ||
380 | - return ret; | ||
381 | - if(cab_chkname(pt, 0)) | ||
382 | - cli_dbgmsg("CAB: Invalid name of next cabinet\n"); | ||
383 | - else | ||
384 | - cli_dbgmsg("CAB: Next cabinet name: %s\n", pt); | ||
385 | - free(pt); | ||
386 | - /* info */ | ||
387 | - pt = cab_readstr(map, &cur_offset, &ret); | ||
388 | - if(ret) | ||
389 | - return ret; | ||
390 | - if(cab_chkname(pt, 0)) | ||
391 | - cli_dbgmsg("CAB: Invalid info for next cabinet\n"); | ||
392 | - else | ||
393 | - cli_dbgmsg("CAB: Next cabinet info: %s\n", pt); | ||
394 | - free(pt); | ||
395 | - } | ||
396 | - | ||
397 | - /* folders */ | ||
398 | - for(i = 0; i < cab->nfolders; i++) { | ||
399 | - const struct cab_folder_hdr *folder_hdr; | ||
400 | - | ||
401 | - if(!(folder_hdr = fmap_need_off_once(map, cur_offset, sizeof(*folder_hdr)))) { | ||
402 | - cli_dbgmsg("cab_open: Can't read header for folder %u\n", i); | ||
403 | - break; | ||
404 | - } | ||
405 | - | ||
406 | - cur_offset += sizeof(*folder_hdr) + resfold; | ||
407 | - | ||
408 | - if(EC32(folder_hdr->coffCabStart) + offset > rsize) { | ||
409 | - cli_dbgmsg("CAB: Folder out of file\n"); | ||
410 | - continue; | ||
411 | - } | ||
412 | - | ||
413 | - if((EC16(folder_hdr->typeCompress) & 0x000f) > 3) { | ||
414 | - cli_dbgmsg("CAB: Unknown compression method\n"); | ||
415 | - continue; | ||
416 | - } | ||
417 | - | ||
418 | - folder = (struct cab_folder *) cli_calloc(1, sizeof(struct cab_folder)); | ||
419 | - if(!folder) { | ||
420 | - cli_errmsg("cab_open: Can't allocate memory for folder\n"); | ||
421 | - cab_free(cab); | ||
422 | - return CL_EMEM; | ||
423 | - } | ||
424 | - | ||
425 | - folder->cab = (struct cab_archive *) cab; | ||
426 | - folder->offset = (off_t) EC32(folder_hdr->coffCabStart) + offset; | ||
427 | - folder->nblocks = EC16(folder_hdr->cCFData); | ||
428 | - folder->cmethod = EC16(folder_hdr->typeCompress); | ||
429 | - | ||
430 | - cli_dbgmsg("CAB: Folder record %u\n", i); | ||
431 | - cli_dbgmsg("CAB: Folder offset: %u\n", (unsigned int) folder->offset); | ||
432 | - cli_dbgmsg("CAB: Folder compression method: %d\n", folder->cmethod); | ||
433 | - | ||
434 | - if(!lfolder) | ||
435 | - cab->folders = folder; | ||
436 | - else | ||
437 | - lfolder->next = folder; | ||
438 | - | ||
439 | - lfolder = folder; | ||
440 | - folders++; | ||
441 | - } | ||
442 | - cli_dbgmsg("CAB: Recorded folders: %u\n", folders); | ||
443 | - | ||
444 | - /* files */ | ||
445 | - if(cab->nfolders != folders) { | ||
446 | - if(coffFiles >= rsize) { | ||
447 | - cli_dbgmsg("cab_open: Can't lseek to hdr.coffFiles\n"); | ||
448 | - cab_free(cab); | ||
449 | - return CL_EFORMAT; | ||
450 | - } | ||
451 | - cur_offset = coffFiles; | ||
452 | - } | ||
453 | - for(i = 0; i < cab->nfiles; i++) { | ||
454 | - const struct cab_file_hdr *file_hdr; | ||
455 | - | ||
456 | - if(!(file_hdr = fmap_need_off_once(map, cur_offset, sizeof(*file_hdr)))) { | ||
457 | - cli_dbgmsg("cab_open: Can't read file %u header\n", i); | ||
458 | - break; | ||
459 | - } | ||
460 | - cur_offset += sizeof(*file_hdr); | ||
461 | - | ||
462 | - file = (struct cab_file *) cli_calloc(1, sizeof(struct cab_file)); | ||
463 | - if(!file) { | ||
464 | - cli_errmsg("cab_open: Can't allocate memory for file\n"); | ||
465 | - cab_free(cab); | ||
466 | - return CL_EMEM; | ||
467 | - } | ||
468 | - | ||
469 | - file->cab = cab; | ||
470 | - cab->map = map; | ||
471 | - file->offset = EC32(file_hdr->uoffFolderStart); | ||
472 | - file->length = EC32(file_hdr->cbFile); | ||
473 | - file->attribs = EC16(file_hdr->attribs); | ||
474 | - fidx = EC16(file_hdr->iFolder); | ||
475 | - file->error = CL_SUCCESS; | ||
476 | - | ||
477 | - file->name = cab_readstr(map, &cur_offset, &ret); | ||
478 | - if(ret) { | ||
479 | - free(file); | ||
480 | - continue; | ||
481 | - } | ||
482 | - cab_chkname(file->name, 1); | ||
483 | - | ||
484 | - cli_dbgmsg("CAB: File record %u\n", i); | ||
485 | - cli_dbgmsg("CAB: File name: %s\n", file->name); | ||
486 | - cli_dbgmsg("CAB: File offset: %u\n", (unsigned int) file->offset); | ||
487 | - cli_dbgmsg("CAB: File folder index: %u\n", fidx); | ||
488 | - cli_dbgmsg("CAB: File attribs: 0x%x\n", file->attribs); | ||
489 | - if(file->attribs & 0x01) | ||
490 | - cli_dbgmsg("CAB: * file is read-only\n"); | ||
491 | - if(file->attribs & 0x02) | ||
492 | - cli_dbgmsg("CAB: * file is hidden\n"); | ||
493 | - if(file->attribs & 0x04) | ||
494 | - cli_dbgmsg("CAB: * file is a system file\n"); | ||
495 | - if(file->attribs & 0x20) | ||
496 | - cli_dbgmsg("CAB: * file modified since last backup\n"); | ||
497 | - if(file->attribs & 0x40) | ||
498 | - cli_dbgmsg("CAB: * file to be run after extraction\n"); | ||
499 | - if(file->attribs & 0x80) | ||
500 | - cli_dbgmsg("CAB: * file name contains UTF\n"); | ||
501 | - | ||
502 | - /* folder index */ | ||
503 | - if(fidx < 0xfffd) { | ||
504 | - if(fidx > cab->nfolders) { | ||
505 | - cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name); | ||
506 | - free(file->name); | ||
507 | - free(file); | ||
508 | - continue; | ||
509 | - } | ||
510 | - | ||
511 | - file->folder = cab->folders; | ||
512 | - while(file->folder && fidx--) | ||
513 | - file->folder = file->folder->next; | ||
514 | - | ||
515 | - if(!file->folder) { | ||
516 | - cli_dbgmsg("cab_open: Folder not found for file %s\n", file->name); | ||
517 | - free(file->name); | ||
518 | - free(file); | ||
519 | - continue; | ||
520 | - } | ||
521 | - | ||
522 | - } else { | ||
523 | - cli_dbgmsg("CAB: File is split *skipping*\n"); | ||
524 | - free(file->name); | ||
525 | - free(file); | ||
526 | - continue; | ||
527 | - } | ||
528 | - | ||
529 | - if(!lfile) | ||
530 | - cab->files = file; | ||
531 | - else | ||
532 | - lfile->next = file; | ||
533 | - | ||
534 | - lfile = file; | ||
535 | - | ||
536 | - } | ||
537 | - | ||
538 | - return CL_SUCCESS; | ||
539 | -} | ||
540 | - | ||
541 | -static int cab_read_block(struct cab_file *file) | ||
542 | -{ | ||
543 | - const struct cab_block_hdr *block_hdr; | ||
544 | - struct cab_state *state = file->cab->state; | ||
545 | - | ||
546 | - if(!(block_hdr = fmap_need_off_once(file->cab->map, file->cab->cur_offset, sizeof(*block_hdr)))) { | ||
547 | - cli_dbgmsg("cab_read_block: Can't read block header\n"); | ||
548 | - return CL_EFORMAT; /* most likely a corrupted file */ | ||
549 | - } | ||
550 | - | ||
551 | - file->cab->cur_offset += sizeof(*block_hdr) + file->cab->resdata; | ||
552 | - state->blklen = EC16(block_hdr->cbData); | ||
553 | - state->outlen = EC16(block_hdr->cbUncomp); | ||
554 | - | ||
555 | - if(fmap_readn(file->cab->map, state->block, file->cab->cur_offset, state->blklen) != state->blklen) { | ||
556 | - cli_dbgmsg("cab_read_block: Can't read block data\n"); | ||
557 | - return CL_EFORMAT; /* most likely a corrupted file */ | ||
558 | - } | ||
559 | - | ||
560 | - file->cab->cur_offset += state->blklen; | ||
561 | - state->pt = state->end = state->block; | ||
562 | - state->end += state->blklen; | ||
563 | - | ||
564 | - return CL_SUCCESS; | ||
565 | -} | ||
566 | - | ||
567 | -static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes) | ||
568 | -{ | ||
569 | - uint16_t todo, left; | ||
570 | - | ||
571 | - | ||
572 | - if((file->cab->state->blknum > file->folder->nblocks) && !file->lread) { | ||
573 | - file->error = CL_BREAK; | ||
574 | - return -1; | ||
575 | - } | ||
576 | - | ||
577 | - todo = bytes; | ||
578 | - while(todo > 0) { | ||
579 | - left = file->cab->state->end - file->cab->state->pt; | ||
580 | - | ||
581 | - if(left) { | ||
582 | - if(left > todo) | ||
583 | - left = todo; | ||
584 | - | ||
585 | - memcpy(buffer, file->cab->state->pt, left); | ||
586 | - file->cab->state->pt += left; | ||
587 | - buffer += left; | ||
588 | - todo -= left; | ||
589 | - | ||
590 | - } else { | ||
591 | - if(file->cab->state->blknum++ >= file->folder->nblocks) | ||
592 | - break; | ||
593 | - | ||
594 | - file->error = cab_read_block(file); | ||
595 | - if(file->error) | ||
596 | - return -1; | ||
597 | - | ||
598 | - if((file->folder->cmethod & 0x000f) == 0x0002) /* Quantum hack */ | ||
599 | - *file->cab->state->end++ = 0xff; | ||
600 | - | ||
601 | - if(file->cab->state->blknum >= file->folder->nblocks) { | ||
602 | - if((file->folder->cmethod & 0x000f) == 0x0003) { /* LZX hack */ | ||
603 | - lzx_set_output_length(file->cab->state->stream, (off_t) ((file->cab->state->blknum - 1) * 32768 + file->cab->state->outlen)); | ||
604 | - } | ||
605 | - } else { | ||
606 | - if(file->cab->state->outlen != 32768) { | ||
607 | - cli_dbgmsg("cab_read: WARNING: partial data block\n"); | ||
608 | - } | ||
609 | - } | ||
610 | - } | ||
611 | - } | ||
612 | - | ||
613 | - return file->lread = bytes - todo; | ||
614 | -} | ||
615 | - | ||
616 | -static int cab_unstore(struct cab_file *file) | ||
617 | -{ | ||
618 | - int todo, bread, bytes = file->length; | ||
619 | - unsigned char buff[4096]; | ||
620 | - | ||
621 | - | ||
622 | - if(bytes < 0) { | ||
623 | - cli_dbgmsg("cab_unstore: bytes < 0\n"); | ||
624 | - return CL_EFORMAT; | ||
625 | - } | ||
626 | - | ||
627 | - todo = MIN((unsigned int) bytes, file->max_size); | ||
628 | - | ||
629 | - while(1) { | ||
630 | - | ||
631 | - if((unsigned int) todo <= sizeof(buff)) | ||
632 | - bread = todo; | ||
633 | - else | ||
634 | - bread = sizeof(buff); | ||
635 | - | ||
636 | - if((bread = cab_read(file, buff, bread)) == -1) { | ||
637 | - cli_dbgmsg("cab_unstore: cab_read failed\n"); | ||
638 | - return file->error; | ||
639 | - } else if(cli_writen(file->ofd, buff, bread) != bread) { | ||
640 | - cli_warnmsg("cab_unstore: Can't write %d bytes to descriptor %d\n", bread, file->ofd); | ||
641 | - return CL_EWRITE; | ||
642 | - } | ||
643 | - | ||
644 | - todo -= bread; | ||
645 | - | ||
646 | - if(!bread || todo <= 0) | ||
647 | - break; | ||
648 | - } | ||
649 | - | ||
650 | - return CL_SUCCESS; | ||
651 | -} | ||
652 | - | ||
653 | -#define CAB_CHGFOLDER \ | ||
654 | - if(!file->cab->actfol || (file->folder != file->cab->actfol) \ | ||
655 | - || (file->cab->state && file->cab->state->cmethod != file->folder->cmethod)) { \ | ||
656 | - if(file->cab->state) { \ | ||
657 | - if(file->cab->state->stream) { \ | ||
658 | - switch(file->cab->state->cmethod & 0x000f) { \ | ||
659 | - case 0x0001: \ | ||
660 | - mszip_free(file->cab->state->stream); \ | ||
661 | - break; \ | ||
662 | - case 0x0002: \ | ||
663 | - qtm_free(file->cab->state->stream); \ | ||
664 | - break; \ | ||
665 | - case 0x0003: \ | ||
666 | - lzx_free(file->cab->state->stream); \ | ||
667 | - } \ | ||
668 | - } \ | ||
669 | - free(file->cab->state); \ | ||
670 | - file->cab->state = NULL; \ | ||
671 | - } \ | ||
672 | - file->cab->cur_offset = file->folder->offset; \ | ||
673 | - file->cab->state = (struct cab_state *) cli_calloc(1, sizeof(struct cab_state)); \ | ||
674 | - if(!file->cab->state) { \ | ||
675 | - cli_errmsg("cab_extract: Can't allocate memory for internal state\n"); \ | ||
676 | - close(file->ofd); \ | ||
677 | - return CL_EMEM; \ | ||
678 | - } \ | ||
679 | - file->cab->state->cmethod = file->folder->cmethod; \ | ||
680 | - switch(file->folder->cmethod & 0x000f) { \ | ||
681 | - case 0x0001: \ | ||
682 | - file->cab->state->stream = (struct mszip_stream *) mszip_init(file->ofd, 4096, 1, file, &cab_read); \ | ||
683 | - break; \ | ||
684 | - case 0x0002: \ | ||
685 | - file->cab->state->stream = (struct qtm_stream *) qtm_init(file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read); \ | ||
686 | - break; \ | ||
687 | - case 0x0003: \ | ||
688 | - file->cab->state->stream = (struct lzx_stream *) lzx_init(file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read); \ | ||
689 | - } \ | ||
690 | - if((file->folder->cmethod & 0x000f) && !file->cab->state->stream) { \ | ||
691 | - close(file->ofd); \ | ||
692 | - return CL_EUNPACK; \ | ||
693 | - } \ | ||
694 | - file->cab->actfol = file->folder; \ | ||
695 | - } else { \ | ||
696 | - if(file->cab->state && file->cab->state->stream) { \ | ||
697 | - switch(file->cab->state->cmethod & 0x000f) { \ | ||
698 | - case 0x0001: \ | ||
699 | - ((struct mszip_stream *) file->cab->state->stream)->ofd = file->ofd; \ | ||
700 | - break; \ | ||
701 | - case 0x0002: \ | ||
702 | - ((struct qtm_stream *) file->cab->state->stream)->ofd = file->ofd; \ | ||
703 | - break; \ | ||
704 | - case 0x0003: \ | ||
705 | - ((struct lzx_stream *) file->cab->state->stream)->ofd = file->ofd; \ | ||
706 | - break; \ | ||
707 | - } \ | ||
708 | - } \ | ||
709 | - } | ||
710 | - | ||
711 | - | ||
712 | -int cab_extract(struct cab_file *file, const char *name) | ||
713 | -{ | ||
714 | - int ret; | ||
715 | - | ||
716 | - | ||
717 | - if(!file || !name) { | ||
718 | - cli_errmsg("cab_extract: !file || !name\n"); | ||
719 | - return CL_ENULLARG; | ||
720 | - } | ||
721 | - | ||
722 | - if(!file->folder) { | ||
723 | - cli_errmsg("cab_extract: file->folder == NULL\n"); | ||
724 | - return CL_ENULLARG; | ||
725 | - } | ||
726 | - | ||
727 | - file->ofd = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); | ||
728 | - if(file->ofd == -1) { | ||
729 | - cli_errmsg("cab_extract: Can't open file %s in write mode\n", name); | ||
730 | - return CL_ECREAT; | ||
731 | - } | ||
732 | - | ||
733 | - switch(file->folder->cmethod & 0x000f) { | ||
734 | - case 0x0000: /* STORE */ | ||
735 | - cli_dbgmsg("CAB: Compression method: STORED\n"); | ||
736 | - CAB_CHGFOLDER; | ||
737 | - if(file->length > file->cab->length) { | ||
738 | - cli_dbgmsg("cab_extract: Stored file larger than archive itself, trimming down\n"); | ||
739 | - file->length = file->cab->length; | ||
740 | - } | ||
741 | - ret = cab_unstore(file); | ||
742 | - break; | ||
743 | - | ||
744 | - case 0x0001: /* MSZIP */ | ||
745 | - cli_dbgmsg("CAB: Compression method: MSZIP\n"); | ||
746 | - CAB_CHGFOLDER; | ||
747 | - ret = mszip_decompress(file->cab->state->stream, file->length); | ||
748 | - break; | ||
749 | - | ||
750 | - case 0x0002: /* QUANTUM */ | ||
751 | - cli_dbgmsg("CAB: Compression method: QUANTUM\n"); | ||
752 | - CAB_CHGFOLDER; | ||
753 | - ret = qtm_decompress(file->cab->state->stream, file->length); | ||
754 | - break; | ||
755 | - | ||
756 | - case 0x0003: /* LZX */ | ||
757 | - cli_dbgmsg("CAB: Compression method: LZX\n"); | ||
758 | - CAB_CHGFOLDER; | ||
759 | - ret = lzx_decompress(file->cab->state->stream, file->length); | ||
760 | - break; | ||
761 | - | ||
762 | - default: | ||
763 | - cli_dbgmsg("CAB: Not supported compression method: 0x%x\n", file->folder->cmethod & 0x000f); | ||
764 | - ret = CL_EFORMAT; | ||
765 | - } | ||
766 | - | ||
767 | - close(file->ofd); | ||
768 | - | ||
769 | - if(ret == CL_BREAK) | ||
770 | - ret = CL_SUCCESS; | ||
771 | - | ||
772 | - return ret; | ||
773 | -} | ||
774 | diff --git a/libclamav/cab.h b/libclamav/cab.h | ||
775 | deleted file mode 100644 | ||
776 | index 795900d555e9..000000000000 | ||
777 | --- a/libclamav/cab.h | ||
778 | +++ /dev/null | ||
779 | @@ -1,81 +0,0 @@ | ||
780 | -/* | ||
781 | - * Copyright (C) 2007-2008 Sourcefire, Inc. | ||
782 | - * | ||
783 | - * Authors: Tomasz Kojm | ||
784 | - * | ||
785 | - * This program is free software; you can redistribute it and/or modify | ||
786 | - * it under the terms of the GNU General Public License version 2 as | ||
787 | - * published by the Free Software Foundation. | ||
788 | - * | ||
789 | - * This program is distributed in the hope that it will be useful, | ||
790 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
791 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
792 | - * GNU General Public License for more details. | ||
793 | - * | ||
794 | - * You should have received a copy of the GNU General Public License | ||
795 | - * along with this program; if not, write to the Free Software | ||
796 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
797 | - * MA 02110-1301, USA. | ||
798 | - */ | ||
799 | - | ||
800 | -#ifndef __CAB_H | ||
801 | -#define __CAB_H | ||
802 | - | ||
803 | -#include <sys/types.h> | ||
804 | -#include "cltypes.h" | ||
805 | -#include "fmap.h" | ||
806 | - | ||
807 | -#define CAB_BLOCKMAX 65535 | ||
808 | -#define CAB_INPUTMAX (CAB_BLOCKMAX + 6144) | ||
809 | - | ||
810 | -struct cab_archive { | ||
811 | - struct cab_folder *folders, *actfol; | ||
812 | - struct cab_file *files; | ||
813 | - struct cab_state *state; | ||
814 | - fmap_t *map; | ||
815 | - off_t cur_offset; | ||
816 | - uint32_t length; | ||
817 | - uint16_t nfolders; | ||
818 | - uint16_t nfiles; | ||
819 | - uint16_t flags; | ||
820 | - uint16_t reshdr; | ||
821 | - uint8_t resdata; | ||
822 | -}; | ||
823 | - | ||
824 | -struct cab_state { | ||
825 | - unsigned char *pt, *end; | ||
826 | - void *stream; | ||
827 | - unsigned char block[CAB_INPUTMAX]; | ||
828 | - uint16_t blklen; | ||
829 | - uint16_t outlen; | ||
830 | - uint16_t blknum; | ||
831 | - uint16_t cmethod; | ||
832 | -}; | ||
833 | - | ||
834 | -struct cab_file { | ||
835 | - off_t offset; | ||
836 | - char *name; | ||
837 | - uint32_t length; | ||
838 | - int error; | ||
839 | - int lread; | ||
840 | - int ofd; | ||
841 | - struct cab_folder *folder; | ||
842 | - struct cab_file *next; | ||
843 | - struct cab_archive *cab; | ||
844 | - uint16_t attribs; | ||
845 | - uint64_t max_size, written_size; | ||
846 | -}; | ||
847 | - | ||
848 | -struct cab_folder { | ||
849 | - struct cab_archive *cab; | ||
850 | - off_t offset; | ||
851 | - struct cab_folder *next; | ||
852 | - uint16_t cmethod; | ||
853 | - uint16_t nblocks; | ||
854 | -}; | ||
855 | - | ||
856 | -int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab); | ||
857 | -int cab_extract(struct cab_file *file, const char *name); | ||
858 | -void cab_free(struct cab_archive *cab); | ||
859 | - | ||
860 | -#endif | ||
861 | diff --git a/libclamav/chmunpack.h b/libclamav/chmunpack.h | ||
862 | deleted file mode 100644 | ||
863 | index 7864386b921f..000000000000 | ||
864 | --- a/libclamav/chmunpack.h | ||
865 | +++ /dev/null | ||
866 | @@ -1,122 +0,0 @@ | ||
867 | -/* | ||
868 | - * Extract component parts of MS CHM files | ||
869 | - * | ||
870 | - * Copyright (C) 2007-2008 Sourcefire, Inc. | ||
871 | - * | ||
872 | - * Authors: Trog | ||
873 | - * | ||
874 | - * This program is free software; you can redistribute it and/or modify | ||
875 | - * it under the terms of the GNU General Public License version 2 as | ||
876 | - * published by the Free Software Foundation. | ||
877 | - * | ||
878 | - * This program is distributed in the hope that it will be useful, | ||
879 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
880 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
881 | - * GNU General Public License for more details. | ||
882 | - * | ||
883 | - * You should have received a copy of the GNU General Public License | ||
884 | - * along with this program; if not, write to the Free Software | ||
885 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
886 | - * MA 02110-1301, USA. | ||
887 | - */ | ||
888 | - | ||
889 | -#ifndef __CHM_UNPACK_H | ||
890 | -#define __CHM_UNPACK_H | ||
891 | - | ||
892 | -#if HAVE_CONFIG_H | ||
893 | -#include "clamav-config.h" | ||
894 | -#endif | ||
895 | - | ||
896 | -#include "cltypes.h" | ||
897 | -#include "others.h" | ||
898 | -#include "fmap.h" | ||
899 | - | ||
900 | -#ifndef HAVE_ATTRIB_PACKED | ||
901 | -#define __attribute__(x) | ||
902 | -#endif | ||
903 | - | ||
904 | -#ifdef HAVE_PRAGMA_PACK | ||
905 | -#pragma pack(1) | ||
906 | -#endif | ||
907 | - | ||
908 | -#ifdef HAVE_PRAGMA_PACK_HPPA | ||
909 | -#pragma pack 1 | ||
910 | -#endif | ||
911 | - | ||
912 | -#define CHM_ITSF_MIN_LEN (0x60) | ||
913 | -typedef struct chm_itsf_header_tag | ||
914 | -{ | ||
915 | - unsigned char signature[4]; | ||
916 | - int32_t version __attribute__ ((packed)); | ||
917 | - int32_t header_len __attribute__ ((packed)); | ||
918 | - uint32_t unknown __attribute__ ((packed)); | ||
919 | - uint32_t last_modified __attribute__ ((packed)); | ||
920 | - uint32_t lang_id __attribute__ ((packed)); | ||
921 | - unsigned char dir_clsid[16]; | ||
922 | - unsigned char stream_clsid[16]; | ||
923 | - uint64_t sec0_offset __attribute__ ((packed)); | ||
924 | - uint64_t sec0_len __attribute__ ((packed)); | ||
925 | - uint64_t dir_offset __attribute__ ((packed)); | ||
926 | - uint64_t dir_len __attribute__ ((packed)); | ||
927 | - uint64_t data_offset __attribute__ ((packed)); | ||
928 | -} chm_itsf_header_t; | ||
929 | - | ||
930 | -#define CHM_ITSP_LEN (0x54) | ||
931 | -typedef struct chm_itsp_header_tag | ||
932 | -{ | ||
933 | - unsigned char signature[4]; | ||
934 | - int32_t version __attribute__ ((packed)); | ||
935 | - int32_t header_len __attribute__ ((packed)); | ||
936 | - int32_t unknown1 __attribute__ ((packed)); | ||
937 | - uint32_t block_len __attribute__ ((packed)); | ||
938 | - int32_t blockidx_intvl __attribute__ ((packed)); | ||
939 | - int32_t index_depth __attribute__ ((packed)); | ||
940 | - int32_t index_root __attribute__ ((packed)); | ||
941 | - int32_t index_head __attribute__ ((packed)); | ||
942 | - int32_t index_tail __attribute__ ((packed)); | ||
943 | - int32_t unknown2 __attribute__ ((packed)); | ||
944 | - uint32_t num_blocks __attribute__ ((packed)); | ||
945 | - uint32_t lang_id __attribute__ ((packed)); | ||
946 | - unsigned char system_clsid[16]; | ||
947 | - unsigned char unknown4[16]; | ||
948 | -} chm_itsp_header_t; | ||
949 | - | ||
950 | -#ifdef HAVE_PRAGMA_PACK | ||
951 | -#pragma pack() | ||
952 | -#endif | ||
953 | - | ||
954 | -#ifdef HAVE_PRAGMA_PACK_HPPA | ||
955 | -#pragma pack | ||
956 | -#endif | ||
957 | - | ||
958 | -typedef struct chm_sys_entry_tag | ||
959 | -{ | ||
960 | - uint64_t offset; | ||
961 | - uint64_t length; | ||
962 | -} chm_sys_entry_t; | ||
963 | - | ||
964 | -typedef struct chm_metadata_tag { | ||
965 | - uint64_t file_length; | ||
966 | - uint64_t file_offset; | ||
967 | - chm_sys_entry_t sys_control; | ||
968 | - chm_sys_entry_t sys_content; | ||
969 | - chm_sys_entry_t sys_reset; | ||
970 | - off_t m_length; | ||
971 | - chm_itsf_header_t itsf_hdr; | ||
972 | - chm_itsp_header_t itsp_hdr; | ||
973 | - int ufd; | ||
974 | - int ofd; | ||
975 | - uint32_t num_chunks; | ||
976 | - off_t chunk_offset; | ||
977 | - const char *chunk_data; | ||
978 | - const char *chunk_current; | ||
979 | - const char *chunk_end; | ||
980 | - fmap_t *map; | ||
981 | - uint16_t chunk_entries; | ||
982 | -} chm_metadata_t; | ||
983 | - | ||
984 | -int cli_chm_open(const char *dirname, chm_metadata_t *metadata, cli_ctx *ctx); | ||
985 | -int cli_chm_prepare_file(chm_metadata_t *metadata); | ||
986 | -int cli_chm_extract_file(char *dirname, chm_metadata_t *metadata, cli_ctx *ctx); | ||
987 | -void cli_chm_close(chm_metadata_t *metadata); | ||
988 | -#endif | ||
989 | diff --git a/libclamav/libmspack.c b/libclamav/libmspack.c | ||
990 | new file mode 100644 | ||
991 | index 000000000000..e94312e6dad3 | ||
992 | --- /dev/null | ||
993 | +++ b/libclamav/libmspack.c | ||
994 | @@ -0,0 +1,525 @@ | ||
995 | +/* | ||
996 | + * Glue code for libmspack handling. | ||
997 | + * Author: 웃 Sebastian Andrzej Siewior | ||
998 | + * ✉ sebastian @ breakpoint ̣cc | ||
999 | + */ | ||
1000 | + | ||
1001 | +#include <stdio.h> | ||
1002 | +#include <stdlib.h> | ||
1003 | +#include <sys/stat.h> | ||
1004 | +#include <fcntl.h> | ||
1005 | + | ||
1006 | +#include <mspack.h> | ||
1007 | + | ||
1008 | +#include "clamav.h" | ||
1009 | +#include "fmap.h" | ||
1010 | +#include "scanners.h" | ||
1011 | +#include "others.h" | ||
1012 | + | ||
1013 | +enum mspack_type { | ||
1014 | + FILETYPE_DUNNO, | ||
1015 | + FILETYPE_FMAP, | ||
1016 | + FILETYPE_FILENAME, | ||
1017 | +}; | ||
1018 | + | ||
1019 | +struct mspack_name { | ||
1020 | + fmap_t *fmap; | ||
1021 | + off_t org; | ||
1022 | +}; | ||
1023 | + | ||
1024 | +struct mspack_system_ex { | ||
1025 | + struct mspack_system ops; | ||
1026 | + off_t max_size; | ||
1027 | +}; | ||
1028 | + | ||
1029 | +struct mspack_handle { | ||
1030 | + enum mspack_type type; | ||
1031 | + | ||
1032 | + fmap_t *fmap; | ||
1033 | + off_t org; | ||
1034 | + off_t offset; | ||
1035 | + | ||
1036 | + FILE *f; | ||
1037 | + off_t max_size; | ||
1038 | +}; | ||
1039 | + | ||
1040 | +#define container_of(ptr, type, member) ({ \ | ||
1041 | + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
1042 | + (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
1043 | + | ||
1044 | +#define min_t(type, x, y) ({ \ | ||
1045 | + type __min1 = (x); \ | ||
1046 | + type __min2 = (y); \ | ||
1047 | + __min1 < __min2 ? __min1: __min2; }) | ||
1048 | + | ||
1049 | +static struct mspack_file *mspack_fmap_open(struct mspack_system *self, | ||
1050 | + const char *filename, int mode) | ||
1051 | +{ | ||
1052 | + struct mspack_name *mspack_name; | ||
1053 | + struct mspack_handle *mspack_handle; | ||
1054 | + struct mspack_system_ex *self_ex; | ||
1055 | + const char *fmode; | ||
1056 | + | ||
1057 | + if (!filename) { | ||
1058 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1059 | + return NULL; | ||
1060 | + } | ||
1061 | + mspack_handle = malloc(sizeof(*mspack_handle)); | ||
1062 | + if (!mspack_handle) { | ||
1063 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1064 | + return NULL; | ||
1065 | + } | ||
1066 | + switch (mode) { | ||
1067 | + case MSPACK_SYS_OPEN_READ: | ||
1068 | + mspack_handle->type = FILETYPE_FMAP; | ||
1069 | + | ||
1070 | + mspack_name = (struct mspack_name *)filename; | ||
1071 | + mspack_handle->fmap = mspack_name->fmap; | ||
1072 | + mspack_handle->org = mspack_name->org; | ||
1073 | + mspack_handle->offset = 0; | ||
1074 | + | ||
1075 | + return (struct mspack_file *)mspack_handle; | ||
1076 | + | ||
1077 | + case MSPACK_SYS_OPEN_WRITE: | ||
1078 | + fmode = "wb"; | ||
1079 | + break; | ||
1080 | + case MSPACK_SYS_OPEN_UPDATE: | ||
1081 | + fmode = "r+b"; | ||
1082 | + break; | ||
1083 | + case MSPACK_SYS_OPEN_APPEND: | ||
1084 | + fmode = "ab"; | ||
1085 | + break; | ||
1086 | + default: | ||
1087 | + cli_dbgmsg("%s() wrong mode\n", __func__); | ||
1088 | + goto out_err; | ||
1089 | + } | ||
1090 | + | ||
1091 | + mspack_handle->type = FILETYPE_FILENAME; | ||
1092 | + | ||
1093 | + mspack_handle->f = fopen(filename, fmode); | ||
1094 | + if (!mspack_handle->f) { | ||
1095 | + cli_dbgmsg("%s() failed %d\n", __func__, __LINE__); | ||
1096 | + goto out_err; | ||
1097 | + } | ||
1098 | + self_ex = container_of(self, struct mspack_system_ex, ops); | ||
1099 | + mspack_handle->max_size = self_ex->max_size; | ||
1100 | + return (struct mspack_file *)mspack_handle; | ||
1101 | + | ||
1102 | +out_err: | ||
1103 | + free(mspack_handle); | ||
1104 | + return NULL; | ||
1105 | +} | ||
1106 | + | ||
1107 | +static void mspack_fmap_close(struct mspack_file *file) | ||
1108 | +{ | ||
1109 | + struct mspack_handle *mspack_handle = (struct mspack_handle *)file; | ||
1110 | + | ||
1111 | + if (!mspack_handle) | ||
1112 | + return; | ||
1113 | + | ||
1114 | + if (mspack_handle->type == FILETYPE_FILENAME) | ||
1115 | + fclose(mspack_handle->f); | ||
1116 | + free(mspack_handle); | ||
1117 | +} | ||
1118 | + | ||
1119 | +static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes) | ||
1120 | +{ | ||
1121 | + struct mspack_handle *mspack_handle = (struct mspack_handle *)file; | ||
1122 | + off_t offset; | ||
1123 | + size_t count; | ||
1124 | + int ret; | ||
1125 | + | ||
1126 | + if (bytes < 0) { | ||
1127 | + cli_dbgmsg("%s() %d\n", __func__, __LINE__); | ||
1128 | + return -1; | ||
1129 | + } | ||
1130 | + if (!mspack_handle) { | ||
1131 | + cli_dbgmsg("%s() %d\n", __func__, __LINE__); | ||
1132 | + return -1; | ||
1133 | + } | ||
1134 | + | ||
1135 | + if (mspack_handle->type == FILETYPE_FMAP) { | ||
1136 | + offset = mspack_handle->offset + mspack_handle->org; | ||
1137 | + | ||
1138 | + ret = fmap_readn(mspack_handle->fmap, buffer, offset, bytes); | ||
1139 | + if (ret != bytes) { | ||
1140 | + cli_dbgmsg("%s() %d %d, %d\n", __func__, __LINE__, bytes, ret); | ||
1141 | + return ret; | ||
1142 | + } | ||
1143 | + | ||
1144 | + mspack_handle->offset += bytes; | ||
1145 | + return bytes; | ||
1146 | + } | ||
1147 | + count = fread(buffer, bytes, 1, mspack_handle->f); | ||
1148 | + if (count < 1) { | ||
1149 | + cli_dbgmsg("%s() %d %d, %zd\n", __func__, __LINE__, bytes, count); | ||
1150 | + return -1; | ||
1151 | + } | ||
1152 | + return bytes; | ||
1153 | +} | ||
1154 | + | ||
1155 | +static int mspack_fmap_write(struct mspack_file *file, void *buffer, int bytes) | ||
1156 | +{ | ||
1157 | + struct mspack_handle *mspack_handle = (struct mspack_handle *)file; | ||
1158 | + size_t count; | ||
1159 | + off_t max_size; | ||
1160 | + | ||
1161 | + if (bytes < 0 || !mspack_handle) { | ||
1162 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1163 | + return -1; | ||
1164 | + } | ||
1165 | + | ||
1166 | + if (mspack_handle->type == FILETYPE_FMAP) { | ||
1167 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1168 | + return -1; | ||
1169 | + } | ||
1170 | + | ||
1171 | + if (!bytes) | ||
1172 | + return 0; | ||
1173 | + | ||
1174 | + max_size = mspack_handle->max_size; | ||
1175 | + if (!max_size) | ||
1176 | + return bytes; | ||
1177 | + | ||
1178 | + max_size = min_t(off_t, max_size, bytes); | ||
1179 | + mspack_handle->max_size -= max_size; | ||
1180 | + | ||
1181 | + count = fwrite(buffer, max_size, 1, mspack_handle->f); | ||
1182 | + if (count < 1) { | ||
1183 | + cli_dbgmsg("%s() err %m <%zd %d>\n", __func__, count, bytes); | ||
1184 | + return -1; | ||
1185 | + } | ||
1186 | + | ||
1187 | + return bytes; | ||
1188 | +} | ||
1189 | + | ||
1190 | +static int mspack_fmap_seek(struct mspack_file *file, off_t offset, int mode) | ||
1191 | +{ | ||
1192 | + struct mspack_handle *mspack_handle = (struct mspack_handle *)file; | ||
1193 | + | ||
1194 | + if (!mspack_handle) { | ||
1195 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1196 | + return -1; | ||
1197 | + } | ||
1198 | + | ||
1199 | + if (mspack_handle->type == FILETYPE_FMAP) { | ||
1200 | + off_t new_pos; | ||
1201 | + | ||
1202 | + switch (mode) { | ||
1203 | + case MSPACK_SYS_SEEK_START: | ||
1204 | + new_pos = offset; | ||
1205 | + break; | ||
1206 | + case MSPACK_SYS_SEEK_CUR: | ||
1207 | + new_pos = mspack_handle->offset + offset; | ||
1208 | + break; | ||
1209 | + case MSPACK_SYS_SEEK_END: | ||
1210 | + new_pos = mspack_handle->fmap->len + offset; | ||
1211 | + break; | ||
1212 | + default: | ||
1213 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1214 | + return -1; | ||
1215 | + } | ||
1216 | + if (new_pos < 0 || new_pos > mspack_handle->fmap->len) { | ||
1217 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1218 | + return -1; | ||
1219 | + } | ||
1220 | + | ||
1221 | + mspack_handle->offset = new_pos; | ||
1222 | + return 0; | ||
1223 | + } | ||
1224 | + | ||
1225 | + switch (mode) { | ||
1226 | + case MSPACK_SYS_SEEK_START: | ||
1227 | + mode = SEEK_SET; | ||
1228 | + break; | ||
1229 | + case MSPACK_SYS_SEEK_CUR: | ||
1230 | + mode = SEEK_CUR; | ||
1231 | + break; | ||
1232 | + case MSPACK_SYS_SEEK_END: | ||
1233 | + mode = SEEK_END; | ||
1234 | + break; | ||
1235 | + default: | ||
1236 | + cli_dbgmsg("%s() err %d\n", __func__, __LINE__); | ||
1237 | + return -1; | ||
1238 | + } | ||
1239 | + | ||
1240 | + return fseeko(mspack_handle->f, offset, mode); | ||
1241 | +} | ||
1242 | + | ||
1243 | +static off_t mspack_fmap_tell(struct mspack_file *file) | ||
1244 | +{ | ||
1245 | + struct mspack_handle *mspack_handle = (struct mspack_handle *)file; | ||
1246 | + | ||
1247 | + if (!mspack_handle) | ||
1248 | + return -1; | ||
1249 | + | ||
1250 | + if (mspack_handle->type == FILETYPE_FMAP) | ||
1251 | + return mspack_handle->offset; | ||
1252 | + | ||
1253 | + return ftello(mspack_handle->f); | ||
1254 | +} | ||
1255 | + | ||
1256 | +static void mspack_fmap_message(struct mspack_file *file, const char *fmt, ...) | ||
1257 | +{ | ||
1258 | + cli_dbgmsg("%s() %s\n", __func__, fmt); | ||
1259 | +} | ||
1260 | +static void *mspack_fmap_alloc(struct mspack_system *self, size_t num) | ||
1261 | +{ | ||
1262 | + return malloc(num); | ||
1263 | +} | ||
1264 | + | ||
1265 | +static void mspack_fmap_free(void *mem) | ||
1266 | +{ | ||
1267 | + free(mem); | ||
1268 | +} | ||
1269 | + | ||
1270 | +static void mspack_fmap_copy(void *src, void *dst, size_t num) | ||
1271 | +{ | ||
1272 | + memcpy(dst, src, num); | ||
1273 | +} | ||
1274 | + | ||
1275 | +static struct mspack_system mspack_sys_fmap_ops = { | ||
1276 | + .open = mspack_fmap_open, | ||
1277 | + .close = mspack_fmap_close, | ||
1278 | + .read = mspack_fmap_read, | ||
1279 | + .write = mspack_fmap_write, | ||
1280 | + .seek = mspack_fmap_seek, | ||
1281 | + .tell = mspack_fmap_tell, | ||
1282 | + .message = mspack_fmap_message, | ||
1283 | + .alloc = mspack_fmap_alloc, | ||
1284 | + .free = mspack_fmap_free, | ||
1285 | + .copy = mspack_fmap_copy, | ||
1286 | +}; | ||
1287 | + | ||
1288 | +static int cli_scanfile(const char *filename, cli_ctx *ctx) | ||
1289 | +{ | ||
1290 | + int fd, ret; | ||
1291 | + | ||
1292 | + /* internal version of cl_scanfile with arec/mrec preserved */ | ||
1293 | + fd = safe_open(filename, O_RDONLY|O_BINARY); | ||
1294 | + if (fd < 0) | ||
1295 | + return CL_EOPEN; | ||
1296 | + | ||
1297 | + ret = cli_magic_scandesc(fd, ctx); | ||
1298 | + | ||
1299 | + close(fd); | ||
1300 | + return ret; | ||
1301 | +} | ||
1302 | + | ||
1303 | +int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset) | ||
1304 | +{ | ||
1305 | + struct mscab_decompressor *cab_d; | ||
1306 | + struct mscabd_cabinet *cab_h; | ||
1307 | + struct mscabd_file *cab_f; | ||
1308 | + int ret; | ||
1309 | + int files; | ||
1310 | + int virus_num = 0; | ||
1311 | + struct mspack_name mspack_fmap = { | ||
1312 | + .fmap = *ctx->fmap, | ||
1313 | + .org = sfx_offset, | ||
1314 | + }; | ||
1315 | + struct mspack_system_ex ops_ex = { | ||
1316 | + .ops = mspack_sys_fmap_ops, | ||
1317 | + }; | ||
1318 | + | ||
1319 | + MSPACK_SYS_SELFTEST(ret); | ||
1320 | + if (ret) { | ||
1321 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1322 | + return CL_EUNPACK; | ||
1323 | + } | ||
1324 | + | ||
1325 | + cab_d = mspack_create_cab_decompressor(&ops_ex.ops); | ||
1326 | + if (!cab_d) { | ||
1327 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1328 | + return CL_EUNPACK; | ||
1329 | + } | ||
1330 | + | ||
1331 | + cab_h = cab_d->open(cab_d, (char *)&mspack_fmap); | ||
1332 | + if (!cab_h) { | ||
1333 | + ret = CL_EFORMAT; | ||
1334 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1335 | + goto out_dest; | ||
1336 | + } | ||
1337 | + files = 0; | ||
1338 | + for (cab_f = cab_h->files; cab_f; cab_f = cab_f->next) { | ||
1339 | + off_t max_size; | ||
1340 | + char *tmp_fname; | ||
1341 | + | ||
1342 | + ret = cli_matchmeta(ctx, cab_f->filename, 0, cab_f->length, 0, | ||
1343 | + files, 0, NULL); | ||
1344 | + if (ret) { | ||
1345 | + if (ret == CL_VIRUS) { | ||
1346 | + virus_num++; | ||
1347 | + if (!SCAN_ALL) | ||
1348 | + break; | ||
1349 | + } | ||
1350 | + goto out_close; | ||
1351 | + } | ||
1352 | + | ||
1353 | + if (ctx->engine->maxscansize) { | ||
1354 | + if (ctx->scansize >= ctx->engine->maxscansize) { | ||
1355 | + ret = CL_CLEAN; | ||
1356 | + break; | ||
1357 | + } | ||
1358 | + } | ||
1359 | + | ||
1360 | + if (ctx->engine->maxscansize && | ||
1361 | + ctx->scansize + ctx->engine->maxfilesize >= | ||
1362 | + ctx->engine->maxscansize) | ||
1363 | + max_size = ctx->engine->maxscansize - | ||
1364 | + ctx->scansize; | ||
1365 | + else | ||
1366 | + max_size = ctx->engine->maxfilesize ? | ||
1367 | + ctx->engine->maxfilesize : | ||
1368 | + 0xffffffff; | ||
1369 | + | ||
1370 | + tmp_fname = cli_gentemp(ctx->engine->tmpdir); | ||
1371 | + if (!tmp_fname) { | ||
1372 | + ret = CL_EMEM; | ||
1373 | + break; | ||
1374 | + } | ||
1375 | + | ||
1376 | + ops_ex.max_size = max_size; | ||
1377 | + /* scan */ | ||
1378 | + ret = cab_d->extract(cab_d, cab_f, tmp_fname); | ||
1379 | + if (ret) { | ||
1380 | + /* Failed to extract */ | ||
1381 | + cli_dbgmsg("%s() failed to extract %d\n", __func__, ret); | ||
1382 | + } else { | ||
1383 | + ret = cli_scanfile(tmp_fname, ctx); | ||
1384 | + if (ret == CL_VIRUS) | ||
1385 | + virus_num++; | ||
1386 | + } | ||
1387 | + if (!ctx->engine->keeptmp) { | ||
1388 | + if (!access(tmp_fname, R_OK) && cli_unlink(tmp_fname)) { | ||
1389 | + free(tmp_fname); | ||
1390 | + ret = CL_EUNLINK; | ||
1391 | + break; | ||
1392 | + } | ||
1393 | + } | ||
1394 | + free(tmp_fname); | ||
1395 | + files++; | ||
1396 | + if (ret == CL_VIRUS && SCAN_ALL) | ||
1397 | + continue; | ||
1398 | + if (ret) | ||
1399 | + break; | ||
1400 | + } | ||
1401 | + | ||
1402 | +out_close: | ||
1403 | + cab_d->close(cab_d, cab_h); | ||
1404 | +out_dest: | ||
1405 | + mspack_destroy_cab_decompressor(cab_d); | ||
1406 | + if (virus_num) | ||
1407 | + return CL_VIRUS; | ||
1408 | + return ret; | ||
1409 | +} | ||
1410 | + | ||
1411 | +int cli_scanmschm(cli_ctx *ctx) | ||
1412 | +{ | ||
1413 | + struct mschm_decompressor *mschm_d; | ||
1414 | + struct mschmd_header *mschm_h; | ||
1415 | + struct mschmd_file *mschm_f; | ||
1416 | + int ret; | ||
1417 | + int files; | ||
1418 | + int virus_num = 0; | ||
1419 | + struct mspack_name mspack_fmap = { | ||
1420 | + .fmap = *ctx->fmap, | ||
1421 | + }; | ||
1422 | + struct mspack_system_ex ops_ex = { | ||
1423 | + .ops = mspack_sys_fmap_ops, | ||
1424 | + }; | ||
1425 | + | ||
1426 | + MSPACK_SYS_SELFTEST(ret); | ||
1427 | + if (ret) { | ||
1428 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1429 | + return CL_EUNPACK; | ||
1430 | + } | ||
1431 | + | ||
1432 | + mschm_d = mspack_create_chm_decompressor(&ops_ex.ops); | ||
1433 | + if (!mschm_d) { | ||
1434 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1435 | + return CL_EUNPACK; | ||
1436 | + } | ||
1437 | + | ||
1438 | + mschm_h = mschm_d->open(mschm_d, (char *)&mspack_fmap); | ||
1439 | + if (!mschm_h) { | ||
1440 | + ret = CL_EFORMAT; | ||
1441 | + cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__); | ||
1442 | + goto out_dest; | ||
1443 | + } | ||
1444 | + files = 0; | ||
1445 | + for (mschm_f = mschm_h->files; mschm_f; mschm_f = mschm_f->next) { | ||
1446 | + off_t max_size; | ||
1447 | + char *tmp_fname; | ||
1448 | + | ||
1449 | + ret = cli_matchmeta(ctx, mschm_f->filename, 0, mschm_f->length, | ||
1450 | + 0, files, 0, NULL); | ||
1451 | + if (ret) { | ||
1452 | + if (ret == CL_VIRUS) { | ||
1453 | + virus_num++; | ||
1454 | + if (!SCAN_ALL) | ||
1455 | + break; | ||
1456 | + } | ||
1457 | + goto out_close; | ||
1458 | + } | ||
1459 | + | ||
1460 | + if (ctx->engine->maxscansize) { | ||
1461 | + if (ctx->scansize >= ctx->engine->maxscansize) { | ||
1462 | + ret = CL_CLEAN; | ||
1463 | + break; | ||
1464 | + } | ||
1465 | + } | ||
1466 | + | ||
1467 | + if (ctx->engine->maxscansize && | ||
1468 | + ctx->scansize + ctx->engine->maxfilesize >= | ||
1469 | + ctx->engine->maxscansize) | ||
1470 | + max_size = ctx->engine->maxscansize - | ||
1471 | + ctx->scansize; | ||
1472 | + else | ||
1473 | + max_size = ctx->engine->maxfilesize ? | ||
1474 | + ctx->engine->maxfilesize : | ||
1475 | + 0xffffffff; | ||
1476 | + | ||
1477 | + ops_ex.max_size = max_size; | ||
1478 | + | ||
1479 | + tmp_fname = cli_gentemp(ctx->engine->tmpdir); | ||
1480 | + if (!tmp_fname) { | ||
1481 | + ret = CL_EMEM; | ||
1482 | + break; | ||
1483 | + } | ||
1484 | + | ||
1485 | + /* scan */ | ||
1486 | + ret = mschm_d->extract(mschm_d, mschm_f, tmp_fname); | ||
1487 | + if (ret) { | ||
1488 | + /* Failed to extract */ | ||
1489 | + cli_dbgmsg("%s() failed to extract %d\n", __func__, ret); | ||
1490 | + } else { | ||
1491 | + ret = cli_scanfile(tmp_fname, ctx); | ||
1492 | + if (ret == CL_VIRUS) | ||
1493 | + virus_num++; | ||
1494 | + } | ||
1495 | + if (!ctx->engine->keeptmp) { | ||
1496 | + if (!access(tmp_fname, R_OK) && cli_unlink(tmp_fname)) { | ||
1497 | + free(tmp_fname); | ||
1498 | + ret = CL_EUNLINK; | ||
1499 | + break; | ||
1500 | + } | ||
1501 | + } | ||
1502 | + free(tmp_fname); | ||
1503 | + files++; | ||
1504 | + if (ret == CL_VIRUS && SCAN_ALL) | ||
1505 | + continue; | ||
1506 | + if (ret) | ||
1507 | + break; | ||
1508 | + } | ||
1509 | + | ||
1510 | +out_close: | ||
1511 | + mschm_d->close(mschm_d, mschm_h); | ||
1512 | +out_dest: | ||
1513 | + mspack_destroy_chm_decompressor(mschm_d); | ||
1514 | + if (virus_num) | ||
1515 | + return CL_VIRUS; | ||
1516 | + return ret; | ||
1517 | + | ||
1518 | + return 0; | ||
1519 | +} | ||
1520 | diff --git a/libclamav/libmspack.h b/libclamav/libmspack.h | ||
1521 | new file mode 100644 | ||
1522 | index 000000000000..07a9442bf253 | ||
1523 | --- /dev/null | ||
1524 | +++ b/libclamav/libmspack.h | ||
1525 | @@ -0,0 +1,7 @@ | ||
1526 | +#ifndef __LIBMSPACK_H__ | ||
1527 | +#define __LIBMSPACK_H__ | ||
1528 | + | ||
1529 | +int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset); | ||
1530 | +int cli_scanmschm(cli_ctx *ctx); | ||
1531 | + | ||
1532 | +#endif | ||
1533 | diff --git a/libclamav/mspack.c b/libclamav/mspack.c | ||
1534 | deleted file mode 100644 | ||
1535 | index cc4c0a59fc9a..000000000000 | ||
1536 | --- a/libclamav/mspack.c | ||
1537 | +++ /dev/null | ||
1538 | @@ -1,2026 +0,0 @@ | ||
1539 | -/* | ||
1540 | - * This file includes code from libmspack adapted for libclamav by | ||
1541 | - * tkojm@clamav.net and draynor@sourcefire.com | ||
1542 | - * | ||
1543 | - * Copyright (C) 2003-2004 Stuart Caie | ||
1544 | - * | ||
1545 | - * This library is free software; you can redistribute it and/or | ||
1546 | - * modify it under the terms of the GNU Lesser General Public | ||
1547 | - * License version 2.1 as published by the Free Software Foundation. | ||
1548 | - * | ||
1549 | - * This library is distributed in the hope that it will be useful, | ||
1550 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1551 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1552 | - * Lesser General Public License for more details. | ||
1553 | - * | ||
1554 | - * You should have received a copy of the GNU Lesser General Public | ||
1555 | - * License along with this library; if not, write to the Free Software | ||
1556 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | ||
1557 | - * USA | ||
1558 | - */ | ||
1559 | - | ||
1560 | -#if HAVE_CONFIG_H | ||
1561 | -#include "clamav-config.h" | ||
1562 | -#endif | ||
1563 | - | ||
1564 | -#include <stdio.h> | ||
1565 | -#include <string.h> | ||
1566 | - | ||
1567 | -#include "others.h" | ||
1568 | -#include "clamav.h" | ||
1569 | -#include "mspack.h" | ||
1570 | - | ||
1571 | -#if HAVE_LIMITS_H | ||
1572 | -# include <limits.h> | ||
1573 | -#endif | ||
1574 | -#ifndef CHAR_BIT | ||
1575 | -# define CHAR_BIT (8) | ||
1576 | -#endif | ||
1577 | - | ||
1578 | - | ||
1579 | -/*************************************************************************** | ||
1580 | - * MS-ZIP decompression implementation | ||
1581 | - *************************************************************************** | ||
1582 | - * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted | ||
1583 | - * by Microsoft Corporation. | ||
1584 | - * | ||
1585 | - * The deflate method was created by Phil Katz. MSZIP is equivalent to the | ||
1586 | - * deflate method. | ||
1587 | - * | ||
1588 | - */ | ||
1589 | - | ||
1590 | -/* match lengths for literal codes 257.. 285 */ | ||
1591 | -static const unsigned short mszip_lit_lengths[29] = { | ||
1592 | - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, | ||
1593 | - 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 | ||
1594 | -}; | ||
1595 | - | ||
1596 | -/* match offsets for distance codes 0 .. 29 */ | ||
1597 | -static const unsigned short mszip_dist_offsets[30] = { | ||
1598 | - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, | ||
1599 | - 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 | ||
1600 | -}; | ||
1601 | - | ||
1602 | -/* extra bits required for literal codes 257.. 285 */ | ||
1603 | -static const unsigned char mszip_lit_extrabits[29] = { | ||
1604 | - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, | ||
1605 | - 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 | ||
1606 | -}; | ||
1607 | - | ||
1608 | -/* extra bits required for distance codes 0 .. 29 */ | ||
1609 | -static const unsigned char mszip_dist_extrabits[30] = { | ||
1610 | - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, | ||
1611 | - 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 | ||
1612 | -}; | ||
1613 | - | ||
1614 | -/* the order of the bit length Huffman code lengths */ | ||
1615 | -static const unsigned char mszip_bitlen_order[19] = { | ||
1616 | - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 | ||
1617 | -}; | ||
1618 | - | ||
1619 | -/* ANDing with mszip_bit_mask[n] masks the lower n bits */ | ||
1620 | -static const unsigned short mszip_bit_mask_tab[17] = { | ||
1621 | - 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, | ||
1622 | - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | ||
1623 | -}; | ||
1624 | - | ||
1625 | -#define MSZIP_STORE_BITS do { \ | ||
1626 | - zip->i_ptr = i_ptr; \ | ||
1627 | - zip->i_end = i_end; \ | ||
1628 | - zip->bit_buffer = bit_buffer; \ | ||
1629 | - zip->bits_left = bits_left; \ | ||
1630 | -} while (0) | ||
1631 | - | ||
1632 | -#define MSZIP_RESTORE_BITS do { \ | ||
1633 | - i_ptr = zip->i_ptr; \ | ||
1634 | - i_end = zip->i_end; \ | ||
1635 | - bit_buffer = zip->bit_buffer; \ | ||
1636 | - bits_left = zip->bits_left; \ | ||
1637 | -} while (0) | ||
1638 | - | ||
1639 | -#define MSZIP_ENSURE_BITS(nbits) do { \ | ||
1640 | - while (bits_left < (nbits)) { \ | ||
1641 | - if (i_ptr >= i_end) { \ | ||
1642 | - if (mszip_read_input(zip)) return zip->error; \ | ||
1643 | - i_ptr = zip->i_ptr; \ | ||
1644 | - i_end = zip->i_end; \ | ||
1645 | - if(i_ptr == i_end) break; \ | ||
1646 | - } \ | ||
1647 | - bit_buffer |= *i_ptr++ << bits_left; bits_left += 8; \ | ||
1648 | - } \ | ||
1649 | -} while (0) | ||
1650 | - | ||
1651 | -#define MSZIP_PEEK_BITS(nbits) (bit_buffer & ((1<<(nbits))-1)) | ||
1652 | -#define MSZIP_PEEK_BITS_T(nbits) (bit_buffer & mszip_bit_mask_tab[(nbits)]) | ||
1653 | - | ||
1654 | -#define MSZIP_REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits))) | ||
1655 | - | ||
1656 | -#define MSZIP_READ_BITS(val, nbits) do { \ | ||
1657 | - MSZIP_ENSURE_BITS(nbits); (val) = MSZIP_PEEK_BITS(nbits); MSZIP_REMOVE_BITS(nbits); \ | ||
1658 | -} while (0) | ||
1659 | - | ||
1660 | -#define MSZIP_READ_BITS_T(val, nbits) do { \ | ||
1661 | - MSZIP_ENSURE_BITS(nbits); (val) = MSZIP_PEEK_BITS_T(nbits); MSZIP_REMOVE_BITS(nbits); \ | ||
1662 | -} while (0) | ||
1663 | - | ||
1664 | -static int mszip_read_input(struct mszip_stream *zip) { | ||
1665 | - int nread = zip->read_cb(zip->file, zip->inbuf, (int)zip->inbuf_size); | ||
1666 | - if (nread < 0) { | ||
1667 | - if (zip->file->error == CL_BREAK) { | ||
1668 | - if ((unsigned int)nread == zip->last) { | ||
1669 | - cli_dbgmsg("mszip_read_input: Two consecutive CL_BREAKs reached.\n"); | ||
1670 | - return CL_BREAK; | ||
1671 | - } | ||
1672 | - // Need short circuit to ensure scanning small files | ||
1673 | - cli_dbgmsg("mszip_read_input: First CL_BREAK reached.\n"); | ||
1674 | - zip->i_ptr = zip->i_end; | ||
1675 | - zip->last = nread; | ||
1676 | - return CL_SUCCESS; | ||
1677 | - } | ||
1678 | - else | ||
1679 | - return zip->error = CL_EFORMAT; | ||
1680 | - } | ||
1681 | - | ||
1682 | - zip->last = nread; | ||
1683 | - zip->i_ptr = &zip->inbuf[0]; | ||
1684 | - zip->i_end = &zip->inbuf[nread]; | ||
1685 | - | ||
1686 | - return CL_SUCCESS; | ||
1687 | -} | ||
1688 | - | ||
1689 | -/* inflate() error codes */ | ||
1690 | -#define INF_ERR_BLOCKTYPE (-1) /* unknown block type */ | ||
1691 | -#define INF_ERR_COMPLEMENT (-2) /* block size complement mismatch */ | ||
1692 | -#define INF_ERR_FLUSH (-3) /* error from flush_window() callback */ | ||
1693 | -#define INF_ERR_BITBUF (-4) /* too many bits in bit buffer */ | ||
1694 | -#define INF_ERR_SYMLENS (-5) /* too many symbols in blocktype 2 header */ | ||
1695 | -#define INF_ERR_BITLENTBL (-6) /* failed to build bitlens huffman table */ | ||
1696 | -#define INF_ERR_LITERALTBL (-7) /* failed to build literals huffman table */ | ||
1697 | -#define INF_ERR_DISTANCETBL (-8) /* failed to build distance huffman table */ | ||
1698 | -#define INF_ERR_BITOVERRUN (-9) /* bitlen RLE code goes over table size */ | ||
1699 | -#define INF_ERR_BADBITLEN (-10) /* invalid bit-length code */ | ||
1700 | -#define INF_ERR_LITCODE (-11) /* out-of-range literal code */ | ||
1701 | -#define INF_ERR_DISTCODE (-12) /* out-of-range distance code */ | ||
1702 | -#define INF_ERR_DISTANCE (-13) /* somehow, distance is beyond 32k */ | ||
1703 | -#define INF_ERR_HUFFSYM (-14) /* out of bits decoding huffman symbol */ | ||
1704 | - | ||
1705 | -/* mszip_make_decode_table(nsyms, nbits, length[], table[]) | ||
1706 | - * | ||
1707 | - * This function was coded by David Tritscher. It builds a fast huffman | ||
1708 | - * decoding table out of just a canonical huffman code lengths table. | ||
1709 | - * | ||
1710 | - * NOTE: this is NOT identical to the mszip_make_decode_table() in lzxd.c. This | ||
1711 | - * one reverses the quick-lookup bit pattern. Bits are read MSB to LSB in LZX, | ||
1712 | - * but LSB to MSB in MSZIP. | ||
1713 | - * | ||
1714 | - * nsyms = total number of symbols in this huffman tree. | ||
1715 | - * nbits = any symbols with a code length of nbits or less can be decoded | ||
1716 | - * in one lookup of the table. | ||
1717 | - * length = A table to get code lengths from [0 to nsyms-1] | ||
1718 | - * table = The table to fill up with decoded symbols and pointers. | ||
1719 | - * | ||
1720 | - * Returns 0 for OK or 1 for error | ||
1721 | - */ | ||
1722 | -static int mszip_make_decode_table(unsigned int nsyms, unsigned int nbits, | ||
1723 | - unsigned char *length, unsigned short *table) | ||
1724 | -{ | ||
1725 | - register unsigned int leaf, reverse, fill; | ||
1726 | - register unsigned short sym, next_sym; | ||
1727 | - register unsigned char bit_num; | ||
1728 | - unsigned int pos = 0; /* the current position in the decode table */ | ||
1729 | - unsigned int table_mask = 1 << nbits; | ||
1730 | - unsigned int mszip_bit_mask = table_mask >> 1; /* don't do 0 length codes */ | ||
1731 | - | ||
1732 | - /* fill entries for codes short enough for a direct mapping */ | ||
1733 | - for (bit_num = 1; bit_num <= nbits; bit_num++) { | ||
1734 | - for (sym = 0; sym < nsyms; sym++) { | ||
1735 | - if (length[sym] != bit_num) continue; | ||
1736 | - | ||
1737 | - /* reverse the significant bits */ | ||
1738 | - fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0; | ||
1739 | - do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill); | ||
1740 | - | ||
1741 | - if((pos += mszip_bit_mask) > table_mask) return 1; /* table overrun */ | ||
1742 | - | ||
1743 | - /* fill all possible lookups of this symbol with the symbol itself */ | ||
1744 | - fill = mszip_bit_mask; next_sym = 1 << bit_num; | ||
1745 | - do { table[leaf] = sym; leaf += next_sym; } while (--fill); | ||
1746 | - } | ||
1747 | - mszip_bit_mask >>= 1; | ||
1748 | - } | ||
1749 | - | ||
1750 | - /* exit with success if table is now complete */ | ||
1751 | - if (pos == table_mask) return 0; | ||
1752 | - | ||
1753 | - /* mark all remaining table entries as unused */ | ||
1754 | - for (sym = pos; sym < table_mask; sym++) { | ||
1755 | - reverse = sym; leaf = 0; fill = nbits; | ||
1756 | - do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill); | ||
1757 | - table[leaf] = 0xFFFF; | ||
1758 | - } | ||
1759 | - | ||
1760 | - /* where should the longer codes be allocated from? */ | ||
1761 | - next_sym = ((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1); | ||
1762 | - | ||
1763 | - /* give ourselves room for codes to grow by up to 16 more bits. | ||
1764 | - * codes now start at bit nbits+16 and end at (nbits+16-codelength) */ | ||
1765 | - pos <<= 16; | ||
1766 | - table_mask <<= 16; | ||
1767 | - mszip_bit_mask = 1 << 15; | ||
1768 | - | ||
1769 | - for (bit_num = nbits+1; bit_num <= MSZIP_MAX_HUFFBITS; bit_num++) { | ||
1770 | - for (sym = 0; sym < nsyms; sym++) { | ||
1771 | - if (length[sym] != bit_num) continue; | ||
1772 | - | ||
1773 | - /* leaf = the first nbits of the code, reversed */ | ||
1774 | - reverse = pos >> 16; leaf = 0; fill = nbits; | ||
1775 | - do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill); | ||
1776 | - | ||
1777 | - for (fill = 0; fill < (bit_num - nbits); fill++) { | ||
1778 | - /* if this path hasn't been taken yet, 'allocate' two entries */ | ||
1779 | - if (table[leaf] == 0xFFFF) { | ||
1780 | - table[(next_sym << 1) ] = 0xFFFF; | ||
1781 | - table[(next_sym << 1) + 1 ] = 0xFFFF; | ||
1782 | - table[leaf] = next_sym++; | ||
1783 | - } | ||
1784 | - /* follow the path and select either left or right for next bit */ | ||
1785 | - leaf = (table[leaf] << 1) | ((pos >> (15 - fill)) & 1); | ||
1786 | - } | ||
1787 | - table[leaf] = sym; | ||
1788 | - | ||
1789 | - if ((pos += mszip_bit_mask) > table_mask) return 1; /* table overflow */ | ||
1790 | - } | ||
1791 | - mszip_bit_mask >>= 1; | ||
1792 | - } | ||
1793 | - | ||
1794 | - /* full table? */ | ||
1795 | - return (pos != table_mask) ? 1 : 0; | ||
1796 | -} | ||
1797 | - | ||
1798 | -/* MSZIP_READ_HUFFSYM(tablename, var) decodes one huffman symbol from the | ||
1799 | - * bitstream using the stated table and puts it in var. | ||
1800 | - */ | ||
1801 | -#define MSZIP_READ_HUFFSYM(tbl, var) do { \ | ||
1802 | - /* huffman symbols can be up to 16 bits long */ \ | ||
1803 | - MSZIP_ENSURE_BITS(MSZIP_MAX_HUFFBITS); \ | ||
1804 | - /* immediate table lookup of [tablebits] bits of the code */ \ | ||
1805 | - sym = zip->tbl##_table[MSZIP_PEEK_BITS(MSZIP_##tbl##_TABLEBITS)]; \ | ||
1806 | - /* is the symbol is longer than [tablebits] bits? (i=node index) */ \ | ||
1807 | - if (sym >= MSZIP_##tbl##_MAXSYMBOLS) { \ | ||
1808 | - /* decode remaining bits by tree traversal */ \ | ||
1809 | - i = MSZIP_##tbl##_TABLEBITS - 1; \ | ||
1810 | - do { \ | ||
1811 | - /* check next bit. error if we run out of bits before decode */ \ | ||
1812 | - if (i++ > MSZIP_MAX_HUFFBITS) { \ | ||
1813 | - cli_dbgmsg("zip_inflate: out of bits in huffman decode\n"); \ | ||
1814 | - return INF_ERR_HUFFSYM; \ | ||
1815 | - } \ | ||
1816 | - sym = (sym << 1) | ((bit_buffer >> i) & 1); \ | ||
1817 | - if(sym >= MSZIP_##tbl##_TABLESIZE) { \ | ||
1818 | - cli_dbgmsg("zip_inflate: index out of table\n"); \ | ||
1819 | - return INF_ERR_HUFFSYM; \ | ||
1820 | - } \ | ||
1821 | - /* double node index and add 0 (left branch) or 1 (right) */ \ | ||
1822 | - sym = zip->tbl##_table[sym]; \ | ||
1823 | - /* while we are still in node indicies, not decoded symbols */ \ | ||
1824 | - } while (sym >= MSZIP_##tbl##_MAXSYMBOLS); \ | ||
1825 | - } \ | ||
1826 | - /* result */ \ | ||
1827 | - (var) = sym; \ | ||
1828 | - /* look up the code length of that symbol and discard those bits */ \ | ||
1829 | - i = zip->tbl##_len[sym]; \ | ||
1830 | - MSZIP_REMOVE_BITS(i); \ | ||
1831 | -} while (0) | ||
1832 | - | ||
1833 | -static int mszip_read_lens(struct mszip_stream *zip) { | ||
1834 | - /* for the bit buffer and huffman decoding */ | ||
1835 | - register unsigned int bit_buffer; | ||
1836 | - register int bits_left; | ||
1837 | - unsigned char *i_ptr, *i_end; | ||
1838 | - | ||
1839 | - /* bitlen Huffman codes -- immediate lookup, 7 bit max code length */ | ||
1840 | - unsigned short bl_table[(1 << 7)]; | ||
1841 | - unsigned char bl_len[19]; | ||
1842 | - | ||
1843 | - unsigned char lens[MSZIP_LITERAL_MAXSYMBOLS + MSZIP_DISTANCE_MAXSYMBOLS]; | ||
1844 | - unsigned int lit_codes, dist_codes, code, last_code=0, bitlen_codes, i, run; | ||
1845 | - | ||
1846 | - MSZIP_RESTORE_BITS; | ||
1847 | - | ||
1848 | - /* read the number of codes */ | ||
1849 | - MSZIP_READ_BITS(lit_codes, 5); lit_codes += 257; | ||
1850 | - MSZIP_READ_BITS(dist_codes, 5); dist_codes += 1; | ||
1851 | - MSZIP_READ_BITS(bitlen_codes, 4); bitlen_codes += 4; | ||
1852 | - if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS) return INF_ERR_SYMLENS; | ||
1853 | - if (dist_codes > MSZIP_DISTANCE_MAXSYMBOLS) return INF_ERR_SYMLENS; | ||
1854 | - | ||
1855 | - /* read in the bit lengths in their unusual order */ | ||
1856 | - for (i = 0; i < bitlen_codes; i++) MSZIP_READ_BITS(bl_len[mszip_bitlen_order[i]], 3); | ||
1857 | - while (i < 19) bl_len[mszip_bitlen_order[i++]] = 0; | ||
1858 | - | ||
1859 | - /* create decoding table with an immediate lookup */ | ||
1860 | - if (mszip_make_decode_table(19, 7, &bl_len[0], &bl_table[0])) { | ||
1861 | - return INF_ERR_BITLENTBL; | ||
1862 | - } | ||
1863 | - | ||
1864 | - /* read literal / distance code lengths */ | ||
1865 | - for (i = 0; i < (lit_codes + dist_codes); i++) { | ||
1866 | - /* single-level huffman lookup */ | ||
1867 | - MSZIP_ENSURE_BITS(7); | ||
1868 | - code = bl_table[MSZIP_PEEK_BITS(7)]; | ||
1869 | - MSZIP_REMOVE_BITS(bl_len[code]); | ||
1870 | - | ||
1871 | - if (code < 16) lens[i] = last_code = code; | ||
1872 | - else { | ||
1873 | - switch (code) { | ||
1874 | - case 16: MSZIP_READ_BITS(run, 2); run += 3; code = last_code; break; | ||
1875 | - case 17: MSZIP_READ_BITS(run, 3); run += 3; code = 0; break; | ||
1876 | - case 18: MSZIP_READ_BITS(run, 7); run += 11; code = 0; break; | ||
1877 | - default: cli_dbgmsg("zip_read_lens: bad code!: %u\n", code); return INF_ERR_BADBITLEN; | ||
1878 | - } | ||
1879 | - if ((i + run) > (lit_codes + dist_codes)) return INF_ERR_BITOVERRUN; | ||
1880 | - while (run--) lens[i++] = code; | ||
1881 | - i--; | ||
1882 | - } | ||
1883 | - } | ||
1884 | - | ||
1885 | - /* copy LITERAL code lengths and clear any remaining */ | ||
1886 | - i = lit_codes; | ||
1887 | - memcpy(&zip->LITERAL_len[0], &lens[0], i); | ||
1888 | - while (i < MSZIP_LITERAL_MAXSYMBOLS) zip->LITERAL_len[i++] = 0; | ||
1889 | - | ||
1890 | - i = dist_codes; | ||
1891 | - memcpy(&zip->DISTANCE_len[0], &lens[lit_codes], i); | ||
1892 | - while (i < MSZIP_DISTANCE_MAXSYMBOLS) zip->DISTANCE_len[i++] = 0; | ||
1893 | - | ||
1894 | - MSZIP_STORE_BITS; | ||
1895 | - return 0; | ||
1896 | -} | ||
1897 | - | ||
1898 | -static int mspack_write(int fd, const void *buff, unsigned int count, struct cab_file *file) | ||
1899 | -{ | ||
1900 | - int ret; | ||
1901 | - | ||
1902 | - if(file->max_size) { | ||
1903 | - if(file->written_size >= file->max_size) | ||
1904 | - return CL_BREAK; | ||
1905 | - | ||
1906 | - if(file->written_size + count > file->max_size) | ||
1907 | - count = file->max_size - file->written_size; | ||
1908 | - } | ||
1909 | - if((ret = cli_writen(fd, buff, count)) > 0) | ||
1910 | - file->written_size += ret; | ||
1911 | - | ||
1912 | - return (ret == -1) ? CL_EWRITE : CL_SUCCESS; | ||
1913 | -} | ||
1914 | - | ||
1915 | -/* a clean implementation of RFC 1951 / inflate */ | ||
1916 | -static int mszip_inflate(struct mszip_stream *zip) { | ||
1917 | - unsigned int last_block, block_type, distance, length, this_run, i; | ||
1918 | - | ||
1919 | - /* for the bit buffer and huffman decoding */ | ||
1920 | - register unsigned int bit_buffer; | ||
1921 | - register int bits_left; | ||
1922 | - register unsigned short sym; | ||
1923 | - unsigned char *i_ptr, *i_end; | ||
1924 | - | ||
1925 | - MSZIP_RESTORE_BITS; | ||
1926 | - | ||
1927 | - do { | ||
1928 | - /* read in last block bit */ | ||
1929 | - MSZIP_READ_BITS(last_block, 1); | ||
1930 | - | ||
1931 | - /* read in block type */ | ||
1932 | - MSZIP_READ_BITS(block_type, 2); | ||
1933 | - | ||
1934 | - if (block_type == 0) { | ||
1935 | - /* uncompressed block */ | ||
1936 | - unsigned char lens_buf[4]; | ||
1937 | - | ||
1938 | - /* go to byte boundary */ | ||
1939 | - i = bits_left & 7; MSZIP_REMOVE_BITS(i); | ||
1940 | - | ||
1941 | - /* read 4 bytes of data, emptying the bit-buffer if necessary */ | ||
1942 | - for (i = 0; (bits_left >= 8); i++) { | ||
1943 | - if (i == 4) return INF_ERR_BITBUF; | ||
1944 | - lens_buf[i] = MSZIP_PEEK_BITS(8); | ||
1945 | - MSZIP_REMOVE_BITS(8); | ||
1946 | - } | ||
1947 | - if (bits_left != 0) return INF_ERR_BITBUF; | ||
1948 | - while (i < 4) { | ||
1949 | - if (i_ptr >= i_end) { | ||
1950 | - if (mszip_read_input(zip)) return zip->error; | ||
1951 | - i_ptr = zip->i_ptr; | ||
1952 | - i_end = zip->i_end; | ||
1953 | - if(i_ptr == i_end) break; | ||
1954 | - } | ||
1955 | - lens_buf[i++] = *i_ptr++; | ||
1956 | - } | ||
1957 | - if (i < 4) return INF_ERR_BITBUF; | ||
1958 | - | ||
1959 | - /* get the length and its complement */ | ||
1960 | - length = lens_buf[0] | (lens_buf[1] << 8); | ||
1961 | - i = lens_buf[2] | (lens_buf[3] << 8); | ||
1962 | - if (length != (~i & 0xFFFF)) return INF_ERR_COMPLEMENT; | ||
1963 | - | ||
1964 | - /* read and copy the uncompressed data into the window */ | ||
1965 | - while (length > 0) { | ||
1966 | - if (i_ptr >= i_end) { | ||
1967 | - if (mszip_read_input(zip)) return zip->error; | ||
1968 | - i_ptr = zip->i_ptr; | ||
1969 | - i_end = zip->i_end; | ||
1970 | - if(i_ptr == i_end) break; | ||
1971 | - } | ||
1972 | - | ||
1973 | - this_run = length; | ||
1974 | - if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr; | ||
1975 | - if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn)) | ||
1976 | - this_run = MSZIP_FRAME_SIZE - zip->window_posn; | ||
1977 | - | ||
1978 | - memcpy(&zip->window[zip->window_posn], i_ptr, this_run); | ||
1979 | - zip->window_posn += this_run; | ||
1980 | - i_ptr += this_run; | ||
1981 | - length -= this_run; | ||
1982 | - | ||
1983 | - if (zip->window_posn == MSZIP_FRAME_SIZE) { | ||
1984 | - if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) return INF_ERR_FLUSH; | ||
1985 | - zip->window_posn = 0; | ||
1986 | - } | ||
1987 | - } | ||
1988 | - } | ||
1989 | - else if ((block_type == 1) || (block_type == 2)) { | ||
1990 | - /* Huffman-compressed LZ77 block */ | ||
1991 | - unsigned int window_posn, match_posn, code; | ||
1992 | - | ||
1993 | - if (block_type == 1) { | ||
1994 | - /* block with fixed Huffman codes */ | ||
1995 | - i = 0; | ||
1996 | - while (i < 144) zip->LITERAL_len[i++] = 8; | ||
1997 | - while (i < 256) zip->LITERAL_len[i++] = 9; | ||
1998 | - while (i < 280) zip->LITERAL_len[i++] = 7; | ||
1999 | - while (i < 288) zip->LITERAL_len[i++] = 8; | ||
2000 | - for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5; | ||
2001 | - } | ||
2002 | - else { | ||
2003 | - /* block with dynamic Huffman codes */ | ||
2004 | - MSZIP_STORE_BITS; | ||
2005 | - if ((i = mszip_read_lens(zip))) return i; | ||
2006 | - MSZIP_RESTORE_BITS; | ||
2007 | - } | ||
2008 | - | ||
2009 | - /* now huffman lengths are read for either kind of block, | ||
2010 | - * create huffman decoding tables */ | ||
2011 | - if (mszip_make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, | ||
2012 | - &zip->LITERAL_len[0], &zip->LITERAL_table[0])) | ||
2013 | - { | ||
2014 | - return INF_ERR_LITERALTBL; | ||
2015 | - } | ||
2016 | - | ||
2017 | - if (mszip_make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS, | ||
2018 | - &zip->DISTANCE_len[0], &zip->DISTANCE_table[0])) | ||
2019 | - { | ||
2020 | - return INF_ERR_DISTANCETBL; | ||
2021 | - } | ||
2022 | - | ||
2023 | - /* decode forever until end of block code */ | ||
2024 | - window_posn = zip->window_posn; | ||
2025 | - while (1) { | ||
2026 | - MSZIP_READ_HUFFSYM(LITERAL, code); | ||
2027 | - if (code < 256) { | ||
2028 | - zip->window[window_posn++] = (unsigned char) code; | ||
2029 | - if (window_posn == MSZIP_FRAME_SIZE) { | ||
2030 | - if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) return INF_ERR_FLUSH; | ||
2031 | - window_posn = 0; | ||
2032 | - } | ||
2033 | - } | ||
2034 | - else if (code == 256) { | ||
2035 | - /* END OF BLOCK CODE: loop break point */ | ||
2036 | - break; | ||
2037 | - } | ||
2038 | - else { | ||
2039 | - code -= 257; | ||
2040 | - if (code >= 29) return INF_ERR_LITCODE; | ||
2041 | - MSZIP_READ_BITS_T(length, mszip_lit_extrabits[code]); | ||
2042 | - length += mszip_lit_lengths[code]; | ||
2043 | - | ||
2044 | - MSZIP_READ_HUFFSYM(DISTANCE, code); | ||
2045 | - if (code >= 30) return INF_ERR_DISTCODE; | ||
2046 | - MSZIP_READ_BITS_T(distance, mszip_dist_extrabits[code]); | ||
2047 | - distance += mszip_dist_offsets[code]; | ||
2048 | - | ||
2049 | - /* match position is window position minus distance. If distance | ||
2050 | - * is more than window position numerically, it must 'wrap | ||
2051 | - * around' the frame size. */ | ||
2052 | - match_posn = ((distance > window_posn) ? MSZIP_FRAME_SIZE : 0) | ||
2053 | - + window_posn - distance; | ||
2054 | - | ||
2055 | - /* copy match */ | ||
2056 | - if (length < 12) { | ||
2057 | - /* short match, use slower loop but no loop setup code */ | ||
2058 | - while (length--) { | ||
2059 | - zip->window[window_posn++] = zip->window[match_posn++]; | ||
2060 | - match_posn &= MSZIP_FRAME_SIZE - 1; | ||
2061 | - | ||
2062 | - if (window_posn == MSZIP_FRAME_SIZE) { | ||
2063 | - if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) | ||
2064 | - return INF_ERR_FLUSH; | ||
2065 | - window_posn = 0; | ||
2066 | - } | ||
2067 | - } | ||
2068 | - } | ||
2069 | - else { | ||
2070 | - /* longer match, use faster loop but with setup expense */ | ||
2071 | - unsigned char *runsrc, *rundest; | ||
2072 | - do { | ||
2073 | - this_run = length; | ||
2074 | - if ((match_posn + this_run) > MSZIP_FRAME_SIZE) | ||
2075 | - this_run = MSZIP_FRAME_SIZE - match_posn; | ||
2076 | - if ((window_posn + this_run) > MSZIP_FRAME_SIZE) | ||
2077 | - this_run = MSZIP_FRAME_SIZE - window_posn; | ||
2078 | - | ||
2079 | - rundest = &zip->window[window_posn]; window_posn += this_run; | ||
2080 | - runsrc = &zip->window[match_posn]; match_posn += this_run; | ||
2081 | - length -= this_run; | ||
2082 | - while (this_run--) *rundest++ = *runsrc++; | ||
2083 | - | ||
2084 | - /* flush if necessary */ | ||
2085 | - if (window_posn == MSZIP_FRAME_SIZE) { | ||
2086 | - if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) | ||
2087 | - return INF_ERR_FLUSH; | ||
2088 | - window_posn = 0; | ||
2089 | - } | ||
2090 | - if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0; | ||
2091 | - } while (length > 0); | ||
2092 | - } | ||
2093 | - | ||
2094 | - } /* else (code >= 257) */ | ||
2095 | - | ||
2096 | - } /* while (forever) -- break point at 'code == 256' */ | ||
2097 | - zip->window_posn = window_posn; | ||
2098 | - } | ||
2099 | - else { | ||
2100 | - /* block_type == 3 -- bad block type */ | ||
2101 | - return INF_ERR_BLOCKTYPE; | ||
2102 | - } | ||
2103 | - } while (!last_block); | ||
2104 | - | ||
2105 | - /* flush the remaining data */ | ||
2106 | - if (zip->window_posn) { | ||
2107 | - if (zip->flush_window(zip, zip->window_posn)) return INF_ERR_FLUSH; | ||
2108 | - } | ||
2109 | - MSZIP_STORE_BITS; | ||
2110 | - | ||
2111 | - /* return success */ | ||
2112 | - return 0; | ||
2113 | -} | ||
2114 | - | ||
2115 | -/* inflate() calls this whenever the window should be flushed. As | ||
2116 | - * MSZIP only expands to the size of the window, the implementation used | ||
2117 | - * simply keeps track of the amount of data flushed, and if more than 32k | ||
2118 | - * is flushed, an error is raised. | ||
2119 | - */ | ||
2120 | -static int mszip_flush_window(struct mszip_stream *zip, | ||
2121 | - unsigned int data_flushed) | ||
2122 | -{ | ||
2123 | - zip->bytes_output += data_flushed; | ||
2124 | - if (zip->bytes_output > MSZIP_FRAME_SIZE) { | ||
2125 | - cli_dbgmsg("mszip_flush_window: overflow: %u bytes flushed, total is now %u\n", data_flushed, zip->bytes_output); | ||
2126 | - return 1; | ||
2127 | - } | ||
2128 | - return 0; | ||
2129 | -} | ||
2130 | - | ||
2131 | -struct mszip_stream *mszip_init(int ofd, | ||
2132 | - int input_buffer_size, | ||
2133 | - int repair_mode, | ||
2134 | - struct cab_file *file, | ||
2135 | - int (*read_cb)(struct cab_file *, unsigned char *, int)) | ||
2136 | -{ | ||
2137 | - struct mszip_stream *zip; | ||
2138 | - | ||
2139 | - input_buffer_size = (input_buffer_size + 1) & -2; | ||
2140 | - if (!input_buffer_size) return NULL; | ||
2141 | - | ||
2142 | - /* allocate decompression state */ | ||
2143 | - if (!(zip = cli_calloc(1, sizeof(struct mszip_stream)))) { | ||
2144 | - cli_errmsg("mszip_stream: Unable to allocate zip buffer\n"); | ||
2145 | - return NULL; | ||
2146 | - } | ||
2147 | - | ||
2148 | - /* allocate input buffer */ | ||
2149 | - zip->inbuf = cli_malloc((size_t) input_buffer_size); | ||
2150 | - if (!zip->inbuf) { | ||
2151 | - cli_errmsg("mszip_stream: Unable to allocate input buffer\n"); | ||
2152 | - free(zip); | ||
2153 | - return NULL; | ||
2154 | - } | ||
2155 | - | ||
2156 | - /* initialise decompression state */ | ||
2157 | - zip->ofd = ofd; | ||
2158 | - zip->wflag = 1; | ||
2159 | - zip->inbuf_size = input_buffer_size; | ||
2160 | - zip->error = CL_SUCCESS; | ||
2161 | - zip->repair_mode = repair_mode; | ||
2162 | - zip->flush_window = &mszip_flush_window; | ||
2163 | - zip->input_end = 0; | ||
2164 | - | ||
2165 | - zip->i_ptr = zip->i_end = &zip->inbuf[0]; | ||
2166 | - zip->o_ptr = zip->o_end = NULL; | ||
2167 | - zip->bit_buffer = 0; zip->bits_left = 0; | ||
2168 | - | ||
2169 | - zip->file = file; | ||
2170 | - zip->read_cb = read_cb; | ||
2171 | - | ||
2172 | - return zip; | ||
2173 | -} | ||
2174 | - | ||
2175 | -int mszip_decompress(struct mszip_stream *zip, uint32_t out_bytes) { | ||
2176 | - /* for the bit buffer */ | ||
2177 | - register unsigned int bit_buffer; | ||
2178 | - register int bits_left; | ||
2179 | - unsigned char *i_ptr, *i_end; | ||
2180 | - | ||
2181 | - int i, ret, state, error; | ||
2182 | - | ||
2183 | - /* easy answers */ | ||
2184 | - if (!zip) return CL_ENULLARG; | ||
2185 | - if (zip->error) return zip->error; | ||
2186 | - | ||
2187 | - /* flush out any stored-up bytes before we begin */ | ||
2188 | - i = zip->o_end - zip->o_ptr; | ||
2189 | - if (((off_t) i > out_bytes) && ((int) out_bytes >= 0)) i = (int) out_bytes; | ||
2190 | - if (i) { | ||
2191 | - if (zip->wflag && (ret = mspack_write(zip->ofd, zip->o_ptr, i, zip->file)) != CL_SUCCESS) { | ||
2192 | - return zip->error = ret; | ||
2193 | - } | ||
2194 | - zip->o_ptr += i; | ||
2195 | - out_bytes -= i; | ||
2196 | - } | ||
2197 | - if (out_bytes == 0) return CL_SUCCESS; | ||
2198 | - | ||
2199 | - while (out_bytes > 0) { | ||
2200 | - /* unpack another block */ | ||
2201 | - MSZIP_RESTORE_BITS; | ||
2202 | - | ||
2203 | - /* skip to next read 'CK' header */ | ||
2204 | - i = bits_left & 7; MSZIP_REMOVE_BITS(i); /* align to bytestream */ | ||
2205 | - state = 0; | ||
2206 | - do { | ||
2207 | - MSZIP_READ_BITS(i, 8); | ||
2208 | - if (i == 'C') state = 1; | ||
2209 | - else if ((state == 1) && (i == 'K')) state = 2; | ||
2210 | - else state = 0; | ||
2211 | - } while (state != 2); | ||
2212 | - | ||
2213 | - /* inflate a block, repair and realign if necessary */ | ||
2214 | - zip->window_posn = 0; | ||
2215 | - zip->bytes_output = 0; | ||
2216 | - MSZIP_STORE_BITS; | ||
2217 | - if ((error = mszip_inflate(zip))) { | ||
2218 | - cli_dbgmsg("mszip_decompress: inflate error %d\n", error); | ||
2219 | - if (zip->repair_mode) { | ||
2220 | - cli_dbgmsg("mszip_decompress: MSZIP error, %u bytes of data lost\n", | ||
2221 | - MSZIP_FRAME_SIZE - zip->bytes_output); | ||
2222 | - for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) { | ||
2223 | - zip->window[i] = '\0'; | ||
2224 | - } | ||
2225 | - zip->bytes_output = MSZIP_FRAME_SIZE; | ||
2226 | - } | ||
2227 | - else { | ||
2228 | - return zip->error = (error > 0) ? error : CL_EFORMAT; | ||
2229 | - } | ||
2230 | - } | ||
2231 | - zip->o_ptr = &zip->window[0]; | ||
2232 | - zip->o_end = &zip->o_ptr[zip->bytes_output]; | ||
2233 | - | ||
2234 | - /* write a frame */ | ||
2235 | - i = (out_bytes < (off_t)zip->bytes_output) ? | ||
2236 | - (int)out_bytes : zip->bytes_output; | ||
2237 | - if (zip->wflag && (ret = mspack_write(zip->ofd, zip->o_ptr, i, zip->file)) != CL_SUCCESS) { | ||
2238 | - return zip->error = ret; | ||
2239 | - } | ||
2240 | - | ||
2241 | - /* mspack errors (i.e. read errors) are fatal and can't be recovered */ | ||
2242 | - if ((error > 0) && zip->repair_mode) return error; | ||
2243 | - | ||
2244 | - zip->o_ptr += i; | ||
2245 | - out_bytes -= i; | ||
2246 | - } | ||
2247 | - | ||
2248 | - if (out_bytes) | ||
2249 | - cli_dbgmsg("mszip_decompress: bytes left to output\n"); | ||
2250 | - | ||
2251 | - return CL_SUCCESS; | ||
2252 | -} | ||
2253 | - | ||
2254 | -void mszip_free(struct mszip_stream *zip) { | ||
2255 | - if (zip) { | ||
2256 | - free(zip->inbuf); | ||
2257 | - free(zip); | ||
2258 | - } | ||
2259 | -} | ||
2260 | - | ||
2261 | -/*************************************************************************** | ||
2262 | - * LZX decompression implementation | ||
2263 | - *************************************************************************** | ||
2264 | - * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted | ||
2265 | - * by Microsoft Corporation. | ||
2266 | - * | ||
2267 | - */ | ||
2268 | - | ||
2269 | -/* LZX decompressor input macros | ||
2270 | - * | ||
2271 | - * LZX_STORE_BITS stores bitstream state in lzx_stream structure | ||
2272 | - * LZX_RESTORE_BITS restores bitstream state from lzx_stream structure | ||
2273 | - * LZX_READ_BITS(var,n) takes N bits from the buffer and puts them in var | ||
2274 | - * LZX_ENSURE_BITS(n) ensures there are at least N bits in the bit buffer. | ||
2275 | - * LZX_PEEK_BITS(n) extracts without removing N bits from the bit buffer | ||
2276 | - * LZX_REMOVE_BITS(n) removes N bits from the bit buffer | ||
2277 | - * | ||
2278 | - */ | ||
2279 | - | ||
2280 | -#define LZX_BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT) | ||
2281 | - | ||
2282 | -#define LZX_STORE_BITS do { \ | ||
2283 | - lzx->i_ptr = i_ptr; \ | ||
2284 | - lzx->i_end = i_end; \ | ||
2285 | - lzx->bit_buffer = bit_buffer; \ | ||
2286 | - lzx->bits_left = bits_left; \ | ||
2287 | -} while (0) | ||
2288 | - | ||
2289 | -#define LZX_RESTORE_BITS do { \ | ||
2290 | - i_ptr = lzx->i_ptr; \ | ||
2291 | - i_end = lzx->i_end; \ | ||
2292 | - bit_buffer = lzx->bit_buffer; \ | ||
2293 | - bits_left = lzx->bits_left; \ | ||
2294 | -} while (0) | ||
2295 | - | ||
2296 | -#define LZX_ENSURE_BITS(nbits) \ | ||
2297 | - while (bits_left < (nbits)) { \ | ||
2298 | - if (i_ptr + 1 >= i_end) { \ | ||
2299 | - if (lzx_read_input(lzx)) return lzx->error; \ | ||
2300 | - i_ptr = lzx->i_ptr; \ | ||
2301 | - i_end = lzx->i_end; \ | ||
2302 | - } \ | ||
2303 | - bit_buffer |= ((i_ptr[1] << 8) | i_ptr[0]) \ | ||
2304 | - << (LZX_BITBUF_WIDTH - 16 - bits_left); \ | ||
2305 | - bits_left += 16; \ | ||
2306 | - i_ptr += 2; \ | ||
2307 | - } | ||
2308 | - | ||
2309 | -#define LZX_PEEK_BITS(nbits) (bit_buffer >> (LZX_BITBUF_WIDTH - (nbits))) | ||
2310 | - | ||
2311 | -#define LZX_REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits))) | ||
2312 | - | ||
2313 | -#define LZX_READ_BITS(val, nbits) do { \ | ||
2314 | - LZX_ENSURE_BITS(nbits); \ | ||
2315 | - (val) = LZX_PEEK_BITS(nbits); \ | ||
2316 | - LZX_REMOVE_BITS(nbits); \ | ||
2317 | -} while (0) | ||
2318 | - | ||
2319 | -static int lzx_read_input(struct lzx_stream *lzx) { | ||
2320 | - int bread = lzx->read_cb(lzx->file, &lzx->inbuf[0], (int)lzx->inbuf_size); | ||
2321 | - if (bread < 0) { | ||
2322 | - if (lzx->file->error == CL_BREAK) | ||
2323 | - return lzx->error = CL_BREAK; | ||
2324 | - else | ||
2325 | - return lzx->error = CL_EFORMAT; | ||
2326 | - } | ||
2327 | - | ||
2328 | - /* huff decode's ENSURE_BYTES(16) might overrun the input stream, even | ||
2329 | - * if those bits aren't used, so fake 2 more bytes */ | ||
2330 | - if (bread == 0) { | ||
2331 | - if (lzx->input_end) { | ||
2332 | - cli_dbgmsg("lzx_read_input: out of input bytes\n"); | ||
2333 | - return lzx->error = CL_EREAD; | ||
2334 | - } | ||
2335 | - else { | ||
2336 | - bread = 2; | ||
2337 | - lzx->inbuf[0] = lzx->inbuf[1] = 0; | ||
2338 | - lzx->input_end = 1; | ||
2339 | - } | ||
2340 | - } | ||
2341 | - | ||
2342 | - lzx->i_ptr = &lzx->inbuf[0]; | ||
2343 | - lzx->i_end = &lzx->inbuf[bread]; | ||
2344 | - | ||
2345 | - return CL_SUCCESS; | ||
2346 | -} | ||
2347 | - | ||
2348 | -/* Huffman decoding macros */ | ||
2349 | - | ||
2350 | -/* LZX_READ_HUFFSYM(tablename, var) decodes one huffman symbol from the | ||
2351 | - * bitstream using the stated table and puts it in var. | ||
2352 | - */ | ||
2353 | -#define LZX_READ_HUFFSYM(tbl, var) do { \ | ||
2354 | - /* huffman symbols can be up to 16 bits long */ \ | ||
2355 | - LZX_ENSURE_BITS(16); \ | ||
2356 | - /* immediate table lookup of [tablebits] bits of the code */ \ | ||
2357 | - sym = lzx->tbl##_table[LZX_PEEK_BITS(LZX_##tbl##_TABLEBITS)]; \ | ||
2358 | - /* is the symbol is longer than [tablebits] bits? (i=node index) */ \ | ||
2359 | - if (sym >= LZX_##tbl##_MAXSYMBOLS) { \ | ||
2360 | - /* decode remaining bits by tree traversal */ \ | ||
2361 | - i = 1 << (LZX_BITBUF_WIDTH - LZX_##tbl##_TABLEBITS); \ | ||
2362 | - do { \ | ||
2363 | - /* one less bit. error if we run out of bits before decode */ \ | ||
2364 | - i >>= 1; \ | ||
2365 | - if (i == 0) { \ | ||
2366 | - cli_dbgmsg("lzx: out of bits in huffman decode\n"); \ | ||
2367 | - return lzx->error = CL_EFORMAT; \ | ||
2368 | - } \ | ||
2369 | - /* double node index and add 0 (left branch) or 1 (right) */ \ | ||
2370 | - sym <<= 1; sym |= (bit_buffer & i) ? 1 : 0; \ | ||
2371 | - /* hop to next node index / decoded symbol */ \ | ||
2372 | - if(sym >= (1 << LZX_##tbl##_TABLEBITS) + (LZX_##tbl##_MAXSYMBOLS * 2)) { \ | ||
2373 | - cli_dbgmsg("lzx: index out of table\n"); \ | ||
2374 | - return lzx->error = CL_EFORMAT; \ | ||
2375 | - } \ | ||
2376 | - sym = lzx->tbl##_table[sym]; \ | ||
2377 | - /* while we are still in node indicies, not decoded symbols */ \ | ||
2378 | - } while (sym >= LZX_##tbl##_MAXSYMBOLS); \ | ||
2379 | - } \ | ||
2380 | - /* result */ \ | ||
2381 | - (var) = sym; \ | ||
2382 | - /* look up the code length of that symbol and discard those bits */ \ | ||
2383 | - i = lzx->tbl##_len[sym]; \ | ||
2384 | - LZX_REMOVE_BITS(i); \ | ||
2385 | -} while (0) | ||
2386 | - | ||
2387 | -/* LZX_BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */ | ||
2388 | -#define LZX_BUILD_TABLE(tbl) \ | ||
2389 | - if (lzx_make_decode_table(LZX_##tbl##_MAXSYMBOLS, LZX_##tbl##_TABLEBITS, \ | ||
2390 | - &lzx->tbl##_len[0], &lzx->tbl##_table[0])) \ | ||
2391 | - { \ | ||
2392 | - cli_dbgmsg("lzx: failed to build %s table\n", #tbl); \ | ||
2393 | - return lzx->error = CL_EFORMAT; \ | ||
2394 | - } | ||
2395 | - | ||
2396 | -/* lzx_make_decode_table(nsyms, nbits, length[], table[]) | ||
2397 | - * | ||
2398 | - * This function was coded by David Tritscher. It builds a fast huffman | ||
2399 | - * decoding table from a canonical huffman code lengths table. | ||
2400 | - * | ||
2401 | - * nsyms = total number of symbols in this huffman tree. | ||
2402 | - * nbits = any symbols with a code length of nbits or less can be decoded | ||
2403 | - * in one lookup of the table. | ||
2404 | - * length = A table to get code lengths from [0 to syms-1] | ||
2405 | - * table = The table to fill up with decoded symbols and pointers. | ||
2406 | - * | ||
2407 | - * Returns 0 for OK or 1 for error | ||
2408 | - */ | ||
2409 | - | ||
2410 | -static int lzx_make_decode_table(unsigned int nsyms, unsigned int nbits, | ||
2411 | - unsigned char *length, unsigned short *table) | ||
2412 | -{ | ||
2413 | - register unsigned short sym; | ||
2414 | - register unsigned int leaf, fill; | ||
2415 | - register unsigned char bit_num; | ||
2416 | - unsigned int pos = 0; /* the current position in the decode table */ | ||
2417 | - unsigned int table_mask = 1 << nbits; | ||
2418 | - unsigned int bit_mask = table_mask >> 1; /* don't do 0 length codes */ | ||
2419 | - unsigned int next_symbol = bit_mask; /* base of allocation for long codes */ | ||
2420 | - | ||
2421 | - /* fill entries for codes short enough for a direct mapping */ | ||
2422 | - for (bit_num = 1; bit_num <= nbits; bit_num++) { | ||
2423 | - for (sym = 0; sym < nsyms; sym++) { | ||
2424 | - if (length[sym] != bit_num) continue; | ||
2425 | - leaf = pos; | ||
2426 | - if((pos += bit_mask) > table_mask) return 1; /* table overrun */ | ||
2427 | - /* fill all possible lookups of this symbol with the symbol itself */ | ||
2428 | - for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym; | ||
2429 | - } | ||
2430 | - bit_mask >>= 1; | ||
2431 | - } | ||
2432 | - | ||
2433 | - /* full table already? */ | ||
2434 | - if (pos == table_mask) return 0; | ||
2435 | - | ||
2436 | - /* clear the remainder of the table */ | ||
2437 | - for (sym = pos; sym < table_mask; sym++) table[sym] = 0xFFFF; | ||
2438 | - | ||
2439 | - /* allow codes to be up to nbits+16 long, instead of nbits */ | ||
2440 | - pos <<= 16; | ||
2441 | - table_mask <<= 16; | ||
2442 | - bit_mask = 1 << 15; | ||
2443 | - | ||
2444 | - for (bit_num = nbits+1; bit_num <= 16; bit_num++) { | ||
2445 | - for (sym = 0; sym < nsyms; sym++) { | ||
2446 | - if (length[sym] != bit_num) continue; | ||
2447 | - | ||
2448 | - leaf = pos >> 16; | ||
2449 | - for (fill = 0; fill < bit_num - nbits; fill++) { | ||
2450 | - /* if this path hasn't been taken yet, 'allocate' two entries */ | ||
2451 | - if (table[leaf] == 0xFFFF) { | ||
2452 | - table[(next_symbol << 1)] = 0xFFFF; | ||
2453 | - table[(next_symbol << 1) + 1] = 0xFFFF; | ||
2454 | - table[leaf] = next_symbol++; | ||
2455 | - } | ||
2456 | - /* follow the path and select either left or right for next bit */ | ||
2457 | - leaf = table[leaf] << 1; | ||
2458 | - if ((pos >> (15-fill)) & 1) leaf++; | ||
2459 | - } | ||
2460 | - table[leaf] = sym; | ||
2461 | - | ||
2462 | - if ((pos += bit_mask) > table_mask) return 1; /* table overflow */ | ||
2463 | - } | ||
2464 | - bit_mask >>= 1; | ||
2465 | - } | ||
2466 | - | ||
2467 | - /* full table? */ | ||
2468 | - if (pos == table_mask) return 0; | ||
2469 | - | ||
2470 | - /* either erroneous table, or all elements are 0 - let's find out. */ | ||
2471 | - for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1; | ||
2472 | - return 0; | ||
2473 | -} | ||
2474 | - | ||
2475 | -/* LZX_READ_LENGTHS(tablename, first, last) reads in code lengths for symbols | ||
2476 | - * first to last in the given table. The code lengths are stored in their | ||
2477 | - * own special LZX way. | ||
2478 | - */ | ||
2479 | -#define LZX_READ_LENGTHS(tbl, first, last) do { \ | ||
2480 | - LZX_STORE_BITS; \ | ||
2481 | - if (lzx_read_lens(lzx, &lzx->tbl##_len[0], (first), \ | ||
2482 | - (unsigned int)(last))) return lzx->error; \ | ||
2483 | - LZX_RESTORE_BITS; \ | ||
2484 | -} while (0) | ||
2485 | - | ||
2486 | -static int lzx_read_lens(struct lzx_stream *lzx, unsigned char *lens, | ||
2487 | - unsigned int first, unsigned int last) | ||
2488 | -{ | ||
2489 | - /* bit buffer and huffman symbol decode variables */ | ||
2490 | - register unsigned int bit_buffer; | ||
2491 | - register int bits_left, i; | ||
2492 | - register unsigned short sym; | ||
2493 | - unsigned char *i_ptr, *i_end; | ||
2494 | - | ||
2495 | - unsigned int x, y; | ||
2496 | - int z; | ||
2497 | - | ||
2498 | - LZX_RESTORE_BITS; | ||
2499 | - | ||
2500 | - /* read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) */ | ||
2501 | - for (x = 0; x < 20; x++) { | ||
2502 | - LZX_READ_BITS(y, 4); | ||
2503 | - lzx->PRETREE_len[x] = y; | ||
2504 | - } | ||
2505 | - LZX_BUILD_TABLE(PRETREE); | ||
2506 | - | ||
2507 | - for (x = first; x < last; ) { | ||
2508 | - LZX_READ_HUFFSYM(PRETREE, z); | ||
2509 | - if (z == 17) { | ||
2510 | - /* code = 17, run of ([read 4 bits]+4) zeros */ | ||
2511 | - LZX_READ_BITS(y, 4); y += 4; | ||
2512 | - while (y--) lens[x++] = 0; | ||
2513 | - } | ||
2514 | - else if (z == 18) { | ||
2515 | - /* code = 18, run of ([read 5 bits]+20) zeros */ | ||
2516 | - LZX_READ_BITS(y, 5); y += 20; | ||
2517 | - while (y--) lens[x++] = 0; | ||
2518 | - } | ||
2519 | - else if (z == 19) { | ||
2520 | - /* code = 19, run of ([read 1 bit]+4) [read huffman symbol] */ | ||
2521 | - LZX_READ_BITS(y, 1); y += 4; | ||
2522 | - LZX_READ_HUFFSYM(PRETREE, z); | ||
2523 | - z = lens[x] - z; if (z < 0) z += 17; | ||
2524 | - while (y--) lens[x++] = z; | ||
2525 | - } | ||
2526 | - else { | ||
2527 | - /* code = 0 to 16, delta current length entry */ | ||
2528 | - z = lens[x] - z; if (z < 0) z += 17; | ||
2529 | - lens[x++] = z; | ||
2530 | - } | ||
2531 | - } | ||
2532 | - | ||
2533 | - LZX_STORE_BITS; | ||
2534 | - | ||
2535 | - return CL_SUCCESS; | ||
2536 | -} | ||
2537 | - | ||
2538 | -static void lzx_reset_state(struct lzx_stream *lzx) { | ||
2539 | - int i; | ||
2540 | - | ||
2541 | - lzx->R0 = 1; | ||
2542 | - lzx->R1 = 1; | ||
2543 | - lzx->R2 = 1; | ||
2544 | - lzx->header_read = 0; | ||
2545 | - lzx->block_remaining = 0; | ||
2546 | - lzx->block_type = LZX_BLOCKTYPE_INVALID; | ||
2547 | - | ||
2548 | - /* initialise tables to 0 (because deltas will be applied to them) */ | ||
2549 | - for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) lzx->MAINTREE_len[i] = 0; | ||
2550 | - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) lzx->LENGTH_len[i] = 0; | ||
2551 | -} | ||
2552 | - | ||
2553 | -/*-------- main LZX code --------*/ | ||
2554 | - | ||
2555 | -struct lzx_stream *lzx_init(int ofd, | ||
2556 | - int window_bits, | ||
2557 | - int reset_interval, | ||
2558 | - int input_buffer_size, | ||
2559 | - off_t output_length, | ||
2560 | - struct cab_file *file, | ||
2561 | - int (*read_cb)(struct cab_file *, unsigned char *, int)) | ||
2562 | -{ | ||
2563 | - unsigned int window_size = 1 << window_bits; | ||
2564 | - struct lzx_stream *lzx; | ||
2565 | - int i, j; | ||
2566 | - | ||
2567 | - /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ | ||
2568 | - if (window_bits < 15 || window_bits > 21) return NULL; | ||
2569 | - | ||
2570 | - input_buffer_size = (input_buffer_size + 1) & -2; | ||
2571 | - if (!input_buffer_size) return NULL; | ||
2572 | - | ||
2573 | - /* allocate decompression state */ | ||
2574 | - if (!(lzx = cli_calloc(1, sizeof(struct lzx_stream)))) { | ||
2575 | - return NULL; | ||
2576 | - } | ||
2577 | - | ||
2578 | - for (i = 0, j = 0; i < 51; i += 2) { | ||
2579 | - lzx->extra_bits[i] = j; /* 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7... */ | ||
2580 | - if(i < 50) | ||
2581 | - lzx->extra_bits[i+1] = j; | ||
2582 | - if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ | ||
2583 | - } | ||
2584 | - | ||
2585 | - for (i = 0, j = 0; i < 51; i++) { | ||
2586 | - lzx->position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ | ||
2587 | - j += 1 << lzx->extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ | ||
2588 | - } | ||
2589 | - | ||
2590 | - /* allocate decompression window and input buffer */ | ||
2591 | - lzx->window = cli_calloc(1, (size_t) window_size); | ||
2592 | - if(!lzx->window) { | ||
2593 | - free(lzx); | ||
2594 | - return NULL; | ||
2595 | - } | ||
2596 | - | ||
2597 | - lzx->inbuf = cli_calloc(1, (size_t) input_buffer_size); | ||
2598 | - if (!lzx->inbuf) { | ||
2599 | - free(lzx->window); | ||
2600 | - free(lzx); | ||
2601 | - return NULL; | ||
2602 | - } | ||
2603 | - | ||
2604 | - /* initialise decompression state */ | ||
2605 | - lzx->ofd = ofd; | ||
2606 | - lzx->wflag = 1; | ||
2607 | - lzx->offset = 0; | ||
2608 | - lzx->length = output_length; | ||
2609 | - lzx->file = file; | ||
2610 | - lzx->read_cb = read_cb; | ||
2611 | - | ||
2612 | - lzx->inbuf_size = input_buffer_size; | ||
2613 | - lzx->window_size = 1 << window_bits; | ||
2614 | - lzx->window_posn = 0; | ||
2615 | - lzx->frame_posn = 0; | ||
2616 | - lzx->frame = 0; | ||
2617 | - lzx->reset_interval = reset_interval; | ||
2618 | - lzx->intel_filesize = 0; | ||
2619 | - lzx->intel_curpos = 0; | ||
2620 | - | ||
2621 | - /* window bits: 15 16 17 18 19 20 21 | ||
2622 | - * position slots: 30 32 34 36 38 42 50 */ | ||
2623 | - lzx->posn_slots = ((window_bits == 21) ? 50 : | ||
2624 | - ((window_bits == 20) ? 42 : (window_bits << 1))); | ||
2625 | - lzx->intel_started = 0; | ||
2626 | - lzx->input_end = 0; | ||
2627 | - | ||
2628 | - lzx->error = CL_SUCCESS; | ||
2629 | - | ||
2630 | - lzx->i_ptr = lzx->i_end = &lzx->inbuf[0]; | ||
2631 | - lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0]; | ||
2632 | - lzx->bit_buffer = lzx->bits_left = 0; | ||
2633 | - | ||
2634 | - lzx_reset_state(lzx); | ||
2635 | - return lzx; | ||
2636 | -} | ||
2637 | - | ||
2638 | -void lzx_set_output_length(struct lzx_stream *lzx, off_t out_bytes) { | ||
2639 | - if (lzx) lzx->length = out_bytes; | ||
2640 | -} | ||
2641 | - | ||
2642 | -int lzx_decompress(struct lzx_stream *lzx, uint32_t out_bytes) { | ||
2643 | - /* bitstream reading and huffman variables */ | ||
2644 | - register unsigned int bit_buffer; | ||
2645 | - register int bits_left, i=0; | ||
2646 | - register unsigned short sym; | ||
2647 | - unsigned char *i_ptr, *i_end; | ||
2648 | - | ||
2649 | - int match_length, length_footer, extra, verbatim_bits, bytes_todo; | ||
2650 | - int this_run, main_element, aligned_bits, j, ret, warned=0; | ||
2651 | - unsigned char *window, *runsrc, *rundest, buf[12]; | ||
2652 | - unsigned int frame_size=0, end_frame, match_offset, window_posn; | ||
2653 | - unsigned int R0, R1, R2; | ||
2654 | - | ||
2655 | - /* easy answers */ | ||
2656 | - if (!lzx) return CL_ENULLARG; | ||
2657 | - if (lzx->error) return lzx->error; | ||
2658 | - | ||
2659 | - /* flush out any stored-up bytes before we begin */ | ||
2660 | - i = lzx->o_end - lzx->o_ptr; | ||
2661 | - if (((off_t) i > out_bytes) && ((int) out_bytes >= 0)) i = (int) out_bytes; | ||
2662 | - if (i) { | ||
2663 | - if (lzx->wflag && (ret = mspack_write(lzx->ofd, lzx->o_ptr, i, lzx->file)) != CL_SUCCESS) { | ||
2664 | - return lzx->error = ret; | ||
2665 | - } | ||
2666 | - lzx->o_ptr += i; | ||
2667 | - lzx->offset += i; | ||
2668 | - out_bytes -= i; | ||
2669 | - } | ||
2670 | - if (out_bytes == 0) return CL_SUCCESS; | ||
2671 | - | ||
2672 | - /* restore local state */ | ||
2673 | - LZX_RESTORE_BITS; | ||
2674 | - window = lzx->window; | ||
2675 | - window_posn = lzx->window_posn; | ||
2676 | - R0 = lzx->R0; | ||
2677 | - R1 = lzx->R1; | ||
2678 | - R2 = lzx->R2; | ||
2679 | - | ||
2680 | - end_frame = (unsigned int)((lzx->offset + out_bytes) / LZX_FRAME_SIZE) + 1; | ||
2681 | - cli_dbgmsg("lzx_decompress: end frame = %u\n", end_frame); | ||
2682 | - | ||
2683 | - while (lzx->frame < end_frame) { | ||
2684 | - cli_dbgmsg("lzx_decompress: current frame = %u\n", lzx->frame); | ||
2685 | - /* have we reached the reset interval? (if there is one?) */ | ||
2686 | - if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) { | ||
2687 | - if (lzx->block_remaining) { | ||
2688 | - /* this is a file format error, but we need to extract what we can and scan that */ | ||
2689 | - cli_dbgmsg("lzx_decompress: %d bytes remaining at reset interval\n", lzx->block_remaining); | ||
2690 | - if (!warned) { | ||
2691 | - cli_dbgmsg("Detected an invalid reset interval during decompression.\n"); | ||
2692 | - warned++; | ||
2693 | - } | ||
2694 | - if (!lzx->header_read) { | ||
2695 | - /* cannot continue if no header at all */ | ||
2696 | - return lzx->error = CL_EFORMAT; | ||
2697 | - } | ||
2698 | - } else { | ||
2699 | - /* re-read the intel header and reset the huffman lengths */ | ||
2700 | - lzx_reset_state(lzx); | ||
2701 | - } | ||
2702 | - } | ||
2703 | - | ||
2704 | - /* read header if necessary */ | ||
2705 | - if (!lzx->header_read) { | ||
2706 | - /* read 1 bit. if bit=0, intel filesize = 0. | ||
2707 | - * if bit=1, read intel filesize (32 bits) */ | ||
2708 | - j = 0; LZX_READ_BITS(i, 1); if (i) { LZX_READ_BITS(i, 16); LZX_READ_BITS(j, 16); } | ||
2709 | - lzx->intel_filesize = (i << 16) | j; | ||
2710 | - lzx->header_read = 1; | ||
2711 | - } | ||
2712 | - | ||
2713 | - /* calculate size of frame: all frames are 32k except the final frame | ||
2714 | - * which is 32kb or less. this can only be calculated when lzx->length | ||
2715 | - * has been filled in. */ | ||
2716 | - frame_size = LZX_FRAME_SIZE; | ||
2717 | - if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) { | ||
2718 | - frame_size = lzx->length - lzx->offset; | ||
2719 | - } | ||
2720 | - | ||
2721 | - /* decode until one more frame is available */ | ||
2722 | - bytes_todo = lzx->frame_posn + frame_size - window_posn; | ||
2723 | - while (bytes_todo > 0) { | ||
2724 | - /* initialise new block, if one is needed */ | ||
2725 | - if (lzx->block_remaining == 0) { | ||
2726 | - /* realign if previous block was an odd-sized UNCOMPRESSED block */ | ||
2727 | - if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && | ||
2728 | - (lzx->block_length & 1)) | ||
2729 | - { | ||
2730 | - if (i_ptr == i_end) { | ||
2731 | - if (lzx_read_input(lzx)) return lzx->error; | ||
2732 | - i_ptr = lzx->i_ptr; | ||
2733 | - i_end = lzx->i_end; | ||
2734 | - } | ||
2735 | - i_ptr++; | ||
2736 | - } | ||
2737 | - | ||
2738 | - /* read block type (3 bits) and block length (24 bits) */ | ||
2739 | - LZX_READ_BITS(lzx->block_type, 3); | ||
2740 | - LZX_READ_BITS(i, 16); LZX_READ_BITS(j, 8); | ||
2741 | - lzx->block_remaining = lzx->block_length = (i << 8) | j; | ||
2742 | - | ||
2743 | - /* read individual block headers */ | ||
2744 | - switch (lzx->block_type) { | ||
2745 | - case LZX_BLOCKTYPE_ALIGNED: | ||
2746 | - /* read lengths of and build aligned huffman decoding tree */ | ||
2747 | - for (i = 0; i < 8; i++) { LZX_READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; } | ||
2748 | - LZX_BUILD_TABLE(ALIGNED); | ||
2749 | - /* no break -- rest of aligned header is same as verbatim */ | ||
2750 | - case LZX_BLOCKTYPE_VERBATIM: | ||
2751 | - /* read lengths of and build main huffman decoding tree */ | ||
2752 | - LZX_READ_LENGTHS(MAINTREE, 0, 256); | ||
2753 | - LZX_READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3)); | ||
2754 | - LZX_BUILD_TABLE(MAINTREE); | ||
2755 | - /* if the literal 0xE8 is anywhere in the block... */ | ||
2756 | - if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1; | ||
2757 | - /* read lengths of and build lengths huffman decoding tree */ | ||
2758 | - LZX_READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); | ||
2759 | - LZX_BUILD_TABLE(LENGTH); | ||
2760 | - break; | ||
2761 | - | ||
2762 | - case LZX_BLOCKTYPE_UNCOMPRESSED: | ||
2763 | - /* because we can't assume otherwise */ | ||
2764 | - lzx->intel_started = 1; | ||
2765 | - | ||
2766 | - /* read 1-16 (not 0-15) bits to align to bytes */ | ||
2767 | - LZX_ENSURE_BITS(16); | ||
2768 | - if (bits_left > 16) i_ptr -= 2; | ||
2769 | - bits_left = 0; bit_buffer = 0; | ||
2770 | - | ||
2771 | - /* read 12 bytes of stored R0 / R1 / R2 values */ | ||
2772 | - for (rundest = &buf[0], i = 0; i < 12; i++) { | ||
2773 | - if (i_ptr == i_end) { | ||
2774 | - if (lzx_read_input(lzx)) return lzx->error; | ||
2775 | - i_ptr = lzx->i_ptr; | ||
2776 | - i_end = lzx->i_end; | ||
2777 | - } | ||
2778 | - *rundest++ = *i_ptr++; | ||
2779 | - } | ||
2780 | - R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); | ||
2781 | - R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); | ||
2782 | - R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24); | ||
2783 | - break; | ||
2784 | - | ||
2785 | - default: | ||
2786 | - cli_dbgmsg("lzx_decompress: bad block type (0x%x)\n", lzx->block_type); | ||
2787 | - return lzx->error = CL_EFORMAT; | ||
2788 | - } | ||
2789 | - } | ||
2790 | - | ||
2791 | - /* decode more of the block: | ||
2792 | - * run = min(what's available, what's needed) */ | ||
2793 | - this_run = lzx->block_remaining; | ||
2794 | - if (this_run > bytes_todo) this_run = bytes_todo; | ||
2795 | - | ||
2796 | - /* assume we decode exactly this_run bytes, for now */ | ||
2797 | - bytes_todo -= this_run; | ||
2798 | - lzx->block_remaining -= this_run; | ||
2799 | - | ||
2800 | - /* decode at least this_run bytes */ | ||
2801 | - switch (lzx->block_type) { | ||
2802 | - case LZX_BLOCKTYPE_VERBATIM: | ||
2803 | - while (this_run > 0) { | ||
2804 | - LZX_READ_HUFFSYM(MAINTREE, main_element); | ||
2805 | - if (main_element < LZX_NUM_CHARS) { | ||
2806 | - /* literal: 0 to LZX_NUM_CHARS-1 */ | ||
2807 | - window[window_posn++] = main_element; | ||
2808 | - this_run--; | ||
2809 | - } | ||
2810 | - else { | ||
2811 | - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ | ||
2812 | - main_element -= LZX_NUM_CHARS; | ||
2813 | - | ||
2814 | - /* get match length */ | ||
2815 | - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; | ||
2816 | - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { | ||
2817 | - LZX_READ_HUFFSYM(LENGTH, length_footer); | ||
2818 | - match_length += length_footer; | ||
2819 | - } | ||
2820 | - match_length += LZX_MIN_MATCH; | ||
2821 | - | ||
2822 | - /* get match offset */ | ||
2823 | - switch ((match_offset = (main_element >> 3))) { | ||
2824 | - case 0: match_offset = R0; break; | ||
2825 | - case 1: match_offset = R1; R1=R0; R0 = match_offset; break; | ||
2826 | - case 2: match_offset = R2; R2=R0; R0 = match_offset; break; | ||
2827 | - case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break; | ||
2828 | - default: | ||
2829 | - extra = lzx->extra_bits[match_offset]; | ||
2830 | - LZX_READ_BITS(verbatim_bits, extra); | ||
2831 | - match_offset = lzx->position_base[match_offset] - 2 + verbatim_bits; | ||
2832 | - R2 = R1; R1 = R0; R0 = match_offset; | ||
2833 | - } | ||
2834 | - | ||
2835 | - if ((window_posn + match_length) > lzx->window_size) { | ||
2836 | - cli_dbgmsg("lzx_decompress: match ran over window wrap\n"); | ||
2837 | - return lzx->error = CL_EFORMAT; | ||
2838 | - } | ||
2839 | - | ||
2840 | - /* copy match */ | ||
2841 | - rundest = &window[window_posn]; | ||
2842 | - i = match_length; | ||
2843 | - /* does match offset wrap the window? */ | ||
2844 | - if (match_offset > window_posn) { | ||
2845 | - /* j = length from match offset to end of window */ | ||
2846 | - j = match_offset - window_posn; | ||
2847 | - if (j > (int) lzx->window_size) { | ||
2848 | - cli_dbgmsg("lzx_decompress: match offset beyond window boundaries\n"); | ||
2849 | - return lzx->error = CL_EFORMAT; | ||
2850 | - } | ||
2851 | - runsrc = &window[lzx->window_size - j]; | ||
2852 | - if (j < i) { | ||
2853 | - /* if match goes over the window edge, do two copy runs */ | ||
2854 | - i -= j; while (j-- > 0) *rundest++ = *runsrc++; | ||
2855 | - runsrc = window; | ||
2856 | - } | ||
2857 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
2858 | - } | ||
2859 | - else { | ||
2860 | - runsrc = rundest - match_offset; | ||
2861 | - if(i > (int) (lzx->window_size - window_posn)) | ||
2862 | - i = lzx->window_size - window_posn; | ||
2863 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
2864 | - } | ||
2865 | - | ||
2866 | - this_run -= match_length; | ||
2867 | - window_posn += match_length; | ||
2868 | - } | ||
2869 | - } /* while (this_run > 0) */ | ||
2870 | - break; | ||
2871 | - | ||
2872 | - case LZX_BLOCKTYPE_ALIGNED: | ||
2873 | - while (this_run > 0) { | ||
2874 | - LZX_READ_HUFFSYM(MAINTREE, main_element); | ||
2875 | - if (main_element < LZX_NUM_CHARS) { | ||
2876 | - /* literal: 0 to LZX_NUM_CHARS-1 */ | ||
2877 | - window[window_posn++] = main_element; | ||
2878 | - this_run--; | ||
2879 | - } | ||
2880 | - else { | ||
2881 | - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ | ||
2882 | - main_element -= LZX_NUM_CHARS; | ||
2883 | - | ||
2884 | - /* get match length */ | ||
2885 | - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; | ||
2886 | - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { | ||
2887 | - LZX_READ_HUFFSYM(LENGTH, length_footer); | ||
2888 | - match_length += length_footer; | ||
2889 | - } | ||
2890 | - match_length += LZX_MIN_MATCH; | ||
2891 | - | ||
2892 | - /* get match offset */ | ||
2893 | - switch ((match_offset = (main_element >> 3))) { | ||
2894 | - case 0: match_offset = R0; break; | ||
2895 | - case 1: match_offset = R1; R1 = R0; R0 = match_offset; break; | ||
2896 | - case 2: match_offset = R2; R2 = R0; R0 = match_offset; break; | ||
2897 | - default: | ||
2898 | - extra = lzx->extra_bits[match_offset]; | ||
2899 | - match_offset = lzx->position_base[match_offset] - 2; | ||
2900 | - if (extra > 3) { | ||
2901 | - /* verbatim and aligned bits */ | ||
2902 | - extra -= 3; | ||
2903 | - LZX_READ_BITS(verbatim_bits, extra); | ||
2904 | - match_offset += (verbatim_bits << 3); | ||
2905 | - LZX_READ_HUFFSYM(ALIGNED, aligned_bits); | ||
2906 | - match_offset += aligned_bits; | ||
2907 | - } | ||
2908 | - else if (extra == 3) { | ||
2909 | - /* aligned bits only */ | ||
2910 | - LZX_READ_HUFFSYM(ALIGNED, aligned_bits); | ||
2911 | - match_offset += aligned_bits; | ||
2912 | - } | ||
2913 | - else if (extra > 0) { /* extra==1, extra==2 */ | ||
2914 | - /* verbatim bits only */ | ||
2915 | - LZX_READ_BITS(verbatim_bits, extra); | ||
2916 | - match_offset += verbatim_bits; | ||
2917 | - } | ||
2918 | - else /* extra == 0 */ { | ||
2919 | - /* ??? not defined in LZX specification! */ | ||
2920 | - match_offset = 1; | ||
2921 | - } | ||
2922 | - /* update repeated offset LRU queue */ | ||
2923 | - R2 = R1; R1 = R0; R0 = match_offset; | ||
2924 | - } | ||
2925 | - | ||
2926 | - if ((window_posn + match_length) > lzx->window_size) { | ||
2927 | - cli_dbgmsg("lzx_decompress: match ran over window wrap\n"); | ||
2928 | - return lzx->error = CL_EFORMAT; | ||
2929 | - } | ||
2930 | - | ||
2931 | - /* copy match */ | ||
2932 | - rundest = &window[window_posn]; | ||
2933 | - i = match_length; | ||
2934 | - /* does match offset wrap the window? */ | ||
2935 | - if (match_offset > window_posn) { | ||
2936 | - /* j = length from match offset to end of window */ | ||
2937 | - j = match_offset - window_posn; | ||
2938 | - if (j > (int) lzx->window_size) { | ||
2939 | - cli_dbgmsg("lzx_decompress: match offset beyond window boundaries\n"); | ||
2940 | - return lzx->error = CL_EFORMAT; | ||
2941 | - } | ||
2942 | - runsrc = &window[lzx->window_size - j]; | ||
2943 | - if (j < i) { | ||
2944 | - /* if match goes over the window edge, do two copy runs */ | ||
2945 | - i -= j; while (j-- > 0) *rundest++ = *runsrc++; | ||
2946 | - runsrc = window; | ||
2947 | - } | ||
2948 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
2949 | - } | ||
2950 | - else { | ||
2951 | - runsrc = rundest - match_offset; | ||
2952 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
2953 | - } | ||
2954 | - | ||
2955 | - this_run -= match_length; | ||
2956 | - window_posn += match_length; | ||
2957 | - } | ||
2958 | - } /* while (this_run > 0) */ | ||
2959 | - break; | ||
2960 | - | ||
2961 | - case LZX_BLOCKTYPE_UNCOMPRESSED: | ||
2962 | - /* as this_run is limited not to wrap a frame, this also means it | ||
2963 | - * won't wrap the window (as the window is a multiple of 32k) */ | ||
2964 | - rundest = &window[window_posn]; | ||
2965 | - window_posn += this_run; | ||
2966 | - while (this_run > 0) { | ||
2967 | - if ((i = i_end - i_ptr)) { | ||
2968 | - if (i > this_run) i = this_run; | ||
2969 | - memcpy(rundest, i_ptr, (size_t) i); | ||
2970 | - rundest += i; | ||
2971 | - i_ptr += i; | ||
2972 | - this_run -= i; | ||
2973 | - } | ||
2974 | - else { | ||
2975 | - if (lzx_read_input(lzx)) return lzx->error; | ||
2976 | - i_ptr = lzx->i_ptr; | ||
2977 | - i_end = lzx->i_end; | ||
2978 | - } | ||
2979 | - } | ||
2980 | - break; | ||
2981 | - | ||
2982 | - default: | ||
2983 | - return lzx->error = CL_EFORMAT; /* might as well */ | ||
2984 | - } | ||
2985 | - | ||
2986 | - /* did the final match overrun our desired this_run length? */ | ||
2987 | - if (this_run < 0) { | ||
2988 | - if ((unsigned int)(-this_run) > lzx->block_remaining) { | ||
2989 | - cli_dbgmsg("lzx_decompress: overrun went past end of block by %d (%d remaining)\n", -this_run, lzx->block_remaining); | ||
2990 | - return lzx->error = CL_EFORMAT; | ||
2991 | - } | ||
2992 | - lzx->block_remaining -= -this_run; | ||
2993 | - } | ||
2994 | - } /* while (bytes_todo > 0) */ | ||
2995 | - | ||
2996 | - /* streams don't extend over frame boundaries */ | ||
2997 | - if ((window_posn - lzx->frame_posn) != frame_size) { | ||
2998 | - cli_dbgmsg("lzx_decompress: decode beyond output frame limits! %d != %d\n", window_posn - lzx->frame_posn, frame_size); | ||
2999 | - return lzx->error = CL_EFORMAT; | ||
3000 | - } | ||
3001 | - | ||
3002 | - /* re-align input bitstream */ | ||
3003 | - if (bits_left > 0) LZX_ENSURE_BITS(16); | ||
3004 | - if (bits_left & 15) LZX_REMOVE_BITS(bits_left & 15); | ||
3005 | - | ||
3006 | - /* check that we've used all of the previous frame first */ | ||
3007 | - if (lzx->o_ptr != lzx->o_end) { | ||
3008 | - cli_dbgmsg("lzx_decompress: %ld avail bytes, new %d frame\n", lzx->o_end-lzx->o_ptr, frame_size); | ||
3009 | - return lzx->error = CL_EFORMAT; | ||
3010 | - } | ||
3011 | - | ||
3012 | - /* does this intel block _really_ need decoding? */ | ||
3013 | - if (lzx->intel_started && lzx->intel_filesize && | ||
3014 | - (lzx->frame <= 32768) && (frame_size > 10)) | ||
3015 | - { | ||
3016 | - unsigned char *data = &lzx->e8_buf[0]; | ||
3017 | - unsigned char *dataend = &lzx->e8_buf[frame_size - 10]; | ||
3018 | - signed int curpos = lzx->intel_curpos; | ||
3019 | - signed int filesize = lzx->intel_filesize; | ||
3020 | - signed int abs_off, rel_off; | ||
3021 | - | ||
3022 | - /* copy e8 block to the e8 buffer and tweak if needed */ | ||
3023 | - lzx->o_ptr = data; | ||
3024 | - memcpy(data, &lzx->window[lzx->frame_posn], frame_size); | ||
3025 | - | ||
3026 | - while (data < dataend) { | ||
3027 | - if (*data++ != 0xE8) { curpos++; continue; } | ||
3028 | - abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); | ||
3029 | - if ((abs_off >= -curpos) && (abs_off < filesize)) { | ||
3030 | - rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; | ||
3031 | - data[0] = (unsigned char) rel_off; | ||
3032 | - data[1] = (unsigned char) (rel_off >> 8); | ||
3033 | - data[2] = (unsigned char) (rel_off >> 16); | ||
3034 | - data[3] = (unsigned char) (rel_off >> 24); | ||
3035 | - } | ||
3036 | - data += 4; | ||
3037 | - curpos += 5; | ||
3038 | - } | ||
3039 | - lzx->intel_curpos += frame_size; | ||
3040 | - } | ||
3041 | - else { | ||
3042 | - lzx->o_ptr = &lzx->window[lzx->frame_posn]; | ||
3043 | - if (lzx->intel_filesize) lzx->intel_curpos += frame_size; | ||
3044 | - } | ||
3045 | - lzx->o_end = &lzx->o_ptr[frame_size]; | ||
3046 | - | ||
3047 | - /* write a frame */ | ||
3048 | - i = (out_bytes < (off_t)frame_size) ? (unsigned int)out_bytes : frame_size; | ||
3049 | - if (lzx->wflag && (ret = mspack_write(lzx->ofd, lzx->o_ptr, i, lzx->file)) != CL_SUCCESS) { | ||
3050 | - return lzx->error = ret; | ||
3051 | - } | ||
3052 | - lzx->o_ptr += i; | ||
3053 | - lzx->offset += i; | ||
3054 | - out_bytes -= i; | ||
3055 | - | ||
3056 | - /* advance frame start position */ | ||
3057 | - lzx->frame_posn += frame_size; | ||
3058 | - lzx->frame++; | ||
3059 | - | ||
3060 | - /* wrap window / frame position pointers */ | ||
3061 | - if (window_posn == lzx->window_size) window_posn = 0; | ||
3062 | - if (lzx->frame_posn == lzx->window_size) lzx->frame_posn = 0; | ||
3063 | - | ||
3064 | - } /* while (lzx->frame < end_frame) */ | ||
3065 | - | ||
3066 | - if (out_bytes) | ||
3067 | - cli_dbgmsg("lzx_decompress: bytes left to output\n"); | ||
3068 | - | ||
3069 | - /* store local state */ | ||
3070 | - LZX_STORE_BITS; | ||
3071 | - lzx->window_posn = window_posn; | ||
3072 | - lzx->R0 = R0; | ||
3073 | - lzx->R1 = R1; | ||
3074 | - lzx->R2 = R2; | ||
3075 | - | ||
3076 | - return CL_SUCCESS; | ||
3077 | -} | ||
3078 | - | ||
3079 | -void lzx_free(struct lzx_stream *lzx) { | ||
3080 | - if (lzx) { | ||
3081 | - free(lzx->inbuf); | ||
3082 | - free(lzx->window); | ||
3083 | - free(lzx); | ||
3084 | - } | ||
3085 | -} | ||
3086 | - | ||
3087 | -/*************************************************************************** | ||
3088 | - * Quantum decompression implementation | ||
3089 | - *************************************************************************** | ||
3090 | - * The Quantum method was created by David Stafford, adapted by Microsoft | ||
3091 | - * Corporation. | ||
3092 | - * | ||
3093 | - * This decompressor is based on an implementation by Matthew Russotto, used | ||
3094 | - * with permission. | ||
3095 | - * | ||
3096 | - * This decompressor was researched and implemented by Matthew Russotto. It | ||
3097 | - * has since been tidied up by Stuart Caie. More information can be found at | ||
3098 | - * http://www.speakeasy.org/~russotto/quantumcomp.html | ||
3099 | - */ | ||
3100 | - | ||
3101 | -/* Quantum decompressor bitstream reading macros | ||
3102 | - * | ||
3103 | - * QTM_STORE_BITS stores bitstream state in qtm_stream structure | ||
3104 | - * QTM_RESTORE_BITS restores bitstream state from qtm_stream structure | ||
3105 | - * QTM_READ_BITS(var,n) takes N bits from the buffer and puts them in var | ||
3106 | - * QTM_FILL_BUFFER if there is room for another 16 bits, reads another | ||
3107 | - * 16 bits from the input stream. | ||
3108 | - * QTM_PEEK_BITS(n) extracts without removing N bits from the bit buffer | ||
3109 | - * QTM_REMOVE_BITS(n) removes N bits from the bit buffer | ||
3110 | - * | ||
3111 | - * These bit access routines work by using the area beyond the MSB and the | ||
3112 | - * LSB as a free source of zeroes. This avoids having to mask any bits. | ||
3113 | - * So we have to know the bit width of the bitbuffer variable. | ||
3114 | - */ | ||
3115 | - | ||
3116 | -#define QTM_BITBUF_WIDTH (sizeof(unsigned int) * CHAR_BIT) | ||
3117 | - | ||
3118 | -#define QTM_STORE_BITS do { \ | ||
3119 | - qtm->i_ptr = i_ptr; \ | ||
3120 | - qtm->i_end = i_end; \ | ||
3121 | - qtm->bit_buffer = bit_buffer; \ | ||
3122 | - qtm->bits_left = bits_left; \ | ||
3123 | -} while (0) | ||
3124 | - | ||
3125 | -#define QTM_RESTORE_BITS do { \ | ||
3126 | - i_ptr = qtm->i_ptr; \ | ||
3127 | - i_end = qtm->i_end; \ | ||
3128 | - bit_buffer = qtm->bit_buffer; \ | ||
3129 | - bits_left = qtm->bits_left; \ | ||
3130 | -} while (0) | ||
3131 | - | ||
3132 | -/* adds 16 bits to bit buffer, if there's space for the new bits */ | ||
3133 | -#define QTM_FILL_BUFFER do { \ | ||
3134 | - if (bits_left <= (QTM_BITBUF_WIDTH - 16)) { \ | ||
3135 | - if (i_ptr >= i_end) { \ | ||
3136 | - if (qtm_read_input(qtm)) return qtm->error; \ | ||
3137 | - i_ptr = qtm->i_ptr; \ | ||
3138 | - i_end = qtm->i_end; \ | ||
3139 | - } \ | ||
3140 | - bit_buffer |= ((i_ptr[0] << 8) | i_ptr[1]) \ | ||
3141 | - << (QTM_BITBUF_WIDTH - 16 - bits_left); \ | ||
3142 | - bits_left += 16; \ | ||
3143 | - i_ptr += 2; \ | ||
3144 | - } \ | ||
3145 | -} while (0) | ||
3146 | - | ||
3147 | -#define QTM_PEEK_BITS(n) (bit_buffer >> (QTM_BITBUF_WIDTH - (n))) | ||
3148 | -#define QTM_REMOVE_BITS(n) ((bit_buffer <<= (n)), (bits_left -= (n))) | ||
3149 | - | ||
3150 | -#define QTM_READ_BITS(val, bits) do { \ | ||
3151 | - (val) = 0; \ | ||
3152 | - for (bits_needed = (bits); bits_needed > 0; bits_needed -= bit_run) { \ | ||
3153 | - QTM_FILL_BUFFER; \ | ||
3154 | - bit_run = (bits_left < bits_needed) ? bits_left : bits_needed; \ | ||
3155 | - (val) = ((val) << bit_run) | QTM_PEEK_BITS(bit_run); \ | ||
3156 | - QTM_REMOVE_BITS(bit_run); \ | ||
3157 | - } \ | ||
3158 | -} while (0) | ||
3159 | - | ||
3160 | -static int qtm_read_input(struct qtm_stream *qtm) { | ||
3161 | - int nread = qtm->read_cb(qtm->file, &qtm->inbuf[0], (int)qtm->inbuf_size); | ||
3162 | - if (nread < 0) { | ||
3163 | - if (qtm->file->error == CL_BREAK) | ||
3164 | - return qtm->error = CL_BREAK; | ||
3165 | - else | ||
3166 | - return qtm->error = CL_EFORMAT; | ||
3167 | - } | ||
3168 | - | ||
3169 | - if (nread == 0) { | ||
3170 | - if (qtm->input_end) { | ||
3171 | - cli_dbgmsg("qtm_read_input: out of input bytes\n"); | ||
3172 | - return qtm->error = CL_EREAD; | ||
3173 | - } | ||
3174 | - else { | ||
3175 | - nread = 2; | ||
3176 | - qtm->inbuf[0] = qtm->inbuf[1] = 0; | ||
3177 | - qtm->input_end = 1; | ||
3178 | - } | ||
3179 | - } | ||
3180 | - | ||
3181 | - qtm->i_ptr = &qtm->inbuf[0]; | ||
3182 | - qtm->i_end = &qtm->inbuf[nread]; | ||
3183 | - return CL_SUCCESS; | ||
3184 | -} | ||
3185 | - | ||
3186 | -/* Arithmetic decoder: | ||
3187 | - * | ||
3188 | - * QTM_GET_SYMBOL(model, var) fetches the next symbol from the stated model | ||
3189 | - * and puts it in var. | ||
3190 | - * | ||
3191 | - * If necessary, qtm_update_model() is called. | ||
3192 | - */ | ||
3193 | -#define QTM_GET_SYMBOL(model, var) do { \ | ||
3194 | - range = ((H - L) & 0xFFFF) + 1; \ | ||
3195 | - symf = ((((C - L + 1) * model.syms[0].cumfreq)-1) / range) & 0xFFFF; \ | ||
3196 | - \ | ||
3197 | - for (i = 1; i < model.entries; i++) { \ | ||
3198 | - if (model.syms[i].cumfreq <= symf) break; \ | ||
3199 | - } \ | ||
3200 | - (var) = model.syms[i-1].sym; \ | ||
3201 | - \ | ||
3202 | - range = (H - L) + 1; \ | ||
3203 | - symf = model.syms[0].cumfreq; \ | ||
3204 | - H = L + ((model.syms[i-1].cumfreq * range) / symf) - 1; \ | ||
3205 | - L = L + ((model.syms[i].cumfreq * range) / symf); \ | ||
3206 | - \ | ||
3207 | - do { model.syms[--i].cumfreq += 8; } while (i > 0); \ | ||
3208 | - if (model.syms[0].cumfreq > 3800) qtm_update_model(&model); \ | ||
3209 | - \ | ||
3210 | - while (1) { \ | ||
3211 | - if ((L & 0x8000) != (H & 0x8000)) { \ | ||
3212 | - if ((L & 0x4000) && !(H & 0x4000)) { \ | ||
3213 | - /* underflow case */ \ | ||
3214 | - C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \ | ||
3215 | - } \ | ||
3216 | - else break; \ | ||
3217 | - } \ | ||
3218 | - L <<= 1; H = (H << 1) | 1; \ | ||
3219 | - QTM_FILL_BUFFER; \ | ||
3220 | - C = (C << 1) | QTM_PEEK_BITS(1); \ | ||
3221 | - QTM_REMOVE_BITS(1); \ | ||
3222 | - } \ | ||
3223 | -} while (0) | ||
3224 | - | ||
3225 | -static void qtm_update_model(struct qtm_model *model) { | ||
3226 | - struct qtm_modelsym tmp; | ||
3227 | - int i, j; | ||
3228 | - | ||
3229 | - if (--model->shiftsleft) { | ||
3230 | - for (i = model->entries - 1; i >= 0; i--) { | ||
3231 | - /* -1, not -2; the 0 entry saves this */ | ||
3232 | - model->syms[i].cumfreq >>= 1; | ||
3233 | - if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) { | ||
3234 | - model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1; | ||
3235 | - } | ||
3236 | - } | ||
3237 | - } | ||
3238 | - else { | ||
3239 | - model->shiftsleft = 50; | ||
3240 | - for (i = 0; i < model->entries; i++) { | ||
3241 | - /* no -1, want to include the 0 entry */ | ||
3242 | - /* this converts cumfreqs into frequencies, then shifts right */ | ||
3243 | - model->syms[i].cumfreq -= model->syms[i+1].cumfreq; | ||
3244 | - model->syms[i].cumfreq++; /* avoid losing things entirely */ | ||
3245 | - model->syms[i].cumfreq >>= 1; | ||
3246 | - } | ||
3247 | - | ||
3248 | - /* now sort by frequencies, decreasing order -- this must be an | ||
3249 | - * inplace selection sort, or a sort with the same (in)stability | ||
3250 | - * characteristics */ | ||
3251 | - for (i = 0; i < model->entries - 1; i++) { | ||
3252 | - for (j = i + 1; j < model->entries; j++) { | ||
3253 | - if (model->syms[i].cumfreq < model->syms[j].cumfreq) { | ||
3254 | - tmp = model->syms[i]; | ||
3255 | - model->syms[i] = model->syms[j]; | ||
3256 | - model->syms[j] = tmp; | ||
3257 | - } | ||
3258 | - } | ||
3259 | - } | ||
3260 | - | ||
3261 | - /* then convert frequencies back to cumfreq */ | ||
3262 | - for (i = model->entries - 1; i >= 0; i--) { | ||
3263 | - model->syms[i].cumfreq += model->syms[i+1].cumfreq; | ||
3264 | - } | ||
3265 | - } | ||
3266 | -} | ||
3267 | - | ||
3268 | -/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */ | ||
3269 | -static void qtm_init_model(struct qtm_model *model, | ||
3270 | - struct qtm_modelsym *syms, int start, int len) | ||
3271 | -{ | ||
3272 | - int i; | ||
3273 | - | ||
3274 | - model->shiftsleft = 4; | ||
3275 | - model->entries = len; | ||
3276 | - model->syms = syms; | ||
3277 | - | ||
3278 | - for (i = 0; i <= len; i++) { | ||
3279 | - syms[i].sym = start + i; /* actual symbol */ | ||
3280 | - syms[i].cumfreq = len - i; /* current frequency of that symbol */ | ||
3281 | - } | ||
3282 | -} | ||
3283 | - | ||
3284 | - | ||
3285 | -/*-------- main Quantum code --------*/ | ||
3286 | - | ||
3287 | -struct qtm_stream *qtm_init(int ofd, | ||
3288 | - int window_bits, int input_buffer_size, | ||
3289 | - struct cab_file *file, | ||
3290 | - int (*read_cb)(struct cab_file *, unsigned char *, int)) | ||
3291 | -{ | ||
3292 | - unsigned int window_size = 1 << window_bits; | ||
3293 | - struct qtm_stream *qtm; | ||
3294 | - unsigned offset; | ||
3295 | - int i; | ||
3296 | - | ||
3297 | - /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ | ||
3298 | - | ||
3299 | - /* tk: temporary fix: only process 32KB+ window sizes */ | ||
3300 | - if (window_bits < 15 || window_bits > 21) return NULL; | ||
3301 | - | ||
3302 | - input_buffer_size = (input_buffer_size + 1) & -2; | ||
3303 | - if (input_buffer_size < 2) return NULL; | ||
3304 | - | ||
3305 | - /* allocate decompression state */ | ||
3306 | - if (!(qtm = cli_calloc(1, sizeof(struct qtm_stream)))) { | ||
3307 | - return NULL; | ||
3308 | - } | ||
3309 | - | ||
3310 | - for (i = 0, offset = 0; i < 42; i++) { | ||
3311 | - qtm->position_base[i] = offset; | ||
3312 | - qtm->extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1; | ||
3313 | - offset += 1 << qtm->extra_bits[i]; | ||
3314 | - } | ||
3315 | - | ||
3316 | - for (i = 0, offset = 0; i < 26; i++) { | ||
3317 | - qtm->length_base[i] = offset; | ||
3318 | - qtm->length_extra[i] = (i < 2 ? 0 : i - 2) >> 2; | ||
3319 | - offset += 1 << qtm->length_extra[i]; | ||
3320 | - } | ||
3321 | - qtm->length_base[26] = 254; qtm->length_extra[26] = 0; | ||
3322 | - | ||
3323 | - /* allocate decompression window and input buffer */ | ||
3324 | - qtm->window = cli_malloc((size_t) window_size); | ||
3325 | - if (!qtm->window) { | ||
3326 | - cli_errmsg("qtm_init: Unable to allocate decompression window\n"); | ||
3327 | - free(qtm); | ||
3328 | - return NULL; | ||
3329 | - } | ||
3330 | - | ||
3331 | - qtm->inbuf = cli_malloc((size_t) input_buffer_size); | ||
3332 | - if (!qtm->inbuf) { | ||
3333 | - cli_errmsg("qtm_init: Unable to allocate input buffer\n"); | ||
3334 | - free(qtm->window); | ||
3335 | - free(qtm); | ||
3336 | - return NULL; | ||
3337 | - } | ||
3338 | - | ||
3339 | - /* initialise decompression state */ | ||
3340 | - qtm->ofd = ofd; | ||
3341 | - qtm->wflag = 1; | ||
3342 | - qtm->inbuf_size = input_buffer_size; | ||
3343 | - qtm->window_size = window_size; | ||
3344 | - qtm->window_posn = 0; | ||
3345 | - qtm->frame_start = 0; | ||
3346 | - qtm->header_read = 0; | ||
3347 | - qtm->error = CL_SUCCESS; | ||
3348 | - | ||
3349 | - qtm->i_ptr = qtm->i_end = &qtm->inbuf[0]; | ||
3350 | - qtm->o_ptr = qtm->o_end = &qtm->window[0]; | ||
3351 | - qtm->bits_left = 0; | ||
3352 | - qtm->bit_buffer = 0; | ||
3353 | - | ||
3354 | - /* initialise arithmetic coding models | ||
3355 | - * - model 4 depends on window size, ranges from 20 to 24 | ||
3356 | - * - model 5 depends on window size, ranges from 20 to 36 | ||
3357 | - * - model 6pos depends on window size, ranges from 20 to 42 | ||
3358 | - */ | ||
3359 | - i = window_bits * 2; | ||
3360 | - qtm_init_model(&qtm->model0, &qtm->m0sym[0], 0, 64); | ||
3361 | - qtm_init_model(&qtm->model1, &qtm->m1sym[0], 64, 64); | ||
3362 | - qtm_init_model(&qtm->model2, &qtm->m2sym[0], 128, 64); | ||
3363 | - qtm_init_model(&qtm->model3, &qtm->m3sym[0], 192, 64); | ||
3364 | - qtm_init_model(&qtm->model4, &qtm->m4sym[0], 0, (i > 24) ? 24 : i); | ||
3365 | - qtm_init_model(&qtm->model5, &qtm->m5sym[0], 0, (i > 36) ? 36 : i); | ||
3366 | - qtm_init_model(&qtm->model6, &qtm->m6sym[0], 0, i); | ||
3367 | - qtm_init_model(&qtm->model6len, &qtm->m6lsym[0], 0, 27); | ||
3368 | - qtm_init_model(&qtm->model7, &qtm->m7sym[0], 0, 7); | ||
3369 | - | ||
3370 | - qtm->file = file; | ||
3371 | - qtm->read_cb = read_cb; | ||
3372 | - | ||
3373 | - /* all ok */ | ||
3374 | - return qtm; | ||
3375 | -} | ||
3376 | - | ||
3377 | -int qtm_decompress(struct qtm_stream *qtm, uint32_t out_bytes) { | ||
3378 | - unsigned int frame_start, frame_end, window_posn, match_offset, range; | ||
3379 | - unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest; | ||
3380 | - int i, j, selector, extra, sym, match_length, ret; | ||
3381 | - unsigned short H, L, C, symf; | ||
3382 | - | ||
3383 | - register unsigned int bit_buffer; | ||
3384 | - register unsigned char bits_left; | ||
3385 | - unsigned char bits_needed, bit_run; | ||
3386 | - | ||
3387 | - /* easy answers */ | ||
3388 | - if (!qtm) return CL_ENULLARG; | ||
3389 | - if (qtm->error) return qtm->error; | ||
3390 | - | ||
3391 | - /* flush out any stored-up bytes before we begin */ | ||
3392 | - i = qtm->o_end - qtm->o_ptr; | ||
3393 | - if (((off_t) i > out_bytes) && ((int) out_bytes >= 0)) i = (int) out_bytes; | ||
3394 | - if (i) { | ||
3395 | - if (qtm->wflag && (ret = mspack_write(qtm->ofd, qtm->o_ptr, i, qtm->file)) != CL_SUCCESS) { | ||
3396 | - return qtm->error = ret; | ||
3397 | - } | ||
3398 | - qtm->o_ptr += i; | ||
3399 | - out_bytes -= i; | ||
3400 | - } | ||
3401 | - if (out_bytes == 0) return CL_SUCCESS; | ||
3402 | - | ||
3403 | - /* restore local state */ | ||
3404 | - QTM_RESTORE_BITS; | ||
3405 | - window = qtm->window; | ||
3406 | - window_posn = qtm->window_posn; | ||
3407 | - frame_start = qtm->frame_start; | ||
3408 | - H = qtm->H; | ||
3409 | - L = qtm->L; | ||
3410 | - C = qtm->C; | ||
3411 | - | ||
3412 | - /* while we do not have enough decoded bytes in reserve: */ | ||
3413 | - while ((qtm->o_end - qtm->o_ptr) < out_bytes) { | ||
3414 | - | ||
3415 | - /* read header if necessary. Initialises H, L and C */ | ||
3416 | - if (!qtm->header_read) { | ||
3417 | - H = 0xFFFF; L = 0; QTM_READ_BITS(C, 16); | ||
3418 | - qtm->header_read = 1; | ||
3419 | - } | ||
3420 | - | ||
3421 | - /* decode more, at most up to to frame boundary */ | ||
3422 | - frame_end = window_posn + (out_bytes - (qtm->o_end - qtm->o_ptr)); | ||
3423 | - if ((frame_start + QTM_FRAME_SIZE) < frame_end) { | ||
3424 | - frame_end = frame_start + QTM_FRAME_SIZE; | ||
3425 | - } | ||
3426 | - if (frame_end < window_posn) { | ||
3427 | - cli_dbgmsg("qtm_decompress: window position beyond end of frame\n"); | ||
3428 | - return qtm->error = CL_EFORMAT; | ||
3429 | - } | ||
3430 | - | ||
3431 | - while (window_posn < frame_end) { | ||
3432 | - QTM_GET_SYMBOL(qtm->model7, selector); | ||
3433 | - if (selector < 4) { | ||
3434 | - struct qtm_model *mdl = (selector == 0) ? &qtm->model0 : | ||
3435 | - ((selector == 1) ? &qtm->model1 : | ||
3436 | - ((selector == 2) ? &qtm->model2 : | ||
3437 | - &qtm->model3)); | ||
3438 | - QTM_GET_SYMBOL((*mdl), sym); | ||
3439 | - window[window_posn++] = sym; | ||
3440 | - } | ||
3441 | - else { | ||
3442 | - switch (selector) { | ||
3443 | - case 4: /* selector 4 = fixed length match (3 bytes) */ | ||
3444 | - QTM_GET_SYMBOL(qtm->model4, sym); | ||
3445 | - QTM_READ_BITS(extra, qtm->extra_bits[sym]); | ||
3446 | - match_offset = qtm->position_base[sym] + extra + 1; | ||
3447 | - match_length = 3; | ||
3448 | - break; | ||
3449 | - | ||
3450 | - case 5: /* selector 5 = fixed length match (4 bytes) */ | ||
3451 | - QTM_GET_SYMBOL(qtm->model5, sym); | ||
3452 | - QTM_READ_BITS(extra, qtm->extra_bits[sym]); | ||
3453 | - match_offset = qtm->position_base[sym] + extra + 1; | ||
3454 | - match_length = 4; | ||
3455 | - break; | ||
3456 | - | ||
3457 | - case 6: /* selector 6 = variable length match */ | ||
3458 | - QTM_GET_SYMBOL(qtm->model6len, sym); | ||
3459 | - QTM_READ_BITS(extra, qtm->length_extra[sym]); | ||
3460 | - match_length = qtm->length_base[sym] + extra + 5; | ||
3461 | - | ||
3462 | - QTM_GET_SYMBOL(qtm->model6, sym); | ||
3463 | - QTM_READ_BITS(extra, qtm->extra_bits[sym]); | ||
3464 | - match_offset = qtm->position_base[sym] + extra + 1; | ||
3465 | - break; | ||
3466 | - | ||
3467 | - default: | ||
3468 | - /* should be impossible, model7 can only return 0-6 */ | ||
3469 | - return qtm->error = CL_EFORMAT; | ||
3470 | - } | ||
3471 | - | ||
3472 | - if (window_posn + match_length > qtm->window_size) { | ||
3473 | - cli_dbgmsg("qtm_decompress: match ran over window wrap\n"); | ||
3474 | - return qtm->error = CL_EFORMAT; | ||
3475 | - } | ||
3476 | - | ||
3477 | - rundest = &window[window_posn]; | ||
3478 | - i = match_length; | ||
3479 | - /* does match offset wrap the window? */ | ||
3480 | - if (match_offset > window_posn) { | ||
3481 | - /* j = length from match offset to end of window */ | ||
3482 | - j = match_offset - window_posn; | ||
3483 | - if (j > (int) qtm->window_size) { | ||
3484 | - cli_dbgmsg("qtm_decompress: match offset beyond window boundaries\n"); | ||
3485 | - return qtm->error = CL_EFORMAT; | ||
3486 | - } | ||
3487 | - runsrc = &window[qtm->window_size - j]; | ||
3488 | - if (j < i) { | ||
3489 | - /* if match goes over the window edge, do two copy runs */ | ||
3490 | - i -= j; while (j-- > 0) *rundest++ = *runsrc++; | ||
3491 | - runsrc = window; | ||
3492 | - } | ||
3493 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
3494 | - } | ||
3495 | - else { | ||
3496 | - runsrc = rundest - match_offset; | ||
3497 | - if(i > (int) (qtm->window_size - window_posn)) | ||
3498 | - i = qtm->window_size - window_posn; | ||
3499 | - while (i-- > 0) *rundest++ = *runsrc++; | ||
3500 | - } | ||
3501 | - window_posn += match_length; | ||
3502 | - } | ||
3503 | - } /* while (window_posn < frame_end) */ | ||
3504 | - | ||
3505 | - qtm->o_end = &window[window_posn]; | ||
3506 | - | ||
3507 | - /* another frame completed? */ | ||
3508 | - if ((window_posn - frame_start) >= QTM_FRAME_SIZE) { | ||
3509 | - if ((window_posn - frame_start) != QTM_FRAME_SIZE) { | ||
3510 | - cli_dbgmsg("qtm_decompress: overshot frame alignment\n"); | ||
3511 | - return qtm->error = CL_EFORMAT; | ||
3512 | - } | ||
3513 | - | ||
3514 | - /* re-align input */ | ||
3515 | - if (bits_left & 7) QTM_REMOVE_BITS(bits_left & 7); | ||
3516 | - do { QTM_READ_BITS(i, 8); } while (i != 0xFF); | ||
3517 | - qtm->header_read = 0; | ||
3518 | - | ||
3519 | - /* window wrap? */ | ||
3520 | - if (window_posn == qtm->window_size) { | ||
3521 | - /* flush all currently stored data */ | ||
3522 | - i = (qtm->o_end - qtm->o_ptr); | ||
3523 | - if(i <= 0) | ||
3524 | - break; | ||
3525 | - if (qtm->wflag && (ret = mspack_write(qtm->ofd, qtm->o_ptr, i, qtm->file)) != CL_SUCCESS) { | ||
3526 | - return qtm->error = ret; | ||
3527 | - } | ||
3528 | - out_bytes -= i; | ||
3529 | - qtm->o_ptr = &window[0]; | ||
3530 | - qtm->o_end = &window[0]; | ||
3531 | - window_posn = 0; | ||
3532 | - } | ||
3533 | - | ||
3534 | - frame_start = window_posn; | ||
3535 | - } | ||
3536 | - | ||
3537 | - } /* while (more bytes needed) */ | ||
3538 | - | ||
3539 | - if (out_bytes > 0) { | ||
3540 | - i = (int) out_bytes; | ||
3541 | - if (qtm->wflag && (ret = mspack_write(qtm->ofd, qtm->o_ptr, i, qtm->file)) != CL_SUCCESS) { | ||
3542 | - return qtm->error = ret; | ||
3543 | - } | ||
3544 | - qtm->o_ptr += i; | ||
3545 | - } | ||
3546 | - | ||
3547 | - /* store local state */ | ||
3548 | - QTM_STORE_BITS; | ||
3549 | - qtm->window_posn = window_posn; | ||
3550 | - qtm->frame_start = frame_start; | ||
3551 | - qtm->H = H; | ||
3552 | - qtm->L = L; | ||
3553 | - qtm->C = C; | ||
3554 | - | ||
3555 | - return CL_SUCCESS; | ||
3556 | -} | ||
3557 | - | ||
3558 | -void qtm_free(struct qtm_stream *qtm) { | ||
3559 | - if (qtm) { | ||
3560 | - free(qtm->window); | ||
3561 | - free(qtm->inbuf); | ||
3562 | - free(qtm); | ||
3563 | - } | ||
3564 | -} | ||
3565 | diff --git a/libclamav/mspack.h b/libclamav/mspack.h | ||
3566 | deleted file mode 100644 | ||
3567 | index 0ed472caeea3..000000000000 | ||
3568 | --- a/libclamav/mspack.h | ||
3569 | +++ /dev/null | ||
3570 | @@ -1,294 +0,0 @@ | ||
3571 | -/* | ||
3572 | - * This file includes code from libmspack adapted for libclamav by | ||
3573 | - * tkojm@clamav.net | ||
3574 | - * | ||
3575 | - * Copyright (C) 2003-2004 Stuart Caie | ||
3576 | - * | ||
3577 | - * This library is free software; you can redistribute it and/or | ||
3578 | - * modify it under the terms of the GNU Lesser General Public | ||
3579 | - * License version 2.1 as published by the Free Software Foundation. | ||
3580 | - * | ||
3581 | - * This library is distributed in the hope that it will be useful, | ||
3582 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3583 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
3584 | - * Lesser General Public License for more details. | ||
3585 | - * | ||
3586 | - * You should have received a copy of the GNU Lesser General Public | ||
3587 | - * License along with this library; if not, write to the Free Software | ||
3588 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | ||
3589 | - * USA | ||
3590 | - */ | ||
3591 | - | ||
3592 | -#ifndef __MSPACK_H | ||
3593 | -#define __MSPACK_H | ||
3594 | - | ||
3595 | -#include <sys/types.h> | ||
3596 | -#include "cab.h" | ||
3597 | - | ||
3598 | - | ||
3599 | -/*************************************************************************** | ||
3600 | - * MS-ZIP decompression definitions * | ||
3601 | - ***************************************************************************/ | ||
3602 | - | ||
3603 | -#define MSZIP_FRAME_SIZE (32768) /* size of LZ history window */ | ||
3604 | -#define MSZIP_MAX_HUFFBITS (16) /* maximum huffman code length */ | ||
3605 | -#define MSZIP_LITERAL_MAXSYMBOLS (288) /* literal/length huffman tree */ | ||
3606 | -#define MSZIP_LITERAL_TABLEBITS (9) | ||
3607 | -#define MSZIP_DISTANCE_MAXSYMBOLS (32) /* distance huffman tree */ | ||
3608 | -#define MSZIP_DISTANCE_TABLEBITS (6) | ||
3609 | - | ||
3610 | -/* if there are less direct lookup entries than symbols, the longer | ||
3611 | - * code pointers will be <= maxsymbols. This must not happen, or we | ||
3612 | - * will decode entries badly */ | ||
3613 | -#if (1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2) | ||
3614 | -# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4) | ||
3615 | -#else | ||
3616 | -# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \ | ||
3617 | - (MSZIP_LITERAL_MAXSYMBOLS * 2)) | ||
3618 | -#endif | ||
3619 | - | ||
3620 | -#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2) | ||
3621 | -# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4) | ||
3622 | -#else | ||
3623 | -# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \ | ||
3624 | - (MSZIP_DISTANCE_MAXSYMBOLS * 2)) | ||
3625 | -#endif | ||
3626 | - | ||
3627 | -struct mszip_stream { | ||
3628 | - int ofd; /* output file descriptor */ | ||
3629 | - | ||
3630 | - /* inflate() will call this whenever the window should be emptied. */ | ||
3631 | - int (*flush_window)(struct mszip_stream *, unsigned int); | ||
3632 | - | ||
3633 | - int error, repair_mode, bytes_output, input_end; | ||
3634 | - | ||
3635 | - /* I/O buffering */ | ||
3636 | - unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end; | ||
3637 | - unsigned int bit_buffer, bits_left, inbuf_size; | ||
3638 | - | ||
3639 | - unsigned int window_posn; /* offset within window */ | ||
3640 | - | ||
3641 | - /* huffman code lengths */ | ||
3642 | - unsigned char LITERAL_len[MSZIP_LITERAL_MAXSYMBOLS]; | ||
3643 | - unsigned char DISTANCE_len[MSZIP_DISTANCE_MAXSYMBOLS]; | ||
3644 | - | ||
3645 | - /* huffman decoding tables */ | ||
3646 | - unsigned short LITERAL_table [MSZIP_LITERAL_TABLESIZE]; | ||
3647 | - unsigned short DISTANCE_table[MSZIP_DISTANCE_TABLESIZE]; | ||
3648 | - | ||
3649 | - /* 32kb history window */ | ||
3650 | - unsigned char window[MSZIP_FRAME_SIZE]; | ||
3651 | - | ||
3652 | - /* cabinet related stuff */ | ||
3653 | - struct cab_file *file; | ||
3654 | - int (*read_cb)(struct cab_file *, unsigned char *, int); | ||
3655 | - | ||
3656 | - unsigned char wflag; /* write flag */ | ||
3657 | - unsigned int last; /* prior end of content buffer */ | ||
3658 | - | ||
3659 | -}; | ||
3660 | - | ||
3661 | -struct mszip_stream *mszip_init(int ofd, | ||
3662 | - int input_buffer_size, | ||
3663 | - int repair_mode, | ||
3664 | - struct cab_file *file, | ||
3665 | - int (*read_cb)(struct cab_file *, unsigned char *, int)); | ||
3666 | - | ||
3667 | -extern int mszip_decompress(struct mszip_stream *zip, uint32_t out_bytes); | ||
3668 | - | ||
3669 | -void mszip_free(struct mszip_stream *zip); | ||
3670 | - | ||
3671 | - | ||
3672 | -/*************************************************************************** | ||
3673 | - * Quantum decompression definitions * | ||
3674 | - ***************************************************************************/ | ||
3675 | - | ||
3676 | -/* Quantum compression / decompression definitions */ | ||
3677 | - | ||
3678 | -#define QTM_FRAME_SIZE (32768) | ||
3679 | - | ||
3680 | -struct qtm_modelsym { | ||
3681 | - unsigned short sym, cumfreq; | ||
3682 | -}; | ||
3683 | - | ||
3684 | -struct qtm_model { | ||
3685 | - int shiftsleft, entries; | ||
3686 | - struct qtm_modelsym *syms; | ||
3687 | -}; | ||
3688 | - | ||
3689 | -struct qtm_stream { | ||
3690 | - int ofd; /* output file descriptor */ | ||
3691 | - | ||
3692 | - unsigned char *window; /* decoding window */ | ||
3693 | - unsigned int window_size; /* window size */ | ||
3694 | - unsigned int window_posn; /* decompression offset within window */ | ||
3695 | - unsigned int frame_start; /* start of current frame within window */ | ||
3696 | - | ||
3697 | - unsigned short H, L, C; /* high/low/current: arith coding state */ | ||
3698 | - unsigned char header_read; /* have we started decoding a new frame? */ | ||
3699 | - unsigned char wflag; /* write flag */ | ||
3700 | - | ||
3701 | - int error, input_end; | ||
3702 | - | ||
3703 | - /* data tables */ | ||
3704 | - unsigned int position_base[42]; | ||
3705 | - unsigned char extra_bits[42], length_base[27], length_extra[27]; | ||
3706 | - | ||
3707 | - /* four literal models, each representing 64 symbols | ||
3708 | - * model0 for literals from 0 to 63 (selector = 0) | ||
3709 | - * model1 for literals from 64 to 127 (selector = 1) | ||
3710 | - * model2 for literals from 128 to 191 (selector = 2) | ||
3711 | - * model3 for literals from 129 to 255 (selector = 3) */ | ||
3712 | - struct qtm_model model0, model1, model2, model3; | ||
3713 | - | ||
3714 | - /* three match models. | ||
3715 | - * model4 for match with fixed length of 3 bytes | ||
3716 | - * model5 for match with fixed length of 4 bytes | ||
3717 | - * model6 for variable length match, encoded with model6len model */ | ||
3718 | - struct qtm_model model4, model5, model6, model6len; | ||
3719 | - | ||
3720 | - /* selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6) */ | ||
3721 | - struct qtm_model model7; | ||
3722 | - | ||
3723 | - /* symbol arrays for all models */ | ||
3724 | - struct qtm_modelsym m0sym[64 + 1]; | ||
3725 | - struct qtm_modelsym m1sym[64 + 1]; | ||
3726 | - struct qtm_modelsym m2sym[64 + 1]; | ||
3727 | - struct qtm_modelsym m3sym[64 + 1]; | ||
3728 | - struct qtm_modelsym m4sym[24 + 1]; | ||
3729 | - struct qtm_modelsym m5sym[36 + 1]; | ||
3730 | - struct qtm_modelsym m6sym[42 + 1], m6lsym[27 + 1]; | ||
3731 | - struct qtm_modelsym m7sym[7 + 1]; | ||
3732 | - | ||
3733 | - /* I/O buffers - 1*/ | ||
3734 | - unsigned int bit_buffer; | ||
3735 | - | ||
3736 | - /* cabinet related stuff */ | ||
3737 | - struct cab_file *file; | ||
3738 | - int (*read_cb)(struct cab_file *, unsigned char *, int); | ||
3739 | - | ||
3740 | - /* I/O buffers - 2*/ | ||
3741 | - unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end; | ||
3742 | - unsigned int inbuf_size; | ||
3743 | - unsigned char bits_left; | ||
3744 | - | ||
3745 | -}; | ||
3746 | - | ||
3747 | -extern struct qtm_stream *qtm_init(int ofd, | ||
3748 | - int window_bits, | ||
3749 | - int input_buffer_size, | ||
3750 | - struct cab_file *file, | ||
3751 | - int (*read_cb)(struct cab_file *, unsigned char *, int)); | ||
3752 | - | ||
3753 | -extern int qtm_decompress(struct qtm_stream *qtm, uint32_t out_bytes); | ||
3754 | - | ||
3755 | -void qtm_free(struct qtm_stream *qtm); | ||
3756 | - | ||
3757 | -/*************************************************************************** | ||
3758 | - * LZX decompression definitions * | ||
3759 | - ***************************************************************************/ | ||
3760 | - | ||
3761 | -/* some constants defined by the LZX specification */ | ||
3762 | -#define LZX_MIN_MATCH (2) | ||
3763 | -#define LZX_MAX_MATCH (257) | ||
3764 | -#define LZX_NUM_CHARS (256) | ||
3765 | -#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */ | ||
3766 | -#define LZX_BLOCKTYPE_VERBATIM (1) | ||
3767 | -#define LZX_BLOCKTYPE_ALIGNED (2) | ||
3768 | -#define LZX_BLOCKTYPE_UNCOMPRESSED (3) | ||
3769 | -#define LZX_PRETREE_NUM_ELEMENTS (20) | ||
3770 | -#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */ | ||
3771 | -#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */ | ||
3772 | -#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */ | ||
3773 | - | ||
3774 | -/* LZX huffman defines: tweak tablebits as desired */ | ||
3775 | -#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) | ||
3776 | -#define LZX_PRETREE_TABLEBITS (6) | ||
3777 | -#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) | ||
3778 | -#define LZX_MAINTREE_TABLEBITS (12) | ||
3779 | -#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) | ||
3780 | -#define LZX_LENGTH_TABLEBITS (12) | ||
3781 | -#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS) | ||
3782 | -#define LZX_ALIGNED_TABLEBITS (7) | ||
3783 | -#define LZX_LENTABLE_SAFETY (64) /* table decoding overruns are allowed */ | ||
3784 | - | ||
3785 | -#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */ | ||
3786 | - | ||
3787 | -struct lzx_stream { | ||
3788 | - int ofd; /* output file descriptor */ | ||
3789 | - | ||
3790 | - off_t offset; /* number of bytes actually output */ | ||
3791 | - off_t length; /* overall decompressed length of stream */ | ||
3792 | - | ||
3793 | - unsigned char *window; /* decoding window */ | ||
3794 | - unsigned int window_size; /* window size */ | ||
3795 | - unsigned int window_posn; /* decompression offset within window */ | ||
3796 | - unsigned int frame_posn; /* current frame offset within in window */ | ||
3797 | - unsigned int frame; /* the number of 32kb frames processed */ | ||
3798 | - unsigned int reset_interval; /* which frame do we reset the compressor? */ | ||
3799 | - | ||
3800 | - unsigned int R0, R1, R2; /* for the LRU offset system */ | ||
3801 | - unsigned int block_length; /* uncompressed length of this LZX block */ | ||
3802 | - unsigned int block_remaining; /* uncompressed bytes still left to decode */ | ||
3803 | - | ||
3804 | - signed int intel_filesize; /* magic header value used for transform */ | ||
3805 | - signed int intel_curpos; /* current offset in transform space */ | ||
3806 | - | ||
3807 | - unsigned char intel_started; /* has intel E8 decoding started? */ | ||
3808 | - unsigned char block_type; /* type of the current block */ | ||
3809 | - unsigned char header_read; /* have we started decoding at all yet? */ | ||
3810 | - unsigned char posn_slots; /* how many posn slots in stream? */ | ||
3811 | - | ||
3812 | - int error; | ||
3813 | - | ||
3814 | - /* I/O buffering */ | ||
3815 | - unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end; | ||
3816 | - unsigned int bit_buffer, bits_left, inbuf_size; | ||
3817 | - | ||
3818 | - /* huffman code lengths */ | ||
3819 | - unsigned char PRETREE_len [LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY]; | ||
3820 | - unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY]; | ||
3821 | - unsigned char LENGTH_len [LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY]; | ||
3822 | - unsigned char ALIGNED_len [LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY]; | ||
3823 | - | ||
3824 | - /* huffman decoding tables */ | ||
3825 | - unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) + | ||
3826 | - (LZX_PRETREE_MAXSYMBOLS * 2)]; | ||
3827 | - unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) + | ||
3828 | - (LZX_MAINTREE_MAXSYMBOLS * 2)]; | ||
3829 | - unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) + | ||
3830 | - (LZX_LENGTH_MAXSYMBOLS * 2)]; | ||
3831 | - unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) + | ||
3832 | - (LZX_ALIGNED_MAXSYMBOLS * 2)]; | ||
3833 | - unsigned char input_end; /* have we reached the end of input? */ | ||
3834 | - unsigned char wflag; /* write flag */ | ||
3835 | - | ||
3836 | - /* this is used purely for doing the intel E8 transform */ | ||
3837 | - unsigned char e8_buf[LZX_FRAME_SIZE]; | ||
3838 | - | ||
3839 | - unsigned int position_base[51]; | ||
3840 | - | ||
3841 | - /* cabinet related stuff */ | ||
3842 | - struct cab_file *file; | ||
3843 | - int (*read_cb)(struct cab_file *, unsigned char *, int); | ||
3844 | - | ||
3845 | - unsigned char extra_bits[51]; | ||
3846 | - | ||
3847 | -}; | ||
3848 | - | ||
3849 | -struct lzx_stream *lzx_init(int ofd, | ||
3850 | - int window_bits, | ||
3851 | - int reset_interval, | ||
3852 | - int input_buffer_size, | ||
3853 | - off_t output_length, | ||
3854 | - struct cab_file *file, | ||
3855 | - int (*read_cb)(struct cab_file *, unsigned char *, int)); | ||
3856 | - | ||
3857 | -extern void lzx_set_output_length(struct lzx_stream *lzx, | ||
3858 | - off_t output_length); | ||
3859 | - | ||
3860 | -extern int lzx_decompress(struct lzx_stream *lzx, uint32_t out_bytes); | ||
3861 | - | ||
3862 | -void lzx_free(struct lzx_stream *lzx); | ||
3863 | - | ||
3864 | -#endif | ||
3865 | diff --git a/libclamav/scanners.c b/libclamav/scanners.c | ||
3866 | index fa9063d08018..07a38eedc7a5 100644 | ||
3867 | --- a/libclamav/scanners.c | ||
3868 | +++ b/libclamav/scanners.c | ||
3869 | @@ -60,7 +60,7 @@ | ||
3870 | #include "vba_extract.h" | ||
3871 | #include "msexpand.h" | ||
3872 | #include "mbox.h" | ||
3873 | -#include "chmunpack.h" | ||
3874 | +#include "libmspack.h" | ||
3875 | #include "pe.h" | ||
3876 | #include "elf.h" | ||
3877 | #include "filetypes.h" | ||
3878 | @@ -73,8 +73,6 @@ | ||
3879 | #include "sis.h" | ||
3880 | #include "pdf.h" | ||
3881 | #include "str.h" | ||
3882 | -#include "mspack.h" | ||
3883 | -#include "cab.h" | ||
3884 | #include "rtf.h" | ||
3885 | #include "unarj.h" | ||
3886 | #include "nsis/nulsft.h" | ||
3887 | @@ -853,82 +851,6 @@ static int cli_scanszdd(cli_ctx *ctx) | ||
3888 | return ret; | ||
3889 | } | ||
3890 | |||
3891 | -static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset) | ||
3892 | -{ | ||
3893 | - char *tempname; | ||
3894 | - int ret; | ||
3895 | - unsigned int files = 0; | ||
3896 | - struct cab_archive cab; | ||
3897 | - struct cab_file *file; | ||
3898 | - unsigned int corrupted_input; | ||
3899 | - unsigned int viruses_found = 0; | ||
3900 | - | ||
3901 | - cli_dbgmsg("in cli_scanmscab()\n"); | ||
3902 | - | ||
3903 | - if((ret = cab_open(*ctx->fmap, sfx_offset, &cab))) | ||
3904 | - return ret; | ||
3905 | - | ||
3906 | - for(file = cab.files; file; file = file->next) { | ||
3907 | - files++; | ||
3908 | - | ||
3909 | - if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) { | ||
3910 | - if (!SCAN_ALL) { | ||
3911 | - ret = CL_VIRUS; | ||
3912 | - break; | ||
3913 | - } | ||
3914 | - viruses_found++; | ||
3915 | - } | ||
3916 | - | ||
3917 | - if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) { | ||
3918 | - ret = CL_CLEAN; | ||
3919 | - break; | ||
3920 | - } | ||
3921 | - | ||
3922 | - if(!(tempname = cli_gentemp(ctx->engine->tmpdir))) { | ||
3923 | - ret = CL_EMEM; | ||
3924 | - break; | ||
3925 | - } | ||
3926 | - | ||
3927 | - if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize) | ||
3928 | - file->max_size = ctx->engine->maxscansize - ctx->scansize; | ||
3929 | - else | ||
3930 | - file->max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff; | ||
3931 | - | ||
3932 | - cli_dbgmsg("CAB: Extracting file %s to %s, size %u, max_size: %u\n", file->name, tempname, file->length, (unsigned int) file->max_size); | ||
3933 | - file->written_size = 0; | ||
3934 | - if((ret = cab_extract(file, tempname))) { | ||
3935 | - cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret)); | ||
3936 | - } else { | ||
3937 | - corrupted_input = ctx->corrupted_input; | ||
3938 | - if(file->length != file->written_size) { | ||
3939 | - cli_dbgmsg("CAB: Length from header %u but wrote %u bytes\n", (unsigned int) file->length, (unsigned int) file->written_size); | ||
3940 | - ctx->corrupted_input = 1; | ||
3941 | - } | ||
3942 | - ret = cli_scanfile(tempname, ctx); | ||
3943 | - ctx->corrupted_input = corrupted_input; | ||
3944 | - } | ||
3945 | - if(!ctx->engine->keeptmp) { | ||
3946 | - if (!access(tempname, R_OK) && cli_unlink(tempname)) { | ||
3947 | - free(tempname); | ||
3948 | - ret = CL_EUNLINK; | ||
3949 | - break; | ||
3950 | - } | ||
3951 | - } | ||
3952 | - free(tempname); | ||
3953 | - if(ret == CL_VIRUS) { | ||
3954 | - if (SCAN_ALL) | ||
3955 | - viruses_found++; | ||
3956 | - else | ||
3957 | - break; | ||
3958 | - } | ||
3959 | - } | ||
3960 | - | ||
3961 | - cab_free(&cab); | ||
3962 | - if (viruses_found) | ||
3963 | - return CL_VIRUS; | ||
3964 | - return ret; | ||
3965 | -} | ||
3966 | - | ||
3967 | static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ctx) | ||
3968 | { | ||
3969 | struct cli_matcher *groot = ctx->engine->root[0]; | ||
3970 | @@ -1568,72 +1490,6 @@ static int cli_scantar(cli_ctx *ctx, unsigned int posix) | ||
3971 | return ret; | ||
3972 | } | ||
3973 | |||
3974 | -static int cli_scanmschm(cli_ctx *ctx) | ||
3975 | -{ | ||
3976 | - int ret = CL_CLEAN, rc; | ||
3977 | - chm_metadata_t metadata; | ||
3978 | - char *dir; | ||
3979 | - unsigned int viruses_found = 0; | ||
3980 | - | ||
3981 | - cli_dbgmsg("in cli_scanmschm()\n"); | ||
3982 | - | ||
3983 | - /* generate the temporary directory */ | ||
3984 | - if(!(dir = cli_gentemp(ctx->engine->tmpdir))) | ||
3985 | - return CL_EMEM; | ||
3986 | - | ||
3987 | - if(mkdir(dir, 0700)) { | ||
3988 | - cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir); | ||
3989 | - free(dir); | ||
3990 | - return CL_ETMPDIR; | ||
3991 | - } | ||
3992 | - | ||
3993 | - ret = cli_chm_open(dir, &metadata, ctx); | ||
3994 | - if (ret != CL_SUCCESS) { | ||
3995 | - if(!ctx->engine->keeptmp) | ||
3996 | - cli_rmdirs(dir); | ||
3997 | - free(dir); | ||
3998 | - cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret)); | ||
3999 | - return ret; | ||
4000 | - } | ||
4001 | - | ||
4002 | - do { | ||
4003 | - ret = cli_chm_prepare_file(&metadata); | ||
4004 | - if (ret != CL_SUCCESS) { | ||
4005 | - break; | ||
4006 | - } | ||
4007 | - ret = cli_chm_extract_file(dir, &metadata, ctx); | ||
4008 | - if (ret == CL_SUCCESS) { | ||
4009 | - rc = cli_magic_scandesc(metadata.ofd, ctx); | ||
4010 | - close(metadata.ofd); | ||
4011 | - if (rc == CL_VIRUS) { | ||
4012 | - cli_dbgmsg("CHM: infected with %s\n", cli_get_last_virus(ctx)); | ||
4013 | - if (SCAN_ALL) | ||
4014 | - viruses_found++; | ||
4015 | - else { | ||
4016 | - ret = CL_VIRUS; | ||
4017 | - break; | ||
4018 | - } | ||
4019 | - } | ||
4020 | - } | ||
4021 | - | ||
4022 | - } while(ret == CL_SUCCESS); | ||
4023 | - | ||
4024 | - cli_chm_close(&metadata); | ||
4025 | - | ||
4026 | - if(!ctx->engine->keeptmp) | ||
4027 | - cli_rmdirs(dir); | ||
4028 | - | ||
4029 | - free(dir); | ||
4030 | - | ||
4031 | - cli_dbgmsg("CHM: Exit code: %d\n", ret); | ||
4032 | - if (ret == CL_BREAK) | ||
4033 | - ret = CL_CLEAN; | ||
4034 | - | ||
4035 | - if (SCAN_ALL && viruses_found) | ||
4036 | - return CL_VIRUS; | ||
4037 | - return ret; | ||
4038 | -} | ||
4039 | - | ||
4040 | static int cli_scanscrenc(cli_ctx *ctx) | ||
4041 | { | ||
4042 | char *tempname; | ||