Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / cabinet / fdi.c
blobc4278de711f0707d87095a395b910431b8a3a2ad
1 /*
2 * File Decompression Interface
4 * Copyright 2000-2002 Stuart Caie
5 * Copyright 2002 Patrik Stridvall
6 * Copyright 2003 Greg Turner
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * This is a largely redundant reimplementation of the stuff in cabextract.c. It
24 * would be theoretically preferable to have only one, shared implementation, however
25 * there are semantic differences which may discourage efforts to unify the two. It
26 * should be possible, if awkward, to go back and reimplement cabextract.c using FDI.
27 * But this approach would be quite a bit less performant. Probably a better way
28 * would be to create a "library" of routines in cabextract.c which do the actual
29 * decompression, and have both fdi.c and cabextract share those routines. The rest
30 * of the code is not sufficiently similar to merit a shared implementation.
32 * The worst thing about this API is the bug. "The bug" is this: when you extract a
33 * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that
34 * there is no subsequent cabinet, even if there is one. wine faithfully reproduces
35 * this behavior.
37 * TODO:
39 * Wine does not implement the AFAIK undocumented "enumerate" callback during
40 * FDICopy. It is implemented in Windows and therefore worth investigating...
42 * Lots of pointers flying around here... am I leaking RAM?
44 * WTF is FDITruncate?
46 * Probably, I need to weed out some dead code-paths.
48 * Test unit(s).
50 * The fdintNEXT_CABINET callbacks are probably not working quite as they should.
51 * There are several FIXME's in the source describing some of the deficiencies in
52 * some detail. Additionally, we do not do a very good job of returning the right
53 * error codes to this callback.
55 * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller
56 * functions would be nice.
58 * -gmt
61 #include "config.h"
63 #include <stdarg.h>
64 #include <stdio.h>
66 #include "windef.h"
67 #include "winbase.h"
68 #include "winerror.h"
69 #include "fdi.h"
70 #include "cabinet.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
76 THOSE_ZIP_CONSTS;
78 struct fdi_file {
79 struct fdi_file *next; /* next file in sequence */
80 LPCSTR filename; /* output name of file */
81 int fh; /* open file handle or NULL */
82 cab_ULONG length; /* uncompressed length of file */
83 cab_ULONG offset; /* uncompressed offset in folder */
84 cab_UWORD index; /* magic index number of folder */
85 cab_UWORD time, date, attribs; /* MS-DOS time/date/attributes */
86 BOOL oppressed; /* never to be processed */
89 struct fdi_folder {
90 struct fdi_folder *next;
91 cab_off_t offset; /* offset to data blocks (32 bit) */
92 cab_UWORD comp_type; /* compression format/window size */
93 cab_ULONG comp_size; /* compressed size of folder */
94 cab_UBYTE num_splits; /* number of split blocks + 1 */
95 cab_UWORD num_blocks; /* total number of blocks */
99 * this structure fills the gaps between what is available in a PFDICABINETINFO
100 * vs what is needed by FDICopy. Memory allocated for these becomes the responsibility
101 * of the caller to free. Yes, I am aware that this is totally, utterly inelegant.
102 * To make things even more unnecessarily confusing, we now attach these to the
103 * fdi_decomp_state.
105 typedef struct {
106 char *prevname, *previnfo;
107 char *nextname, *nextinfo;
108 BOOL hasnext; /* bug free indicator */
109 int folder_resv, header_resv;
110 cab_UBYTE block_resv;
111 } MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;
114 * ugh, well, this ended up being pretty damn silly...
115 * now that I've conceded to build equivalent structures to struct cab.*,
116 * I should have just used those, or, better yet, unified the two... sue me.
117 * (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt).
118 * Nevertheless, I've come this far, it works, so I'm not gonna change it
119 * for now. This implementation has significant semantic differences anyhow.
122 typedef struct fdi_cds_fwd {
123 void *hfdi; /* the hfdi we are using */
124 int filehf, cabhf; /* file handle we are using */
125 struct fdi_folder *current; /* current folder we're extracting from */
126 cab_ULONG offset; /* uncompressed offset within folder */
127 cab_UBYTE *outpos; /* (high level) start of data to use up */
128 cab_UWORD outlen; /* (high level) amount of data to use up */
129 int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn */
130 cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */
131 cab_UBYTE outbuf[CAB_BLOCKMAX];
132 union {
133 struct ZIPstate zip;
134 struct QTMstate qtm;
135 struct LZXstate lzx;
136 } methods;
137 /* some temp variables for use during decompression */
138 cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
139 cab_ULONG q_position_base[42];
140 cab_ULONG lzx_position_base[51];
141 cab_UBYTE extra_bits[51];
142 USHORT setID; /* Cabinet set ID */
143 USHORT iCabinet; /* Cabinet number in set (0 based) */
144 struct fdi_cds_fwd *decomp_cab;
145 MORE_ISCAB_INFO mii;
146 struct fdi_folder *firstfol;
147 struct fdi_file *firstfile;
148 struct fdi_cds_fwd *next;
149 } fdi_decomp_state;
151 /****************************************************************
152 * QTMupdatemodel (internal)
154 void QTMupdatemodel(struct QTMmodel *model, int sym) {
155 struct QTMmodelsym temp;
156 int i, j;
158 for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8;
160 if (model->syms[0].cumfreq > 3800) {
161 if (--model->shiftsleft) {
162 for (i = model->entries - 1; i >= 0; i--) {
163 /* -1, not -2; the 0 entry saves this */
164 model->syms[i].cumfreq >>= 1;
165 if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
166 model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
170 else {
171 model->shiftsleft = 50;
172 for (i = 0; i < model->entries ; i++) {
173 /* no -1, want to include the 0 entry */
174 /* this converts cumfreqs into frequencies, then shifts right */
175 model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
176 model->syms[i].cumfreq++; /* avoid losing things entirely */
177 model->syms[i].cumfreq >>= 1;
180 /* now sort by frequencies, decreasing order -- this must be an
181 * inplace selection sort, or a sort with the same (in)stability
182 * characteristics
184 for (i = 0; i < model->entries - 1; i++) {
185 for (j = i + 1; j < model->entries; j++) {
186 if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
187 temp = model->syms[i];
188 model->syms[i] = model->syms[j];
189 model->syms[j] = temp;
194 /* then convert frequencies back to cumfreq */
195 for (i = model->entries - 1; i >= 0; i--) {
196 model->syms[i].cumfreq += model->syms[i+1].cumfreq;
198 /* then update the other part of the table */
199 for (i = 0; i < model->entries; i++) {
200 model->tabloc[model->syms[i].sym] = i;
206 /*************************************************************************
207 * make_decode_table (internal)
209 * This function was coded by David Tritscher. It builds a fast huffman
210 * decoding table out of just a canonical huffman code lengths table.
212 * PARAMS
213 * nsyms: total number of symbols in this huffman tree.
214 * nbits: any symbols with a code length of nbits or less can be decoded
215 * in one lookup of the table.
216 * length: A table to get code lengths from [0 to syms-1]
217 * table: The table to fill up with decoded symbols and pointers.
219 * RETURNS
220 * OK: 0
221 * error: 1
223 int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, const cab_UBYTE *length, cab_UWORD *table) {
224 register cab_UWORD sym;
225 register cab_ULONG leaf;
226 register cab_UBYTE bit_num = 1;
227 cab_ULONG fill;
228 cab_ULONG pos = 0; /* the current position in the decode table */
229 cab_ULONG table_mask = 1 << nbits;
230 cab_ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
231 cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */
233 /* fill entries for codes short enough for a direct mapping */
234 while (bit_num <= nbits) {
235 for (sym = 0; sym < nsyms; sym++) {
236 if (length[sym] == bit_num) {
237 leaf = pos;
239 if((pos += bit_mask) > table_mask) return 1; /* table overrun */
241 /* fill all possible lookups of this symbol with the symbol itself */
242 fill = bit_mask;
243 while (fill-- > 0) table[leaf++] = sym;
246 bit_mask >>= 1;
247 bit_num++;
250 /* if there are any codes longer than nbits */
251 if (pos != table_mask) {
252 /* clear the remainder of the table */
253 for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
255 /* give ourselves room for codes to grow by up to 16 more bits */
256 pos <<= 16;
257 table_mask <<= 16;
258 bit_mask = 1 << 15;
260 while (bit_num <= 16) {
261 for (sym = 0; sym < nsyms; sym++) {
262 if (length[sym] == bit_num) {
263 leaf = pos >> 16;
264 for (fill = 0; fill < bit_num - nbits; fill++) {
265 /* if this path hasn't been taken yet, 'allocate' two entries */
266 if (table[leaf] == 0) {
267 table[(next_symbol << 1)] = 0;
268 table[(next_symbol << 1) + 1] = 0;
269 table[leaf] = next_symbol++;
271 /* follow the path and select either left or right for next bit */
272 leaf = table[leaf] << 1;
273 if ((pos >> (15-fill)) & 1) leaf++;
275 table[leaf] = sym;
277 if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
280 bit_mask >>= 1;
281 bit_num++;
285 /* full table? */
286 if (pos == table_mask) return 0;
288 /* either erroneous table, or all elements are 0 - let's find out. */
289 for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
290 return 0;
293 /*************************************************************************
294 * checksum (internal)
296 cab_ULONG checksum(const cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) {
297 int len;
298 cab_ULONG ul = 0;
300 for (len = bytes >> 2; len--; data += 4) {
301 csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
304 switch (bytes & 3) {
305 case 3: ul |= *data++ << 16;
306 case 2: ul |= *data++ << 8;
307 case 1: ul |= *data;
309 csum ^= ul;
311 return csum;
314 /***********************************************************************
315 * FDICreate (CABINET.20)
317 * Provided with several callbacks (all of them are mandatory),
318 * returns a handle which can be used to perform operations
319 * on cabinet files.
321 * PARAMS
322 * pfnalloc [I] A pointer to a function which allocates ram. Uses
323 * the same interface as malloc.
324 * pfnfree [I] A pointer to a function which frees ram. Uses the
325 * same interface as free.
326 * pfnopen [I] A pointer to a function which opens a file. Uses
327 * the same interface as _open.
328 * pfnread [I] A pointer to a function which reads from a file into
329 * a caller-provided buffer. Uses the same interface
330 * as _read
331 * pfnwrite [I] A pointer to a function which writes to a file from
332 * a caller-provided buffer. Uses the same interface
333 * as _write.
334 * pfnclose [I] A pointer to a function which closes a file handle.
335 * Uses the same interface as _close.
336 * pfnseek [I] A pointer to a function which seeks in a file.
337 * Uses the same interface as _lseek.
338 * cpuType [I] The type of CPU; ignored in wine (recommended value:
339 * cpuUNKNOWN, aka -1).
340 * perf [IO] A pointer to an ERF structure. When FDICreate
341 * returns an error condition, error information may
342 * be found here as well as from GetLastError.
344 * RETURNS
345 * On success, returns an FDI handle of type HFDI.
346 * On failure, the NULL file handle is returned. Error
347 * info can be retrieved from perf.
349 * INCLUDES
350 * fdi.h
353 HFDI __cdecl FDICreate(
354 PFNALLOC pfnalloc,
355 PFNFREE pfnfree,
356 PFNOPEN pfnopen,
357 PFNREAD pfnread,
358 PFNWRITE pfnwrite,
359 PFNCLOSE pfnclose,
360 PFNSEEK pfnseek,
361 int cpuType,
362 PERF perf)
364 HFDI rv;
366 TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, "
367 "pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n",
368 pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek,
369 cpuType, perf);
371 if ((!pfnalloc) || (!pfnfree)) {
372 perf->erfOper = FDIERROR_NONE;
373 perf->erfType = ERROR_BAD_ARGUMENTS;
374 perf->fError = TRUE;
376 SetLastError(ERROR_BAD_ARGUMENTS);
377 return NULL;
380 if (!((rv = ((HFDI) (*pfnalloc)(sizeof(FDI_Int)))))) {
381 perf->erfOper = FDIERROR_ALLOC_FAIL;
382 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
383 perf->fError = TRUE;
385 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
386 return NULL;
389 PFDI_INT(rv)->FDI_Intmagic = FDI_INT_MAGIC;
390 PFDI_INT(rv)->pfnalloc = pfnalloc;
391 PFDI_INT(rv)->pfnfree = pfnfree;
392 PFDI_INT(rv)->pfnopen = pfnopen;
393 PFDI_INT(rv)->pfnread = pfnread;
394 PFDI_INT(rv)->pfnwrite = pfnwrite;
395 PFDI_INT(rv)->pfnclose = pfnclose;
396 PFDI_INT(rv)->pfnseek = pfnseek;
397 /* no-brainer: we ignore the cpu type; this is only used
398 for the 16-bit versions in Windows anyhow... */
399 PFDI_INT(rv)->perf = perf;
401 return rv;
404 /*******************************************************************
405 * FDI_getoffset (internal)
407 * returns the file pointer position of a file handle.
409 static long FDI_getoffset(HFDI hfdi, INT_PTR hf)
411 return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR);
414 /**********************************************************************
415 * FDI_realloc (internal)
417 * we can't use _msize; the user might not be using malloc, so we require
418 * an explicit specification of the previous size. inefficient.
420 static void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
422 void *rslt = NULL;
423 char *irslt, *imem;
424 size_t copysize = (prevsize < newsize) ? prevsize : newsize;
425 if (prevsize == newsize) return mem;
426 rslt = PFDI_ALLOC(hfdi, newsize);
427 if (rslt)
428 for (irslt = (char *)rslt, imem = (char *)mem; (copysize); copysize--)
429 *irslt++ = *imem++;
430 PFDI_FREE(hfdi, mem);
431 return rslt;
434 /**********************************************************************
435 * FDI_read_string (internal)
437 * allocate and read an arbitrarily long string from the cabinet
439 static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
441 size_t len=256,
442 oldlen = 0,
443 base = FDI_getoffset(hfdi, hf),
444 maxlen = cabsize - base;
445 BOOL ok = FALSE;
446 unsigned int i;
447 cab_UBYTE *buf = NULL;
449 TRACE("(hfdi == ^%p, hf == %d)\n", hfdi, hf);
451 do {
452 if (len > maxlen) len = maxlen;
453 if (!(buf = FDI_realloc(hfdi, buf, oldlen, len))) break;
454 oldlen = len;
455 if (!PFDI_READ(hfdi, hf, buf, len)) break;
457 /* search for a null terminator in what we've just read */
458 for (i=0; i < len; i++) {
459 if (!buf[i]) {ok=TRUE; break;}
462 if (!ok) {
463 if (len == maxlen) {
464 ERR("cabinet is truncated\n");
465 break;
467 len += 256;
468 PFDI_SEEK(hfdi, hf, base, SEEK_SET);
470 } while (!ok);
472 if (!ok) {
473 if (buf)
474 PFDI_FREE(hfdi, buf);
475 else
476 ERR("out of memory!\n");
477 return NULL;
480 /* otherwise, set the stream to just after the string and return */
481 PFDI_SEEK(hfdi, hf, base + ((cab_off_t) strlen((char *) buf)) + 1, SEEK_SET);
483 return (char *) buf;
486 /******************************************************************
487 * FDI_read_entries (internal)
489 * process the cabinet header in the style of FDIIsCabinet, but
490 * without the sanity checks (and bug)
492 static BOOL FDI_read_entries(
493 HFDI hfdi,
494 INT_PTR hf,
495 PFDICABINETINFO pfdici,
496 PMORE_ISCAB_INFO pmii)
498 int num_folders, num_files, header_resv, folder_resv = 0;
499 LONG base_offset, cabsize;
500 USHORT setid, cabidx, flags;
501 cab_UBYTE buf[64], block_resv;
502 char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL;
504 TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici);
507 * FIXME: I just noticed that I am memorizing the initial file pointer
508 * offset and restoring it before reading in the rest of the header
509 * information in the cabinet. Perhaps that's correct -- that is, perhaps
510 * this API is supposed to support "streaming" cabinets which are embedded
511 * in other files, or cabinets which begin at file offsets other than zero.
512 * Otherwise, I should instead go to the absolute beginning of the file.
513 * (Either way, the semantics of wine's FDICopy require me to leave the
514 * file pointer where it is afterwards -- If Windows does not do so, we
515 * ought to duplicate the native behavior in the FDIIsCabinet API, not here.
517 * So, the answer lies in Windows; will native cabinet.dll recognize a
518 * cabinet "file" embedded in another file? Note that cabextract.c does
519 * support this, which implies that Microsoft's might. I haven't tried it
520 * yet so I don't know. ATM, most of wine's FDI cabinet routines (except
521 * this one) would not work in this way. To fix it, we could just make the
522 * various references to absolute file positions in the code relative to an
523 * initial "beginning" offset. Because the FDICopy API doesn't take a
524 * file-handle like this one, we would therein need to search through the
525 * file for the beginning of the cabinet (as we also do in cabextract.c).
526 * Note that this limits us to a maximum of one cabinet per. file: the first.
528 * So, in summary: either the code below is wrong, or the rest of fdi.c is
529 * wrong... I cannot imagine that both are correct ;) One of these flaws
530 * should be fixed after determining the behavior on Windows. We ought
531 * to check both FDIIsCabinet and FDICopy for the right behavior.
533 * -gmt
536 /* get basic offset & size info */
537 base_offset = FDI_getoffset(hfdi, hf);
539 if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) {
540 if (pmii) {
541 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
542 PFDI_INT(hfdi)->perf->erfType = 0;
543 PFDI_INT(hfdi)->perf->fError = TRUE;
545 return FALSE;
548 cabsize = FDI_getoffset(hfdi, hf);
550 if ((cabsize == -1) || (base_offset == -1) ||
551 ( PFDI_SEEK(hfdi, hf, base_offset, SEEK_SET) == -1 )) {
552 if (pmii) {
553 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
554 PFDI_INT(hfdi)->perf->erfType = 0;
555 PFDI_INT(hfdi)->perf->fError = TRUE;
557 return FALSE;
560 /* read in the CFHEADER */
561 if (PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) {
562 if (pmii) {
563 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
564 PFDI_INT(hfdi)->perf->erfType = 0;
565 PFDI_INT(hfdi)->perf->fError = TRUE;
567 return FALSE;
570 /* check basic MSCF signature */
571 if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) {
572 if (pmii) {
573 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
574 PFDI_INT(hfdi)->perf->erfType = 0;
575 PFDI_INT(hfdi)->perf->fError = TRUE;
577 return FALSE;
580 /* get the number of folders */
581 num_folders = EndGetI16(buf+cfhead_NumFolders);
582 if (num_folders == 0) {
583 /* PONDERME: is this really invalid? */
584 WARN("weird cabinet detect failure: no folders in cabinet\n");
585 if (pmii) {
586 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
587 PFDI_INT(hfdi)->perf->erfType = 0;
588 PFDI_INT(hfdi)->perf->fError = TRUE;
590 return FALSE;
593 /* get the number of files */
594 num_files = EndGetI16(buf+cfhead_NumFiles);
595 if (num_files == 0) {
596 /* PONDERME: is this really invalid? */
597 WARN("weird cabinet detect failure: no files in cabinet\n");
598 if (pmii) {
599 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
600 PFDI_INT(hfdi)->perf->erfType = 0;
601 PFDI_INT(hfdi)->perf->fError = TRUE;
603 return FALSE;
606 /* setid */
607 setid = EndGetI16(buf+cfhead_SetID);
609 /* cabinet (set) index */
610 cabidx = EndGetI16(buf+cfhead_CabinetIndex);
612 /* check the header revision */
613 if ((buf[cfhead_MajorVersion] > 1) ||
614 (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
616 WARN("cabinet format version > 1.3\n");
617 if (pmii) {
618 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION;
619 PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
620 PFDI_INT(hfdi)->perf->fError = TRUE;
622 return FALSE;
625 /* pull the flags out */
626 flags = EndGetI16(buf+cfhead_Flags);
628 /* read the reserved-sizes part of header, if present */
629 if (flags & cfheadRESERVE_PRESENT) {
630 if (PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) {
631 ERR("bunk reserve-sizes?\n");
632 if (pmii) {
633 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
634 PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
635 PFDI_INT(hfdi)->perf->fError = TRUE;
637 return FALSE;
640 header_resv = EndGetI16(buf+cfheadext_HeaderReserved);
641 if (pmii) pmii->header_resv = header_resv;
642 folder_resv = buf[cfheadext_FolderReserved];
643 if (pmii) pmii->folder_resv = folder_resv;
644 block_resv = buf[cfheadext_DataReserved];
645 if (pmii) pmii->block_resv = block_resv;
647 if (header_resv > 60000) {
648 WARN("WARNING; header reserved space > 60000\n");
651 /* skip the reserved header */
652 if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1)) {
653 ERR("seek failure: header_resv\n");
654 if (pmii) {
655 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
656 PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
657 PFDI_INT(hfdi)->perf->fError = TRUE;
659 return FALSE;
663 if (flags & cfheadPREV_CABINET) {
664 prevname = FDI_read_string(hfdi, hf, cabsize);
665 if (!prevname) {
666 if (pmii) {
667 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
668 PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
669 PFDI_INT(hfdi)->perf->fError = TRUE;
671 return FALSE;
672 } else
673 if (pmii)
674 pmii->prevname = prevname;
675 else
676 PFDI_FREE(hfdi, prevname);
677 previnfo = FDI_read_string(hfdi, hf, cabsize);
678 if (previnfo) {
679 if (pmii)
680 pmii->previnfo = previnfo;
681 else
682 PFDI_FREE(hfdi, previnfo);
686 if (flags & cfheadNEXT_CABINET) {
687 if (pmii)
688 pmii->hasnext = TRUE;
689 nextname = FDI_read_string(hfdi, hf, cabsize);
690 if (!nextname) {
691 if ((flags & cfheadPREV_CABINET) && pmii) {
692 if (pmii->prevname) PFDI_FREE(hfdi, prevname);
693 if (pmii->previnfo) PFDI_FREE(hfdi, previnfo);
695 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
696 PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
697 PFDI_INT(hfdi)->perf->fError = TRUE;
698 return FALSE;
699 } else
700 if (pmii)
701 pmii->nextname = nextname;
702 else
703 PFDI_FREE(hfdi, nextname);
704 nextinfo = FDI_read_string(hfdi, hf, cabsize);
705 if (nextinfo) {
706 if (pmii)
707 pmii->nextinfo = nextinfo;
708 else
709 PFDI_FREE(hfdi, nextinfo);
713 /* we could process the whole cabinet searching for problems;
714 instead lets stop here. Now let's fill out the paperwork */
715 pfdici->cbCabinet = cabsize;
716 pfdici->cFolders = num_folders;
717 pfdici->cFiles = num_files;
718 pfdici->setID = setid;
719 pfdici->iCabinet = cabidx;
720 pfdici->fReserve = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE;
721 pfdici->hasprev = (flags & cfheadPREV_CABINET) ? TRUE : FALSE;
722 pfdici->hasnext = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE;
723 return TRUE;
726 /***********************************************************************
727 * FDIIsCabinet (CABINET.21)
729 * Informs the caller as to whether or not the provided file handle is
730 * really a cabinet or not, filling out the provided PFDICABINETINFO
731 * structure with information about the cabinet. Brief explanations of
732 * the elements of this structure are available as comments accompanying
733 * its definition in wine's include/fdi.h.
735 * PARAMS
736 * hfdi [I] An HFDI from FDICreate
737 * hf [I] The file handle about which the caller inquires
738 * pfdici [IO] Pointer to a PFDICABINETINFO structure which will
739 * be filled out with information about the cabinet
740 * file indicated by hf if, indeed, it is determined
741 * to be a cabinet.
743 * RETURNS
744 * TRUE if the file is a cabinet. The info pointed to by pfdici will
745 * be provided.
746 * FALSE if the file is not a cabinet, or if an error was encountered
747 * while processing the cabinet. The PERF structure provided to
748 * FDICreate can be queried for more error information.
750 * INCLUDES
751 * fdi.c
753 BOOL __cdecl FDIIsCabinet(
754 HFDI hfdi,
755 INT_PTR hf,
756 PFDICABINETINFO pfdici)
758 BOOL rv;
760 TRACE("(hfdi == ^%p, hf == ^%d, pfdici == ^%p)\n", hfdi, hf, pfdici);
762 if (!REALLY_IS_FDI(hfdi)) {
763 ERR("REALLY_IS_FDI failed on ^%p\n", hfdi);
764 SetLastError(ERROR_INVALID_HANDLE);
765 return FALSE;
768 if (!hf) {
769 ERR("(!hf)!\n");
770 /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
771 PFDI_INT(hfdi)->perf->erfType = ERROR_INVALID_HANDLE;
772 PFDI_INT(hfdi)->perf->fError = TRUE; */
773 SetLastError(ERROR_INVALID_HANDLE);
774 return FALSE;
777 if (!pfdici) {
778 ERR("(!pfdici)!\n");
779 /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NONE;
780 PFDI_INT(hfdi)->perf->erfType = ERROR_BAD_ARGUMENTS;
781 PFDI_INT(hfdi)->perf->fError = TRUE; */
782 SetLastError(ERROR_BAD_ARGUMENTS);
783 return FALSE;
785 rv = FDI_read_entries(hfdi, hf, pfdici, NULL);
787 if (rv)
788 pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */
790 return rv;
793 /******************************************************************
794 * QTMfdi_initmodel (internal)
796 * Initialize a model which decodes symbols from [s] to [s]+[n]-1
798 static void QTMfdi_initmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) {
799 int i;
800 m->shiftsleft = 4;
801 m->entries = n;
802 m->syms = sym;
803 memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */
804 for (i = 0; i < n; i++) {
805 m->tabloc[i+s] = i; /* set up a look-up entry for symbol */
806 m->syms[i].sym = i+s; /* actual symbol */
807 m->syms[i].cumfreq = n-i; /* current frequency of that symbol */
809 m->syms[n].cumfreq = 0;
812 /******************************************************************
813 * QTMfdi_init (internal)
815 static int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
816 unsigned int wndsize = 1 << window;
817 int msz = window * 2, i;
818 cab_ULONG j;
820 /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
821 /* if a previously allocated window is big enough, keep it */
822 if (window < 10 || window > 21) return DECR_DATAFORMAT;
823 if (QTM(actual_size) < wndsize) {
824 if (QTM(window)) PFDI_FREE(CAB(hfdi), QTM(window));
825 QTM(window) = NULL;
827 if (!QTM(window)) {
828 if (!(QTM(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY;
829 QTM(actual_size) = wndsize;
831 QTM(window_size) = wndsize;
832 QTM(window_posn) = 0;
834 /* initialize static slot/extrabits tables */
835 for (i = 0, j = 0; i < 27; i++) {
836 CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
837 CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]);
839 for (i = 0, j = 0; i < 42; i++) {
840 CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1;
841 CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i];
844 /* initialize arithmetic coding models */
846 QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0);
848 QTMfdi_initmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00);
849 QTMfdi_initmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40);
850 QTMfdi_initmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80);
851 QTMfdi_initmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0);
853 /* model 4 depends on table size, ranges from 20 to 24 */
854 QTMfdi_initmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0);
855 /* model 5 depends on table size, ranges from 20 to 36 */
856 QTMfdi_initmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0);
857 /* model 6pos depends on table size, ranges from 20 to 42 */
858 QTMfdi_initmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0);
859 QTMfdi_initmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0);
861 return DECR_OK;
864 /************************************************************
865 * LZXfdi_init (internal)
867 static int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
868 static const cab_UBYTE bits[] =
869 { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
870 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
871 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
872 17, 17, 17};
873 static const cab_ULONG base[] =
874 { 0, 1, 2, 3, 4, 6, 8, 12,
875 16, 24, 32, 48, 64, 96, 128, 192,
876 256, 384, 512, 768, 1024, 1536, 2048, 3072,
877 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
878 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
879 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
880 1835008, 1966080, 2097152};
881 cab_ULONG wndsize = 1 << window;
882 int posn_slots;
884 /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
885 /* if a previously allocated window is big enough, keep it */
886 if (window < 15 || window > 21) return DECR_DATAFORMAT;
887 if (LZX(actual_size) < wndsize) {
888 if (LZX(window)) PFDI_FREE(CAB(hfdi), LZX(window));
889 LZX(window) = NULL;
891 if (!LZX(window)) {
892 if (!(LZX(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY;
893 LZX(actual_size) = wndsize;
895 LZX(window_size) = wndsize;
897 /* initialize static tables */
898 memcpy(CAB(extra_bits), bits, sizeof(bits));
899 memcpy(CAB(lzx_position_base), base, sizeof(base));
901 /* calculate required position slots */
902 if (window == 20) posn_slots = 42;
903 else if (window == 21) posn_slots = 50;
904 else posn_slots = window << 1;
906 /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */
908 LZX(R0) = LZX(R1) = LZX(R2) = 1;
909 LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3);
910 LZX(header_read) = 0;
911 LZX(frames_read) = 0;
912 LZX(block_remaining) = 0;
913 LZX(block_type) = LZX_BLOCKTYPE_INVALID;
914 LZX(intel_curpos) = 0;
915 LZX(intel_started) = 0;
916 LZX(window_posn) = 0;
918 /* initialize tables to 0 (because deltas will be applied to them) */
919 memset(LZX(MAINTREE_len), 0, sizeof(LZX(MAINTREE_len)));
920 memset(LZX(LENGTH_len), 0, sizeof(LZX(LENGTH_len)));
922 return DECR_OK;
925 /****************************************************
926 * NONEfdi_decomp(internal)
928 static int NONEfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
930 if (inlen != outlen) return DECR_ILLEGALDATA;
931 memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen);
932 return DECR_OK;
935 /********************************************************
936 * Ziphuft_free (internal)
938 static void fdi_Ziphuft_free(HFDI hfdi, struct Ziphuft *t)
940 register struct Ziphuft *p, *q;
942 /* Go through linked list, freeing from the allocated (t[-1]) address. */
943 p = t;
944 while (p != (struct Ziphuft *)NULL)
946 q = (--p)->v.t;
947 PFDI_FREE(hfdi, p);
948 p = q;
952 /*********************************************************
953 * fdi_Ziphuft_build (internal)
955 static cab_LONG fdi_Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, const cab_UWORD *d, const cab_UWORD *e,
956 struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state)
958 cab_ULONG a; /* counter for codes of length k */
959 cab_ULONG el; /* length of EOB code (value 256) */
960 cab_ULONG f; /* i repeats in table every f entries */
961 cab_LONG g; /* maximum code length */
962 cab_LONG h; /* table level */
963 register cab_ULONG i; /* counter, current code */
964 register cab_ULONG j; /* counter */
965 register cab_LONG k; /* number of bits in current code */
966 cab_LONG *l; /* stack of bits per table */
967 register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */
968 register struct Ziphuft *q; /* points to current table */
969 struct Ziphuft r; /* table entry for structure assignment */
970 register cab_LONG w; /* bits before this table == (l * h) */
971 cab_ULONG *xp; /* pointer into x */
972 cab_LONG y; /* number of dummy codes added */
973 cab_ULONG z; /* number of entries in current table */
975 l = ZIP(lx)+1;
977 /* Generate counts for each bit length */
978 el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
980 for(i = 0; i < ZIPBMAX+1; ++i)
981 ZIP(c)[i] = 0;
982 p = b; i = n;
985 ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */
986 } while (--i);
987 if (ZIP(c)[0] == n) /* null input--all zero length codes */
989 *t = (struct Ziphuft *)NULL;
990 *m = 0;
991 return 0;
994 /* Find minimum and maximum length, bound *m by those */
995 for (j = 1; j <= ZIPBMAX; j++)
996 if (ZIP(c)[j])
997 break;
998 k = j; /* minimum code length */
999 if ((cab_ULONG)*m < j)
1000 *m = j;
1001 for (i = ZIPBMAX; i; i--)
1002 if (ZIP(c)[i])
1003 break;
1004 g = i; /* maximum code length */
1005 if ((cab_ULONG)*m > i)
1006 *m = i;
1008 /* Adjust last length count to fill out codes, if needed */
1009 for (y = 1 << j; j < i; j++, y <<= 1)
1010 if ((y -= ZIP(c)[j]) < 0)
1011 return 2; /* bad input: more codes than bits */
1012 if ((y -= ZIP(c)[i]) < 0)
1013 return 2;
1014 ZIP(c)[i] += y;
1016 /* Generate starting offsets LONGo the value table for each length */
1017 ZIP(x)[1] = j = 0;
1018 p = ZIP(c) + 1; xp = ZIP(x) + 2;
1019 while (--i)
1020 { /* note that i == g from above */
1021 *xp++ = (j += *p++);
1024 /* Make a table of values in order of bit lengths */
1025 p = b; i = 0;
1027 if ((j = *p++) != 0)
1028 ZIP(v)[ZIP(x)[j]++] = i;
1029 } while (++i < n);
1032 /* Generate the Huffman codes and for each, make the table entries */
1033 ZIP(x)[0] = i = 0; /* first Huffman code is zero */
1034 p = ZIP(v); /* grab values in bit order */
1035 h = -1; /* no tables yet--level -1 */
1036 w = l[-1] = 0; /* no bits decoded yet */
1037 ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */
1038 q = (struct Ziphuft *)NULL; /* ditto */
1039 z = 0; /* ditto */
1041 /* go through the bit lengths (k already is bits in shortest code) */
1042 for (; k <= g; k++)
1044 a = ZIP(c)[k];
1045 while (a--)
1047 /* here i is the Huffman code of length k bits for value *p */
1048 /* make tables up to required level */
1049 while (k > w + l[h])
1051 w += l[h++]; /* add bits already decoded */
1053 /* compute minimum size table less than or equal to *m bits */
1054 z = (z = g - w) > (cab_ULONG)*m ? *m : z; /* upper limit */
1055 if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
1056 { /* too few codes for k-w bit table */
1057 f -= a + 1; /* deduct codes from patterns left */
1058 xp = ZIP(c) + k;
1059 while (++j < z) /* try smaller tables up to z bits */
1061 if ((f <<= 1) <= *++xp)
1062 break; /* enough codes to use up j bits */
1063 f -= *xp; /* else deduct codes from patterns */
1066 if ((cab_ULONG)w + j > el && (cab_ULONG)w < el)
1067 j = el - w; /* make EOB code end at table */
1068 z = 1 << j; /* table entries for j-bit table */
1069 l[h] = j; /* set table size in stack */
1071 /* allocate and link in new table */
1072 if (!(q = (struct Ziphuft *) PFDI_ALLOC(CAB(hfdi), (z + 1)*sizeof(struct Ziphuft))))
1074 if(h)
1075 fdi_Ziphuft_free(CAB(hfdi), ZIP(u)[0]);
1076 return 3; /* not enough memory */
1078 *t = q + 1; /* link to list for Ziphuft_free() */
1079 *(t = &(q->v.t)) = (struct Ziphuft *)NULL;
1080 ZIP(u)[h] = ++q; /* table starts after link */
1082 /* connect to last table, if there is one */
1083 if (h)
1085 ZIP(x)[h] = i; /* save pattern for backing up */
1086 r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */
1087 r.e = (cab_UBYTE)(16 + j); /* bits in this table */
1088 r.v.t = q; /* pointer to this table */
1089 j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
1090 ZIP(u)[h-1][j] = r; /* connect to last table */
1094 /* set up table entry in r */
1095 r.b = (cab_UBYTE)(k - w);
1096 if (p >= ZIP(v) + n)
1097 r.e = 99; /* out of values--invalid code */
1098 else if (*p < s)
1100 r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
1101 r.v.n = *p++; /* simple code is just the value */
1103 else
1105 r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */
1106 r.v.n = d[*p++ - s];
1109 /* fill code-like entries with r */
1110 f = 1 << (k - w);
1111 for (j = i >> w; j < z; j += f)
1112 q[j] = r;
1114 /* backwards increment the k-bit code i */
1115 for (j = 1 << (k - 1); i & j; j >>= 1)
1116 i ^= j;
1117 i ^= j;
1119 /* backup over finished tables */
1120 while ((i & ((1 << w) - 1)) != ZIP(x)[h])
1121 w -= l[--h]; /* don't need to update q */
1125 /* return actual size of base table */
1126 *m = l[0];
1128 /* Return true (1) if we were given an incomplete table */
1129 return y != 0 && g != 1;
1132 /*********************************************************
1133 * fdi_Zipinflate_codes (internal)
1135 static cab_LONG fdi_Zipinflate_codes(const struct Ziphuft *tl, const struct Ziphuft *td,
1136 cab_LONG bl, cab_LONG bd, fdi_decomp_state *decomp_state)
1138 register cab_ULONG e; /* table entry flag/number of extra bits */
1139 cab_ULONG n, d; /* length and index for copy */
1140 cab_ULONG w; /* current window position */
1141 const struct Ziphuft *t; /* pointer to table entry */
1142 cab_ULONG ml, md; /* masks for bl and bd bits */
1143 register cab_ULONG b; /* bit buffer */
1144 register cab_ULONG k; /* number of bits in bit buffer */
1146 /* make local copies of globals */
1147 b = ZIP(bb); /* initialize bit buffer */
1148 k = ZIP(bk);
1149 w = ZIP(window_posn); /* initialize window position */
1151 /* inflate the coded data */
1152 ml = Zipmask[bl]; /* precompute masks for speed */
1153 md = Zipmask[bd];
1155 for(;;)
1157 ZIPNEEDBITS((cab_ULONG)bl)
1158 if((e = (t = tl + ((cab_ULONG)b & ml))->e) > 16)
1161 if (e == 99)
1162 return 1;
1163 ZIPDUMPBITS(t->b)
1164 e -= 16;
1165 ZIPNEEDBITS(e)
1166 } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16);
1167 ZIPDUMPBITS(t->b)
1168 if (e == 16) /* then it's a literal */
1169 CAB(outbuf)[w++] = (cab_UBYTE)t->v.n;
1170 else /* it's an EOB or a length */
1172 /* exit if end of block */
1173 if(e == 15)
1174 break;
1176 /* get length of block to copy */
1177 ZIPNEEDBITS(e)
1178 n = t->v.n + ((cab_ULONG)b & Zipmask[e]);
1179 ZIPDUMPBITS(e);
1181 /* decode distance of block to copy */
1182 ZIPNEEDBITS((cab_ULONG)bd)
1183 if ((e = (t = td + ((cab_ULONG)b & md))->e) > 16)
1184 do {
1185 if (e == 99)
1186 return 1;
1187 ZIPDUMPBITS(t->b)
1188 e -= 16;
1189 ZIPNEEDBITS(e)
1190 } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16);
1191 ZIPDUMPBITS(t->b)
1192 ZIPNEEDBITS(e)
1193 d = w - t->v.n - ((cab_ULONG)b & Zipmask[e]);
1194 ZIPDUMPBITS(e)
1197 n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e);
1200 CAB(outbuf)[w++] = CAB(outbuf)[d++];
1201 } while (--e);
1202 } while (n);
1206 /* restore the globals from the locals */
1207 ZIP(window_posn) = w; /* restore global window pointer */
1208 ZIP(bb) = b; /* restore global bit buffer */
1209 ZIP(bk) = k;
1211 /* done */
1212 return 0;
1215 /***********************************************************
1216 * Zipinflate_stored (internal)
1218 static cab_LONG fdi_Zipinflate_stored(fdi_decomp_state *decomp_state)
1219 /* "decompress" an inflated type 0 (stored) block. */
1221 cab_ULONG n; /* number of bytes in block */
1222 cab_ULONG w; /* current window position */
1223 register cab_ULONG b; /* bit buffer */
1224 register cab_ULONG k; /* number of bits in bit buffer */
1226 /* make local copies of globals */
1227 b = ZIP(bb); /* initialize bit buffer */
1228 k = ZIP(bk);
1229 w = ZIP(window_posn); /* initialize window position */
1231 /* go to byte boundary */
1232 n = k & 7;
1233 ZIPDUMPBITS(n);
1235 /* get the length and its complement */
1236 ZIPNEEDBITS(16)
1237 n = ((cab_ULONG)b & 0xffff);
1238 ZIPDUMPBITS(16)
1239 ZIPNEEDBITS(16)
1240 if (n != (cab_ULONG)((~b) & 0xffff))
1241 return 1; /* error in compressed data */
1242 ZIPDUMPBITS(16)
1244 /* read and output the compressed data */
1245 while(n--)
1247 ZIPNEEDBITS(8)
1248 CAB(outbuf)[w++] = (cab_UBYTE)b;
1249 ZIPDUMPBITS(8)
1252 /* restore the globals from the locals */
1253 ZIP(window_posn) = w; /* restore global window pointer */
1254 ZIP(bb) = b; /* restore global bit buffer */
1255 ZIP(bk) = k;
1256 return 0;
1259 /******************************************************
1260 * fdi_Zipinflate_fixed (internal)
1262 static cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state)
1264 struct Ziphuft *fixed_tl;
1265 struct Ziphuft *fixed_td;
1266 cab_LONG fixed_bl, fixed_bd;
1267 cab_LONG i; /* temporary variable */
1268 cab_ULONG *l;
1270 l = ZIP(ll);
1272 /* literal table */
1273 for(i = 0; i < 144; i++)
1274 l[i] = 8;
1275 for(; i < 256; i++)
1276 l[i] = 9;
1277 for(; i < 280; i++)
1278 l[i] = 7;
1279 for(; i < 288; i++) /* make a complete, but wrong code set */
1280 l[i] = 8;
1281 fixed_bl = 7;
1282 if((i = fdi_Ziphuft_build(l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl, decomp_state)))
1283 return i;
1285 /* distance table */
1286 for(i = 0; i < 30; i++) /* make an incomplete code set */
1287 l[i] = 5;
1288 fixed_bd = 5;
1289 if((i = fdi_Ziphuft_build(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, decomp_state)) > 1)
1291 fdi_Ziphuft_free(CAB(hfdi), fixed_tl);
1292 return i;
1295 /* decompress until an end-of-block code */
1296 i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state);
1298 fdi_Ziphuft_free(CAB(hfdi), fixed_td);
1299 fdi_Ziphuft_free(CAB(hfdi), fixed_tl);
1300 return i;
1303 /**************************************************************
1304 * fdi_Zipinflate_dynamic (internal)
1306 static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
1307 /* decompress an inflated type 2 (dynamic Huffman codes) block. */
1309 cab_LONG i; /* temporary variables */
1310 cab_ULONG j;
1311 cab_ULONG *ll;
1312 cab_ULONG l; /* last length */
1313 cab_ULONG m; /* mask for bit lengths table */
1314 cab_ULONG n; /* number of lengths to get */
1315 struct Ziphuft *tl; /* literal/length code table */
1316 struct Ziphuft *td; /* distance code table */
1317 cab_LONG bl; /* lookup bits for tl */
1318 cab_LONG bd; /* lookup bits for td */
1319 cab_ULONG nb; /* number of bit length codes */
1320 cab_ULONG nl; /* number of literal/length codes */
1321 cab_ULONG nd; /* number of distance codes */
1322 register cab_ULONG b; /* bit buffer */
1323 register cab_ULONG k; /* number of bits in bit buffer */
1325 /* make local bit buffer */
1326 b = ZIP(bb);
1327 k = ZIP(bk);
1328 ll = ZIP(ll);
1330 /* read in table lengths */
1331 ZIPNEEDBITS(5)
1332 nl = 257 + ((cab_ULONG)b & 0x1f); /* number of literal/length codes */
1333 ZIPDUMPBITS(5)
1334 ZIPNEEDBITS(5)
1335 nd = 1 + ((cab_ULONG)b & 0x1f); /* number of distance codes */
1336 ZIPDUMPBITS(5)
1337 ZIPNEEDBITS(4)
1338 nb = 4 + ((cab_ULONG)b & 0xf); /* number of bit length codes */
1339 ZIPDUMPBITS(4)
1340 if(nl > 288 || nd > 32)
1341 return 1; /* bad lengths */
1343 /* read in bit-length-code lengths */
1344 for(j = 0; j < nb; j++)
1346 ZIPNEEDBITS(3)
1347 ll[Zipborder[j]] = (cab_ULONG)b & 7;
1348 ZIPDUMPBITS(3)
1350 for(; j < 19; j++)
1351 ll[Zipborder[j]] = 0;
1353 /* build decoding table for trees--single level, 7 bit lookup */
1354 bl = 7;
1355 if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0)
1357 if(i == 1)
1358 fdi_Ziphuft_free(CAB(hfdi), tl);
1359 return i; /* incomplete code set */
1362 /* read in literal and distance code lengths */
1363 n = nl + nd;
1364 m = Zipmask[bl];
1365 i = l = 0;
1366 while((cab_ULONG)i < n)
1368 ZIPNEEDBITS((cab_ULONG)bl)
1369 j = (td = tl + ((cab_ULONG)b & m))->b;
1370 ZIPDUMPBITS(j)
1371 j = td->v.n;
1372 if (j < 16) /* length of code in bits (0..15) */
1373 ll[i++] = l = j; /* save last length in l */
1374 else if (j == 16) /* repeat last length 3 to 6 times */
1376 ZIPNEEDBITS(2)
1377 j = 3 + ((cab_ULONG)b & 3);
1378 ZIPDUMPBITS(2)
1379 if((cab_ULONG)i + j > n)
1380 return 1;
1381 while (j--)
1382 ll[i++] = l;
1384 else if (j == 17) /* 3 to 10 zero length codes */
1386 ZIPNEEDBITS(3)
1387 j = 3 + ((cab_ULONG)b & 7);
1388 ZIPDUMPBITS(3)
1389 if ((cab_ULONG)i + j > n)
1390 return 1;
1391 while (j--)
1392 ll[i++] = 0;
1393 l = 0;
1395 else /* j == 18: 11 to 138 zero length codes */
1397 ZIPNEEDBITS(7)
1398 j = 11 + ((cab_ULONG)b & 0x7f);
1399 ZIPDUMPBITS(7)
1400 if ((cab_ULONG)i + j > n)
1401 return 1;
1402 while (j--)
1403 ll[i++] = 0;
1404 l = 0;
1408 /* free decoding table for trees */
1409 fdi_Ziphuft_free(CAB(hfdi), tl);
1411 /* restore the global bit buffer */
1412 ZIP(bb) = b;
1413 ZIP(bk) = k;
1415 /* build the decoding tables for literal/length and distance codes */
1416 bl = ZIPLBITS;
1417 if((i = fdi_Ziphuft_build(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, decomp_state)) != 0)
1419 if(i == 1)
1420 fdi_Ziphuft_free(CAB(hfdi), tl);
1421 return i; /* incomplete code set */
1423 bd = ZIPDBITS;
1424 fdi_Ziphuft_build(ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd, decomp_state);
1426 /* decompress until an end-of-block code */
1427 if(fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state))
1428 return 1;
1430 /* free the decoding tables, return */
1431 fdi_Ziphuft_free(CAB(hfdi), tl);
1432 fdi_Ziphuft_free(CAB(hfdi), td);
1433 return 0;
1436 /*****************************************************
1437 * fdi_Zipinflate_block (internal)
1439 static cab_LONG fdi_Zipinflate_block(cab_LONG *e, fdi_decomp_state *decomp_state) /* e == last block flag */
1440 { /* decompress an inflated block */
1441 cab_ULONG t; /* block type */
1442 register cab_ULONG b; /* bit buffer */
1443 register cab_ULONG k; /* number of bits in bit buffer */
1445 /* make local bit buffer */
1446 b = ZIP(bb);
1447 k = ZIP(bk);
1449 /* read in last block bit */
1450 ZIPNEEDBITS(1)
1451 *e = (cab_LONG)b & 1;
1452 ZIPDUMPBITS(1)
1454 /* read in block type */
1455 ZIPNEEDBITS(2)
1456 t = (cab_ULONG)b & 3;
1457 ZIPDUMPBITS(2)
1459 /* restore the global bit buffer */
1460 ZIP(bb) = b;
1461 ZIP(bk) = k;
1463 /* inflate that block type */
1464 if(t == 2)
1465 return fdi_Zipinflate_dynamic(decomp_state);
1466 if(t == 0)
1467 return fdi_Zipinflate_stored(decomp_state);
1468 if(t == 1)
1469 return fdi_Zipinflate_fixed(decomp_state);
1470 /* bad block type */
1471 return 2;
1474 /****************************************************
1475 * ZIPfdi_decomp(internal)
1477 static int ZIPfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
1479 cab_LONG e; /* last block flag */
1481 TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
1483 ZIP(inpos) = CAB(inbuf);
1484 ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0;
1485 if(outlen > ZIPWSIZE)
1486 return DECR_DATAFORMAT;
1488 /* CK = Chris Kirmse, official Microsoft purloiner */
1489 if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B)
1490 return DECR_ILLEGALDATA;
1491 ZIP(inpos) += 2;
1493 do {
1494 if(fdi_Zipinflate_block(&e, decomp_state))
1495 return DECR_ILLEGALDATA;
1496 } while(!e);
1498 /* return success */
1499 return DECR_OK;
1502 /*******************************************************************
1503 * QTMfdi_decomp(internal)
1505 static int QTMfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
1507 cab_UBYTE *inpos = CAB(inbuf);
1508 cab_UBYTE *window = QTM(window);
1509 cab_UBYTE *runsrc, *rundest;
1510 cab_ULONG window_posn = QTM(window_posn);
1511 cab_ULONG window_size = QTM(window_size);
1513 /* used by bitstream macros */
1514 register int bitsleft, bitrun, bitsneed;
1515 register cab_ULONG bitbuf;
1517 /* used by GET_SYMBOL */
1518 cab_ULONG range;
1519 cab_UWORD symf;
1520 int i;
1522 int extra, togo = outlen, match_length = 0, copy_length;
1523 cab_UBYTE selector, sym;
1524 cab_ULONG match_offset = 0;
1526 cab_UWORD H = 0xFFFF, L = 0, C;
1528 TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
1530 /* read initial value of C */
1531 Q_INIT_BITSTREAM;
1532 Q_READ_BITS(C, 16);
1534 /* apply 2^x-1 mask */
1535 window_posn &= window_size - 1;
1536 /* runs can't straddle the window wraparound */
1537 if ((window_posn + togo) > window_size) {
1538 TRACE("straddled run\n");
1539 return DECR_DATAFORMAT;
1542 while (togo > 0) {
1543 GET_SYMBOL(model7, selector);
1544 switch (selector) {
1545 case 0:
1546 GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--;
1547 break;
1548 case 1:
1549 GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--;
1550 break;
1551 case 2:
1552 GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--;
1553 break;
1554 case 3:
1555 GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--;
1556 break;
1558 case 4:
1559 /* selector 4 = fixed length of 3 */
1560 GET_SYMBOL(model4, sym);
1561 Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
1562 match_offset = CAB(q_position_base)[sym] + extra + 1;
1563 match_length = 3;
1564 break;
1566 case 5:
1567 /* selector 5 = fixed length of 4 */
1568 GET_SYMBOL(model5, sym);
1569 Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
1570 match_offset = CAB(q_position_base)[sym] + extra + 1;
1571 match_length = 4;
1572 break;
1574 case 6:
1575 /* selector 6 = variable length */
1576 GET_SYMBOL(model6len, sym);
1577 Q_READ_BITS(extra, CAB(q_length_extra)[sym]);
1578 match_length = CAB(q_length_base)[sym] + extra + 5;
1579 GET_SYMBOL(model6pos, sym);
1580 Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
1581 match_offset = CAB(q_position_base)[sym] + extra + 1;
1582 break;
1584 default:
1585 TRACE("Selector is bogus\n");
1586 return DECR_ILLEGALDATA;
1589 /* if this is a match */
1590 if (selector >= 4) {
1591 rundest = window + window_posn;
1592 togo -= match_length;
1594 /* copy any wrapped around source data */
1595 if (window_posn >= match_offset) {
1596 /* no wrap */
1597 runsrc = rundest - match_offset;
1598 } else {
1599 runsrc = rundest + (window_size - match_offset);
1600 copy_length = match_offset - window_posn;
1601 if (copy_length < match_length) {
1602 match_length -= copy_length;
1603 window_posn += copy_length;
1604 while (copy_length-- > 0) *rundest++ = *runsrc++;
1605 runsrc = window;
1608 window_posn += match_length;
1610 /* copy match data - no worries about destination wraps */
1611 while (match_length-- > 0) *rundest++ = *runsrc++;
1613 } /* while (togo > 0) */
1615 if (togo != 0) {
1616 TRACE("Frame overflow, this_run = %d\n", togo);
1617 return DECR_ILLEGALDATA;
1620 memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) -
1621 outlen, outlen);
1623 QTM(window_posn) = window_posn;
1624 return DECR_OK;
1627 /************************************************************
1628 * fdi_lzx_read_lens (internal)
1630 static int fdi_lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb,
1631 fdi_decomp_state *decomp_state) {
1632 cab_ULONG i,j, x,y;
1633 int z;
1635 register cab_ULONG bitbuf = lb->bb;
1636 register int bitsleft = lb->bl;
1637 cab_UBYTE *inpos = lb->ip;
1638 cab_UWORD *hufftbl;
1640 for (x = 0; x < 20; x++) {
1641 READ_BITS(y, 4);
1642 LENTABLE(PRETREE)[x] = y;
1644 BUILD_TABLE(PRETREE);
1646 for (x = first; x < last; ) {
1647 READ_HUFFSYM(PRETREE, z);
1648 if (z == 17) {
1649 READ_BITS(y, 4); y += 4;
1650 while (y--) lens[x++] = 0;
1652 else if (z == 18) {
1653 READ_BITS(y, 5); y += 20;
1654 while (y--) lens[x++] = 0;
1656 else if (z == 19) {
1657 READ_BITS(y, 1); y += 4;
1658 READ_HUFFSYM(PRETREE, z);
1659 z = lens[x] - z; if (z < 0) z += 17;
1660 while (y--) lens[x++] = z;
1662 else {
1663 z = lens[x] - z; if (z < 0) z += 17;
1664 lens[x++] = z;
1668 lb->bb = bitbuf;
1669 lb->bl = bitsleft;
1670 lb->ip = inpos;
1671 return 0;
1674 /*******************************************************
1675 * LZXfdi_decomp(internal)
1677 static int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) {
1678 cab_UBYTE *inpos = CAB(inbuf);
1679 const cab_UBYTE *endinp = inpos + inlen;
1680 cab_UBYTE *window = LZX(window);
1681 cab_UBYTE *runsrc, *rundest;
1682 cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
1684 cab_ULONG window_posn = LZX(window_posn);
1685 cab_ULONG window_size = LZX(window_size);
1686 cab_ULONG R0 = LZX(R0);
1687 cab_ULONG R1 = LZX(R1);
1688 cab_ULONG R2 = LZX(R2);
1690 register cab_ULONG bitbuf;
1691 register int bitsleft;
1692 cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
1693 struct lzx_bits lb; /* used in READ_LENGTHS macro */
1695 int togo = outlen, this_run, main_element, aligned_bits;
1696 int match_length, copy_length, length_footer, extra, verbatim_bits;
1698 TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen);
1700 INIT_BITSTREAM;
1702 /* read header if necessary */
1703 if (!LZX(header_read)) {
1704 i = j = 0;
1705 READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); }
1706 LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */
1707 LZX(header_read) = 1;
1710 /* main decoding loop */
1711 while (togo > 0) {
1712 /* last block finished, new block expected */
1713 if (LZX(block_remaining) == 0) {
1714 if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) {
1715 if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */
1716 INIT_BITSTREAM;
1719 READ_BITS(LZX(block_type), 3);
1720 READ_BITS(i, 16);
1721 READ_BITS(j, 8);
1722 LZX(block_remaining) = LZX(block_length) = (i << 8) | j;
1724 switch (LZX(block_type)) {
1725 case LZX_BLOCKTYPE_ALIGNED:
1726 for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; }
1727 BUILD_TABLE(ALIGNED);
1728 /* rest of aligned header is same as verbatim */
1730 case LZX_BLOCKTYPE_VERBATIM:
1731 READ_LENGTHS(MAINTREE, 0, 256, fdi_lzx_read_lens);
1732 READ_LENGTHS(MAINTREE, 256, LZX(main_elements), fdi_lzx_read_lens);
1733 BUILD_TABLE(MAINTREE);
1734 if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1;
1736 READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, fdi_lzx_read_lens);
1737 BUILD_TABLE(LENGTH);
1738 break;
1740 case LZX_BLOCKTYPE_UNCOMPRESSED:
1741 LZX(intel_started) = 1; /* because we can't assume otherwise */
1742 ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
1743 if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
1744 R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
1745 R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
1746 R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
1747 break;
1749 default:
1750 return DECR_ILLEGALDATA;
1754 /* buffer exhaustion check */
1755 if (inpos > endinp) {
1756 /* it's possible to have a file where the next run is less than
1757 * 16 bits in size. In this case, the READ_HUFFSYM() macro used
1758 * in building the tables will exhaust the buffer, so we should
1759 * allow for this, but not allow those accidentally read bits to
1760 * be used (so we check that there are at least 16 bits
1761 * remaining - in this boundary case they aren't really part of
1762 * the compressed data)
1764 if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA;
1767 while ((this_run = LZX(block_remaining)) > 0 && togo > 0) {
1768 if (this_run > togo) this_run = togo;
1769 togo -= this_run;
1770 LZX(block_remaining) -= this_run;
1772 /* apply 2^x-1 mask */
1773 window_posn &= window_size - 1;
1774 /* runs can't straddle the window wraparound */
1775 if ((window_posn + this_run) > window_size)
1776 return DECR_DATAFORMAT;
1778 switch (LZX(block_type)) {
1780 case LZX_BLOCKTYPE_VERBATIM:
1781 while (this_run > 0) {
1782 READ_HUFFSYM(MAINTREE, main_element);
1784 if (main_element < LZX_NUM_CHARS) {
1785 /* literal: 0 to LZX_NUM_CHARS-1 */
1786 window[window_posn++] = main_element;
1787 this_run--;
1789 else {
1790 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
1791 main_element -= LZX_NUM_CHARS;
1793 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
1794 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
1795 READ_HUFFSYM(LENGTH, length_footer);
1796 match_length += length_footer;
1798 match_length += LZX_MIN_MATCH;
1800 match_offset = main_element >> 3;
1802 if (match_offset > 2) {
1803 /* not repeated offset */
1804 if (match_offset != 3) {
1805 extra = CAB(extra_bits)[match_offset];
1806 READ_BITS(verbatim_bits, extra);
1807 match_offset = CAB(lzx_position_base)[match_offset]
1808 - 2 + verbatim_bits;
1810 else {
1811 match_offset = 1;
1814 /* update repeated offset LRU queue */
1815 R2 = R1; R1 = R0; R0 = match_offset;
1817 else if (match_offset == 0) {
1818 match_offset = R0;
1820 else if (match_offset == 1) {
1821 match_offset = R1;
1822 R1 = R0; R0 = match_offset;
1824 else /* match_offset == 2 */ {
1825 match_offset = R2;
1826 R2 = R0; R0 = match_offset;
1829 rundest = window + window_posn;
1830 this_run -= match_length;
1832 /* copy any wrapped around source data */
1833 if (window_posn >= match_offset) {
1834 /* no wrap */
1835 runsrc = rundest - match_offset;
1836 } else {
1837 runsrc = rundest + (window_size - match_offset);
1838 copy_length = match_offset - window_posn;
1839 if (copy_length < match_length) {
1840 match_length -= copy_length;
1841 window_posn += copy_length;
1842 while (copy_length-- > 0) *rundest++ = *runsrc++;
1843 runsrc = window;
1846 window_posn += match_length;
1848 /* copy match data - no worries about destination wraps */
1849 while (match_length-- > 0) *rundest++ = *runsrc++;
1852 break;
1854 case LZX_BLOCKTYPE_ALIGNED:
1855 while (this_run > 0) {
1856 READ_HUFFSYM(MAINTREE, main_element);
1858 if (main_element < LZX_NUM_CHARS) {
1859 /* literal: 0 to LZX_NUM_CHARS-1 */
1860 window[window_posn++] = main_element;
1861 this_run--;
1863 else {
1864 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
1865 main_element -= LZX_NUM_CHARS;
1867 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
1868 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
1869 READ_HUFFSYM(LENGTH, length_footer);
1870 match_length += length_footer;
1872 match_length += LZX_MIN_MATCH;
1874 match_offset = main_element >> 3;
1876 if (match_offset > 2) {
1877 /* not repeated offset */
1878 extra = CAB(extra_bits)[match_offset];
1879 match_offset = CAB(lzx_position_base)[match_offset] - 2;
1880 if (extra > 3) {
1881 /* verbatim and aligned bits */
1882 extra -= 3;
1883 READ_BITS(verbatim_bits, extra);
1884 match_offset += (verbatim_bits << 3);
1885 READ_HUFFSYM(ALIGNED, aligned_bits);
1886 match_offset += aligned_bits;
1888 else if (extra == 3) {
1889 /* aligned bits only */
1890 READ_HUFFSYM(ALIGNED, aligned_bits);
1891 match_offset += aligned_bits;
1893 else if (extra > 0) { /* extra==1, extra==2 */
1894 /* verbatim bits only */
1895 READ_BITS(verbatim_bits, extra);
1896 match_offset += verbatim_bits;
1898 else /* extra == 0 */ {
1899 /* ??? */
1900 match_offset = 1;
1903 /* update repeated offset LRU queue */
1904 R2 = R1; R1 = R0; R0 = match_offset;
1906 else if (match_offset == 0) {
1907 match_offset = R0;
1909 else if (match_offset == 1) {
1910 match_offset = R1;
1911 R1 = R0; R0 = match_offset;
1913 else /* match_offset == 2 */ {
1914 match_offset = R2;
1915 R2 = R0; R0 = match_offset;
1918 rundest = window + window_posn;
1919 this_run -= match_length;
1921 /* copy any wrapped around source data */
1922 if (window_posn >= match_offset) {
1923 /* no wrap */
1924 runsrc = rundest - match_offset;
1925 } else {
1926 runsrc = rundest + (window_size - match_offset);
1927 copy_length = match_offset - window_posn;
1928 if (copy_length < match_length) {
1929 match_length -= copy_length;
1930 window_posn += copy_length;
1931 while (copy_length-- > 0) *rundest++ = *runsrc++;
1932 runsrc = window;
1935 window_posn += match_length;
1937 /* copy match data - no worries about destination wraps */
1938 while (match_length-- > 0) *rundest++ = *runsrc++;
1941 break;
1943 case LZX_BLOCKTYPE_UNCOMPRESSED:
1944 if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA;
1945 memcpy(window + window_posn, inpos, (size_t) this_run);
1946 inpos += this_run; window_posn += this_run;
1947 break;
1949 default:
1950 return DECR_ILLEGALDATA; /* might as well */
1956 if (togo != 0) return DECR_ILLEGALDATA;
1957 memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) -
1958 outlen, (size_t) outlen);
1960 LZX(window_posn) = window_posn;
1961 LZX(R0) = R0;
1962 LZX(R1) = R1;
1963 LZX(R2) = R2;
1965 /* intel E8 decoding */
1966 if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) {
1967 if (outlen <= 6 || !LZX(intel_started)) {
1968 LZX(intel_curpos) += outlen;
1970 else {
1971 cab_UBYTE *data = CAB(outbuf);
1972 cab_UBYTE *dataend = data + outlen - 10;
1973 cab_LONG curpos = LZX(intel_curpos);
1974 cab_LONG filesize = LZX(intel_filesize);
1975 cab_LONG abs_off, rel_off;
1977 LZX(intel_curpos) = curpos + outlen;
1979 while (data < dataend) {
1980 if (*data++ != 0xE8) { curpos++; continue; }
1981 abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
1982 if ((abs_off >= -curpos) && (abs_off < filesize)) {
1983 rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
1984 data[0] = (cab_UBYTE) rel_off;
1985 data[1] = (cab_UBYTE) (rel_off >> 8);
1986 data[2] = (cab_UBYTE) (rel_off >> 16);
1987 data[3] = (cab_UBYTE) (rel_off >> 24);
1989 data += 4;
1990 curpos += 5;
1994 return DECR_OK;
1997 /**********************************************************
1998 * fdi_decomp (internal)
2000 * Decompress the requested number of bytes. If savemode is zero,
2001 * do not save the output anywhere, just plow through blocks until we
2002 * reach the specified (uncompressed) distance from the starting point,
2003 * and remember the position of the cabfile pointer (and which cabfile)
2004 * after we are done; otherwise, save the data out to CAB(filehf),
2005 * decompressing the requested number of bytes and writing them out. This
2006 * is also where we jump to additional cabinets in the case of split
2007 * cab's, and provide (some of) the NEXT_CABINET notification semantics.
2009 static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state,
2010 char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser)
2012 cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset);
2013 cab_UBYTE buf[cfdata_SIZEOF], *data;
2014 cab_UWORD inlen, len, outlen, cando;
2015 cab_ULONG cksum;
2016 cab_LONG err;
2017 fdi_decomp_state *cab = (savemode && CAB(decomp_cab)) ? CAB(decomp_cab) : decomp_state;
2019 TRACE("(fi == ^%p, savemode == %d, bytes == %d)\n", fi, savemode, bytes);
2021 while (bytes > 0) {
2022 /* cando = the max number of bytes we can do */
2023 cando = CAB(outlen);
2024 if (cando > bytes) cando = bytes;
2026 /* if cando != 0 */
2027 if (cando && savemode)
2028 PFDI_WRITE(CAB(hfdi), CAB(filehf), CAB(outpos), cando);
2030 CAB(outpos) += cando;
2031 CAB(outlen) -= cando;
2032 bytes -= cando; if (!bytes) break;
2034 /* we only get here if we emptied the output buffer */
2036 /* read data header + data */
2037 inlen = outlen = 0;
2038 while (outlen == 0) {
2039 /* read the block header, skip the reserved part */
2040 if (PFDI_READ(CAB(hfdi), cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF)
2041 return DECR_INPUT;
2043 if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1)
2044 return DECR_INPUT;
2046 /* we shouldn't get blocks over CAB_INPUTMAX in size */
2047 data = CAB(inbuf) + inlen;
2048 len = EndGetI16(buf+cfdata_CompressedSize);
2049 inlen += len;
2050 if (inlen > CAB_INPUTMAX) return DECR_INPUT;
2051 if (PFDI_READ(CAB(hfdi), cab->cabhf, data, len) != len)
2052 return DECR_INPUT;
2054 /* clear two bytes after read-in data */
2055 data[len+1] = data[len+2] = 0;
2057 /* perform checksum test on the block (if one is stored) */
2058 cksum = EndGetI32(buf+cfdata_CheckSum);
2059 if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0)))
2060 return DECR_CHECKSUM; /* checksum is wrong */
2062 outlen = EndGetI16(buf+cfdata_UncompressedSize);
2064 /* outlen=0 means this block was the last contiguous part
2065 of a split block, continued in the next cabinet */
2066 if (outlen == 0) {
2067 int pathlen, filenamelen, idx, i, cabhf;
2068 char fullpath[MAX_PATH], userpath[256];
2069 FDINOTIFICATION fdin;
2070 FDICABINETINFO fdici;
2071 char emptystring = '\0';
2072 cab_UBYTE buf2[64];
2073 int success = FALSE;
2074 struct fdi_folder *fol = NULL, *linkfol = NULL;
2075 struct fdi_file *file = NULL, *linkfile = NULL;
2077 tryanothercab:
2079 /* set up the next decomp_state... */
2080 if (!(cab->next)) {
2081 if (!cab->mii.hasnext) return DECR_INPUT;
2083 if (!((cab->next = PFDI_ALLOC(CAB(hfdi), sizeof(fdi_decomp_state)))))
2084 return DECR_NOMEMORY;
2086 ZeroMemory(cab->next, sizeof(fdi_decomp_state));
2088 /* copy pszCabPath to userpath */
2089 ZeroMemory(userpath, 256);
2090 pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
2091 if (pathlen) {
2092 if (pathlen < 256) {
2093 for (i = 0; i <= pathlen; i++)
2094 userpath[i] = pszCabPath[i];
2095 } /* else we are in a weird place... let's leave it blank and see if the user fixes it */
2098 /* initial fdintNEXT_CABINET notification */
2099 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2100 fdin.psz1 = (cab->mii.nextname) ? cab->mii.nextname : &emptystring;
2101 fdin.psz2 = (cab->mii.nextinfo) ? cab->mii.nextinfo : &emptystring;
2102 fdin.psz3 = &userpath[0];
2103 fdin.fdie = FDIERROR_NONE;
2104 fdin.pv = pvUser;
2106 if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
2108 do {
2110 pathlen = strlen(userpath);
2111 filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 0;
2113 /* slight overestimation here to save CPU cycles in the developer's brain */
2114 if ((pathlen + filenamelen + 3) > MAX_PATH) {
2115 ERR("MAX_PATH exceeded.\n");
2116 return DECR_ILLEGALDATA;
2119 /* paste the path and filename together */
2120 idx = 0;
2121 if (pathlen) {
2122 for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i];
2123 if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
2125 if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i];
2126 fullpath[idx] = '\0';
2128 TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
2130 /* try to get a handle to the cabfile */
2131 cabhf = PFDI_OPEN(CAB(hfdi), fullpath, 32768, _S_IREAD | _S_IWRITE);
2132 if (cabhf == -1) {
2133 /* no file. allow the user to try again */
2134 fdin.fdie = FDIERROR_CABINET_NOT_FOUND;
2135 if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
2136 continue;
2139 if (cabhf == 0) {
2140 ERR("PFDI_OPEN returned zero for %s.\n", fullpath);
2141 fdin.fdie = FDIERROR_CABINET_NOT_FOUND;
2142 if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
2143 continue;
2146 /* check if it's really a cabfile. Note that this doesn't implement the bug */
2147 if (!FDI_read_entries(CAB(hfdi), cabhf, &fdici, &(cab->next->mii))) {
2148 WARN("FDIIsCabinet failed.\n");
2149 PFDI_CLOSE(CAB(hfdi), cabhf);
2150 fdin.fdie = FDIERROR_NOT_A_CABINET;
2151 if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
2152 continue;
2155 if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) {
2156 WARN("Wrong Cabinet.\n");
2157 PFDI_CLOSE(CAB(hfdi), cabhf);
2158 fdin.fdie = FDIERROR_WRONG_CABINET;
2159 if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
2160 continue;
2163 break;
2165 } while (1);
2167 /* cabinet notification */
2168 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2169 fdin.setID = fdici.setID;
2170 fdin.iCabinet = fdici.iCabinet;
2171 fdin.pv = pvUser;
2172 fdin.psz1 = (cab->next->mii.nextname) ? cab->next->mii.nextname : &emptystring;
2173 fdin.psz2 = (cab->next->mii.nextinfo) ? cab->next->mii.nextinfo : &emptystring;
2174 fdin.psz3 = pszCabPath;
2176 if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) return DECR_USERABORT;
2178 cab->next->setID = fdici.setID;
2179 cab->next->iCabinet = fdici.iCabinet;
2180 cab->next->hfdi = CAB(hfdi);
2181 cab->next->filehf = CAB(filehf);
2182 cab->next->cabhf = cabhf;
2183 cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */
2185 cab = cab->next; /* advance to the next cabinet */
2187 /* read folders */
2188 for (i = 0; i < fdici.cFolders; i++) {
2189 if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF)
2190 return DECR_INPUT;
2192 if (cab->mii.folder_resv > 0)
2193 PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.folder_resv, SEEK_CUR);
2195 fol = (struct fdi_folder *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_folder));
2196 if (!fol) {
2197 ERR("out of memory!\n");
2198 return DECR_NOMEMORY;
2200 ZeroMemory(fol, sizeof(struct fdi_folder));
2201 if (!(cab->firstfol)) cab->firstfol = fol;
2203 fol->offset = (cab_off_t) EndGetI32(buf2+cffold_DataOffset);
2204 fol->num_blocks = EndGetI16(buf2+cffold_NumBlocks);
2205 fol->comp_type = EndGetI16(buf2+cffold_CompType);
2207 if (linkfol)
2208 linkfol->next = fol;
2209 linkfol = fol;
2212 /* read files */
2213 for (i = 0; i < fdici.cFiles; i++) {
2214 if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF)
2215 return DECR_INPUT;
2217 file = (struct fdi_file *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_file));
2218 if (!file) {
2219 ERR("out of memory!\n");
2220 return DECR_NOMEMORY;
2222 ZeroMemory(file, sizeof(struct fdi_file));
2223 if (!(cab->firstfile)) cab->firstfile = file;
2225 file->length = EndGetI32(buf2+cffile_UncompressedSize);
2226 file->offset = EndGetI32(buf2+cffile_FolderOffset);
2227 file->index = EndGetI16(buf2+cffile_FolderIndex);
2228 file->time = EndGetI16(buf2+cffile_Time);
2229 file->date = EndGetI16(buf2+cffile_Date);
2230 file->attribs = EndGetI16(buf2+cffile_Attribs);
2231 file->filename = FDI_read_string(CAB(hfdi), cab->cabhf, fdici.cbCabinet);
2233 if (!file->filename) return DECR_INPUT;
2235 if (linkfile)
2236 linkfile->next = file;
2237 linkfile = file;
2240 } else
2241 cab = cab->next; /* advance to the next cabinet */
2243 /* iterate files -- if we encounter the continued file, process it --
2244 otherwise, jump to the label above and keep looking */
2246 for (file = cab->firstfile; (file); file = file->next) {
2247 if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
2248 /* check to ensure a real match */
2249 if (strcasecmp(fi->filename, file->filename) == 0) {
2250 success = TRUE;
2251 if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1)
2252 return DECR_INPUT;
2253 break;
2257 if (!success) goto tryanothercab; /* FIXME: shouldn't this trigger
2258 "Wrong Cabinet" notification? */
2262 /* decompress block */
2263 if ((err = CAB(decompress)(inlen, outlen, decomp_state)))
2264 return err;
2265 CAB(outlen) = outlen;
2266 CAB(outpos) = CAB(outbuf);
2269 CAB(decomp_cab) = cab;
2270 return DECR_OK;
2273 /***********************************************************************
2274 * FDICopy (CABINET.22)
2276 * Iterates through the files in the Cabinet file indicated by name and
2277 * file-location. May chain forward to additional cabinets (typically
2278 * only one) if files which begin in this Cabinet are continued in another
2279 * cabinet. For each file which is partially contained in this cabinet,
2280 * and partially contained in a prior cabinet, provides fdintPARTIAL_FILE
2281 * notification to the pfnfdin callback. For each file which begins in
2282 * this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin
2283 * callback, and the file is optionally decompressed and saved to disk.
2284 * Notification is not provided for files which are not at least partially
2285 * contained in the specified cabinet file.
2287 * See below for a thorough explanation of the various notification
2288 * callbacks.
2290 * PARAMS
2291 * hfdi [I] An HFDI from FDICreate
2292 * pszCabinet [I] C-style string containing the filename of the cabinet
2293 * pszCabPath [I] C-style string containing the file path of the cabinet
2294 * flags [I] "Decoder parameters". Ignored. Suggested value: 0.
2295 * pfnfdin [I] Pointer to a notification function. See CALLBACKS below.
2296 * pfnfdid [I] Pointer to a decryption function. Ignored. Suggested
2297 * value: NULL.
2298 * pvUser [I] arbitrary void * value which is passed to callbacks.
2300 * RETURNS
2301 * TRUE if successful.
2302 * FALSE if unsuccessful (error information is provided in the ERF structure
2303 * associated with the provided decompression handle by FDICreate).
2305 * CALLBACKS
2307 * Two pointers to callback functions are provided as parameters to FDICopy:
2308 * pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT). These
2309 * types are as follows:
2311 * typedef INT_PTR (__cdecl *PFNFDINOTIFY) ( FDINOTIFICATIONTYPE fdint,
2312 * PFDINOTIFICATION pfdin );
2314 * typedef int (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid );
2316 * You can create functions of this type using the FNFDINOTIFY() and
2317 * FNFDIDECRYPT() macros, respectively. For example:
2319 * FNFDINOTIFY(mycallback) {
2320 * / * use variables fdint and pfdin to process notification * /
2323 * The second callback, which could be used for decrypting encrypted data,
2324 * is not used at all.
2326 * Each notification informs the user of some event which has occurred during
2327 * decompression of the cabinet file; each notification is also an opportunity
2328 * for the callee to abort decompression. The information provided to the
2329 * callback and the meaning of the callback's return value vary drastically
2330 * across the various types of notification. The type of notification is the
2331 * fdint parameter; all other information is provided to the callback in
2332 * notification-specific parts of the FDINOTIFICATION structure pointed to by
2333 * pfdin. The only part of that structure which is assigned for every callback
2334 * is the pv element, which contains the arbitrary value which was passed to
2335 * FDICopy in the pvUser argument (psz1 is also used each time, but its meaning
2336 * is highly dependent on fdint).
2338 * If you encounter unknown notifications, you should return zero if you want
2339 * decompression to continue (or -1 to abort). All strings used in the
2340 * callbacks are regular C-style strings. Detailed descriptions of each
2341 * notification type follow:
2343 * fdintCABINET_INFO:
2345 * This is the first notification provided after calling FDICopy, and provides
2346 * the user with various information about the cabinet. Note that this is
2347 * called for each cabinet FDICopy opens, not just the first one. In the
2348 * structure pointed to by pfdin, psz1 contains a pointer to the name of the
2349 * next cabinet file in the set after the one just loaded (if any), psz2
2350 * contains a pointer to the name or "info" of the next disk, psz3
2351 * contains a pointer to the file-path of the current cabinet, setID
2352 * contains an arbitrary constant associated with this set of cabinet files,
2353 * and iCabinet contains the numerical index of the current cabinet within
2354 * that set. Return zero, or -1 to abort.
2356 * fdintPARTIAL_FILE:
2358 * This notification is provided when FDICopy encounters a part of a file
2359 * contained in this cabinet which is missing its beginning. Files can be
2360 * split across cabinets, so this is not necessarily an abnormality; it just
2361 * means that the file in question begins in another cabinet. No file
2362 * corresponding to this notification is extracted from the cabinet. In the
2363 * structure pointed to by pfdin, psz1 contains a pointer to the name of the
2364 * partial file, psz2 contains a pointer to the file name of the cabinet in
2365 * which this file begins, and psz3 contains a pointer to the disk name or
2366 * "info" of the cabinet where the file begins. Return zero, or -1 to abort.
2368 * fdintCOPY_FILE:
2370 * This notification is provided when FDICopy encounters a file which starts
2371 * in the cabinet file, provided to FDICopy in pszCabinet. (FDICopy will not
2372 * look for files in cabinets after the first one). One notification will be
2373 * sent for each such file, before the file is decompressed. By returning
2374 * zero, the callback can instruct FDICopy to skip the file. In the structure
2375 * pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains
2376 * the size of the file (uncompressed), attribs contains the file attributes,
2377 * and date and time contain the date and time of the file. attributes, date,
2378 * and time are of the 16-bit ms-dos variety. Return -1 to abort decompression
2379 * for the entire cabinet, 0 to skip just this file but continue scanning the
2380 * cabinet for more files, or an FDIClose()-compatible file-handle.
2382 * fdintCLOSE_FILE_INFO:
2384 * This notification is important, don't forget to implement it. This
2385 * notification indicates that a file has been successfully uncompressed and
2386 * written to disk. Upon receipt of this notification, the callee is expected
2387 * to close the file handle, to set the attributes and date/time of the
2388 * closed file, and possibly to execute the file. In the structure pointed to
2389 * by pfdin, psz1 contains a pointer to the name of the file, hf will be the
2390 * open file handle (close it), cb contains 1 or zero, indicating respectively
2391 * that the callee should or should not execute the file, and date, time
2392 * and attributes will be set as in fdintCOPY_FILE. Bizarrely, the Cabinet SDK
2393 * specifies that _A_EXEC will be xor'ed out of attributes! wine does not do
2394 * do so. Return TRUE, or FALSE to abort decompression.
2396 * fdintNEXT_CABINET:
2398 * This notification is called when FDICopy must load in another cabinet. This
2399 * can occur when a file's data is "split" across multiple cabinets. The
2400 * callee has the opportunity to request that FDICopy look in a different file
2401 * path for the specified cabinet file, by writing that data into a provided
2402 * buffer (see below for more information). This notification will be received
2403 * more than once per-cabinet in the instance that FDICopy failed to find a
2404 * valid cabinet at the location specified by the first per-cabinet
2405 * fdintNEXT_CABINET notification. In such instances, the fdie element of the
2406 * structure pointed to by pfdin indicates the error which prevented FDICopy
2407 * from proceeding successfully. Return zero to indicate success, or -1 to
2408 * indicate failure and abort FDICopy.
2410 * Upon receipt of this notification, the structure pointed to by pfdin will
2411 * contain the following values: psz1 pointing to the name of the cabinet
2412 * which FDICopy is attempting to open, psz2 pointing to the name ("info") of
2413 * the next disk, psz3 pointing to the presumed file-location of the cabinet,
2414 * and fdie containing either FDIERROR_NONE, or one of the following:
2416 * FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET,
2417 * FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET,
2418 * FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and
2419 * FDIERROR_WRONG_CABINET.
2421 * The callee may choose to change the path where FDICopy will look for the
2422 * cabinet after this notification. To do so, the caller may write the new
2423 * pathname to the buffer pointed to by psz3, which is 256 characters in
2424 * length, including the terminating null character, before returning zero.
2426 * fdintENUMERATE:
2428 * Undocumented and unimplemented in wine, this seems to be sent each time
2429 * a cabinet is opened, along with the fdintCABINET_INFO notification. It
2430 * probably has an interface similar to that of fdintCABINET_INFO; maybe this
2431 * provides information about the current cabinet instead of the next one....
2432 * this is just a guess, it has not been looked at closely.
2434 * INCLUDES
2435 * fdi.c
2437 BOOL __cdecl FDICopy(
2438 HFDI hfdi,
2439 char *pszCabinet,
2440 char *pszCabPath,
2441 int flags,
2442 PFNFDINOTIFY pfnfdin,
2443 PFNFDIDECRYPT pfnfdid,
2444 void *pvUser)
2446 FDICABINETINFO fdici;
2447 FDINOTIFICATION fdin;
2448 int cabhf, filehf = 0, idx;
2449 unsigned int i;
2450 char fullpath[MAX_PATH];
2451 size_t pathlen, filenamelen;
2452 char emptystring = '\0';
2453 cab_UBYTE buf[64];
2454 struct fdi_folder *fol = NULL, *linkfol = NULL;
2455 struct fdi_file *file = NULL, *linkfile = NULL;
2456 fdi_decomp_state _decomp_state;
2457 fdi_decomp_state *decomp_state = &_decomp_state;
2459 TRACE("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, "
2460 "pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p)\n",
2461 hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser);
2463 if (!REALLY_IS_FDI(hfdi)) {
2464 SetLastError(ERROR_INVALID_HANDLE);
2465 return FALSE;
2468 ZeroMemory(decomp_state, sizeof(fdi_decomp_state));
2470 pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
2471 filenamelen = (pszCabinet) ? strlen(pszCabinet) : 0;
2473 /* slight overestimation here to save CPU cycles in the developer's brain */
2474 if ((pathlen + filenamelen + 3) > MAX_PATH) {
2475 ERR("MAX_PATH exceeded.\n");
2476 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
2477 PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND;
2478 PFDI_INT(hfdi)->perf->fError = TRUE;
2479 SetLastError(ERROR_FILE_NOT_FOUND);
2480 return FALSE;
2483 /* paste the path and filename together */
2484 idx = 0;
2485 if (pathlen) {
2486 for (i = 0; i < pathlen; i++) fullpath[idx++] = pszCabPath[i];
2487 if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
2489 if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = pszCabinet[i];
2490 fullpath[idx] = '\0';
2492 TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
2494 /* get a handle to the cabfile */
2495 cabhf = PFDI_OPEN(hfdi, fullpath, 32768, _S_IREAD | _S_IWRITE);
2496 if (cabhf == -1) {
2497 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
2498 PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND;
2499 PFDI_INT(hfdi)->perf->fError = TRUE;
2500 SetLastError(ERROR_FILE_NOT_FOUND);
2501 return FALSE;
2504 if (cabhf == 0) {
2505 ERR("PFDI_OPEN returned zero for %s.\n", fullpath);
2506 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
2507 PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND;
2508 PFDI_INT(hfdi)->perf->fError = TRUE;
2509 SetLastError(ERROR_FILE_NOT_FOUND);
2510 return FALSE;
2513 /* check if it's really a cabfile. Note that this doesn't implement the bug */
2514 if (!FDI_read_entries(hfdi, cabhf, &fdici, &(CAB(mii)))) {
2515 ERR("FDIIsCabinet failed.\n");
2516 PFDI_CLOSE(hfdi, cabhf);
2517 return FALSE;
2520 /* cabinet notification */
2521 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2522 fdin.setID = fdici.setID;
2523 fdin.iCabinet = fdici.iCabinet;
2524 fdin.pv = pvUser;
2525 fdin.psz1 = (CAB(mii).nextname) ? CAB(mii).nextname : &emptystring;
2526 fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring;
2527 fdin.psz3 = pszCabPath;
2529 if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) {
2530 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
2531 PFDI_INT(hfdi)->perf->erfType = 0;
2532 PFDI_INT(hfdi)->perf->fError = TRUE;
2533 goto bail_and_fail;
2536 CAB(setID) = fdici.setID;
2537 CAB(iCabinet) = fdici.iCabinet;
2538 CAB(cabhf) = cabhf;
2540 /* read folders */
2541 for (i = 0; i < fdici.cFolders; i++) {
2542 if (PFDI_READ(hfdi, cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) {
2543 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2544 PFDI_INT(hfdi)->perf->erfType = 0;
2545 PFDI_INT(hfdi)->perf->fError = TRUE;
2546 goto bail_and_fail;
2549 if (CAB(mii).folder_resv > 0)
2550 PFDI_SEEK(hfdi, cabhf, CAB(mii).folder_resv, SEEK_CUR);
2552 fol = (struct fdi_folder *) PFDI_ALLOC(hfdi, sizeof(struct fdi_folder));
2553 if (!fol) {
2554 ERR("out of memory!\n");
2555 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
2556 PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2557 PFDI_INT(hfdi)->perf->fError = TRUE;
2558 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2559 goto bail_and_fail;
2561 ZeroMemory(fol, sizeof(struct fdi_folder));
2562 if (!CAB(firstfol)) CAB(firstfol) = fol;
2564 fol->offset = (cab_off_t) EndGetI32(buf+cffold_DataOffset);
2565 fol->num_blocks = EndGetI16(buf+cffold_NumBlocks);
2566 fol->comp_type = EndGetI16(buf+cffold_CompType);
2568 if (linkfol)
2569 linkfol->next = fol;
2570 linkfol = fol;
2573 /* read files */
2574 for (i = 0; i < fdici.cFiles; i++) {
2575 if (PFDI_READ(hfdi, cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) {
2576 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2577 PFDI_INT(hfdi)->perf->erfType = 0;
2578 PFDI_INT(hfdi)->perf->fError = TRUE;
2579 goto bail_and_fail;
2582 file = (struct fdi_file *) PFDI_ALLOC(hfdi, sizeof(struct fdi_file));
2583 if (!file) {
2584 ERR("out of memory!\n");
2585 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
2586 PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2587 PFDI_INT(hfdi)->perf->fError = TRUE;
2588 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2589 goto bail_and_fail;
2591 ZeroMemory(file, sizeof(struct fdi_file));
2592 if (!CAB(firstfile)) CAB(firstfile) = file;
2594 file->length = EndGetI32(buf+cffile_UncompressedSize);
2595 file->offset = EndGetI32(buf+cffile_FolderOffset);
2596 file->index = EndGetI16(buf+cffile_FolderIndex);
2597 file->time = EndGetI16(buf+cffile_Time);
2598 file->date = EndGetI16(buf+cffile_Date);
2599 file->attribs = EndGetI16(buf+cffile_Attribs);
2600 file->filename = FDI_read_string(hfdi, cabhf, fdici.cbCabinet);
2602 if (!file->filename) {
2603 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2604 PFDI_INT(hfdi)->perf->erfType = 0;
2605 PFDI_INT(hfdi)->perf->fError = TRUE;
2606 goto bail_and_fail;
2609 if (linkfile)
2610 linkfile->next = file;
2611 linkfile = file;
2614 for (file = CAB(firstfile); (file); file = file->next) {
2617 * FIXME: This implementation keeps multiple cabinet files open at once
2618 * when encountering a split cabinet. It is a quirk of this implementation
2619 * that sometimes we decrypt the same block of data more than once, to find
2620 * the right starting point for a file, moving the file-pointer backwards.
2621 * If we kept a cache of certain file-pointer information, we could eliminate
2622 * that behavior... in fact I am not sure that the caching we already have
2623 * is not sufficient.
2625 * The current implementation seems to work fine in straightforward situations
2626 * where all the cabinet files needed for decryption are simultaneously
2627 * available. But presumably, the API is supposed to support cabinets which
2628 * are split across multiple CDROMS; we may need to change our implementation
2629 * to strictly serialize it's file usage so that it opens only one cabinet
2630 * at a time. Some experimentation with Windows is needed to figure out the
2631 * precise semantics required. The relevant code is here and in fdi_decomp().
2634 /* partial-file notification */
2635 if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
2637 * FIXME: Need to create a Cabinet with a single file spanning multiple files
2638 * and perform some tests to figure out the right behavior. The SDK says
2639 * FDICopy will notify the user of the filename and "disk name" (info) of
2640 * the cabinet where the spanning file /started/.
2642 * That would certainly be convenient for the API-user, who could abort,
2643 * everything (or parallelize, if that's allowed (it is in wine)), and call
2644 * FDICopy again with the provided filename, so as to avoid partial file
2645 * notification and successfully unpack. This task could be quite unpleasant
2646 * from wine's perspective: the information specifying the "start cabinet" for
2647 * a file is associated nowhere with the file header and is not to be found in
2648 * the cabinet header. We have only the index of the cabinet wherein the folder
2649 * begins, which contains the file. To find that cabinet, we must consider the
2650 * index of the current cabinet, and chain backwards, cabinet-by-cabinet (for
2651 * each cabinet refers to its "next" and "previous" cabinet only, like a linked
2652 * list).
2654 * Bear in mind that, in the spirit of CABINET.DLL, we must assume that any
2655 * cabinet other than the active one might be at another filepath than the
2656 * current one, or on another CDROM. This could get rather dicey, especially
2657 * if we imagine parallelized access to the FDICopy API.
2659 * The current implementation punts -- it just returns the previous cabinet and
2660 * it's info from the header of this cabinet. This provides the right answer in
2661 * 95% of the cases; its worth checking if Microsoft cuts the same corner before
2662 * we "fix" it.
2664 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2665 fdin.pv = pvUser;
2666 fdin.psz1 = (char *)file->filename;
2667 fdin.psz2 = (CAB(mii).prevname) ? CAB(mii).prevname : &emptystring;
2668 fdin.psz3 = (CAB(mii).previnfo) ? CAB(mii).previnfo : &emptystring;
2670 if (((*pfnfdin)(fdintPARTIAL_FILE, &fdin))) {
2671 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
2672 PFDI_INT(hfdi)->perf->erfType = 0;
2673 PFDI_INT(hfdi)->perf->fError = TRUE;
2674 goto bail_and_fail;
2676 /* I don't think we are supposed to decompress partial files. This prevents it. */
2677 file->oppressed = TRUE;
2679 if (file->oppressed) {
2680 filehf = 0;
2681 } else {
2682 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2683 fdin.pv = pvUser;
2684 fdin.psz1 = (char *)file->filename;
2685 fdin.cb = file->length;
2686 fdin.date = file->date;
2687 fdin.time = file->time;
2688 fdin.attribs = file->attribs;
2689 if ((filehf = ((*pfnfdin)(fdintCOPY_FILE, &fdin))) == -1) {
2690 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
2691 PFDI_INT(hfdi)->perf->erfType = 0;
2692 PFDI_INT(hfdi)->perf->fError = TRUE;
2693 filehf = 0;
2694 goto bail_and_fail;
2698 /* find the folder for this file if necc. */
2699 if (filehf) {
2700 int i2;
2702 fol = CAB(firstfol);
2703 if ((file->index & cffileCONTINUED_TO_NEXT) == cffileCONTINUED_TO_NEXT) {
2704 /* pick the last folder */
2705 while (fol->next) fol = fol->next;
2706 } else {
2707 for (i2 = 0; (i2 < file->index); i2++)
2708 if (fol->next) /* bug resistance, should always be true */
2709 fol = fol->next;
2713 if (filehf) {
2714 cab_UWORD comptype = fol->comp_type;
2715 int ct1 = comptype & cffoldCOMPTYPE_MASK;
2716 int ct2 = CAB(current) ? (CAB(current)->comp_type & cffoldCOMPTYPE_MASK) : 0;
2717 int err = 0;
2719 TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename));
2721 /* set up decomp_state */
2722 CAB(hfdi) = hfdi;
2723 CAB(filehf) = filehf;
2725 /* Was there a change of folder? Compression type? Did we somehow go backwards? */
2726 if ((ct1 != ct2) || (CAB(current) != fol) || (file->offset < CAB(offset))) {
2728 TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename));
2730 /* free stuff for the old decompresser */
2731 switch (ct2) {
2732 case cffoldCOMPTYPE_LZX:
2733 if (LZX(window)) {
2734 PFDI_FREE(hfdi, LZX(window));
2735 LZX(window) = NULL;
2737 break;
2738 case cffoldCOMPTYPE_QUANTUM:
2739 if (QTM(window)) {
2740 PFDI_FREE(hfdi, QTM(window));
2741 QTM(window) = NULL;
2743 break;
2746 CAB(decomp_cab) = NULL;
2747 PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset, SEEK_SET);
2748 CAB(offset) = 0;
2749 CAB(outlen) = 0;
2751 /* initialize the new decompresser */
2752 switch (ct1) {
2753 case cffoldCOMPTYPE_NONE:
2754 CAB(decompress) = NONEfdi_decomp;
2755 break;
2756 case cffoldCOMPTYPE_MSZIP:
2757 CAB(decompress) = ZIPfdi_decomp;
2758 break;
2759 case cffoldCOMPTYPE_QUANTUM:
2760 CAB(decompress) = QTMfdi_decomp;
2761 err = QTMfdi_init((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state);
2762 break;
2763 case cffoldCOMPTYPE_LZX:
2764 CAB(decompress) = LZXfdi_decomp;
2765 err = LZXfdi_init((comptype >> 8) & 0x1f, decomp_state);
2766 break;
2767 default:
2768 err = DECR_DATAFORMAT;
2772 CAB(current) = fol;
2774 switch (err) {
2775 case DECR_OK:
2776 break;
2777 case DECR_NOMEMORY:
2778 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
2779 PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2780 PFDI_INT(hfdi)->perf->fError = TRUE;
2781 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2782 goto bail_and_fail;
2783 default:
2784 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2785 PFDI_INT(hfdi)->perf->erfOper = 0;
2786 PFDI_INT(hfdi)->perf->fError = TRUE;
2787 goto bail_and_fail;
2790 if (file->offset > CAB(offset)) {
2791 /* decode bytes and send them to /dev/null */
2792 switch ((err = fdi_decomp(file, 0, decomp_state, pszCabPath, pfnfdin, pvUser))) {
2793 case DECR_OK:
2794 break;
2795 case DECR_USERABORT:
2796 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
2797 PFDI_INT(hfdi)->perf->erfType = 0;
2798 PFDI_INT(hfdi)->perf->fError = TRUE;
2799 goto bail_and_fail;
2800 case DECR_NOMEMORY:
2801 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
2802 PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2803 PFDI_INT(hfdi)->perf->fError = TRUE;
2804 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2805 goto bail_and_fail;
2806 default:
2807 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2808 PFDI_INT(hfdi)->perf->erfOper = 0;
2809 PFDI_INT(hfdi)->perf->fError = TRUE;
2810 goto bail_and_fail;
2812 CAB(offset) = file->offset;
2815 /* now do the actual decompression */
2816 err = fdi_decomp(file, 1, decomp_state, pszCabPath, pfnfdin, pvUser);
2817 if (err) CAB(current) = NULL; else CAB(offset) += file->length;
2819 /* fdintCLOSE_FILE_INFO notification */
2820 ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
2821 fdin.pv = pvUser;
2822 fdin.psz1 = (char *)file->filename;
2823 fdin.hf = filehf;
2824 fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */
2825 fdin.date = file->date;
2826 fdin.time = file->time;
2827 fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */
2828 ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin));
2829 filehf = 0;
2831 switch (err) {
2832 case DECR_OK:
2833 break;
2834 case DECR_USERABORT:
2835 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
2836 PFDI_INT(hfdi)->perf->erfType = 0;
2837 PFDI_INT(hfdi)->perf->fError = TRUE;
2838 goto bail_and_fail;
2839 case DECR_NOMEMORY:
2840 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
2841 PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2842 PFDI_INT(hfdi)->perf->fError = TRUE;
2843 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2844 goto bail_and_fail;
2845 default:
2846 PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
2847 PFDI_INT(hfdi)->perf->erfOper = 0;
2848 PFDI_INT(hfdi)->perf->fError = TRUE;
2849 goto bail_and_fail;
2854 /* free decompression temps */
2855 switch (fol->comp_type & cffoldCOMPTYPE_MASK) {
2856 case cffoldCOMPTYPE_LZX:
2857 if (LZX(window)) {
2858 PFDI_FREE(hfdi, LZX(window));
2859 LZX(window) = NULL;
2861 break;
2862 case cffoldCOMPTYPE_QUANTUM:
2863 if (QTM(window)) {
2864 PFDI_FREE(hfdi, QTM(window));
2865 QTM(window) = NULL;
2867 break;
2870 while (decomp_state) {
2871 fdi_decomp_state *prev_fds;
2873 PFDI_CLOSE(hfdi, CAB(cabhf));
2875 /* free the storage remembered by mii */
2876 if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname);
2877 if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo);
2878 if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname);
2879 if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo);
2881 while (CAB(firstfol)) {
2882 fol = CAB(firstfol);
2883 CAB(firstfol) = CAB(firstfol)->next;
2884 PFDI_FREE(hfdi, fol);
2886 while (CAB(firstfile)) {
2887 file = CAB(firstfile);
2888 if (file->filename) PFDI_FREE(hfdi, (void *)file->filename);
2889 CAB(firstfile) = CAB(firstfile)->next;
2890 PFDI_FREE(hfdi, file);
2892 prev_fds = decomp_state;
2893 decomp_state = CAB(next);
2894 if (prev_fds != &_decomp_state)
2895 PFDI_FREE(hfdi, prev_fds);
2898 return TRUE;
2900 bail_and_fail: /* here we free ram before error returns */
2902 /* free decompression temps */
2903 switch (fol->comp_type & cffoldCOMPTYPE_MASK) {
2904 case cffoldCOMPTYPE_LZX:
2905 if (LZX(window)) {
2906 PFDI_FREE(hfdi, LZX(window));
2907 LZX(window) = NULL;
2909 break;
2910 case cffoldCOMPTYPE_QUANTUM:
2911 if (QTM(window)) {
2912 PFDI_FREE(hfdi, QTM(window));
2913 QTM(window) = NULL;
2915 break;
2918 if (filehf) PFDI_CLOSE(hfdi, filehf);
2920 while (decomp_state) {
2921 fdi_decomp_state *prev_fds;
2923 PFDI_CLOSE(hfdi, CAB(cabhf));
2925 /* free the storage remembered by mii */
2926 if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname);
2927 if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo);
2928 if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname);
2929 if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo);
2931 while (CAB(firstfol)) {
2932 fol = CAB(firstfol);
2933 CAB(firstfol) = CAB(firstfol)->next;
2934 PFDI_FREE(hfdi, fol);
2936 while (CAB(firstfile)) {
2937 file = CAB(firstfile);
2938 if (file->filename) PFDI_FREE(hfdi, (void *)file->filename);
2939 CAB(firstfile) = CAB(firstfile)->next;
2940 PFDI_FREE(hfdi, file);
2942 prev_fds = decomp_state;
2943 decomp_state = CAB(next);
2944 if (prev_fds != &_decomp_state)
2945 PFDI_FREE(hfdi, prev_fds);
2948 return FALSE;
2951 /***********************************************************************
2952 * FDIDestroy (CABINET.23)
2954 * Frees a handle created by FDICreate. Do /not/ call this in the middle
2955 * of FDICopy. Only reason for failure would be an invalid handle.
2957 * PARAMS
2958 * hfdi [I] The HFDI to free
2960 * RETURNS
2961 * TRUE for success
2962 * FALSE for failure
2964 BOOL __cdecl FDIDestroy(HFDI hfdi)
2966 TRACE("(hfdi == ^%p)\n", hfdi);
2967 if (REALLY_IS_FDI(hfdi)) {
2968 PFDI_INT(hfdi)->FDI_Intmagic = 0; /* paranoia */
2969 PFDI_FREE(hfdi, hfdi); /* confusing, but correct */
2970 return TRUE;
2971 } else {
2972 SetLastError(ERROR_INVALID_HANDLE);
2973 return FALSE;
2977 /***********************************************************************
2978 * FDITruncateCabinet (CABINET.24)
2980 * Removes all folders of a cabinet file after and including the
2981 * specified folder number.
2983 * PARAMS
2984 * hfdi [I] Handle to the FDI context.
2985 * pszCabinetName [I] Filename of the cabinet.
2986 * iFolderToDelete [I] Index of the first folder to delete.
2988 * RETURNS
2989 * Success: TRUE.
2990 * Failure: FALSE.
2992 * NOTES
2993 * The PFNWRITE function supplied to FDICreate must truncate the
2994 * file at the current position if the number of bytes to write is 0.
2996 BOOL __cdecl FDITruncateCabinet(
2997 HFDI hfdi,
2998 char *pszCabinetName,
2999 USHORT iFolderToDelete)
3001 FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n",
3002 hfdi, debugstr_a(pszCabinetName), iFolderToDelete);
3004 if (!REALLY_IS_FDI(hfdi)) {
3005 SetLastError(ERROR_INVALID_HANDLE);
3006 return FALSE;
3009 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3010 return FALSE;