cab_C_01.diff

Gregory M. Turner gmturner007 at ameritech.net
Fri Jun 6 20:14:43 CDT 2003


relative, of course, to cab_C_00.  Still not particularly useful,
as it doesn't decode anything, but at least now I'm protected from
rm -rf.

License: LGPL (sorry, Stuart Caie's IP is in there)

Changelog:

* dlls/cabinet: cabinet.h, fdi.c:
  Greg Turner <gmturner007 at ameritech.net>
- implement FDI{Create,Destroy,IsCabinet}
- fix a typo
- duplicate a bug
- some blathering about code duplication
- change fdi.c indentation to be consistent with cabextract.c
  (and how i like it ;))

--
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine/dlls/cabinet/cabinet.h ./dlls/cabinet/cabinet.h
--- ../wine/dlls/cabinet/cabinet.h	2003-06-06 19:39:58.000000000 -0500
+++ ./dlls/cabinet/cabinet.h	2003-06-06 15:43:03.000000000 -0500
@@ -21,6 +21,8 @@
 #define __WINE_CABINET_H
 
 #include "winnt.h"
+#include "fdi.h"
+#include "fci.h"
 
 #define CAB_SPLITMAX (10)
 
@@ -285,6 +287,50 @@
   } methods;
 } cab_decomp_state;
 
+/* _Int as in "Internal" fyi */
+
+typedef struct {
+  unsigned int     FCI_Intmagic;
+} FCI_Int, *PFCI_Int;
+
+typedef struct {
+  unsigned int FDI_Intmagic;
+  PFNALLOC pfnalloc;
+  PFNFREE  pfnfree;
+  PFNOPEN  pfnopen;
+  PFNREAD  pfnread;
+  PFNWRITE pfnwrite;
+  PFNCLOSE pfnclose;
+  PFNSEEK  pfnseek;
+  PERF     perf;
+} FDI_Int, *PFDI_Int;
+
+/* cast an HFCI into a PFCI_Int */
+#define PFCI_INT(hfci) ((PFDI_Int)(hfci))
+
+/* cast an HFDI into a PFDI_Int */
+#define PFDI_INT(hfdi) ((PFDI_Int)(hfdi))
+
+/* quickie pfdi method invokers */
+#define PFDI_ALLOC(hfdi, size)            ((*PFDI_INT(hfdi)->pfnalloc) (size))
+#define PFDI_FREE(hfdi, ptr)              ((*PFDI_INT(hfdi)->pfnfree)  (ptr))
+#define PFDI_OPEN(hfdi, file, flag, mode) ((*PFDI_INT(hfdi)->pfnopen)  (file, flag, mode))
+#define PFDI_READ(hfdi, hf, pv, cb)       ((*PFDI_INT(hfdi)->pfnread)  (hf, pv, cb))
+#define PFDI_WRITE(hfdi, hf, pv, cb)      ((*PFDI_INT(hfdi)->pfnwrite) (hf, pv, cb))
+#define PFDI_CLOSE(hfdi, hf)              ((*PFDI_INT(hfdi)->pfnclose) (hf))
+#define PFDI_SEEK(hfdi, hf, dist, type)   ((*PFDI_INT(hfdi)->pfnseek)  (hf, dist, type))
+
+#define FCI_INT_MAGIC 0xfcfcfc05
+#define FDI_INT_MAGIC 0xfdfdfd05
+
+#define REALLY_IS_FCI(hfci) ( \
+  (((void *) hfci) != NULL) && \
+  (PFCI_INT(hfci)->FCI_Intmagic == FCI_INT_MAGIC) )
+
+#define REALLY_IS_FDI(hfdi) ( \
+  (((void *) hfdi) != NULL) && \
+  (PFDI_INT(hfdi)->FDI_Intmagic == FDI_INT_MAGIC) )
+
 /* from cabextract.c */
 BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower);
 
diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine/dlls/cabinet/fdi.c ./dlls/cabinet/fdi.c
--- ../wine/dlls/cabinet/fdi.c	2002-12-19 15:16:56.000000000 -0600
+++ ./dlls/cabinet/fdi.c	2003-06-06 19:48:24.000000000 -0500
@@ -1,7 +1,9 @@
 /*
  * File Decompression Interface
  *
- * Copyright 2002 Patrik Stridvall
+ * Copyright 2000-2002 Stuart Caie,
+ *           2002 Patrik Stridvall,
+ *           2003 Greg Turner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,6 +18,14 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * 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).
+ *   -gmt
  */
 
 #include "config.h"
@@ -23,8 +33,11 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
+#include "stdio.h"
 #include "fdi.h"
 
+#include "cabinet.h"
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
@@ -43,19 +56,291 @@
 	int      cpuType,
 	PERF     perf)
 {
-    FIXME("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, \
-           pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p): stub\n", 
-	  pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek,
-	  cpuType, perf);
+  HFDI rv;
 
+  TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, \
+        pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n", 
+        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 can we.... */
+  if ((!pfnalloc) || (!pfnfree)) {
     perf->erfOper = FDIERROR_NONE;
-    perf->erfType = 0;
+    perf->erfType = ERROR_BAD_ARGUMENTS;
     perf->fError = TRUE;
 
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    SetLastError(ERROR_BAD_ARGUMENTS);
     return NULL;
+  }
+
+  if (!((rv = ((HFDI) (*pfnalloc)(sizeof(FDI_Int)))))) {
+    perf->erfOper = FDIERROR_ALLOC_FAIL;
+    perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
+    perf->fError = TRUE;
+
+    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+    return NULL;
+  }
+  
+  PFDI_INT(rv)->FDI_Intmagic = FDI_INT_MAGIC;
+  PFDI_INT(rv)->pfnalloc = pfnalloc;
+  PFDI_INT(rv)->pfnfree = pfnfree;
+  PFDI_INT(rv)->pfnopen = pfnopen;
+  PFDI_INT(rv)->pfnread = pfnread;
+  PFDI_INT(rv)->pfnwrite = pfnwrite;
+  PFDI_INT(rv)->pfnclose = pfnclose;
+  PFDI_INT(rv)->pfnseek = pfnseek;
+  /* no-brainer: we ignore the cpu type; this is only used
+     for the 16-bit versions in Windows anyhow... */
+  PFDI_INT(rv)->perf = perf;
+
+  return rv;
+}
+
+/*******************************************************************
+ * FDI_getoffset (internal)
+ *
+ * returns the file pointer position of a cab
+ */
+long FDI_getoffset(HFDI hfdi, INT_PTR hf)
+{
+  return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR);
+}
+
+/**********************************************************************
+ * 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.
+ */
+void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
+{
+  void *rslt = NULL;
+  char *irslt, *imem;
+  size_t copysize = (prevsize < newsize) ? prevsize : newsize;
+  if (prevsize == newsize) return mem;
+  rslt = PFDI_ALLOC(hfdi, newsize); 
+  if (rslt)
+    for (irslt = (char *)rslt, imem = (char *)mem; (copysize); copysize--)
+      *irslt++ = *imem++;
+  PFDI_FREE(hfdi, mem);
+  return rslt;
 }
 
+/**********************************************************************
+ * FDI_read_string (internal)
+ *
+ * allocate and read an aribitrarily long string from the cabinet
+ */
+char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
+{
+  size_t len=256,
+         oldlen = 0,
+         base = FDI_getoffset(hfdi, hf),
+         maxlen = cabsize - base;
+  BOOL ok = FALSE;
+  int i;
+  cab_UBYTE *buf = NULL;
+
+  TRACE("(hfdi == ^%p, hf == %d)\n", hfdi, hf);
+
+  do {
+    if (len > maxlen) len = maxlen;
+    if (!(buf = FDI_realloc(hfdi, buf, oldlen, len))) break;
+    oldlen = len;
+    if (!PFDI_READ(hfdi, hf, buf, len)) break;
+
+    /* search for a null terminator in what we've just read */
+    for (i=0; i < len; i++) {
+      if (!buf[i]) {ok=TRUE; break;}
+    }
+
+    if (!ok) {
+      if (len == maxlen) {
+        ERR("WARNING: cabinet is truncated\n");
+        break;
+      }
+      len += 256;
+      PFDI_SEEK(hfdi, hf, base, SEEK_SET);
+    }
+  } while (!ok);
+
+  if (!ok) {
+    if (buf)
+      PFDI_FREE(hfdi, buf);
+    else
+      ERR("out of memory!\n");
+    return NULL;
+  }
+
+  /* otherwise, set the stream to just after the string and return */
+  PFDI_SEEK(hfdi, hf, base + ((cab_off_t) strlen((char *) buf)) + 1, SEEK_SET);
+
+  return (char *) buf;
+}
+
+/******************************************************************
+ * FDI_read_entries (internal)
+ *
+ * process the cabinet header in the style of FDIIsCabinet, but
+ * without the sanity checks (and bug)
+ */
+BOOL FDI_read_entries(
+	HFDI            hfdi,
+	INT_PTR         hf,
+	PFDICABINETINFO pfdici)
+{
+  int num_folders, num_files, header_resv, folder_resv = 0;
+  LONG base_offset, cabsize;
+  USHORT setid, cabidx, flags;
+  cab_UBYTE buf[64], block_resv;
+  char *prevname, *previnfo, *nextname, *nextinfo;
+
+  TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici);
+
+  /* get basic offset & size info */
+  base_offset = FDI_getoffset(hfdi, hf);
+
+  if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) {
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  cabsize = FDI_getoffset(hfdi, hf);
+
+  if ((cabsize == -1) || (base_offset == -1) || 
+      ( PFDI_SEEK(hfdi, hf, base_offset, SEEK_SET) == -1 )) {
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  /* read in the CFHEADER */
+  if (!PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF)) {
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+  
+  /* check basic MSCF signature */
+  if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) {
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  /* get the number of folders */
+  num_folders = EndGetI16(buf+cfhead_NumFolders);
+  if (num_folders == 0) {
+    /* PONDERME: is this really invalid? */
+    WARN("wierd cabinet detect failure: no folders in cabinet\n");
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  /* get the number of files */
+  num_files = EndGetI16(buf+cfhead_NumFiles);
+  if (num_files == 0) {
+    /* PONDERME: is this really invalid? */
+    WARN("wierd cabinet detect failure: no files in cabinet\n");
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
+    PFDI_INT(hfdi)->perf->erfType = 0;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  /* setid */
+  setid = EndGetI16(buf+cfhead_SetID);
+
+  /* cabinet (set) index */
+  cabidx = EndGetI16(buf+cfhead_CabinetIndex);
+
+  /* check the header revision */
+  if ((buf[cfhead_MajorVersion] > 1) ||
+      (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
+  {
+    WARN("cabinet format version > 1.3\n");
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION;
+    PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    return FALSE;
+  }
+
+  /* pull the flags out */
+  flags = EndGetI16(buf+cfhead_Flags);
+
+  /* read the reserved-sizes part of header, if present */
+  if (flags & cfheadRESERVE_PRESENT) {
+    if (!PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF)) {
+      WARN("bunk reserve-sizes?\n");
+      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
+      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
+      PFDI_INT(hfdi)->perf->fError = TRUE;
+      return FALSE;
+    }
+
+    header_resv = EndGetI16(buf+cfheadext_HeaderReserved);
+    folder_resv = buf[cfheadext_FolderReserved];
+    block_resv  = buf[cfheadext_DataReserved];
+
+    if (header_resv > 60000) {
+      WARN("WARNING; header reserved space > 60000\n");
+    }
+
+    /* skip the reserved header */
+    if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1L)) {
+      ERR("seek failure: header_resv\n");
+      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
+      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
+      PFDI_INT(hfdi)->perf->fError = TRUE;
+      return FALSE;
+    }
+  }
+
+  if (flags & cfheadPREV_CABINET) {
+    prevname = FDI_read_string(hfdi, hf, cabsize);
+    if (!prevname) {
+      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
+      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
+      PFDI_INT(hfdi)->perf->fError = TRUE;
+      return FALSE;
+    }
+    previnfo = FDI_read_string(hfdi, hf, cabsize);
+  }
+
+  if (flags & cfheadNEXT_CABINET) {
+    nextname = FDI_read_string(hfdi, hf, cabsize);
+    if (!nextname) {
+      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
+      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
+      PFDI_INT(hfdi)->perf->fError = TRUE;
+      return FALSE;
+    }
+    nextinfo = FDI_read_string(hfdi, hf, cabsize);
+  }
+
+  /* we could process the whole cabinet searching for problems;
+     instead lets stop here.  Now let's fill out the paperwork */
+  pfdici->cbCabinet = cabsize;
+  pfdici->cFolders  = num_folders;
+  pfdici->cFiles    = num_files;
+  pfdici->setID     = setid;
+  pfdici->iCabinet  = cabidx;
+  pfdici->fReserve  = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE;
+  pfdici->hasprev   = (flags & cfheadPREV_CABINET) ? TRUE : FALSE;
+  pfdici->hasnext   = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE;
+  return TRUE;
+}
 
 /***********************************************************************
  *		FDIIsCabinet (CABINET.21)
@@ -65,10 +350,39 @@
 	INT_PTR         hf,
 	PFDICABINETINFO pfdici)
 {
-    FIXME("(hfdi == ^%p, hf == ^%d, pfdici == ^%p): stub\n", hfdi, hf, pfdici);
+  BOOL rv;
 
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  TRACE("(hfdi == ^%p, hf == ^%d, pfdici == ^%p)\n", hfdi, hf, pfdici);
+
+  if (!REALLY_IS_FDI(hfdi)) {
+    ERR("REALLY_IS_FDI failed on ^%p\n", hfdi);
+    SetLastError(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+
+  if (!hf) {
+    ERR("(!hf)!\n");
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
+    PFDI_INT(hfdi)->perf->erfType = ERROR_INVALID_HANDLE;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    SetLastError(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+
+  if (!pfdici) {
+    ERR("(!pfdici)!\n");
+    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NONE;
+    PFDI_INT(hfdi)->perf->erfType = ERROR_BAD_ARGUMENTS;
+    PFDI_INT(hfdi)->perf->fError = TRUE;
+    SetLastError(ERROR_BAD_ARGUMENTS);
     return FALSE;
+  }
+  rv = FDI_read_entries(hfdi, hf, pfdici); 
+
+  if (rv)
+    pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */
+
+  return rv;
 }
 
 /***********************************************************************
@@ -83,12 +397,17 @@
 	PFNFDIDECRYPT  pfnfdid,
 	void          *pvUser)
 {
-    FIXME("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, \
-           pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p): stub\n",
-	  hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser);
+  FIXME("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, \
+        pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p): stub\n",
+        hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser);
 
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  if (!REALLY_IS_FDI(hfdi)) {
+    SetLastError(ERROR_INVALID_HANDLE);
     return FALSE;
+  }
+
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
 }
 
 /***********************************************************************
@@ -96,24 +415,33 @@
  */
 BOOL __cdecl FDIDestroy(HFDI hfdi)
 {
-    FIXME("(hfdi == ^%p): stub\n", hfdi);
-
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  TRACE("(hfdi == ^%p)\n", hfdi);
+  if (REALLY_IS_FDI(hfdi)) {
+    PFDI_INT(hfdi)->FDI_Intmagic = 0; /* paranoia */
+    PFDI_FREE(hfdi, hfdi); /* confusing, but correct */
+    return TRUE;
+  } else {
+    SetLastError(ERROR_INVALID_HANDLE);
     return FALSE;
+  }
 }
 
 /***********************************************************************
- *		FDICreate (CABINET.20)
+ *		FDITruncateCabinet (CABINET.24)
  */
 BOOL __cdecl FDITruncateCabinet(
 	HFDI    hfdi,
 	char   *pszCabinetName,
 	USHORT  iFolderToDelete)
 {
-    FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n",
-      hfdi, debugstr_a(pszCabinetName), iFolderToDelete);
-
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n",
+    hfdi, debugstr_a(pszCabinetName), iFolderToDelete);
 
+  if (!REALLY_IS_FDI(hfdi)) {
+    SetLastError(ERROR_INVALID_HANDLE);
     return FALSE;
+  }
+
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
 }
-- 
"A just security to property is not afforded by that government,
under which unequal taxes oppress one species of property and
reward another species." --James Madison

gmt




More information about the wine-patches mailing list