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