cab_G_01
Gregory M. Turner
gmturner007 at ameritech.net
Tue Aug 5 10:27:54 CDT 2003
relative to cvs; should not interfere with cab_G_00, which is still
pending, so it is safe to go ahead and apply.
License: Bugroff
ChangeLog:
* dlls/cabinet: fdi.c:
Greg Turner <gmturner007 at ameritech.net>
- many words about cabinets
--
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/dlls/cabinet/fdi.c ./dlls/cabinet/fdi.c
--- ../wine.test/dlls/cabinet/fdi.c 2003-08-01 21:14:37.000000000 -0500
+++ ./dlls/cabinet/fdi.c 2003-08-05 10:06:08.000000000 -0500
@@ -20,13 +20,40 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
- * This is (or will be) a largely redundant reimplementation of the stuff in
- * 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). Also,
- * cabextract's implementation is pretty efficient; fdi.c is, by contrast, extremely
- * wasteful...
+ * This is a largely redundant reimplementation of the stuff in cabextract.c. It
+ * would be theoretically 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.
+ * But this approach would be quite a bit less performant. Probably a better way
+ * would be to create a "library" of routines in cabextract.c which do the actual
+ * decompression, and have both fdi.c and cabextract share those routines. The rest
+ * of the code is not sufficiently similar to merit a shared implementation.
+ *
+ * The worst thing about this API is the bug. "The bug" is this: when you extract a
+ * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that
+ * there is no subsequent cabinet, even if there is one. wine faithfully reproduces
+ * this behavior.
+ *
+ * TODO:
+ *
+ * Wine does not implement the AFAIK undocumented "enumerate" callback during
+ * FDICopy. It is implemented in Windows and therefore worth investigating...
+ *
+ * Lots of pointers flying around here... am I leaking RAM?
+ *
+ * WTF is FDITruncate?
+ *
+ * Probably, I need to weed out some dead code-paths.
+ *
+ * Test unit(s).
+ *
+ * The fdintNEXT_CABINET callbacks are probably not working quite as they should.
+ * There are several FIXME's in the source describing some of the deficiencies in
+ * some detail. Additionally, we do not do a very good job of returning the right
+ * error codes to this callback.
+ *
+ * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller
+ * functions would be nice.
*
* -gmt
*/
@@ -55,7 +82,7 @@
cab_ULONG offset; /* uncompressed offset in folder */
cab_UWORD index; /* magic index number of folder */
cab_UWORD time, date, attribs; /* MS-DOS time/date/attributes */
- BOOL oppressed; /* never to be processed */
+ BOOL oppressed; /* never to be processed */
};
struct fdi_folder {
@@ -71,7 +98,7 @@
* 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
+ * To make things even more unnecessarily confusing, we now attach these to the
* fdi_decomp_state.
*/
typedef struct {
@@ -84,7 +111,7 @@
/*
* ugh, well, this ended up being pretty damn silly...
- * now that I've conceeded to build equivalent structures to struct cab.*,
+ * now that I've conceded 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
@@ -122,6 +149,42 @@
/***********************************************************************
* FDICreate (CABINET.20)
+ *
+ * Provided with several callbacks (all of them are mandatory),
+ * returns a handle which can be used to perform operations
+ * on cabinet files.
+ *
+ * PARAMS
+ * pfnalloc [I] A pointer to a function which allocates ram. Uses
+ * the same interface as malloc.
+ * pfnfree [I] A pointer to a function which frees ram. Uses the
+ * same interface as free.
+ * pfnopen [I] A pointer to a function which opens a file. Uses
+ * the same interface as _open.
+ * pfnread [I] A pointer to a function which reads from a file into
+ * a caller-provided buffer. Uses the same interface
+ * as _read
+ * pfnwrite [I] A pointer to a function which writes to a file from
+ * a caller-provided buffer. Uses the same interface
+ * as _write.
+ * pfnclose [I] A pointer to a function which closes a file handle.
+ * Uses the same interface as _close.
+ * pfnseek [I] A pointer to a function which seeks in a file.
+ * Uses the same interface as _lseek.
+ * cpuType [I] The type of CPU; ignored in wine (recommended value:
+ * cpuUNKNOWN, aka -1).
+ * perf [IO] A pointer to an ERF structure. When FDICreate
+ * returns an error condition, error information may
+ * be found here as well as from GetLastError.
+ *
+ * RETURNS
+ * On success, returns an FDI handle of type HFDI.
+ * On failure, the NULL file handle is returned. Error
+ * info can be retrieved from perf.
+ *
+ * INCLUDES
+ * fdi.h
+ *
*/
HFDI __cdecl FDICreate(
PFNALLOC pfnalloc,
@@ -177,7 +240,7 @@
/*******************************************************************
* FDI_getoffset (internal)
*
- * returns the file pointer position of a cab
+ * returns the file pointer position of a file handle.
*/
long FDI_getoffset(HFDI hfdi, INT_PTR hf)
{
@@ -188,7 +251,7 @@
* FDI_realloc (internal)
*
* we can't use _msize; the user might not be using malloc, so we require
- * an explicit specification of the previous size. utterly inefficient.
+ * an explicit specification of the previous size. inefficient.
*/
void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
{
@@ -207,7 +270,7 @@
/**********************************************************************
* FDI_read_string (internal)
*
- * allocate and read an aribitrarily long string from the cabinet
+ * allocate and read an arbitrarily long string from the cabinet
*/
char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
{
@@ -261,7 +324,6 @@
*
* process the cabinet header in the style of FDIIsCabinet, but
* without the sanity checks (and bug)
- *
*/
BOOL FDI_read_entries(
HFDI hfdi,
@@ -277,6 +339,36 @@
TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici);
+ /*
+ * FIXME: I just noticed that I am memorizing the initial file pointer
+ * offset and restoring it before reading in the rest of the header
+ * information in the cabinet. Perhaps that's correct -- that is, perhaps
+ * this API is supposed to support "streaming" cabinets which are embedded
+ * in other files, or cabinets which begin at file offsets other than zero.
+ * Otherwise, I should instead go to the absolute beginning of the file.
+ * (Either way, the semantics of wine's FDICopy require me to leave the
+ * file pointer where it is afterwards -- If Windows does not do so, we
+ * ought to duplicate the native behavior in the FDIIsCabinet API, not here.
+ *
+ * So, the answer lies in Windows; will native cabinet.dll recognize a
+ * cabinet "file" embedded in another file? Note that cabextract.c does
+ * support this, which implies that Microsoft's might. I haven't tried it
+ * yet so I don't know. ATM, most of wine's FDI cabinet routines (except
+ * this one) would not work in this way. To fix it, we could just make the
+ * various references to absolute file positions in the code relative to an
+ * initial "beginning" offset. Because the FDICopy API doesn't take a
+ * file-handle like this one, we would therein need to search through the
+ * file for the beginning of the cabinet (as we also do in cabextract.c).
+ * Note that this limits us to a maximum of one cabinet per. file: the first.
+ *
+ * So, in summary: either the code below is wrong, or the rest of fdi.c is
+ * wrong... I cannot imagine that both are correct ;) One of these flaws
+ * should be fixed after determining the behavior on Windows. We ought
+ * to check both FDIIsCabinet and FDICopy for the right behavior.
+ *
+ * -gmt
+ */
+
/* get basic offset & size info */
base_offset = FDI_getoffset(hfdi, hf);
@@ -449,6 +541,30 @@
/***********************************************************************
* FDIIsCabinet (CABINET.21)
+ *
+ * Informs the caller as to whether or not the provided file handle is
+ * really a cabinet or not, filling out the provided PFDICABINETINFO
+ * structure with information about the cabinet. Brief explanations of
+ * the elements of this structure are available as comments accompanying
+ * its definition in wine's include/fdi.h.
+ *
+ * PARAMS
+ * hfdi [I] An HFDI from FDICreate
+ * hf [I] The file handle about which the caller inquires
+ * pfdici [IO] Pointer to a PFDICABINETINFO structure which will
+ * be filled out with information about the cabinet
+ * file indicated by hf if, indeed, it is determined
+ * to be a cabinet.
+ *
+ * RETURNS
+ * TRUE if the file is a cabinet. The info pointed to by pfdici will
+ * be provided.
+ * FALSE if the file is not a cabinet, or if an error was encountered
+ * while processing the cabinet. The PERF structure provided to
+ * FDICreate can be queried for more error information.
+ *
+ * INCLUDES
+ * fdi.c
*/
BOOL __cdecl FDIIsCabinet(
HFDI hfdi,
@@ -493,7 +609,7 @@
/******************************************************************
* QTMfdi_initmodel (internal)
*
- * Initialise a model which decodes symbols from [s] to [s]+[n]-1
+ * Initialize a model which decodes symbols from [s] to [s]+[n]-1
*/
void QTMfdi_initmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) {
int i;
@@ -530,7 +646,7 @@
QTM(window_size) = wndsize;
QTM(window_posn) = 0;
- /* initialise static slot/extrabits tables */
+ /* initialize static slot/extrabits tables */
for (i = 0, j = 0; i < 27; 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]);
@@ -540,7 +656,7 @@
CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i];
}
- /* initialise arithmetic coding models */
+ /* initialize arithmetic coding models */
QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0);
@@ -580,7 +696,7 @@
}
LZX(window_size) = wndsize;
- /* initialise static tables */
+ /* initialize static tables */
for (i=0, j=0; i <= 50; i += 2) {
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... */
@@ -607,7 +723,7 @@
LZX(intel_started) = 0;
LZX(window_posn) = 0;
- /* initialise tables to 0 (because deltas will be applied to them) */
+ /* initialize tables to 0 (because deltas will be applied to them) */
for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0;
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0;
@@ -1694,13 +1810,14 @@
/**********************************************************
* fdi_decomp (internal)
*
- * Decompress the "appropriate" number of bytes. If savemode is zero,
+ * Decompress the requested 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.
+ * reach the specified (uncompressed) distance from the starting point,
+ * and remember the position of the cabfile pointer (and which cabfile)
+ * after we are done; otherwise, save the data out to CAB(filehf),
+ * decompressing the requested number of bytes and writing them out. This
+ * is also where we jump to additional cabinets in the case of split
+ * cab's, and provide (some of) the NEXT_CABINET notification semantics.
*/
int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state,
char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser)
@@ -1788,7 +1905,7 @@
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 */
+ } /* else we are in a weird place... let's leave it blank and see if the user fixes it */
}
/* initial fdintNEXT_CABINET notification */
@@ -1950,7 +2067,8 @@
}
}
}
- if (!success) goto tryanothercab; /* this should never happen */
+ if (!success) goto tryanothercab; /* FIXME: shouldn't this trigger
+ "Wrong Cabinet" notification? */
}
}
@@ -1967,6 +2085,167 @@
/***********************************************************************
* FDICopy (CABINET.22)
+ *
+ * Iterates through the files in the Cabinet file indicated by name and
+ * file-location. May chain forward to additional cabinets (typically
+ * only one) if files which begin in this Cabinet are continued in another
+ * cabinet. For each file which is partially contained in this cabinet,
+ * and partially contained in a prior cabinet, provides fdintPARTIAL_FILE
+ * notification to the pfnfdin callback. For each file which begins in
+ * this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin
+ * callback, and the file is optionally decompressed and saved to disk.
+ * Notification is not provided for files which are not at least partially
+ * contained in the specified cabinet file.
+ *
+ * See below for a thorough explanation of the various notification
+ * callbacks.
+ *
+ * PARAMS
+ * hfdi [I] An HFDI from FDICreate
+ * pszCabinet [I] C-style string containing the filename of the cabinet
+ * pszCabPath [I] C-style string containing the file path of the cabinet
+ * flags [I] "Decoder parameters". Ignored. Suggested value: 0.
+ * pfnfdin [I] Pointer to a notification function. See CALLBACKS below.
+ * pfnfdid [I] Pointer to a decryption function. Ignored. Suggested
+ * value: NULL.
+ * pvUser [I] arbitrary void * value which is passed to callbacks.
+ *
+ * RETURNS
+ * TRUE if successful.
+ * FALSE if unsuccessful (error information is provided in the ERF structure
+ * associated with the provided decompression handle by FDICreate).
+ *
+ * CALLBACKS
+ *
+ * Two pointers to callback functions are provided as parameters to FDICopy:
+ * pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT). These
+ * types are as follows:
+ *
+ * typedef INT_PTR (__cdecl *PFNFDINOTIFY) ( FDINOTIFICATIONTYPE fdint,
+ * PFDINOTIFICATION pfdin );
+ *
+ * typedef int (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid );
+ *
+ * You can create functions of this type using the FNFDINOTIFY() and
+ * FNFDIDECRYPT() macros, respectively. For example:
+ *
+ * FNFDINOTIFY(mycallback) {
+ * / * use variables fdint and pfdin to process notification * /
+ * }
+ *
+ * The second callback, which could be used for decrypting encrypted data,
+ * is not used at all.
+ *
+ * Each notification informs the user of some event which has occurred during
+ * decompression of the cabinet file; each notification is also an opportunity
+ * for the callee to abort decompression. The information provided to the
+ * callback and the meaning of the callback's return value vary drastically
+ * across the various types of notification. The type of notification is the
+ * fdint parameter; all other information is provided to the callback in
+ * notification-specific parts of the FDINOTIFICATION structure pointed to by
+ * pfdin. The only part of that structure which is assigned for every callback
+ * is the pv element, which contains the arbitrary value which was passed to
+ * FDICopy in the pvUser argument (psz1 is also used each time, but its meaning
+ * is highly dependant on fdint).
+ *
+ * If you encounter unknown notifications, you should return zero if you want
+ * decompression to continue (or -1 to abort). All strings used in the
+ * callbacks are regular C-style strings. Detailed descriptions of each
+ * notification type follow:
+ *
+ * fdintCABINET_INFO:
+ *
+ * This is the first notification provided after calling FDICopy, and provides
+ * the user with various information about the cabinet. Note that this is
+ * called for each cabinet FDICopy opens, not just the first one. In the
+ * structure pointed to by pfdin, psz1 contains a pointer to the name of the
+ * next cabinet file in the set after the one just loaded (if any), psz2
+ * contains a pointer to the name or "info" of the next disk, psz3
+ * contains a pointer to the file-path of the current cabinet, setID
+ * contains an arbitrary constant associated with this set of cabinet files,
+ * and iCabinet contains the numerical index of the current cabinet within
+ * that set. Return zero, or -1 to abort.
+ *
+ * fdintPARTIAL_FILE:
+ *
+ * This notification is provided when FDICopy encounters a part of a file
+ * contained in this cabinet which is missing its beginning. Files can be
+ * split across cabinets, so this is not necessarily an abnormality; it just
+ * means that the file in question begins in another cabinet. No file
+ * corresponding to this notification is extracted from the cabinet. In the
+ * structure pointed to by pfdin, psz1 contains a pointer to the name of the
+ * partial file, psz2 contains a pointer to the file name of the cabinet in
+ * which this file begins, and psz3 contains a pointer to the disk name or
+ * "info" of the cabinet where the file begins. Return zero, or -1 to abort.
+ *
+ * fdintCOPY_FILE:
+ *
+ * This notification is provided when FDICopy encounters a file which starts
+ * in the cabinet file, provided to FDICopy in pszCabinet. (FDICopy will not
+ * look for files in cabinets after the first one). One notification will be
+ * sent for each such file, before the file is decompressed. By returning
+ * zero, the callback can instruct FDICopy to skip the file. In the structure
+ * pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains
+ * the size of the file (uncompressed), attribs contains the file attributes,
+ * and date and time contain the date and time of the file. attributes, date,
+ * and time are of the 16-bit ms-dos variety. Return -1 to abort decompression
+ * for the entire cabinet, 0 to skip just this file but continue scanning the
+ * cabinet for more files, or an FDIClose()-compatible file-handle.
+ *
+ * fdintCLOSE_FILE_INFO:
+ *
+ * This notification is important, don't forget to implement it. This
+ * notification indicates that a file has been successfully uncompressed and
+ * written to disk. Upon receipt of this notification, the callee is expected
+ * to close the file handle, to set the attributes and date/time of the
+ * closed file, and possibly to execute the file. In the structure pointed to
+ * by pfdin, psz1 contains a pointer to the name of the file, hf will be the
+ * open file handle (close it), cb contains 1 or zero, indicating respectively
+ * that the callee should or should not execute the file, and date, time
+ * and attributes will be set as in fdintCOPY_FILE. Bizarrely, the Cabinet SDK
+ * specifies that _A_EXEC will be xor'ed out of attributes! wine does not do
+ * do so. Return TRUE, or FALSE to abort decompression.
+ *
+ * fdintNEXT_CABINET:
+ *
+ * This notification is called when FDICopy must load in another cabinet. This
+ * can occur when a file's data is "split" across multiple cabinets. The
+ * callee has the opportunity to request that FDICopy look in a different file
+ * path for the specified cabinet file, by writing that data into a provided
+ * buffer (see below for more information). This notification will be received
+ * more than once per-cabinet in the instance that FDICopy failed to find a
+ * valid cabinet at the location specified by the first per-cabinet
+ * fdintNEXT_CABINET notification. In such instances, the fdie element of the
+ * structure pointed to by pfdin indicates the error which prevented FDICopy
+ * from proceeding successfully. Return zero to indicate success, or -1 to
+ * indicate failure and abort FDICopy.
+ *
+ * Upon receipt of this notification, the structure pointed to by pfdin will
+ * contain the following values: psz1 pointing to the name of the cabinet
+ * which FDICopy is attempting to open, psz2 pointing to the name ("info") of
+ * the next disk, psz3 pointing to the presumed file-location of the cabinet,
+ * and fdie containing either FDIERROR_NONE, or one of the following:
+ *
+ * FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET,
+ * FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET,
+ * FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and
+ * FDIERROR_WRONG_CABINET.
+ *
+ * The callee may choose to change the path where FDICopy will look for the
+ * cabinet after this notification. To do so, the caller may write the new
+ * pathname to the buffer pointed to by psz3, which is 256 characters in
+ * length, including the terminating null character, before returning zero.
+ *
+ * fdintENUMERATE:
+ *
+ * Undocumented and unimplemented in wine, this seems to be sent each time
+ * a cabinet is opened, along with the fdintCABINET_INFO notification. It
+ * probably has an interface similar to that of fdintCABINET_INFO; maybe this
+ * provides information about the current cabinet instead of the next one....
+ * this is just a guess, it has not been looked at closely.
+ *
+ * INCLUDES
+ * fdi.c
*/
BOOL __cdecl FDICopy(
HFDI hfdi,
@@ -2145,25 +2424,54 @@
}
for (file = CAB(firstfile); (file); file = file->next) {
- /* partial-file notification (do it just once for the first cabinet) */
+
+ /*
+ * FIXME: This implementation keeps multiple cabinet files open at once
+ * when encountering a split cabinet. It is a quirk of this implementation
+ * that sometimes we decrypt the same block of data more than once, to find
+ * the right starting point for a file, moving the file-pointer backwards.
+ * If we kept a cache of certain file-pointer information, we could eliminate
+ * that behavior... in fact I am not sure that the caching we already have
+ * is not sufficient.
+ *
+ * The current implementation seems to work fine in straightforward situations
+ * where all the cabinet files needed for decryption are simultaneously
+ * available. But presumably, the API is supposed to support cabinets which
+ * are split across multiple CDROMS; we may need to change our implementation
+ * to strictly serialize it's file usage so that it opens only one cabinet
+ * at a time. Some experimentation with Windows is needed to figure out the
+ * precise semantics required. The relevant code is here and in fdi_decomp().
+ */
+
+ /* partial-file notification */
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 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
- * if it contains a single spanning file that's continued from yet another prior cabinet,
- * and so-on, until we find the beginning. Note that cabextract.c has code to do exactly
- * this. Luckily, MS clearly didn't implement this logic, so we don't have to either.
- * Watching the callbacks (and debugmsg +file) clearly shows that they don't open
- * the preceeding cabinet -- and therefore, I deduce, there is NO WAY they could
- * have implemented what's in the spec. Instead, they are obviously just returning
- * the previous cabinet and it's info from the header of this cabinet. So we shall
- * do the same. Of course, I could be missing something...
+ /*
+ * FIXME: Need to create a Cabinet with a single file spanning multiple files
+ * and perform some tests to figure out the right behavior. The SDK says
+ * FDICopy will 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 API-user, who could abort,
+ * everything (or parallelize, if that's allowed (it is in wine)), and call
+ * FDICopy again with the provided filename, so as to avoid partial file
+ * notification and successfully unpack. This task could be quite unpleasant
+ * from wine's perspective: the information specifying the "start cabinet" for
+ * a file is associated nowhere with the file header and is not to be found in
+ * the cabinet header. We have only the index of the cabinet wherein the folder
+ * begins, which contains the file. To find that cabinet, we must consider the
+ * index of the current cabinet, and chain backwards, cabinet-by-cabinet (for
+ * each cabinet refers to its "next" and "previous" cabinet only, like a linked
+ * list).
+ *
+ * Bear in mind that, in the spirit of CABINET.DLL, we must assume that any
+ * cabinet other than the active one might be at another filepath than the
+ * current one, or on another CDROM. This could get rather dicey, especially
+ * if we imagine parallelized access to the FDICopy API.
+ *
+ * The current implementation punts -- it just returns the previous cabinet and
+ * it's info from the header of this cabinet. This provides the right answer in
+ * 95% of the cases; its worth checking if Microsoft cuts the same corner before
+ * we "fix" it.
*/
ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
fdin.pv = pvUser;
@@ -2231,7 +2539,7 @@
TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename));
- /* free stuff for the old decompressor */
+ /* free stuff for the old decompresser */
switch (ct2) {
case cffoldCOMPTYPE_LZX:
if (LZX(window)) {
@@ -2252,7 +2560,7 @@
CAB(offset) = 0;
CAB(outlen) = 0;
- /* initialize the new decompressor */
+ /* initialize the new decompresser */
switch (ct1) {
case cffoldCOMPTYPE_NONE:
CAB(decompress) = NONEfdi_decomp;
@@ -2346,10 +2654,10 @@
fdin.pv = pvUser;
fdin.psz1 = (char *)file->filename;
fdin.hf = filehf;
- fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE;
+ fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */
fdin.date = file->date;
fdin.time = file->time;
- fdin.attribs = file->attribs;
+ fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */
err = ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin));
if (err == FALSE || err == -1) {
/*
@@ -2450,6 +2758,16 @@
/***********************************************************************
* FDIDestroy (CABINET.23)
+ *
+ * Frees a handle created by FDICreate. Do /not/ call this in the middle
+ * of FDICopy. Only reason for failure would be an invalid handle.
+ *
+ * PARAMS
+ * hfdi [I] The HFDI to free
+ *
+ * RETURNS
+ * TRUE for success
+ * FALSE for failure
*/
BOOL __cdecl FDIDestroy(HFDI hfdi)
{
@@ -2466,6 +2784,8 @@
/***********************************************************************
* FDITruncateCabinet (CABINET.24)
+ *
+ * Undocumented and unimplemented.
*/
BOOL __cdecl FDITruncateCabinet(
HFDI hfdi,
--
gmt
"Microsoft is committed to making cabinet files an open technology"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncabsdk/html/cabdl.asp
More information about the wine-patches
mailing list