cab_E_00.diff
Gregory M. Turner
gmturner007 at ameritech.net
Fri Jul 18 16:32:23 CDT 2003
relative to cvs.
Finally, I think I've nailed down the blasted split cabs. I would like
to produce some tests, but otherwise, I plan to give myself a break from
cabinet.dll for now, unless there are bugs to fix.
Tom: you can put cabinet.dll at 80% now... and I will be working
on your todo-list next.
Gerold: I can't find my O2K discs... could you test the
Office 2000 installer again? I will test OXP when I
find the time.
License: LGPL (sorry)
ChangeLog:
* dlls/cabinet: cabextract.c, cabinet.h, fdi.c:
Greg Turner <gmturner007 at ameritech.net>
- eliminate pesky global variables; should be threadsafe now.
- fix more memory leaks
- fix some bugs
- some decruftification
- implement support for split cabinets and "NEXT_CABINET" notification
--
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.vanilla/dlls/cabinet/cabextract.c ./dlls/cabinet/cabextract.c
--- ../wine.vanilla/dlls/cabinet/cabextract.c 2003-06-19 14:48:24.000000000 -0500
+++ ./dlls/cabinet/cabextract.c 2003-07-18 15:16:46.000000000 -0500
@@ -1123,10 +1123,6 @@
/* This decruncher was researched and implemented by Matthew Russoto. */
/* It has since been tidied up by Stuart Caie */
-/* FIXME: eliminate global variables */
-static cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
-static cab_ULONG q_position_base[42];
-
/******************************************************************
* QTMinitmodel (internal)
*
@@ -1169,12 +1165,12 @@
/* initialise static slot/extrabits tables */
for (i = 0, j = 0; i < 27; i++) {
- q_length_extra[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
- q_length_base[i] = j; j += 1 << ((i == 26) ? 5 : q_length_extra[i]);
+ CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
+ CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]);
}
for (i = 0, j = 0; i < 42; i++) {
- q_extra_bits[i] = (i < 2 ? 0 : i-2) >> 1;
- q_position_base[i] = j; j += 1 << q_extra_bits[i];
+ CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1;
+ CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i];
}
/* initialise arithmetic coding models */
@@ -1312,27 +1308,27 @@
case 4:
/* selector 4 = fixed length of 3 */
GET_SYMBOL(model4, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
match_length = 3;
break;
case 5:
/* selector 5 = fixed length of 4 */
GET_SYMBOL(model5, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
match_length = 4;
break;
case 6:
/* selector 6 = variable length */
GET_SYMBOL(model6len, sym);
- Q_READ_BITS(extra, q_length_extra[sym]);
- match_length = q_length_base[sym] + extra + 5;
+ Q_READ_BITS(extra, CAB(q_length_extra)[sym]);
+ match_length = CAB(q_length_base)[sym] + extra + 5;
GET_SYMBOL(model6pos, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
break;
default:
@@ -1434,10 +1430,6 @@
* - lzx_extra_bits states how many bits of offset-from-base data is needed.
*/
-/* FIXME: Eliminate global variables */
-static cab_ULONG lzx_position_base[51];
-static cab_UBYTE extra_bits[51];
-
/************************************************************
* LZXinit (internal)
*/
@@ -1460,12 +1452,12 @@
/* initialise static tables */
for (i=0, j=0; i <= 50; i += 2) {
- extra_bits[i] = extra_bits[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
+ CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */
}
for (i=0, j=0; i <= 50; i++) {
- lzx_position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
- j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
+ CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
+ j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
}
/* calculate required position slots */
@@ -1473,7 +1465,7 @@
else if (window == 21) posn_slots = 50;
else posn_slots = window << 1;
- /*posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
+ /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */
LZX(R0) = LZX(R1) = LZX(R2) = 1;
LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3);
@@ -1757,9 +1749,9 @@
if (match_offset > 2) {
/* not repeated offset */
if (match_offset != 3) {
- extra = extra_bits[match_offset];
+ extra = CAB(extra_bits)[match_offset];
READ_BITS(verbatim_bits, extra);
- match_offset = lzx_position_base[match_offset]
+ match_offset = CAB(lzx_position_base)[match_offset]
- 2 + verbatim_bits;
}
else {
@@ -1830,8 +1822,8 @@
if (match_offset > 2) {
/* not repeated offset */
- extra = extra_bits[match_offset];
- match_offset = lzx_position_base[match_offset] - 2;
+ extra = CAB(extra_bits)[match_offset];
+ match_offset = CAB(lzx_position_base)[match_offset] - 2;
if (extra > 3) {
/* verbatim and aligned bits */
extra -= 3;
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.vanilla/dlls/cabinet/cabinet.h ./dlls/cabinet/cabinet.h
--- ../wine.vanilla/dlls/cabinet/cabinet.h 2003-06-19 14:48:24.000000000 -0500
+++ ./dlls/cabinet/cabinet.h 2003-07-18 15:18:04.000000000 -0500
@@ -269,6 +269,10 @@
int (*decompress)(int, int, struct cds_forward *); /* chosen compress fn */
cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */
cab_UBYTE outbuf[CAB_BLOCKMAX];
+ cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
+ cab_ULONG q_position_base[42];
+ cab_ULONG lzx_position_base[51];
+ cab_UBYTE extra_bits[51];
union {
struct ZIPstate zip;
struct QTMstate qtm;
@@ -344,6 +348,7 @@
#define DECR_CHECKSUM (4)
#define DECR_INPUT (5)
#define DECR_OUTPUT (6)
+#define DECR_USERABORT (7)
/* Bitstream reading macros (Quantum / normal byte order)
*
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.vanilla/dlls/cabinet/fdi.c ./dlls/cabinet/fdi.c
--- ../wine.vanilla/dlls/cabinet/fdi.c 2003-07-15 20:02:50.000000000 -0500
+++ ./dlls/cabinet/fdi.c 2003-07-18 15:55:44.000000000 -0500
@@ -24,7 +24,10 @@
* cabextract.c... it would theoretically be preferable to have only one, shared
* implementation, however there are semantic differences which may discourage efforts
* to unify the two. It should be possible, if awkward, to go back and reimplement
- * cabextract.c using FDI (once the FDI implementation is complete, of course).
+ * cabextract.c using FDI (once the FDI implementation is complete, of course). Also,
+ * cabextract's implementation is pretty efficient; fdi.c is, by contrast, extremely
+ * wasteful...
+ *
* -gmt
*/
@@ -47,7 +50,6 @@
struct fdi_file {
struct fdi_file *next; /* next file in sequence */
- struct fdi_folder *folder; /* folder that contains this file */
LPCSTR filename; /* output name of file */
int fh; /* open file handle or NULL */
cab_ULONG length; /* uncompressed length of file */
@@ -59,32 +61,44 @@
struct fdi_folder {
struct fdi_folder *next;
- cab_off_t offset[CAB_SPLITMAX]; /* offset to data blocks (32 bit) */
+ cab_off_t offset; /* offset to data blocks (32 bit) */
cab_UWORD comp_type; /* compression format/window size */
cab_ULONG comp_size; /* compressed size of folder */
cab_UBYTE num_splits; /* number of split blocks + 1 */
cab_UWORD num_blocks; /* total number of blocks */
- struct fdi_file *contfile; /* the first split file */
};
/*
+ * this structure fills the gaps between what is available in a PFDICABINETINFO
+ * vs what is needed by FDICopy. Memory allocated for these becomes the responsibility
+ * of the caller to free. Yes, I am aware that this is totally, utterly inelegant.
+ * To make things even more unneccesarily confusing, we now attach these to the
+ * fdi_decomp_state.
+ */
+typedef struct {
+ char *prevname, *previnfo;
+ char *nextname, *nextinfo;
+ BOOL hasnext; /* bug free indicator */
+ int folder_resv, header_resv;
+ cab_UBYTE block_resv;
+} MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;
+
+/*
* ugh, well, this ended up being pretty damn silly...
* now that I've conceeded to build equivalent structures to struct cab.*,
* I should have just used those, or, better yet, unified the two... sue me.
* (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt).
* Nevertheless, I've come this far, it works, so I'm not gonna change it
- * for now.
+ * for now. This implementation has significant semantic differences anyhow.
*/
typedef struct fdi_cds_fwd {
void *hfdi; /* the hfdi we are using */
int filehf, cabhf; /* file handle we are using */
struct fdi_folder *current; /* current folder we're extracting from */
- cab_UBYTE block_resv;
cab_ULONG offset; /* uncompressed offset within folder */
cab_UBYTE *outpos; /* (high level) start of data to use up */
cab_UWORD outlen; /* (high level) amount of data to use up */
- cab_UWORD split; /* at which split in current folder? */
int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn */
cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */
cab_UBYTE outbuf[CAB_BLOCKMAX];
@@ -93,23 +107,20 @@
struct QTMstate qtm;
struct LZXstate lzx;
} methods;
+ /* some temp variables for use during decompression */
+ cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
+ cab_ULONG q_position_base[42];
+ cab_ULONG lzx_position_base[51];
+ cab_UBYTE extra_bits[51];
+ USHORT setID; /* Cabinet set ID */
+ USHORT iCabinet; /* Cabinet number in set (0 based) */
+ struct fdi_cds_fwd *decomp_cab;
+ MORE_ISCAB_INFO mii;
struct fdi_folder *firstfol;
struct fdi_file *firstfile;
struct fdi_cds_fwd *next;
} fdi_decomp_state;
-/*
- * this structure fills the gaps between what is available in a PFDICABINETINFO
- * vs what is needed by FDICopy. Memory allocated for these becomes the responsibility
- * of the caller to free. Yes, I am aware that this is totally, utterly inelegant.
- */
-typedef struct {
- char *prevname, *previnfo;
- char *nextname, *nextinfo;
- int folder_resv, header_resv;
- cab_UBYTE block_resv;
-} MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;
-
/***********************************************************************
* FDICreate (CABINET.20)
*/
@@ -131,10 +142,6 @@
pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek,
cpuType, perf);
- /* PONDERME: Certainly, we cannot tolerate a missing pfnalloc, as we call it just below.
- pfnfree is tested as well, for symmetry. As for the rest, should we test these
- too? In a vacuum, I would say yes... but does Windows care? If not, then, I guess,
- neither do we.... */
if ((!pfnalloc) || (!pfnfree)) {
perf->erfOper = FDIERROR_NONE;
perf->erfType = ERROR_BAD_ARGUMENTS;
@@ -256,15 +263,12 @@
* process the cabinet header in the style of FDIIsCabinet, but
* without the sanity checks (and bug)
*
- * if pmii is non-null, some info not expressed in FDICABINETINFO struct
- * will be stored there... responsibility to free the enclosed stuff is
- * delegated to the caller in this case.
*/
BOOL FDI_read_entries(
- HFDI hfdi,
- INT_PTR hf,
- PFDICABINETINFO pfdici,
- PMORE_ISCAB_INFO pmii)
+ HFDI hfdi,
+ INT_PTR hf,
+ PFDICABINETINFO pfdici,
+ PMORE_ISCAB_INFO pmii)
{
int num_folders, num_files, header_resv, folder_resv = 0;
LONG base_offset, cabsize;
@@ -274,8 +278,6 @@
TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici);
- if (pmii) ZeroMemory(pmii, sizeof(MORE_ISCAB_INFO));
-
/* get basic offset & size info */
base_offset = FDI_getoffset(hfdi, hf);
@@ -407,6 +409,8 @@
}
if (flags & cfheadNEXT_CABINET) {
+ if (pmii)
+ pmii->hasnext = TRUE;
nextname = FDI_read_string(hfdi, hf, cabsize);
if (!nextname) {
if ((flags & cfheadPREV_CABINET) && pmii) {
@@ -487,10 +491,6 @@
return rv;
}
-/* FIXME: eliminate global variables */
-static cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
-static cab_ULONG q_position_base[42];
-
/******************************************************************
* QTMfdi_initmodel (internal)
*
@@ -533,12 +533,12 @@
/* initialise static slot/extrabits tables */
for (i = 0, j = 0; i < 27; i++) {
- q_length_extra[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
- q_length_base[i] = j; j += 1 << ((i == 26) ? 5 : q_length_extra[i]);
+ CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2;
+ CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]);
}
for (i = 0, j = 0; i < 42; i++) {
- q_extra_bits[i] = (i < 2 ? 0 : i-2) >> 1;
- q_position_base[i] = j; j += 1 << q_extra_bits[i];
+ CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1;
+ CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i];
}
/* initialise arithmetic coding models */
@@ -561,10 +561,6 @@
return DECR_OK;
}
-/* FIXME: Eliminate global variables */
-static cab_ULONG lzx_position_base[51];
-static cab_UBYTE extra_bits[51];
-
/************************************************************
* LZXfdi_init (internal)
*/
@@ -587,12 +583,12 @@
/* initialise static tables */
for (i=0, j=0; i <= 50; i += 2) {
- extra_bits[i] = extra_bits[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
+ CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */
}
for (i=0, j=0; i <= 50; i++) {
- lzx_position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
- j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
+ CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
+ j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
}
/* calculate required position slots */
@@ -600,7 +596,7 @@
else if (window == 21) posn_slots = 50;
else posn_slots = window << 1;
- /*posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
+ /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */
LZX(R0) = LZX(R1) = LZX(R2) = 1;
LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3);
@@ -1260,27 +1256,27 @@
case 4:
/* selector 4 = fixed length of 3 */
GET_SYMBOL(model4, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
match_length = 3;
break;
case 5:
/* selector 5 = fixed length of 4 */
GET_SYMBOL(model5, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
match_length = 4;
break;
case 6:
/* selector 6 = variable length */
GET_SYMBOL(model6len, sym);
- Q_READ_BITS(extra, q_length_extra[sym]);
- match_length = q_length_base[sym] + extra + 5;
+ Q_READ_BITS(extra, CAB(q_length_extra)[sym]);
+ match_length = CAB(q_length_base)[sym] + extra + 5;
GET_SYMBOL(model6pos, sym);
- Q_READ_BITS(extra, q_extra_bits[sym]);
- match_offset = q_position_base[sym] + extra + 1;
+ Q_READ_BITS(extra, CAB(q_extra_bits)[sym]);
+ match_offset = CAB(q_position_base)[sym] + extra + 1;
break;
default:
@@ -1504,9 +1500,9 @@
if (match_offset > 2) {
/* not repeated offset */
if (match_offset != 3) {
- extra = extra_bits[match_offset];
+ extra = CAB(extra_bits)[match_offset];
READ_BITS(verbatim_bits, extra);
- match_offset = lzx_position_base[match_offset]
+ match_offset = CAB(lzx_position_base)[match_offset]
- 2 + verbatim_bits;
}
else {
@@ -1577,8 +1573,8 @@
if (match_offset > 2) {
/* not repeated offset */
- extra = extra_bits[match_offset];
- match_offset = lzx_position_base[match_offset] - 2;
+ extra = CAB(extra_bits)[match_offset];
+ match_offset = CAB(lzx_position_base)[match_offset] - 2;
if (extra > 3) {
/* verbatim and aligned bits */
extra -= 3;
@@ -1698,16 +1694,26 @@
/**********************************************************
* fdi_decomp (internal)
+ *
+ * Decompress the "appropriate" number of bytes. If savemode is zero,
+ * do not save the output anywhere, just plow through blocks until we
+ * reach the starting point for fi, and remember the position of the
+ * cabfile pointer after we are done; otherwise, save it out, decompressing
+ * the number of bytes in the file specified by fi. This is also where we
+ * jumping to additional cabinets in the case of split cab's, and provide
+ * (most of) the NEXT_CABINET notification semantics described in the SDK.
*/
-int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state)
+int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state,
+ char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser)
{
cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset);
cab_UBYTE buf[cfdata_SIZEOF], *data;
cab_UWORD inlen, len, outlen, cando;
cab_ULONG cksum;
cab_LONG err;
+ fdi_decomp_state *cab = (savemode && CAB(decomp_cab)) ? CAB(decomp_cab) : decomp_state;
- TRACE("(fi == ^%p, savemode == %d)\n", fi, savemode);
+ TRACE("(fi == ^%p, savemode == %d, bytes == %d)\n", fi, savemode, bytes);
while (bytes > 0) {
/* cando = the max number of bytes we can do */
@@ -1728,10 +1734,10 @@
inlen = outlen = 0;
while (outlen == 0) {
/* read the block header, skip the reserved part */
- if (PFDI_READ(CAB(hfdi), CAB(cabhf), buf, cfdata_SIZEOF) != cfdata_SIZEOF)
+ if (PFDI_READ(CAB(hfdi), cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF)
return DECR_INPUT;
- if (PFDI_SEEK(CAB(hfdi), CAB(cabhf), CAB(block_resv), SEEK_CUR) == -1)
+ if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1)
return DECR_INPUT;
/* we shouldn't get blocks over CAB_INPUTMAX in size */
@@ -1739,7 +1745,7 @@
len = EndGetI16(buf+cfdata_CompressedSize);
inlen += len;
if (inlen > CAB_INPUTMAX) return DECR_INPUT;
- if (PFDI_READ(CAB(hfdi), CAB(cabhf), data, len) != len)
+ if (PFDI_READ(CAB(hfdi), cab->cabhf, data, len) != len)
return DECR_INPUT;
/* clear two bytes after read-in data */
@@ -1750,16 +1756,195 @@
if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0)))
return DECR_CHECKSUM; /* checksum is wrong */
- /* outlen=0 means this block was part of a split block */
outlen = EndGetI16(buf+cfdata_UncompressedSize);
+
+ /* outlen=0 means this block was the last contiguous part
+ of a split block, continued in the next cabinet */
if (outlen == 0) {
- /*
- cabinet_close(cab);
- cab = CAB(current)->cab[++CAB(split)];
- if (!cabinet_open(cab)) return DECR_INPUT;
- cabinet_seek(cab, CAB(current)->offset[CAB(split)]); */
- FIXME("split block... ack! fix this.\n");
- return DECR_INPUT;
+ int pathlen, filenamelen, idx, i, cabhf;
+ char fullpath[MAX_PATH], userpath[256];
+ FDINOTIFICATION fdin;
+ FDICABINETINFO fdici;
+ char emptystring = '\0';
+ cab_UBYTE buf2[64];
+ int success = FALSE;
+ struct fdi_folder *fol = NULL, *linkfol = NULL;
+ struct fdi_file *file = NULL, *linkfile = NULL;
+
+ tryanothercab:
+
+ /* set up the next decomp_state... */
+ if (!(cab->next)) {
+ if (!cab->mii.hasnext) return DECR_INPUT;
+
+ if (!((cab->next = PFDI_ALLOC(CAB(hfdi), sizeof(fdi_decomp_state)))))
+ return DECR_NOMEMORY;
+
+ ZeroMemory(cab->next, sizeof(fdi_decomp_state));
+
+ /* copy pszCabPath to userpath */
+ ZeroMemory(userpath, 256);
+ pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
+ if (pathlen) {
+ if (pathlen < 256) {
+ for (i = 0; i <= pathlen; i++)
+ userpath[i] = pszCabPath[i];
+ } /* else we are in a wierd place... let's leave it blank and see if the user fixes it */
+ }
+
+ /* initial fdintNEXT_CABINET notification */
+ ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
+ fdin.psz1 = (cab->mii.nextname) ? cab->mii.nextname : &emptystring;
+ fdin.psz2 = (cab->mii.nextinfo) ? cab->mii.nextinfo : &emptystring;
+ fdin.psz3 = &userpath[0];
+ fdin.fdie = FDIERROR_NONE;
+ fdin.pv = pvUser;
+
+ if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
+
+ do {
+
+ pathlen = (userpath) ? strlen(userpath) : 0;
+ filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 0;
+
+ /* slight overestimation here to save CPU cycles in the developer's brain */
+ if ((pathlen + filenamelen + 3) > MAX_PATH) {
+ ERR("MAX_PATH exceeded.\n");
+ return DECR_ILLEGALDATA;
+ }
+
+ /* paste the path and filename together */
+ idx = 0;
+ if (pathlen) {
+ for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i];
+ if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
+ }
+ if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i];
+ fullpath[idx] = '\0';
+
+ TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
+
+ /* try to get a handle to the cabfile */
+ cabhf = PFDI_OPEN(CAB(hfdi), fullpath, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0);
+ if (cabhf == -1) {
+ /* no file. allow the user to try again */
+ fdin.fdie = FDIERROR_CABINET_NOT_FOUND;
+ if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
+ continue;
+ }
+
+ /* check if it's really a cabfile. Note that this doesn't implement the bug */
+ if (!FDI_read_entries(CAB(hfdi), cabhf, &fdici, &(cab->next->mii))) {
+ WARN("FDIIsCabinet failed.\n");
+ PFDI_CLOSE(CAB(hfdi), cabhf);
+ fdin.fdie = FDIERROR_NOT_A_CABINET;
+ if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
+ continue;
+ }
+
+ if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) {
+ WARN("Wrong Cabinet.\n");
+ PFDI_CLOSE(CAB(hfdi), cabhf);
+ fdin.fdie = FDIERROR_WRONG_CABINET;
+ if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
+ continue;
+ }
+
+ break;
+
+ } while (1);
+
+ /* cabinet notification */
+ ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
+ fdin.setID = fdici.setID;
+ fdin.iCabinet = fdici.iCabinet;
+ fdin.pv = pvUser;
+ fdin.psz1 = (cab->next->mii.nextname) ? cab->next->mii.nextname : &emptystring;
+ fdin.psz2 = (cab->next->mii.nextinfo) ? cab->next->mii.nextinfo : &emptystring;
+ fdin.psz3 = pszCabPath;
+
+ if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) return DECR_USERABORT;
+
+ cab->next->setID = fdici.setID;
+ cab->next->iCabinet = fdici.iCabinet;
+ cab->next->hfdi = CAB(hfdi);
+ cab->next->filehf = CAB(filehf);
+ cab->next->cabhf = cabhf;
+ cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */
+
+ cab = cab->next; /* advance to the next cabinet */
+
+ /* read folders */
+ for (i = 0; i < fdici.cFolders; i++) {
+ if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF)
+ return DECR_INPUT;
+
+ if (cab->mii.folder_resv > 0)
+ PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.folder_resv, SEEK_CUR);
+
+ fol = (struct fdi_folder *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_folder));
+ if (!fol) {
+ ERR("out of memory!\n");
+ return DECR_NOMEMORY;
+ }
+ ZeroMemory(fol, sizeof(struct fdi_folder));
+ if (!(cab->firstfol)) cab->firstfol = fol;
+
+ fol->offset = (cab_off_t) EndGetI32(buf2+cffold_DataOffset);
+ fol->num_blocks = EndGetI16(buf2+cffold_NumBlocks);
+ fol->comp_type = EndGetI16(buf2+cffold_CompType);
+
+ if (linkfol)
+ linkfol->next = fol;
+ linkfol = fol;
+ }
+
+ /* read files */
+ for (i = 0; i < fdici.cFiles; i++) {
+ if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF)
+ return DECR_INPUT;
+
+ file = (struct fdi_file *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_file));
+ if (!file) {
+ ERR("out of memory!\n");
+ return DECR_NOMEMORY;
+ }
+ ZeroMemory(file, sizeof(struct fdi_file));
+ if (!(cab->firstfile)) cab->firstfile = file;
+
+ file->length = EndGetI32(buf2+cffile_UncompressedSize);
+ file->offset = EndGetI32(buf2+cffile_FolderOffset);
+ file->index = EndGetI16(buf2+cffile_FolderIndex);
+ file->time = EndGetI16(buf2+cffile_Time);
+ file->date = EndGetI16(buf2+cffile_Date);
+ file->attribs = EndGetI16(buf2+cffile_Attribs);
+ file->filename = FDI_read_string(CAB(hfdi), cab->cabhf, fdici.cbCabinet);
+
+ if (!file->filename) return DECR_INPUT;
+
+ if (linkfile)
+ linkfile->next = file;
+ linkfile = file;
+ }
+
+ } else
+ cab = cab->next; /* advance to the next cabinet */
+
+ /* iterate files -- if we encounter the continued file, process it --
+ otherwise, jump to the label above and keep looking */
+
+ for (file = cab->firstfile; (file); file = file->next) {
+ if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
+ /* check to ensure a real match */
+ if (strcasecmp(fi->filename, file->filename) == 0) {
+ success = TRUE;
+ if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1)
+ return DECR_INPUT;
+ break;
+ }
+ }
+ }
+ if (!success) goto tryanothercab; /* this should never happen */
}
}
@@ -1769,7 +1954,8 @@
CAB(outlen) = outlen;
CAB(outpos) = CAB(outbuf);
}
-
+
+ CAB(decomp_cab) = cab;
return DECR_OK;
}
@@ -1787,14 +1973,12 @@
{
FDICABINETINFO fdici;
FDINOTIFICATION fdin;
- MORE_ISCAB_INFO mii;
int cabhf, filehf;
int i, idx;
char fullpath[MAX_PATH];
size_t pathlen, filenamelen;
char emptystring = '\0';
cab_UBYTE buf[64];
- BOOL initialcab = TRUE;
struct fdi_folder *fol = NULL, *linkfol = NULL;
struct fdi_file *file = NULL, *linkfile = NULL;
fdi_decomp_state _decomp_state;
@@ -1846,7 +2030,7 @@
}
/* check if it's really a cabfile. Note that this doesn't implement the bug */
- if (!FDI_read_entries(hfdi, cabhf, &fdici, &mii)) {
+ if (!FDI_read_entries(hfdi, cabhf, &fdici, &(CAB(mii)))) {
ERR("FDIIsCabinet failed.\n");
PFDI_CLOSE(hfdi, cabhf);
return FALSE;
@@ -1857,8 +2041,8 @@
fdin.setID = fdici.setID;
fdin.iCabinet = fdici.iCabinet;
fdin.pv = pvUser;
- fdin.psz1 = (mii.nextname) ? mii.nextname : &emptystring;
- fdin.psz2 = (mii.nextinfo) ? mii.nextinfo : &emptystring;
+ fdin.psz1 = (CAB(mii).nextname) ? CAB(mii).nextname : &emptystring;
+ fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring;
fdin.psz3 = pszCabPath;
if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) {
@@ -1868,6 +2052,9 @@
goto bail_and_fail;
}
+ CAB(setID) = fdici.setID;
+ CAB(iCabinet) = fdici.iCabinet;
+
/* read folders */
for (i = 0; i < fdici.cFolders; i++) {
if (PFDI_READ(hfdi, cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) {
@@ -1877,8 +2064,8 @@
goto bail_and_fail;
}
- if (mii.folder_resv > 0)
- PFDI_SEEK(hfdi, cabhf, mii.folder_resv, SEEK_CUR);
+ if (CAB(mii).folder_resv > 0)
+ PFDI_SEEK(hfdi, cabhf, CAB(mii).folder_resv, SEEK_CUR);
fol = (struct fdi_folder *) PFDI_ALLOC(hfdi, sizeof(struct fdi_folder));
if (!fol) {
@@ -1892,7 +2079,7 @@
ZeroMemory(fol, sizeof(struct fdi_folder));
if (!CAB(firstfol)) CAB(firstfol) = fol;
- fol->offset[0] = (cab_off_t) EndGetI32(buf+cffold_DataOffset);
+ fol->offset = (cab_off_t) EndGetI32(buf+cffold_DataOffset);
fol->num_blocks = EndGetI16(buf+cffold_NumBlocks);
fol->comp_type = EndGetI16(buf+cffold_CompType);
@@ -1943,14 +2130,14 @@
}
for (file = CAB(firstfile); (file); file = file->next) {
- /* partial file notification (do it just once for the first cabinet) */
- if (initialcab && ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV)) {
+ /* partial-file notification (do it just once for the first cabinet) */
+ if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) {
/* OK, more MS bugs to simulate here, I think. I don't have a huge spanning
* cabinet to test this theory on ATM, but here's the deal. The SDK says that we
* are supposed to notify the user of the filename and "disk name" (info) of
* the cabinet where the spanning file /started/. That would certainly be convenient
* for the consumer, who could decide to abort everything and try to start over with
- * that cabinet so as not to create a front-truncated output file. Note that this
+ * that cabinet so as to avoid partial file notification and successfully unpack. This
* task would be a horrible bitch from the implementor's (wine's) perspective: the
* information is associated nowhere with the file header and is not to be found in
* the cabinet header. So we would have to open the previous cabinet, and check
@@ -1966,8 +2153,8 @@
ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
fdin.pv = pvUser;
fdin.psz1 = (char *)file->filename;
- fdin.psz2 = (mii.prevname) ? mii.prevname : &emptystring;
- fdin.psz3 = (mii.previnfo) ? mii.previnfo : &emptystring;
+ fdin.psz2 = (CAB(mii).prevname) ? CAB(mii).prevname : &emptystring;
+ fdin.psz3 = (CAB(mii).previnfo) ? CAB(mii).previnfo : &emptystring;
if (((*pfnfdin)(fdintPARTIAL_FILE, &fdin))) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
@@ -1975,13 +2162,12 @@
PFDI_INT(hfdi)->perf->fError = TRUE;
goto bail_and_fail;
}
- /* I don't think we are supposed to decompress partial files */
+ /* I don't think we are supposed to decompress partial files. This prevents it. */
file->oppressed = TRUE;
}
if (file->oppressed) {
filehf = 0;
} else {
- /* fdintCOPY_FILE notification (TODO: skip for spanning cab's we already should have hf) */
ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
fdin.pv = pvUser;
fdin.psz1 = (char *)file->filename;
@@ -1997,6 +2183,21 @@
}
}
+ /* find the folder for this file if necc. */
+ if (filehf) {
+ int i2;
+
+ fol = CAB(firstfol);
+ if ((file->index & cffileCONTINUED_TO_NEXT) == cffileCONTINUED_TO_NEXT) {
+ /* pick the last folder */
+ while (fol->next) fol = fol->next;
+ } else {
+ for (i2 = 0; (i2 < file->index); i2++)
+ if (fol->next) /* bug resistance, should always be true */
+ fol = fol->next;
+ }
+ }
+
if (filehf) {
cab_UWORD comptype = fol->comp_type;
int ct1 = comptype & cffoldCOMPTYPE_MASK;
@@ -2004,14 +2205,12 @@
TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename));
- /* set up decomp_state (unnecessary?); at least
- ignore trailing three pointers in the struct */
- ZeroMemory(decomp_state, sizeof(fdi_decomp_state) - sizeof(void*) * 3);
+ /* set up decomp_state */
CAB(hfdi) = hfdi;
CAB(filehf) = filehf;
CAB(cabhf) = cabhf;
- CAB(current) = file->folder;
- CAB(block_resv) = mii.block_resv;
+ CAB(current) = fol;
+ CAB(decomp_cab) = NULL;
/* set up the appropriate decompressor */
switch (ct1) {
@@ -2049,16 +2248,20 @@
goto bail_and_fail;
}
- PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset[0], SEEK_SET);
+ PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset, SEEK_SET);
CAB(offset) = 0;
CAB(outlen) = 0;
- CAB(split) = 0;
if (file->offset > CAB(offset)) {
/* decode bytes and send them to /dev/null */
- switch ((err = fdi_decomp(file, 0, decomp_state))) {
+ switch ((err = fdi_decomp(file, 0, decomp_state, pszCabPath, pfnfdin, pvUser))) {
case DECR_OK:
break;
+ case DECR_USERABORT:
+ PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
+ PFDI_INT(hfdi)->perf->erfType = 0;
+ PFDI_INT(hfdi)->perf->fError = TRUE;
+ goto bail_and_fail;
case DECR_NOMEMORY:
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
@@ -2075,12 +2278,17 @@
}
/* now do the actual decompression */
- err = fdi_decomp(file, 1, decomp_state);
+ err = fdi_decomp(file, 1, decomp_state, pszCabPath, pfnfdin, pvUser);
if (err) CAB(current) = NULL; else CAB(offset) += file->length;
switch (err) {
case DECR_OK:
break;
+ case DECR_USERABORT:
+ PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
+ PFDI_INT(hfdi)->perf->erfType = 0;
+ PFDI_INT(hfdi)->perf->fError = TRUE;
+ goto bail_and_fail;
case DECR_NOMEMORY:
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
@@ -2094,6 +2302,24 @@
goto bail_and_fail;
}
+ /* free decompression temps */
+ switch (ct1) {
+ case cffoldCOMPTYPE_LZX:
+ if (LZX(window)) {
+ PFDI_FREE(hfdi, LZX(window));
+ LZX(window) = NULL;
+ }
+ break;
+ case cffoldCOMPTYPE_QUANTUM:
+ if (QTM(window)) {
+ PFDI_FREE(hfdi, QTM(window));
+ QTM(window) = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
/* fdintCLOSE_FILE_INFO notification */
ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
fdin.pv = pvUser;
@@ -2120,6 +2346,15 @@
while (decomp_state) {
fdi_decomp_state *prev_fds;
+
+ PFDI_CLOSE(hfdi, CAB(cabhf));
+
+ /* free the storage remembered by mii */
+ if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname);
+ if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo);
+ if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname);
+ if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo);
+
while (CAB(firstfol)) {
fol = CAB(firstfol);
CAB(firstfol) = CAB(firstfol)->next;
@@ -2127,6 +2362,7 @@
}
while (CAB(firstfile)) {
file = CAB(firstfile);
+ if (file->filename) PFDI_FREE(hfdi, (void *)file->filename);
CAB(firstfile) = CAB(firstfile)->next;
PFDI_FREE(hfdi, file);
}
@@ -2136,19 +2372,21 @@
PFDI_FREE(hfdi, prev_fds);
}
- /* free the storage remembered by mii */
- if (mii.nextname) PFDI_FREE(hfdi, mii.nextname);
- if (mii.nextinfo) PFDI_FREE(hfdi, mii.nextinfo);
- if (mii.prevname) PFDI_FREE(hfdi, mii.prevname);
- if (mii.previnfo) PFDI_FREE(hfdi, mii.previnfo);
-
- PFDI_CLOSE(hfdi, cabhf);
return TRUE;
bail_and_fail: /* here we free ram before error returns */
while (decomp_state) {
fdi_decomp_state *prev_fds;
+
+ PFDI_CLOSE(hfdi, CAB(cabhf));
+
+ /* free the storage remembered by mii */
+ if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname);
+ if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo);
+ if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname);
+ if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo);
+
while (CAB(firstfol)) {
fol = CAB(firstfol);
CAB(firstfol) = CAB(firstfol)->next;
@@ -2156,6 +2394,7 @@
}
while (CAB(firstfile)) {
file = CAB(firstfile);
+ if (file->filename) PFDI_FREE(hfdi, (void *)file->filename);
CAB(firstfile) = CAB(firstfile)->next;
PFDI_FREE(hfdi, file);
}
@@ -2165,13 +2404,6 @@
PFDI_FREE(hfdi, prev_fds);
}
- /* free the storage remembered by mii */
- if (mii.nextname) PFDI_FREE(hfdi, mii.nextname);
- if (mii.nextinfo) PFDI_FREE(hfdi, mii.nextinfo);
- if (mii.prevname) PFDI_FREE(hfdi, mii.prevname);
- if (mii.previnfo) PFDI_FREE(hfdi, mii.previnfo);
-
- PFDI_CLOSE(hfdi, cabhf);
return FALSE;
}
--
"We must stop thinking of the individual and start
thinking about what is best for society."
-Hillary Clinton, 1993
gmt
More information about the wine-patches
mailing list