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