summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/mspack/cabd.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/mspack/cabd.c')
-rw-r--r--utils/rbutilqt/mspack/cabd.c1508
1 files changed, 1508 insertions, 0 deletions
diff --git a/utils/rbutilqt/mspack/cabd.c b/utils/rbutilqt/mspack/cabd.c
new file mode 100644
index 0000000000..ae66769b24
--- /dev/null
+++ b/utils/rbutilqt/mspack/cabd.c
@@ -0,0 +1,1508 @@
1/* This file is part of libmspack.
2 * (C) 2003-2018 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
11 * "folders", which are compressed spans of data. Each cabinet has
12 * "files", whose metadata is in the cabinet header, but whose actual data
13 * is stored compressed in one of the "folders". Cabinets can span more
14 * than one physical file on disk, in which case they are a "cabinet set",
15 * and usually the last folder of each cabinet extends into the next
16 * cabinet.
17 *
18 * For a complete description of the format, see the MSDN site:
19 * http://msdn.microsoft.com/en-us/library/bb267310.aspx
20 */
21
22/* CAB decompression implementation */
23
24#include "system-mspack.h"
25#include "cab.h"
26#include "mszip.h"
27#include "lzx.h"
28#include "qtm.h"
29
30/* Notes on compliance with cabinet specification:
31 *
32 * One of the main changes between cabextract 0.6 and libmspack's cab
33 * decompressor is the move from block-oriented decompression to
34 * stream-oriented decompression.
35 *
36 * cabextract would read one data block from disk, decompress it with the
37 * appropriate method, then write the decompressed data. The CAB
38 * specification is specifically designed to work like this, as it ensures
39 * compression matches do not span the maximum decompressed block size
40 * limit of 32kb.
41 *
42 * However, the compression algorithms used are stream oriented, with
43 * specific hacks added to them to enforce the "individual 32kb blocks"
44 * rule in CABs. In other file formats, they do not have this limitation.
45 *
46 * In order to make more generalised decompressors, libmspack's CAB
47 * decompressor has moved from being block-oriented to more stream
48 * oriented. This also makes decompression slightly faster.
49 *
50 * However, this leads to incompliance with the CAB specification. The
51 * CAB controller can no longer ensure each block of input given to the
52 * decompressors is matched with their output. The "decompressed size" of
53 * each individual block is thrown away.
54 *
55 * Each CAB block is supposed to be seen as individually compressed. This
56 * means each consecutive data block can have completely different
57 * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
58 * reality, all data blocks in a folder decompress to exactly 32768 bytes,
59 * excepting the final block.
60 *
61 * Given this situation, the decompression algorithms are designed to
62 * realign their input bitstreams on 32768 output-byte boundaries, and
63 * various other special cases have been made. libmspack will not
64 * correctly decompress LZX or Quantum compressed folders where the blocks
65 * do not follow this "32768 bytes until last block" pattern. It could be
66 * implemented if needed, but hopefully this is not necessary -- it has
67 * not been seen in over 3Gb of CAB archives.
68 */
69
70/* prototypes */
71static struct mscabd_cabinet * cabd_open(
72 struct mscab_decompressor *base, const char *filename);
73static void cabd_close(
74 struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
75static int cabd_read_headers(
76 struct mspack_system *sys, struct mspack_file *fh,
77 struct mscabd_cabinet_p *cab, off_t offset, int salvage, int quiet);
78static char *cabd_read_string(
79 struct mspack_system *sys, struct mspack_file *fh, int *error);
80
81static struct mscabd_cabinet *cabd_search(
82 struct mscab_decompressor *base, const char *filename);
83static int cabd_find(
84 struct mscab_decompressor_p *self, unsigned char *buf,
85 struct mspack_file *fh, const char *filename, off_t flen,
86 off_t *firstlen, struct mscabd_cabinet_p **firstcab);
87
88static int cabd_prepend(
89 struct mscab_decompressor *base, struct mscabd_cabinet *cab,
90 struct mscabd_cabinet *prevcab);
91static int cabd_append(
92 struct mscab_decompressor *base, struct mscabd_cabinet *cab,
93 struct mscabd_cabinet *nextcab);
94static int cabd_merge(
95 struct mscab_decompressor *base, struct mscabd_cabinet *lcab,
96 struct mscabd_cabinet *rcab);
97static int cabd_can_merge_folders(
98 struct mspack_system *sys, struct mscabd_folder_p *lfol,
99 struct mscabd_folder_p *rfol);
100
101static int cabd_extract(
102 struct mscab_decompressor *base, struct mscabd_file *file,
103 const char *filename);
104static int cabd_init_decomp(
105 struct mscab_decompressor_p *self, unsigned int ct);
106static void cabd_free_decomp(
107 struct mscab_decompressor_p *self);
108static int cabd_sys_read(
109 struct mspack_file *file, void *buffer, int bytes);
110static int cabd_sys_write(
111 struct mspack_file *file, void *buffer, int bytes);
112static int cabd_sys_read_block(
113 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
114 int ignore_cksum, int ignore_blocksize);
115static unsigned int cabd_checksum(
116 unsigned char *data, unsigned int bytes, unsigned int cksum);
117static struct noned_state *noned_init(
118 struct mspack_system *sys, struct mspack_file *in, struct mspack_file *out,
119 int bufsize);
120
121static int noned_decompress(
122 struct noned_state *s, off_t bytes);
123static void noned_free(
124 struct noned_state *state);
125
126static int cabd_param(
127 struct mscab_decompressor *base, int param, int value);
128
129static int cabd_error(
130 struct mscab_decompressor *base);
131
132
133/***************************************
134 * MSPACK_CREATE_CAB_DECOMPRESSOR
135 ***************************************
136 * constructor
137 */
138struct mscab_decompressor *
139 mspack_create_cab_decompressor(struct mspack_system *sys)
140{
141 struct mscab_decompressor_p *self = NULL;
142
143 if (!sys) sys = mspack_default_system;
144 if (!mspack_valid_system(sys)) return NULL;
145
146 if ((self = (struct mscab_decompressor_p *) sys->alloc(sys, sizeof(struct mscab_decompressor_p)))) {
147 self->base.open = &cabd_open;
148 self->base.close = &cabd_close;
149 self->base.search = &cabd_search;
150 self->base.extract = &cabd_extract;
151 self->base.prepend = &cabd_prepend;
152 self->base.append = &cabd_append;
153 self->base.set_param = &cabd_param;
154 self->base.last_error = &cabd_error;
155 self->system = sys;
156 self->d = NULL;
157 self->error = MSPACK_ERR_OK;
158
159 self->searchbuf_size = 32768;
160 self->fix_mszip = 0;
161 self->buf_size = 4096;
162 self->salvage = 0;
163 }
164 return (struct mscab_decompressor *) self;
165}
166
167/***************************************
168 * MSPACK_DESTROY_CAB_DECOMPRESSOR
169 ***************************************
170 * destructor
171 */
172void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
173 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
174 if (self) {
175 struct mspack_system *sys = self->system;
176 if (self->d) {
177 if (self->d->infh) sys->close(self->d->infh);
178 cabd_free_decomp(self);
179 sys->free(self->d);
180 }
181 sys->free(self);
182 }
183}
184
185
186/***************************************
187 * CABD_OPEN
188 ***************************************
189 * opens a file and tries to read it as a cabinet file
190 */
191static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
192 const char *filename)
193{
194 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
195 struct mscabd_cabinet_p *cab = NULL;
196 struct mspack_system *sys;
197 struct mspack_file *fh;
198 int error;
199
200 if (!base) return NULL;
201 sys = self->system;
202
203 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
204 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
205 cab->base.filename = filename;
206 error = cabd_read_headers(sys, fh, cab, (off_t) 0, self->salvage, 0);
207 if (error) {
208 cabd_close(base, (struct mscabd_cabinet *) cab);
209 cab = NULL;
210 }
211 self->error = error;
212 }
213 else {
214 self->error = MSPACK_ERR_NOMEMORY;
215 }
216 sys->close(fh);
217 }
218 else {
219 self->error = MSPACK_ERR_OPEN;
220 }
221 return (struct mscabd_cabinet *) cab;
222}
223
224/***************************************
225 * CABD_CLOSE
226 ***************************************
227 * frees all memory associated with a given mscabd_cabinet.
228 */
229static void cabd_close(struct mscab_decompressor *base,
230 struct mscabd_cabinet *origcab)
231{
232 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
233 struct mscabd_folder_data *dat, *ndat;
234 struct mscabd_cabinet *cab, *ncab;
235 struct mscabd_folder *fol, *nfol;
236 struct mscabd_file *fi, *nfi;
237 struct mspack_system *sys;
238
239 if (!base) return;
240 sys = self->system;
241
242 self->error = MSPACK_ERR_OK;
243
244 while (origcab) {
245 /* free files */
246 for (fi = origcab->files; fi; fi = nfi) {
247 nfi = fi->next;
248 sys->free(fi->filename);
249 sys->free(fi);
250 }
251
252 /* free folders */
253 for (fol = origcab->folders; fol; fol = nfol) {
254 nfol = fol->next;
255
256 /* free folder decompression state if it has been decompressed */
257 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
258 if (self->d->infh) sys->close(self->d->infh);
259 cabd_free_decomp(self);
260 sys->free(self->d);
261 self->d = NULL;
262 }
263
264 /* free folder data segments */
265 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
266 ndat = dat->next;
267 sys->free(dat);
268 }
269 sys->free(fol);
270 }
271
272 /* free predecessor cabinets (and the original cabinet's strings) */
273 for (cab = origcab; cab; cab = ncab) {
274 ncab = cab->prevcab;
275 sys->free(cab->prevname);
276 sys->free(cab->nextname);
277 sys->free(cab->previnfo);
278 sys->free(cab->nextinfo);
279 if (cab != origcab) sys->free(cab);
280 }
281
282 /* free successor cabinets */
283 for (cab = origcab->nextcab; cab; cab = ncab) {
284 ncab = cab->nextcab;
285 sys->free(cab->prevname);
286 sys->free(cab->nextname);
287 sys->free(cab->previnfo);
288 sys->free(cab->nextinfo);
289 sys->free(cab);
290 }
291
292 /* free actual cabinet structure */
293 cab = origcab->next;
294 sys->free(origcab);
295
296 /* repeat full procedure again with the cab->next pointer (if set) */
297 origcab = cab;
298 }
299}
300
301/***************************************
302 * CABD_READ_HEADERS
303 ***************************************
304 * reads the cabinet file header, folder list and file list.
305 * fills out a pre-existing mscabd_cabinet structure, allocates memory
306 * for folders and files as necessary
307 */
308static int cabd_read_headers(struct mspack_system *sys,
309 struct mspack_file *fh,
310 struct mscabd_cabinet_p *cab,
311 off_t offset, int salvage, int quiet)
312{
313 int num_folders, num_files, folder_resv, i, x, err, fidx;
314 struct mscabd_folder_p *fol, *linkfol = NULL;
315 struct mscabd_file *file, *linkfile = NULL;
316 unsigned char buf[64];
317
318 /* initialise pointers */
319 cab->base.next = NULL;
320 cab->base.files = NULL;
321 cab->base.folders = NULL;
322 cab->base.prevcab = cab->base.nextcab = NULL;
323 cab->base.prevname = cab->base.nextname = NULL;
324 cab->base.previnfo = cab->base.nextinfo = NULL;
325
326 cab->base.base_offset = offset;
327
328 /* seek to CFHEADER */
329 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
330 return MSPACK_ERR_SEEK;
331 }
332
333 /* read in the CFHEADER */
334 if (sys->read(fh, &buf[0], cfhead_SIZEOF) != cfhead_SIZEOF) {
335 return MSPACK_ERR_READ;
336 }
337
338 /* check for "MSCF" signature */
339 if (EndGetI32(&buf[cfhead_Signature]) != 0x4643534D) {
340 return MSPACK_ERR_SIGNATURE;
341 }
342
343 /* some basic header fields */
344 cab->base.length = EndGetI32(&buf[cfhead_CabinetSize]);
345 cab->base.set_id = EndGetI16(&buf[cfhead_SetID]);
346 cab->base.set_index = EndGetI16(&buf[cfhead_CabinetIndex]);
347
348 /* get the number of folders */
349 num_folders = EndGetI16(&buf[cfhead_NumFolders]);
350 if (num_folders == 0) {
351 if (!quiet) sys->message(fh, "no folders in cabinet.");
352 return MSPACK_ERR_DATAFORMAT;
353 }
354
355 /* get the number of files */
356 num_files = EndGetI16(&buf[cfhead_NumFiles]);
357 if (num_files == 0) {
358 if (!quiet) sys->message(fh, "no files in cabinet.");
359 return MSPACK_ERR_DATAFORMAT;
360 }
361
362 /* check cabinet version */
363 if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) {
364 if (!quiet) sys->message(fh, "WARNING; cabinet version is not 1.3");
365 }
366
367 /* read the reserved-sizes part of header, if present */
368 cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
369
370 if (cab->base.flags & cfheadRESERVE_PRESENT) {
371 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
372 return MSPACK_ERR_READ;
373 }
374 cab->base.header_resv = EndGetI16(&buf[cfheadext_HeaderReserved]);
375 folder_resv = buf[cfheadext_FolderReserved];
376 cab->block_resv = buf[cfheadext_DataReserved];
377
378 if (cab->base.header_resv > 60000) {
379 if (!quiet) sys->message(fh, "WARNING; reserved header > 60000.");
380 }
381
382 /* skip the reserved header */
383 if (cab->base.header_resv) {
384 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
385 return MSPACK_ERR_SEEK;
386 }
387 }
388 }
389 else {
390 cab->base.header_resv = 0;
391 folder_resv = 0;
392 cab->block_resv = 0;
393 }
394
395 /* read name and info of preceeding cabinet in set, if present */
396 if (cab->base.flags & cfheadPREV_CABINET) {
397 cab->base.prevname = cabd_read_string(sys, fh, &err);
398 if (err) return err;
399 cab->base.previnfo = cabd_read_string(sys, fh, &err);
400 if (err) return err;
401 }
402
403 /* read name and info of next cabinet in set, if present */
404 if (cab->base.flags & cfheadNEXT_CABINET) {
405 cab->base.nextname = cabd_read_string(sys, fh, &err);
406 if (err) return err;
407 cab->base.nextinfo = cabd_read_string(sys, fh, &err);
408 if (err) return err;
409 }
410
411 /* read folders */
412 for (i = 0; i < num_folders; i++) {
413 if (sys->read(fh, &buf[0], cffold_SIZEOF) != cffold_SIZEOF) {
414 return MSPACK_ERR_READ;
415 }
416 if (folder_resv) {
417 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
418 return MSPACK_ERR_SEEK;
419 }
420 }
421
422 if (!(fol = (struct mscabd_folder_p *) sys->alloc(sys, sizeof(struct mscabd_folder_p)))) {
423 return MSPACK_ERR_NOMEMORY;
424 }
425 fol->base.next = NULL;
426 fol->base.comp_type = EndGetI16(&buf[cffold_CompType]);
427 fol->base.num_blocks = EndGetI16(&buf[cffold_NumBlocks]);
428 fol->data.next = NULL;
429 fol->data.cab = (struct mscabd_cabinet_p *) cab;
430 fol->data.offset = offset + (off_t)
431 ( (unsigned int) EndGetI32(&buf[cffold_DataOffset]) );
432 fol->merge_prev = NULL;
433 fol->merge_next = NULL;
434
435 /* link folder into list of folders */
436 if (!linkfol) cab->base.folders = (struct mscabd_folder *) fol;
437 else linkfol->base.next = (struct mscabd_folder *) fol;
438 linkfol = fol;
439 }
440
441 /* read files */
442 for (i = 0; i < num_files; i++) {
443 if (sys->read(fh, &buf[0], cffile_SIZEOF) != cffile_SIZEOF) {
444 return MSPACK_ERR_READ;
445 }
446
447 if (!(file = (struct mscabd_file *) sys->alloc(sys, sizeof(struct mscabd_file)))) {
448 return MSPACK_ERR_NOMEMORY;
449 }
450
451 file->next = NULL;
452 file->length = EndGetI32(&buf[cffile_UncompressedSize]);
453 file->attribs = EndGetI16(&buf[cffile_Attribs]);
454 file->offset = EndGetI32(&buf[cffile_FolderOffset]);
455
456 /* set folder pointer */
457 fidx = EndGetI16(&buf[cffile_FolderIndex]);
458 if (fidx < cffileCONTINUED_FROM_PREV) {
459 /* normal folder index; count up to the correct folder */
460 if (fidx < num_folders) {
461 struct mscabd_folder *ifol = cab->base.folders;
462 while (fidx--) if (ifol) ifol = ifol->next;
463 file->folder = ifol;
464 }
465 else {
466 D(("invalid folder index"))
467 file->folder = NULL;
468 }
469 }
470 else {
471 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
472 * CONTINUED_PREV_AND_NEXT */
473 if ((fidx == cffileCONTINUED_TO_NEXT) ||
474 (fidx == cffileCONTINUED_PREV_AND_NEXT))
475 {
476 /* get last folder */
477 struct mscabd_folder *ifol = cab->base.folders;
478 while (ifol->next) ifol = ifol->next;
479 file->folder = ifol;
480
481 /* set "merge next" pointer */
482 fol = (struct mscabd_folder_p *) ifol;
483 if (!fol->merge_next) fol->merge_next = file;
484 }
485
486 if ((fidx == cffileCONTINUED_FROM_PREV) ||
487 (fidx == cffileCONTINUED_PREV_AND_NEXT))
488 {
489 /* get first folder */
490 file->folder = cab->base.folders;
491
492 /* set "merge prev" pointer */
493 fol = (struct mscabd_folder_p *) file->folder;
494 if (!fol->merge_prev) fol->merge_prev = file;
495 }
496 }
497
498 /* get time */
499 x = EndGetI16(&buf[cffile_Time]);
500 file->time_h = x >> 11;
501 file->time_m = (x >> 5) & 0x3F;
502 file->time_s = (x << 1) & 0x3E;
503
504 /* get date */
505 x = EndGetI16(&buf[cffile_Date]);
506 file->date_d = x & 0x1F;
507 file->date_m = (x >> 5) & 0xF;
508 file->date_y = (x >> 9) + 1980;
509
510 /* get filename */
511 file->filename = cabd_read_string(sys, fh, &err);
512
513 /* if folder index or filename are bad, either skip it or fail */
514 if (err || !file->folder) {
515 sys->free(file->filename);
516 sys->free(file);
517 if (salvage) continue;
518 return err ? err : MSPACK_ERR_DATAFORMAT;
519 }
520
521 /* link file entry into file list */
522 if (!linkfile) cab->base.files = file;
523 else linkfile->next = file;
524 linkfile = file;
525 }
526
527 if (cab->base.files == NULL) {
528 /* We never actually added any files to the file list. Something went wrong.
529 * The file header may have been invalid */
530 D(("No files found, even though header claimed to have %d files", num_files))
531 return MSPACK_ERR_DATAFORMAT;
532 }
533
534 return MSPACK_ERR_OK;
535}
536
537static char *cabd_read_string(struct mspack_system *sys,
538 struct mspack_file *fh, int *error)
539{
540 off_t base = sys->tell(fh);
541 char buf[256], *str;
542 int len, i, ok;
543
544 /* read up to 256 bytes */
545 if ((len = sys->read(fh, &buf[0], 256)) <= 0) {
546 *error = MSPACK_ERR_READ;
547 return NULL;
548 }
549
550 /* search for a null terminator in the buffer */
551 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
552 /* reject empty strings */
553 if (i == 0) ok = 0;
554
555 if (!ok) {
556 *error = MSPACK_ERR_DATAFORMAT;
557 return NULL;
558 }
559
560 len = i + 1;
561
562 /* set the data stream to just after the string and return */
563 if (sys->seek(fh, base + (off_t)len, MSPACK_SYS_SEEK_START)) {
564 *error = MSPACK_ERR_SEEK;
565 return NULL;
566 }
567
568 if (!(str = (char *) sys->alloc(sys, len))) {
569 *error = MSPACK_ERR_NOMEMORY;
570 return NULL;
571 }
572
573 sys->copy(&buf[0], str, len);
574 *error = MSPACK_ERR_OK;
575 return str;
576}
577
578/***************************************
579 * CABD_SEARCH, CABD_FIND
580 ***************************************
581 * cabd_search opens a file, finds its extent, allocates a search buffer,
582 * then reads through the whole file looking for possible cabinet headers.
583 * if it finds any, it tries to read them as real cabinets. returns a linked
584 * list of results
585 *
586 * cabd_find is the inner loop of cabd_search, to make it easier to
587 * break out of the loop and be sure that all resources are freed
588 */
589static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
590 const char *filename)
591{
592 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
593 struct mscabd_cabinet_p *cab = NULL;
594 struct mspack_system *sys;
595 unsigned char *search_buf;
596 struct mspack_file *fh;
597 off_t filelen, firstlen = 0;
598
599 if (!base) return NULL;
600 sys = self->system;
601
602 /* allocate a search buffer */
603 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->searchbuf_size);
604 if (!search_buf) {
605 self->error = MSPACK_ERR_NOMEMORY;
606 return NULL;
607 }
608
609 /* open file and get its full file length */
610 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
611 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
612 self->error = cabd_find(self, search_buf, fh, filename,
613 filelen, &firstlen, &cab);
614 }
615
616 /* truncated / extraneous data warning: */
617 if (firstlen && (firstlen != filelen) &&
618 (!cab || (cab->base.base_offset == 0)))
619 {
620 if (firstlen < filelen) {
621 sys->message(fh, "WARNING; possible %" LD
622 " extra bytes at end of file.",
623 filelen - firstlen);
624 }
625 else {
626 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
627 firstlen - filelen);
628 }
629 }
630
631 sys->close(fh);
632 }
633 else {
634 self->error = MSPACK_ERR_OPEN;
635 }
636
637 /* free the search buffer */
638 sys->free(search_buf);
639
640 return (struct mscabd_cabinet *) cab;
641}
642
643static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
644 struct mspack_file *fh, const char *filename, off_t flen,
645 off_t *firstlen, struct mscabd_cabinet_p **firstcab)
646{
647 struct mscabd_cabinet_p *cab, *link = NULL;
648 off_t caboff, offset, length;
649 struct mspack_system *sys = self->system;
650 unsigned char *p, *pend, state = 0;
651 unsigned int cablen_u32 = 0, foffset_u32 = 0;
652 int false_cabs = 0;
653
654#if !LARGEFILE_SUPPORT
655 /* detect 32-bit off_t overflow */
656 if (flen < 0) {
657 sys->message(fh, largefile_msg);
658 return MSPACK_ERR_OK;
659 }
660#endif
661
662 /* search through the full file length */
663 for (offset = 0; offset < flen; offset += length) {
664 /* search length is either the full length of the search buffer, or the
665 * amount of data remaining to the end of the file, whichever is less. */
666 length = flen - offset;
667 if (length > self->searchbuf_size) {
668 length = self->searchbuf_size;
669 }
670
671 /* fill the search buffer with data from disk */
672 if (sys->read(fh, &buf[0], (int) length) != (int) length) {
673 return MSPACK_ERR_READ;
674 }
675
676 /* FAQ avoidance strategy */
677 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
678 sys->message(fh, "WARNING; found InstallShield header. Use unshield "
679 "(https://github.com/twogood/unshield) to unpack this file");
680 }
681
682 /* read through the entire buffer. */
683 for (p = &buf[0], pend = &buf[length]; p < pend; ) {
684 switch (state) {
685 /* starting state */
686 case 0:
687 /* we spend most of our time in this while loop, looking for
688 * a leading 'M' of the 'MSCF' signature */
689 while (p < pend && *p != 0x4D) p++;
690 /* if we found tht 'M', advance state */
691 if (p++ < pend) state = 1;
692 break;
693
694 /* verify that the next 3 bytes are 'S', 'C' and 'F' */
695 case 1: state = (*p++ == 0x53) ? 2 : 0; break;
696 case 2: state = (*p++ == 0x43) ? 3 : 0; break;
697 case 3: state = (*p++ == 0x46) ? 4 : 0; break;
698
699 /* we don't care about bytes 4-7 (see default: for action) */
700
701 /* bytes 8-11 are the overall length of the cabinet */
702 case 8: cablen_u32 = *p++; state++; break;
703 case 9: cablen_u32 |= *p++ << 8; state++; break;
704 case 10: cablen_u32 |= *p++ << 16; state++; break;
705 case 11: cablen_u32 |= *p++ << 24; state++; break;
706
707 /* we don't care about bytes 12-15 (see default: for action) */
708
709 /* bytes 16-19 are the offset within the cabinet of the filedata */
710 case 16: foffset_u32 = *p++; state++; break;
711 case 17: foffset_u32 |= *p++ << 8; state++; break;
712 case 18: foffset_u32 |= *p++ << 16; state++; break;
713 case 19: foffset_u32 |= *p++ << 24;
714 /* now we have recieved 20 bytes of potential cab header. work out
715 * the offset in the file of this potential cabinet */
716 caboff = offset + (p - &buf[0]) - 20;
717
718 /* should reading cabinet fail, restart search just after 'MSCF' */
719 offset = caboff + 4;
720
721 /* capture the "length of cabinet" field if there is a cabinet at
722 * offset 0 in the file, regardless of whether the cabinet can be
723 * read correctly or not */
724 if (caboff == 0) *firstlen = (off_t) cablen_u32;
725
726 /* check that the files offset is less than the alleged length of
727 * the cabinet, and that the offset + the alleged length are
728 * 'roughly' within the end of overall file length. In salvage
729 * mode, don't check the alleged length, allow it to be garbage */
730 if ((foffset_u32 < cablen_u32) &&
731 ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
732 (((caboff + (off_t) cablen_u32) < (flen + 32)) || self->salvage))
733 {
734 /* likely cabinet found -- try reading it */
735 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
736 return MSPACK_ERR_NOMEMORY;
737 }
738 cab->base.filename = filename;
739 if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
740 /* destroy the failed cabinet */
741 cabd_close((struct mscab_decompressor *) self,
742 (struct mscabd_cabinet *) cab);
743 false_cabs++;
744 }
745 else {
746 /* cabinet read correctly! */
747
748 /* link the cab into the list */
749 if (!link) *firstcab = cab;
750 else link->base.next = (struct mscabd_cabinet *) cab;
751 link = cab;
752
753 /* cause the search to restart after this cab's data. */
754 offset = caboff + (off_t) cablen_u32;
755
756#if !LARGEFILE_SUPPORT
757 /* detect 32-bit off_t overflow */
758 if (offset < caboff) {
759 sys->message(fh, largefile_msg);
760 return MSPACK_ERR_OK;
761 }
762#endif
763 }
764 }
765
766 /* restart search */
767 if (offset >= flen) return MSPACK_ERR_OK;
768 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
769 return MSPACK_ERR_SEEK;
770 }
771 length = 0;
772 p = pend;
773 state = 0;
774 break;
775
776 /* for bytes 4-7 and 12-15, just advance state/pointer */
777 default:
778 p++, state++;
779 } /* switch(state) */
780 } /* for (... p < pend ...) */
781 } /* for (... offset < length ...) */
782
783 if (false_cabs) {
784 D(("%d false cabinets found", false_cabs))
785 }
786
787 return MSPACK_ERR_OK;
788}
789
790/***************************************
791 * CABD_MERGE, CABD_PREPEND, CABD_APPEND
792 ***************************************
793 * joins cabinets together, also merges split folders between these two
794 * cabinets only. This includes freeing the duplicate folder and file(s)
795 * and allocating a further mscabd_folder_data structure to append to the
796 * merged folder's data parts list.
797 */
798static int cabd_prepend(struct mscab_decompressor *base,
799 struct mscabd_cabinet *cab,
800 struct mscabd_cabinet *prevcab)
801{
802 return cabd_merge(base, prevcab, cab);
803}
804
805static int cabd_append(struct mscab_decompressor *base,
806 struct mscabd_cabinet *cab,
807 struct mscabd_cabinet *nextcab)
808{
809 return cabd_merge(base, cab, nextcab);
810}
811
812static int cabd_merge(struct mscab_decompressor *base,
813 struct mscabd_cabinet *lcab,
814 struct mscabd_cabinet *rcab)
815{
816 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
817 struct mscabd_folder_data *data, *ndata;
818 struct mscabd_folder_p *lfol, *rfol;
819 struct mscabd_file *fi, *rfi, *lfi;
820 struct mscabd_cabinet *cab;
821 struct mspack_system *sys;
822
823 if (!self) return MSPACK_ERR_ARGS;
824 sys = self->system;
825
826 /* basic args check */
827 if (!lcab || !rcab || (lcab == rcab)) {
828 D(("lcab NULL, rcab NULL or lcab = rcab"))
829 return self->error = MSPACK_ERR_ARGS;
830 }
831
832 /* check there's not already a cabinet attached */
833 if (lcab->nextcab || rcab->prevcab) {
834 D(("cabs already joined"))
835 return self->error = MSPACK_ERR_ARGS;
836 }
837
838 /* do not create circular cabinet chains */
839 for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
840 if (cab == rcab) {D(("circular!")) return self->error = MSPACK_ERR_ARGS;}
841 }
842 for (cab = rcab->nextcab; cab; cab = cab->nextcab) {
843 if (cab == lcab) {D(("circular!")) return self->error = MSPACK_ERR_ARGS;}
844 }
845
846 /* warn about odd set IDs or indices */
847 if (lcab->set_id != rcab->set_id) {
848 sys->message(NULL, "WARNING; merged cabinets with differing Set IDs.");
849 }
850
851 if (lcab->set_index > rcab->set_index) {
852 sys->message(NULL, "WARNING; merged cabinets with odd order.");
853 }
854
855 /* merging the last folder in lcab with the first folder in rcab */
856 lfol = (struct mscabd_folder_p *) lcab->folders;
857 rfol = (struct mscabd_folder_p *) rcab->folders;
858 while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
859
860 /* do we need to merge folders? */
861 if (!lfol->merge_next && !rfol->merge_prev) {
862 /* no, at least one of the folders is not for merging */
863
864 /* attach cabs */
865 lcab->nextcab = rcab;
866 rcab->prevcab = lcab;
867
868 /* attach folders */
869 lfol->base.next = (struct mscabd_folder *) rfol;
870
871 /* attach files */
872 fi = lcab->files;
873 while (fi->next) fi = fi->next;
874 fi->next = rcab->files;
875 }
876 else {
877 /* folder merge required - do the files match? */
878 if (! cabd_can_merge_folders(sys, lfol, rfol)) {
879 return self->error = MSPACK_ERR_DATAFORMAT;
880 }
881
882 /* allocate a new folder data structure */
883 if (!(data = (struct mscabd_folder_data *) sys->alloc(sys, sizeof(struct mscabd_folder_data)))) {
884 return self->error = MSPACK_ERR_NOMEMORY;
885 }
886
887 /* attach cabs */
888 lcab->nextcab = rcab;
889 rcab->prevcab = lcab;
890
891 /* append rfol's data to lfol */
892 ndata = &lfol->data;
893 while (ndata->next) ndata = ndata->next;
894 ndata->next = data;
895 *data = rfol->data;
896 rfol->data.next = NULL;
897
898 /* lfol becomes rfol.
899 * NOTE: special case, don't merge if rfol is merge prev and next,
900 * rfol->merge_next is going to be deleted, so keep lfol's version
901 * instead */
902 lfol->base.num_blocks += rfol->base.num_blocks - 1;
903 if ((rfol->merge_next == NULL) ||
904 (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
905 {
906 lfol->merge_next = rfol->merge_next;
907 }
908
909 /* attach the rfol's folder (except the merge folder) */
910 while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
911 lfol->base.next = rfol->base.next;
912
913 /* free disused merge folder */
914 sys->free(rfol);
915
916 /* attach rfol's files */
917 fi = lcab->files;
918 while (fi->next) fi = fi->next;
919 fi->next = rcab->files;
920
921 /* delete all files from rfol's merge folder */
922 lfi = NULL;
923 for (fi = lcab->files; fi ; fi = rfi) {
924 rfi = fi->next;
925 /* if file's folder matches the merge folder, unlink and free it */
926 if (fi->folder == (struct mscabd_folder *) rfol) {
927 if (lfi) lfi->next = rfi; else lcab->files = rfi;
928 sys->free(fi->filename);
929 sys->free(fi);
930 }
931 else lfi = fi;
932 }
933 }
934
935 /* all done! fix files and folders pointers in all cabs so they all
936 * point to the same list */
937 for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
938 cab->files = lcab->files;
939 cab->folders = lcab->folders;
940 }
941
942 for (cab = lcab->nextcab; cab; cab = cab->nextcab) {
943 cab->files = lcab->files;
944 cab->folders = lcab->folders;
945 }
946
947 return self->error = MSPACK_ERR_OK;
948}
949
950/* decides if two folders are OK to merge */
951static int cabd_can_merge_folders(struct mspack_system *sys,
952 struct mscabd_folder_p *lfol,
953 struct mscabd_folder_p *rfol)
954{
955 struct mscabd_file *lfi, *rfi, *l, *r;
956 int matching = 1;
957
958 /* check that both folders use the same compression method/settings */
959 if (lfol->base.comp_type != rfol->base.comp_type) {
960 D(("folder merge: compression type mismatch"))
961 return 0;
962 }
963
964 /* check there are not too many data blocks after merging */
965 if ((lfol->base.num_blocks + rfol->base.num_blocks) > CAB_FOLDERMAX) {
966 D(("folder merge: too many data blocks in merged folders"))
967 return 0;
968 }
969
970 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
971 D(("folder merge: one cabinet has no files to merge"))
972 return 0;
973 }
974
975 /* for all files in lfol (which is the last folder in whichever cab and
976 * only has files to merge), compare them to the files from rfol. They
977 * should be identical in number and order. to verify this, check the
978 * offset and length of each file. */
979 for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
980 if (!r || (l->offset != r->offset) || (l->length != r->length)) {
981 matching = 0;
982 break;
983 }
984 }
985
986 if (matching) return 1;
987
988 /* if rfol does not begin with an identical copy of the files in lfol, make
989 * make a judgement call; if at least ONE file from lfol is in rfol, allow
990 * the merge with a warning about missing files. */
991 matching = 0;
992 for (l = lfi; l; l = l->next) {
993 for (r = rfi; r; r = r->next) {
994 if (l->offset == r->offset && l->length == r->length) break;
995 }
996 if (r) matching = 1; else sys->message(NULL,
997 "WARNING; merged file %s not listed in both cabinets", l->filename);
998 }
999 return matching;
1000}
1001
1002
1003/***************************************
1004 * CABD_EXTRACT
1005 ***************************************
1006 * extracts a file from a cabinet
1007 */
1008static int cabd_extract(struct mscab_decompressor *base,
1009 struct mscabd_file *file, const char *filename)
1010{
1011 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
1012 struct mscabd_folder_p *fol;
1013 struct mspack_system *sys;
1014 struct mspack_file *fh;
1015 off_t filelen;
1016
1017 if (!self) return MSPACK_ERR_ARGS;
1018 if (!file) return self->error = MSPACK_ERR_ARGS;
1019
1020 sys = self->system;
1021 fol = (struct mscabd_folder_p *) file->folder;
1022
1023 /* if offset is beyond 2GB, nothing can be extracted */
1024 if (file->offset > CAB_LENGTHMAX) {
1025 return self->error = MSPACK_ERR_DATAFORMAT;
1026 }
1027
1028 /* if file claims to go beyond 2GB either error out,
1029 * or in salvage mode reduce file length so it fits 2GB limit
1030 */
1031 filelen = file->length;
1032 if (filelen > CAB_LENGTHMAX || (file->offset + filelen) > CAB_LENGTHMAX) {
1033 if (self->salvage) {
1034 filelen = CAB_LENGTHMAX - file->offset;
1035 }
1036 else {
1037 return self->error = MSPACK_ERR_DATAFORMAT;
1038 }
1039 }
1040
1041 /* extraction impossible if no folder, or folder needs predecessor */
1042 if (!fol || fol->merge_prev) {
1043 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1044 "cabinet set is incomplete", file->filename);
1045 return self->error = MSPACK_ERR_DECRUNCH;
1046 }
1047
1048 /* if file goes beyond what can be decoded, given an error.
1049 * In salvage mode, don't assume block sizes, just try decoding
1050 */
1051 if (!self->salvage) {
1052 off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
1053 if ((file->offset + filelen) > maxlen) {
1054 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1055 "cabinet set is incomplete", file->filename);
1056 return self->error = MSPACK_ERR_DECRUNCH;
1057 }
1058 }
1059
1060 /* allocate generic decompression state */
1061 if (!self->d) {
1062 self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
1063 if (!self->d) return self->error = MSPACK_ERR_NOMEMORY;
1064 self->d->folder = NULL;
1065 self->d->data = NULL;
1066 self->d->sys = *sys;
1067 self->d->sys.read = &cabd_sys_read;
1068 self->d->sys.write = &cabd_sys_write;
1069 self->d->state = NULL;
1070 self->d->infh = NULL;
1071 self->d->incab = NULL;
1072 }
1073
1074 /* do we need to change folder or reset the current folder? */
1075 if ((self->d->folder != fol) || (self->d->offset > file->offset) ||
1076 !self->d->state)
1077 {
1078 /* free any existing decompressor */
1079 cabd_free_decomp(self);
1080
1081 /* do we need to open a new cab file? */
1082 if (!self->d->infh || (fol->data.cab != self->d->incab)) {
1083 /* close previous file handle if from a different cab */
1084 if (self->d->infh) sys->close(self->d->infh);
1085 self->d->incab = fol->data.cab;
1086 self->d->infh = sys->open(sys, fol->data.cab->base.filename,
1087 MSPACK_SYS_OPEN_READ);
1088 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
1089 }
1090 /* seek to start of data blocks */
1091 if (sys->seek(self->d->infh, fol->data.offset, MSPACK_SYS_SEEK_START)) {
1092 return self->error = MSPACK_ERR_SEEK;
1093 }
1094
1095 /* set up decompressor */
1096 if (cabd_init_decomp(self, (unsigned int) fol->base.comp_type)) {
1097 return self->error;
1098 }
1099
1100 /* initialise new folder state */
1101 self->d->folder = fol;
1102 self->d->data = &fol->data;
1103 self->d->offset = 0;
1104 self->d->block = 0;
1105 self->d->outlen = 0;
1106 self->d->i_ptr = self->d->i_end = &self->d->input[0];
1107
1108 /* read_error lasts for the lifetime of a decompressor */
1109 self->read_error = MSPACK_ERR_OK;
1110 }
1111
1112 /* open file for output */
1113 if (!(fh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
1114 return self->error = MSPACK_ERR_OPEN;
1115 }
1116
1117 self->error = MSPACK_ERR_OK;
1118
1119 /* if file has more than 0 bytes */
1120 if (filelen) {
1121 off_t bytes;
1122 int error;
1123 /* get to correct offset.
1124 * - use NULL fh to say 'no writing' to cabd_sys_write()
1125 * - if cabd_sys_read() has an error, it will set self->read_error
1126 * and pass back MSPACK_ERR_READ
1127 */
1128 self->d->outfh = NULL;
1129 if ((bytes = file->offset - self->d->offset)) {
1130 error = self->d->decompress(self->d->state, bytes);
1131 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1132 }
1133
1134 /* if getting to the correct offset was error free, unpack file */
1135 if (!self->error) {
1136 self->d->outfh = fh;
1137 error = self->d->decompress(self->d->state, filelen);
1138 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1139 }
1140 }
1141
1142 /* close output file */
1143 sys->close(fh);
1144 self->d->outfh = NULL;
1145
1146 return self->error;
1147}
1148
1149/***************************************
1150 * CABD_INIT_DECOMP, CABD_FREE_DECOMP
1151 ***************************************
1152 * cabd_init_decomp initialises decompression state, according to which
1153 * decompression method was used. relies on self->d->folder being the same
1154 * as when initialised.
1155 *
1156 * cabd_free_decomp frees decompression state, according to which method
1157 * was used.
1158 */
1159static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1160{
1161 struct mspack_file *fh = (struct mspack_file *) self;
1162
1163 self->d->comp_type = ct;
1164
1165 switch (ct & cffoldCOMPTYPE_MASK) {
1166 case cffoldCOMPTYPE_NONE:
1167 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
1168 self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
1169 break;
1170 case cffoldCOMPTYPE_MSZIP:
1171 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
1172 self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
1173 self->fix_mszip);
1174 break;
1175 case cffoldCOMPTYPE_QUANTUM:
1176 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
1177 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
1178 self->buf_size);
1179 break;
1180 case cffoldCOMPTYPE_LZX:
1181 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
1182 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
1183 self->buf_size, (off_t)0,0);
1184 break;
1185 default:
1186 return self->error = MSPACK_ERR_DATAFORMAT;
1187 }
1188 return self->error = (self->d->state) ? MSPACK_ERR_OK : MSPACK_ERR_NOMEMORY;
1189}
1190
1191static void cabd_free_decomp(struct mscab_decompressor_p *self) {
1192 if (!self || !self->d || !self->d->state) return;
1193
1194 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
1195 case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
1196 case cffoldCOMPTYPE_MSZIP: mszipd_free((struct mszipd_stream *) self->d->state); break;
1197 case cffoldCOMPTYPE_QUANTUM: qtmd_free((struct qtmd_stream *) self->d->state); break;
1198 case cffoldCOMPTYPE_LZX: lzxd_free((struct lzxd_stream *) self->d->state); break;
1199 }
1200 self->d->decompress = NULL;
1201 self->d->state = NULL;
1202}
1203
1204/***************************************
1205 * CABD_SYS_READ, CABD_SYS_WRITE
1206 ***************************************
1207 * cabd_sys_read is the internal reader function which the decompressors
1208 * use. will read data blocks (and merge split blocks) from the cabinet
1209 * and serve the read bytes to the decompressors
1210 *
1211 * cabd_sys_write is the internal writer function which the decompressors
1212 * use. it either writes data to disk (self->d->outfh) with the real
1213 * sys->write() function, or does nothing with the data when
1214 * self->d->outfh == NULL. advances self->d->offset
1215 */
1216static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1217 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1218 unsigned char *buf = (unsigned char *) buffer;
1219 struct mspack_system *sys = self->system;
1220 int avail, todo, outlen, ignore_cksum, ignore_blocksize;
1221
1222 ignore_cksum = self->salvage ||
1223 (self->fix_mszip &&
1224 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
1225 ignore_blocksize = self->salvage;
1226
1227 todo = bytes;
1228 while (todo > 0) {
1229 avail = self->d->i_end - self->d->i_ptr;
1230
1231 /* if out of input data, read a new block */
1232 if (avail) {
1233 /* copy as many input bytes available as possible */
1234 if (avail > todo) avail = todo;
1235 sys->copy(self->d->i_ptr, buf, (size_t) avail);
1236 self->d->i_ptr += avail;
1237 buf += avail;
1238 todo -= avail;
1239 }
1240 else {
1241 /* out of data, read a new block */
1242
1243 /* check if we're out of input blocks, advance block counter */
1244 if (self->d->block++ >= self->d->folder->base.num_blocks) {
1245 if (!self->salvage) {
1246 self->read_error = MSPACK_ERR_DATAFORMAT;
1247 }
1248 else {
1249 D(("Ran out of CAB input blocks prematurely"))
1250 }
1251 break;
1252 }
1253
1254 /* read a block */
1255 self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
1256 ignore_cksum, ignore_blocksize);
1257 if (self->read_error) return -1;
1258 self->d->outlen += outlen;
1259
1260 /* special Quantum hack -- trailer byte to allow the decompressor
1261 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
1262 * anything from 0 to 4 trailing null bytes. */
1263 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
1264 *self->d->i_end++ = 0xFF;
1265 }
1266
1267 /* is this the last block? */
1268 if (self->d->block >= self->d->folder->base.num_blocks) {
1269 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1270 /* special LZX hack -- on the last block, inform LZX of the
1271 * size of the output data stream. */
1272 lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
1273 }
1274 }
1275 } /* if (avail) */
1276 } /* while (todo > 0) */
1277 return bytes - todo;
1278}
1279
1280static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1281 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1282 self->d->offset += bytes;
1283 if (self->d->outfh) {
1284 return self->system->write(self->d->outfh, buffer, bytes);
1285 }
1286 return bytes;
1287}
1288
1289/***************************************
1290 * CABD_SYS_READ_BLOCK
1291 ***************************************
1292 * reads a whole data block from a cab file. the block may span more than
1293 * one cab file, if it does then the fragments will be reassembled
1294 */
1295static int cabd_sys_read_block(struct mspack_system *sys,
1296 struct mscabd_decompress_state *d,
1297 int *out, int ignore_cksum,
1298 int ignore_blocksize)
1299{
1300 unsigned char hdr[cfdata_SIZEOF];
1301 unsigned int cksum;
1302 int len, full_len;
1303
1304 /* reset the input block pointer and end of block pointer */
1305 d->i_ptr = d->i_end = &d->input[0];
1306
1307 do {
1308 /* read the block header */
1309 if (sys->read(d->infh, &hdr[0], cfdata_SIZEOF) != cfdata_SIZEOF) {
1310 return MSPACK_ERR_READ;
1311 }
1312
1313 /* skip any reserved block headers */
1314 if (d->data->cab->block_resv &&
1315 sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1316 MSPACK_SYS_SEEK_CUR))
1317 {
1318 return MSPACK_ERR_SEEK;
1319 }
1320
1321 /* blocks must not be over CAB_INPUTMAX in size */
1322 len = EndGetI16(&hdr[cfdata_CompressedSize]);
1323 full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
1324 if (full_len > CAB_INPUTMAX) {
1325 D(("block size %d > CAB_INPUTMAX", full_len));
1326 /* in salvage mode, blocks can be 65535 bytes but no more than that */
1327 if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE) {
1328 return MSPACK_ERR_DATAFORMAT;
1329 }
1330 }
1331
1332 /* blocks must not expand to more than CAB_BLOCKMAX */
1333 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
1334 D(("block size > CAB_BLOCKMAX"))
1335 if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
1336 }
1337
1338 /* read the block data */
1339 if (sys->read(d->infh, d->i_end, len) != len) {
1340 return MSPACK_ERR_READ;
1341 }
1342
1343 /* perform checksum test on the block (if one is stored) */
1344 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
1345 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
1346 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
1347 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1348 sys->message(d->infh, "WARNING; bad block checksum found");
1349 }
1350 }
1351
1352 /* advance end of block pointer to include newly read data */
1353 d->i_end += len;
1354
1355 /* uncompressed size == 0 means this block was part of a split block
1356 * and it continues as the first block of the next cabinet in the set.
1357 * otherwise, this is the last part of the block, and no more block
1358 * reading needs to be done.
1359 */
1360 /* EXIT POINT OF LOOP -- uncompressed size != 0 */
1361 if ((*out = EndGetI16(&hdr[cfdata_UncompressedSize]))) {
1362 return MSPACK_ERR_OK;
1363 }
1364
1365 /* otherwise, advance to next cabinet */
1366
1367 /* close current file handle */
1368 sys->close(d->infh);
1369 d->infh = NULL;
1370
1371 /* advance to next member in the cabinet set */
1372 if (!(d->data = d->data->next)) {
1373 sys->message(d->infh, "WARNING; ran out of cabinets in set. Are any missing?");
1374 return MSPACK_ERR_DATAFORMAT;
1375 }
1376
1377 /* open next cab file */
1378 d->incab = d->data->cab;
1379 if (!(d->infh = sys->open(sys, d->incab->base.filename,
1380 MSPACK_SYS_OPEN_READ)))
1381 {
1382 return MSPACK_ERR_OPEN;
1383 }
1384
1385 /* seek to start of data blocks */
1386 if (sys->seek(d->infh, d->data->offset, MSPACK_SYS_SEEK_START)) {
1387 return MSPACK_ERR_SEEK;
1388 }
1389 } while (1);
1390
1391 /* not reached */
1392 return MSPACK_ERR_OK;
1393}
1394
1395static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1396 unsigned int cksum)
1397{
1398 unsigned int len, ul = 0;
1399
1400 for (len = bytes >> 2; len--; data += 4) {
1401 cksum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
1402 }
1403
1404 switch (bytes & 3) {
1405 case 3: ul |= *data++ << 16; /*@fallthrough@*/
1406 case 2: ul |= *data++ << 8; /*@fallthrough@*/
1407 case 1: ul |= *data;
1408 }
1409 cksum ^= ul;
1410
1411 return cksum;
1412}
1413
1414/***************************************
1415 * NONED_INIT, NONED_DECOMPRESS, NONED_FREE
1416 ***************************************
1417 * the "not compressed" method decompressor
1418 */
1419struct noned_state {
1420 struct mspack_system *sys;
1421 struct mspack_file *i;
1422 struct mspack_file *o;
1423 unsigned char *buf;
1424 int bufsize;
1425};
1426
1427static struct noned_state *noned_init(struct mspack_system *sys,
1428 struct mspack_file *in,
1429 struct mspack_file *out,
1430 int bufsize)
1431{
1432 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
1433 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize);
1434 if (state && buf) {
1435 state->sys = sys;
1436 state->i = in;
1437 state->o = out;
1438 state->buf = buf;
1439 state->bufsize = bufsize;
1440 }
1441 else {
1442 sys->free(buf);
1443 sys->free(state);
1444 state = NULL;
1445 }
1446 return state;
1447}
1448
1449static int noned_decompress(struct noned_state *s, off_t bytes) {
1450 int run;
1451 while (bytes > 0) {
1452 run = (bytes > s->bufsize) ? s->bufsize : (int) bytes;
1453 if (s->sys->read(s->i, &s->buf[0], run) != run) return MSPACK_ERR_READ;
1454 if (s->sys->write(s->o, &s->buf[0], run) != run) return MSPACK_ERR_WRITE;
1455 bytes -= run;
1456 }
1457 return MSPACK_ERR_OK;
1458}
1459
1460static void noned_free(struct noned_state *state) {
1461 struct mspack_system *sys;
1462 if (state) {
1463 sys = state->sys;
1464 sys->free(state->buf);
1465 sys->free(state);
1466 }
1467}
1468
1469
1470/***************************************
1471 * CABD_PARAM
1472 ***************************************
1473 * allows a parameter to be set
1474 */
1475static int cabd_param(struct mscab_decompressor *base, int param, int value) {
1476 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
1477 if (!self) return MSPACK_ERR_ARGS;
1478
1479 switch (param) {
1480 case MSCABD_PARAM_SEARCHBUF:
1481 if (value < 4) return MSPACK_ERR_ARGS;
1482 self->searchbuf_size = value;
1483 break;
1484 case MSCABD_PARAM_FIXMSZIP:
1485 self->fix_mszip = value;
1486 break;
1487 case MSCABD_PARAM_DECOMPBUF:
1488 if (value < 4) return MSPACK_ERR_ARGS;
1489 self->buf_size = value;
1490 break;
1491 case MSCABD_PARAM_SALVAGE:
1492 self->salvage = value;
1493 break;
1494 default:
1495 return MSPACK_ERR_ARGS;
1496 }
1497 return MSPACK_ERR_OK;
1498}
1499
1500/***************************************
1501 * CABD_ERROR
1502 ***************************************
1503 * returns the last error that occurred
1504 */
1505static int cabd_error(struct mscab_decompressor *base) {
1506 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
1507 return (self) ? self->error : MSPACK_ERR_ARGS;
1508}