[CABINET] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / cabinet / fdi.c
index b68ab15..01a0c4d 100644 (file)
@@ -48,7 +48,7 @@
  * 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
+ * There are several FIXMEs 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.
  *
@@ -110,6 +110,21 @@ typedef struct {
    cab_UBYTE block_resv;
 } MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;
 
+typedef struct
+{
+  unsigned int magic;
+  PFNALLOC     alloc;
+  PFNFREE      free;
+  PFNOPEN      open;
+  PFNREAD      read;
+  PFNWRITE     write;
+  PFNCLOSE     close;
+  PFNSEEK      seek;
+  PERF         perf;
+} FDI_Int;
+
+#define FDI_INT_MAGIC 0xfdfdfd05
+
 /*
  * ugh, well, this ended up being pretty damn silly...
  * now that I've conceded to build equivalent structures to struct cab.*,
@@ -120,7 +135,7 @@ typedef struct {
  */
 
 typedef struct fdi_cds_fwd {
-  void *hfdi;                      /* the hfdi we are using                 */
+  FDI_Int *fdi;                    /* the hfdi we are using                 */
   INT_PTR filehf, cabhf;           /* file handle we are using              */
   struct fdi_folder *current;      /* current folder we're extracting from  */
   cab_ULONG offset;                /* uncompressed offset within folder     */
@@ -148,6 +163,47 @@ typedef struct fdi_cds_fwd {
   struct fdi_cds_fwd *next;
 } fdi_decomp_state;
 
+#define ZIPNEEDBITS(n) {while(k<(n)){cab_LONG c=*(ZIP(inpos)++);\
+    b|=((cab_ULONG)c)<<k;k+=8;}}
+#define ZIPDUMPBITS(n) {b>>=(n);k-=(n);}
+
+/* endian-neutral reading of little-endian data */
+#define EndGetI32(a)  ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0]))
+#define EndGetI16(a)  ((((a)[1])<<8)|((a)[0]))
+
+#define CAB(x) (decomp_state->x)
+#define ZIP(x) (decomp_state->methods.zip.x)
+#define QTM(x) (decomp_state->methods.qtm.x)
+#define LZX(x) (decomp_state->methods.lzx.x)
+#define DECR_OK           (0)
+#define DECR_DATAFORMAT   (1)
+#define DECR_ILLEGALDATA  (2)
+#define DECR_NOMEMORY     (3)
+#define DECR_CHECKSUM     (4)
+#define DECR_INPUT        (5)
+#define DECR_OUTPUT       (6)
+#define DECR_USERABORT    (7)
+
+static void set_error( FDI_Int *fdi, int oper, int err )
+{
+    fdi->perf->erfOper = oper;
+    fdi->perf->erfType = err;
+    fdi->perf->fError = TRUE;
+    if (err) SetLastError( err );
+}
+
+static FDI_Int *get_fdi_ptr( HFDI hfdi )
+{
+    FDI_Int *fdi= (FDI_Int *)hfdi;
+
+    if (!fdi || fdi->magic != FDI_INT_MAGIC)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return NULL;
+    }
+    return fdi;
+}
+
 /****************************************************************
  * QTMupdatemodel (internal)
  */
@@ -304,7 +360,9 @@ static cab_ULONG checksum(const cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum
 
   switch (bytes & 3) {
   case 3: ul |= *data++ << 16;
+  /* fall through */
   case 2: ul |= *data++ <<  8;
+  /* fall through */
   case 1: ul |= *data;
   }
   csum ^= ul;
@@ -362,7 +420,7 @@ HFDI __cdecl FDICreate(
        int      cpuType,
        PERF     perf)
 {
-  HFDI rv;
+  FDI_Int *fdi;
 
   TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, "
         "pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n",
@@ -378,28 +436,26 @@ HFDI __cdecl FDICreate(
     return NULL;
   }
 
-  if (!((rv = (*pfnalloc)(sizeof(FDI_Int))))) {
+  if (!((fdi = pfnalloc(sizeof(FDI_Int))))) {
     perf->erfOper = FDIERROR_ALLOC_FAIL;
-    perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
+    perf->erfType = 0;
     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;
+
+  fdi->magic = FDI_INT_MAGIC;
+  fdi->alloc = pfnalloc;
+  fdi->free  = pfnfree;
+  fdi->open  = pfnopen;
+  fdi->read  = pfnread;
+  fdi->write = pfnwrite;
+  fdi->close = pfnclose;
+  fdi->seek  = 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;
+  fdi->perf = perf;
 
-  return rv;
+  return (HFDI)fdi;
 }
 
 /*******************************************************************
@@ -407,9 +463,9 @@ HFDI __cdecl FDICreate(
  *
  * returns the file pointer position of a file handle.
  */
-static long FDI_getoffset(HFDI hfdi, INT_PTR hf)
+static LONG FDI_getoffset(FDI_Int *fdi, INT_PTR hf)
 {
-  return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR);
+  return fdi->seek(hf, 0, SEEK_CUR);
 }
 
 /**********************************************************************
@@ -417,21 +473,21 @@ static long FDI_getoffset(HFDI hfdi, INT_PTR hf)
  *
  * allocate and read an arbitrarily long string from the cabinet
  */
-static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
+static char *FDI_read_string(FDI_Int *fdi, INT_PTR hf, long cabsize)
 {
   size_t len=256,
-         base = FDI_getoffset(hfdi, hf),
+         base = FDI_getoffset(fdi, hf),
          maxlen = cabsize - base;
   BOOL ok = FALSE;
   unsigned int i;
   cab_UBYTE *buf = NULL;
 
-  TRACE("(hfdi == ^%p, hf == %ld, cabsize == %ld)\n", hfdi, hf, cabsize);
+  TRACE("(fdi == %p, hf == %ld, cabsize == %ld)\n", fdi, hf, cabsize);
 
   do {
     if (len > maxlen) len = maxlen;
-    if (!(buf = PFDI_ALLOC(hfdi, len))) break;
-    if (!PFDI_READ(hfdi, hf, buf, len)) break;
+    if (!(buf = fdi->alloc(len))) break;
+    if (!fdi->read(hf, buf, len)) break;
 
     /* search for a null terminator in what we've just read */
     for (i=0; i < len; i++) {
@@ -444,10 +500,10 @@ static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
         break;
       }
       /* The buffer is too small for the string. Reset the file to the point
-       * were we started, free the buffer and increase the size for the next try
+       * where we started, free the buffer and increase the size for the next try
        */
-      PFDI_SEEK(hfdi, hf, base, SEEK_SET);
-      PFDI_FREE(hfdi, buf);
+      fdi->seek(hf, base, SEEK_SET);
+      fdi->free(buf);
       buf = NULL;
       len *= 2;
     }
@@ -455,14 +511,14 @@ static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
 
   if (!ok) {
     if (buf)
-      PFDI_FREE(hfdi, buf);
+      fdi->free(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 + strlen((char *)buf) + 1, SEEK_SET);
+  fdi->seek(hf, base + strlen((char *)buf) + 1, SEEK_SET);
 
   return (char *) buf;
 }
@@ -474,118 +530,39 @@ static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
  * without the sanity checks (and bug)
  */
 static BOOL FDI_read_entries(
-        HFDI             hfdi,
+        FDI_Int         *fdi,
         INT_PTR          hf,
         PFDICABINETINFO  pfdici,
         PMORE_ISCAB_INFO pmii)
 {
   int num_folders, num_files, header_resv, folder_resv = 0;
-  LONG base_offset, cabsize;
+  LONG cabsize;
   USHORT setid, cabidx, flags;
   cab_UBYTE buf[64], block_resv;
   char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL;
 
-  TRACE("(hfdi == ^%p, hf == %ld, 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);
-
-  if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) {
-    if (pmii) {
-      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 )) {
-    if (pmii) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-    }
-    return FALSE;
-  }
+  TRACE("(fdi == ^%p, hf == %ld, pfdici == ^%p)\n", fdi, hf, pfdici);
 
   /* read in the CFHEADER */
-  if (PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) {
-    if (pmii) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-    }
+  if (fdi->read(hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) {
+    if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
     return FALSE;
   }
-  
+
   /* check basic MSCF signature */
   if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) {
-    if (pmii) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-    }
+    if (pmii) set_error( fdi, FDIERROR_NOT_A_CABINET, 0 );
     return FALSE;
   }
 
+  /* get the cabinet size */
+  cabsize = EndGetI32(buf+cfhead_CabinetSize);
+
   /* get the number of folders */
   num_folders = EndGetI16(buf+cfhead_NumFolders);
-  if (num_folders == 0) {
-    /* PONDERME: is this really invalid? */
-    WARN("weird cabinet detect failure: no folders in cabinet\n");
-    if (pmii) {
-      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("weird cabinet detect failure: no files in cabinet\n");
-    if (pmii) {
-      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);
@@ -598,11 +575,7 @@ static BOOL FDI_read_entries(
       (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
   {
     WARN("cabinet format version > 1.3\n");
-    if (pmii) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION;
-      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-    }
+    if (pmii) set_error( fdi, FDIERROR_UNKNOWN_CABINET_VERSION, 0 /* ? */ );
     return FALSE;
   }
 
@@ -611,13 +584,9 @@ static BOOL FDI_read_entries(
 
   /* read the reserved-sizes part of header, if present */
   if (flags & cfheadRESERVE_PRESENT) {
-    if (PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) {
+    if (fdi->read(hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) {
       ERR("bunk reserve-sizes?\n");
-      if (pmii) {
-        PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-        PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
-        PFDI_INT(hfdi)->perf->fError = TRUE;
-      }
+      if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
       return FALSE;
     }
 
@@ -633,64 +602,54 @@ static BOOL FDI_read_entries(
     }
 
     /* skip the reserved header */
-    if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1)) {
+    if ((header_resv) && (fdi->seek(hf, header_resv, SEEK_CUR) == -1)) {
       ERR("seek failure: header_resv\n");
-      if (pmii) {
-        PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-        PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
-        PFDI_INT(hfdi)->perf->fError = TRUE;
-      }
+      if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
       return FALSE;
     }
   }
 
   if (flags & cfheadPREV_CABINET) {
-    prevname = FDI_read_string(hfdi, hf, cabsize);
+    prevname = FDI_read_string(fdi, hf, cabsize);
     if (!prevname) {
-      if (pmii) {
-        PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-        PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
-        PFDI_INT(hfdi)->perf->fError = TRUE;
-      }
+      if (pmii) set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
       return FALSE;
     } else
       if (pmii)
         pmii->prevname = prevname;
       else
-        PFDI_FREE(hfdi, prevname);
-    previnfo = FDI_read_string(hfdi, hf, cabsize);
+        fdi->free(prevname);
+    previnfo = FDI_read_string(fdi, hf, cabsize);
     if (previnfo) {
       if (pmii) 
         pmii->previnfo = previnfo;
       else
-        PFDI_FREE(hfdi, previnfo);
+        fdi->free(previnfo);
     }
   }
 
   if (flags & cfheadNEXT_CABINET) {
     if (pmii)
       pmii->hasnext = TRUE;
-    nextname = FDI_read_string(hfdi, hf, cabsize);
+    nextname = FDI_read_string(fdi, hf, cabsize);
     if (!nextname) {
       if ((flags & cfheadPREV_CABINET) && pmii) {
-        if (pmii->prevname) PFDI_FREE(hfdi, prevname);
-        if (pmii->previnfo) PFDI_FREE(hfdi, previnfo);
+        if (pmii->prevname) fdi->free(prevname);
+        if (pmii->previnfo) fdi->free(previnfo);
       }
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
-      PFDI_INT(hfdi)->perf->fError = TRUE;
+      set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 /* ? */ );
       return FALSE;
     } else
       if (pmii)
         pmii->nextname = nextname;
       else
-        PFDI_FREE(hfdi, nextname);
-    nextinfo = FDI_read_string(hfdi, hf, cabsize);
+        fdi->free(nextname);
+    nextinfo = FDI_read_string(fdi, hf, cabsize);
     if (nextinfo) {
       if (pmii)
         pmii->nextinfo = nextinfo;
       else
-        PFDI_FREE(hfdi, nextinfo);
+        fdi->free(nextinfo);
     }
   }
 
@@ -701,14 +660,14 @@ static BOOL FDI_read_entries(
   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;
+  pfdici->fReserve  = (flags & cfheadRESERVE_PRESENT) != 0;
+  pfdici->hasprev   = (flags & cfheadPREV_CABINET) != 0;
+  pfdici->hasnext   = (flags & cfheadNEXT_CABINET) != 0;
   return TRUE;
 }
 
 /***********************************************************************
- *             FDIIsCabinet (CABINET.21)
+ * 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
@@ -723,7 +682,7 @@ static BOOL FDI_read_entries(
  *               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.
@@ -734,39 +693,20 @@ static BOOL FDI_read_entries(
  * INCLUDES
  *   fdi.c
  */
-BOOL __cdecl FDIIsCabinet(
-       HFDI            hfdi,
-       INT_PTR         hf,
-       PFDICABINETINFO pfdici)
+BOOL __cdecl FDIIsCabinet(HFDI hfdi, INT_PTR hf, PFDICABINETINFO pfdici)
 {
   BOOL rv;
+  FDI_Int *fdi = get_fdi_ptr( hfdi );
 
   TRACE("(hfdi == ^%p, hf == ^%ld, 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 (!fdi) 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, NULL); 
+  rv = FDI_read_entries(fdi, hf, pfdici, NULL);
 
   if (rv)
     pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */
@@ -805,11 +745,11 @@ static int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
   /* if a previously allocated window is big enough, keep it    */
   if (window < 10 || window > 21) return DECR_DATAFORMAT;
   if (QTM(actual_size) < wndsize) {
-    if (QTM(window)) PFDI_FREE(CAB(hfdi), QTM(window));
+    if (QTM(window)) CAB(fdi)->free(QTM(window));
     QTM(window) = NULL;
   }
   if (!QTM(window)) {
-    if (!(QTM(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY;
+    if (!(QTM(window) = CAB(fdi)->alloc(wndsize))) return DECR_NOMEMORY;
     QTM(actual_size) = wndsize;
   }
   QTM(window_size) = wndsize;
@@ -827,20 +767,20 @@ static int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
 
   /* initialize arithmetic coding models */
 
-  QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0);
+  QTMfdi_initmodel(&QTM(model7), QTM(m7sym), 7, 0);
 
-  QTMfdi_initmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00);
-  QTMfdi_initmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40);
-  QTMfdi_initmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80);
-  QTMfdi_initmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0);
+  QTMfdi_initmodel(&QTM(model00), QTM(m00sym), 0x40, 0x00);
+  QTMfdi_initmodel(&QTM(model40), QTM(m40sym), 0x40, 0x40);
+  QTMfdi_initmodel(&QTM(model80), QTM(m80sym), 0x40, 0x80);
+  QTMfdi_initmodel(&QTM(modelC0), QTM(mC0sym), 0x40, 0xC0);
 
   /* model 4 depends on table size, ranges from 20 to 24  */
-  QTMfdi_initmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0);
+  QTMfdi_initmodel(&QTM(model4), QTM(m4sym), (msz < 24) ? msz : 24, 0);
   /* model 5 depends on table size, ranges from 20 to 36  */
-  QTMfdi_initmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0);
+  QTMfdi_initmodel(&QTM(model5), QTM(m5sym), (msz < 36) ? msz : 36, 0);
   /* model 6pos depends on table size, ranges from 20 to 42 */
-  QTMfdi_initmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0);
-  QTMfdi_initmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0);
+  QTMfdi_initmodel(&QTM(model6pos), QTM(m6psym), msz, 0);
+  QTMfdi_initmodel(&QTM(model6len), QTM(m6lsym), 27, 0);
 
   return DECR_OK;
 }
@@ -869,11 +809,11 @@ static int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
   /* if a previously allocated window is big enough, keep it     */
   if (window < 15 || window > 21) return DECR_DATAFORMAT;
   if (LZX(actual_size) < wndsize) {
-    if (LZX(window)) PFDI_FREE(CAB(hfdi), LZX(window));
+    if (LZX(window)) CAB(fdi)->free(LZX(window));
     LZX(window) = NULL;
   }
   if (!LZX(window)) {
-    if (!(LZX(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY;
+    if (!(LZX(window) = CAB(fdi)->alloc(wndsize))) return DECR_NOMEMORY;
     LZX(actual_size) = wndsize;
   }
   LZX(window_size) = wndsize;
@@ -920,7 +860,7 @@ static int NONEfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state)
 /********************************************************
  * Ziphuft_free (internal)
  */
-static void fdi_Ziphuft_free(HFDI hfdi, struct Ziphuft *t)
+static void fdi_Ziphuft_free(FDI_Int *fdi, struct Ziphuft *t)
 {
   register struct Ziphuft *p, *q;
 
@@ -929,7 +869,7 @@ static void fdi_Ziphuft_free(HFDI hfdi, struct Ziphuft *t)
   while (p != NULL)
   {
     q = (--p)->v.t;
-    PFDI_FREE(hfdi, p);
+    fdi->free(p);
     p = q;
   } 
 }
@@ -1055,10 +995,10 @@ struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state)
         l[h] = j;               /* set table size in stack */
 
         /* allocate and link in new table */
-        if (!(q = PFDI_ALLOC(CAB(hfdi), (z + 1)*sizeof(struct Ziphuft))))
+        if (!(q = CAB(fdi)->alloc((z + 1)*sizeof(struct Ziphuft))))
         {
           if(h)
-            fdi_Ziphuft_free(CAB(hfdi), ZIP(u)[0]);
+            fdi_Ziphuft_free(CAB(fdi), ZIP(u)[0]);
           return 3;             /* not enough memory */
         }
         *t = q + 1;             /* link to list for Ziphuft_free() */
@@ -1277,15 +1217,15 @@ static cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state)
   fixed_bd = 5;
   if((i = fdi_Ziphuft_build(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, decomp_state)) > 1)
   {
-    fdi_Ziphuft_free(CAB(hfdi), fixed_tl);
+    fdi_Ziphuft_free(CAB(fdi), fixed_tl);
     return i;
   }
 
   /* decompress until an end-of-block code */
   i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state);
 
-  fdi_Ziphuft_free(CAB(hfdi), fixed_td);
-  fdi_Ziphuft_free(CAB(hfdi), fixed_tl);
+  fdi_Ziphuft_free(CAB(fdi), fixed_td);
+  fdi_Ziphuft_free(CAB(fdi), fixed_tl);
   return i;
 }
 
@@ -1344,7 +1284,7 @@ static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
   if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0)
   {
     if(i == 1)
-      fdi_Ziphuft_free(CAB(hfdi), tl);
+      fdi_Ziphuft_free(CAB(fdi), tl);
     return i;                   /* incomplete code set */
   }
 
@@ -1395,7 +1335,7 @@ static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
   }
 
   /* free decoding table for trees */
-  fdi_Ziphuft_free(CAB(hfdi), tl);
+  fdi_Ziphuft_free(CAB(fdi), tl);
 
   /* restore the global bit buffer */
   ZIP(bb) = b;
@@ -1406,7 +1346,7 @@ static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
   if((i = fdi_Ziphuft_build(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, decomp_state)) != 0)
   {
     if(i == 1)
-      fdi_Ziphuft_free(CAB(hfdi), tl);
+      fdi_Ziphuft_free(CAB(fdi), tl);
     return i;                   /* incomplete code set */
   }
   bd = ZIPDBITS;
@@ -1417,8 +1357,8 @@ static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state)
     return 1;
 
   /* free the decoding tables, return */
-  fdi_Ziphuft_free(CAB(hfdi), tl);
-  fdi_Ziphuft_free(CAB(hfdi), td);
+  fdi_Ziphuft_free(CAB(fdi), tl);
+  fdi_Ziphuft_free(CAB(fdi), td);
   return 0;
 }
 
@@ -2014,7 +1954,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
 
     /* if cando != 0 */
     if (cando && savemode)
-      PFDI_WRITE(CAB(hfdi), CAB(filehf), CAB(outpos), cando);
+      CAB(fdi)->write(CAB(filehf), CAB(outpos), cando);
 
     CAB(outpos) += cando;
     CAB(outlen) -= cando;
@@ -2026,10 +1966,10 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
     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 (CAB(fdi)->read(cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF)
         return DECR_INPUT;
 
-      if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1)
+      if (CAB(fdi)->seek(cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1)
         return DECR_INPUT;
 
       /* we shouldn't get blocks over CAB_INPUTMAX in size */
@@ -2037,7 +1977,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
       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 (CAB(fdi)->read(cab->cabhf, data, len) != len)
         return DECR_INPUT;
 
       /* clear two bytes after read-in data */
@@ -2053,14 +1993,14 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
       /* outlen=0 means this block was the last contiguous part
          of a split block, continued in the next cabinet */
       if (outlen == 0) {
-        int pathlen, filenamelen, idx, i;
+        int pathlen, filenamelen;
         INT_PTR cabhf;
         char fullpath[MAX_PATH], userpath[256];
         FDINOTIFICATION fdin;
         FDICABINETINFO fdici;
         char emptystring = '\0';
         cab_UBYTE buf2[64];
-        int success = FALSE;
+        BOOL success = FALSE;
         struct fdi_folder *fol = NULL, *linkfol = NULL; 
         struct fdi_file   *file = NULL, *linkfile = NULL;
 
@@ -2068,28 +2008,28 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
 
         /* set up the next decomp_state... */
         if (!(cab->next)) {
+          unsigned int i;
+
           if (!cab->mii.hasnext) return DECR_INPUT;
 
-          if (!((cab->next = PFDI_ALLOC(CAB(hfdi), sizeof(fdi_decomp_state)))))
+          if (!((cab->next = CAB(fdi)->alloc(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;
+          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 weird place... let's leave it blank and see if the user fixes it */
-          } 
+            if (pathlen < 256) /* else we are in a weird place... let's leave it blank and see if the user fixes it */
+              strcpy(userpath, pszCabPath);
+          }
 
           /* 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.psz1 = cab->mii.nextname ? cab->mii.nextname : &emptystring;
+          fdin.psz2 = cab->mii.nextinfo ? cab->mii.nextinfo : &emptystring;
+          fdin.psz3 = userpath;
           fdin.fdie = FDIERROR_NONE;
           fdin.pv = pvUser;
 
@@ -2098,7 +2038,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
           do {
 
             pathlen = strlen(userpath);
-            filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 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) {
@@ -2107,36 +2047,50 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
             }
 
             /* paste the path and filename together */
-            idx = 0;
+            fullpath[0] = '\0';
             if (pathlen) {
-              for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i];
-              if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
+              strcpy(fullpath, userpath);
+#ifdef __REACTOS__
+              if (fullpath[pathlen - 1] == '\\')
+                fullpath[pathlen - 1] = '\0';
+#else
+              if (fullpath[pathlen - 1] != '\\')
+                strcat(fullpath, "\\");
+#endif
             }
-            if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i];
-            fullpath[idx] = '\0';
-        
+#ifdef __REACTOS__
+            if (filenamelen) {
+              strcat(fullpath, "\\");
+#else
+            if (filenamelen)
+#endif
+              strcat(fullpath, cab->mii.nextname);
+#ifdef __REACTOS__
+            }
+#endif
+
             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_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
+            cabhf = CAB(fdi)->open(fullpath, _O_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
             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;
             }
-        
+
             if (cabhf == 0) {
               ERR("PFDI_OPEN returned zero for %s.\n", fullpath);
               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))) {
+            if (!FDI_read_entries(CAB(fdi), cabhf, &fdici, &(cab->next->mii))) {
               WARN("FDIIsCabinet failed.\n");
-              PFDI_CLOSE(CAB(hfdi), cabhf);
+              CAB(fdi)->close(cabhf);
               fdin.fdie = FDIERROR_NOT_A_CABINET;
               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
               continue;
@@ -2144,7 +2098,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
 
             if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) {
               WARN("Wrong Cabinet.\n");
-              PFDI_CLOSE(CAB(hfdi), cabhf);
+              CAB(fdi)->close(cabhf);
               fdin.fdie = FDIERROR_WRONG_CABINET;
               if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT;
               continue;
@@ -2167,7 +2121,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
           
           cab->next->setID = fdici.setID;
           cab->next->iCabinet = fdici.iCabinet;
-          cab->next->hfdi = CAB(hfdi);
+          cab->next->fdi = CAB(fdi);
           cab->next->filehf = CAB(filehf);
           cab->next->cabhf = cabhf;
           cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */
@@ -2176,13 +2130,13 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
 
           /* read folders */
           for (i = 0; i < fdici.cFolders; i++) {
-            if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF) 
+            if (CAB(fdi)->read(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);
+              CAB(fdi)->seek(cab->cabhf, cab->mii.folder_resv, SEEK_CUR);
 
-            fol = PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_folder));
+            fol = CAB(fdi)->alloc(sizeof(struct fdi_folder));
             if (!fol) {
               ERR("out of memory!\n");
               return DECR_NOMEMORY;
@@ -2201,10 +2155,10 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
         
           /* read files */
           for (i = 0; i < fdici.cFiles; i++) {
-            if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF)
+            if (CAB(fdi)->read(cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF)
               return DECR_INPUT;
 
-            file = PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_file));
+            file = CAB(fdi)->alloc(sizeof(struct fdi_file));
             if (!file) {
               ERR("out of memory!\n"); 
               return DECR_NOMEMORY;
@@ -2218,7 +2172,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
             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);
+            file->filename = FDI_read_string(CAB(fdi), cab->cabhf, fdici.cbCabinet);
         
             if (!file->filename) return DECR_INPUT;
         
@@ -2238,7 +2192,7 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
             /* check to ensure a real match */
             if (lstrcmpiA(fi->filename, file->filename) == 0) {
               success = TRUE;
-              if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1)
+              if (CAB(fdi)->seek(cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1)
                 return DECR_INPUT;
               break;
             }
@@ -2260,54 +2214,53 @@ static int fdi_decomp(const struct fdi_file *fi, int savemode, fdi_decomp_state
   return DECR_OK;
 }
 
-static void free_decompression_temps(HFDI hfdi, const struct fdi_folder *fol,
+static void free_decompression_temps(FDI_Int *fdi, const struct fdi_folder *fol,
   fdi_decomp_state *decomp_state)
 {
   switch (fol->comp_type & cffoldCOMPTYPE_MASK) {
   case cffoldCOMPTYPE_LZX:
     if (LZX(window)) {
-      PFDI_FREE(hfdi, LZX(window));
+      fdi->free(LZX(window));
       LZX(window) = NULL;
     }
     break;
   case cffoldCOMPTYPE_QUANTUM:
     if (QTM(window)) {
-      PFDI_FREE(hfdi, QTM(window));
+      fdi->free(QTM(window));
       QTM(window) = NULL;
     }
     break;
   }
 }
 
-static void free_decompression_mem(HFDI hfdi,
-  fdi_decomp_state *decomp_state, struct fdi_file *file)
+static void free_decompression_mem(FDI_Int *fdi, fdi_decomp_state *decomp_state)
 {
   struct fdi_folder *fol;
   while (decomp_state) {
     fdi_decomp_state *prev_fds;
 
-    PFDI_CLOSE(hfdi, CAB(cabhf));
+    fdi->close(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);
+    if (CAB(mii).nextname) fdi->free(CAB(mii).nextname);
+    if (CAB(mii).nextinfo) fdi->free(CAB(mii).nextinfo);
+    if (CAB(mii).prevname) fdi->free(CAB(mii).prevname);
+    if (CAB(mii).previnfo) fdi->free(CAB(mii).previnfo);
 
     while (CAB(firstfol)) {
       fol = CAB(firstfol);
       CAB(firstfol) = CAB(firstfol)->next;
-      PFDI_FREE(hfdi, fol);
+      fdi->free(fol);
     }
     while (CAB(firstfile)) {
-      file = CAB(firstfile);
-      if (file->filename) PFDI_FREE(hfdi, file->filename);
+      struct fdi_file *file = CAB(firstfile);
+      if (file->filename) fdi->free(file->filename);
       CAB(firstfile) = CAB(firstfile)->next;
-      PFDI_FREE(hfdi, file);
+      fdi->free(file);
     }
     prev_fds = decomp_state;
     decomp_state = CAB(next);
-    PFDI_FREE(hfdi, prev_fds);
+    fdi->free(prev_fds);
   }
 }
 
@@ -2487,7 +2440,6 @@ BOOL __cdecl FDICopy(
   FDICABINETINFO    fdici;
   FDINOTIFICATION   fdin;
   INT_PTR           cabhf, filehf = 0;
-  int               idx;
   unsigned int      i;
   char              fullpath[MAX_PATH];
   size_t            pathlen, filenamelen;
@@ -2496,76 +2448,58 @@ BOOL __cdecl FDICopy(
   struct fdi_folder *fol = NULL, *linkfol = NULL; 
   struct fdi_file   *file = NULL, *linkfile = NULL;
   fdi_decomp_state *decomp_state;
+  FDI_Int *fdi = get_fdi_ptr( hfdi );
 
-  TRACE("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, "
+  TRACE("(hfdi == ^%p, pszCabinet == %s, pszCabPath == %s, flags == %x, "
         "pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p)\n",
-        hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser);
+        hfdi, debugstr_a(pszCabinet), debugstr_a(pszCabPath), flags, pfnfdin, pfnfdid, pvUser);
 
-  if (!REALLY_IS_FDI(hfdi)) {
-    SetLastError(ERROR_INVALID_HANDLE);
-    return FALSE;
-  }
+  if (!fdi) return FALSE;
 
-  if (!(decomp_state = PFDI_ALLOC(hfdi, sizeof(fdi_decomp_state))))
+  if (!(decomp_state = fdi->alloc(sizeof(fdi_decomp_state))))
   {
       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
       return FALSE;
   }
   ZeroMemory(decomp_state, sizeof(fdi_decomp_state));
 
-  pathlen = (pszCabPath) ? strlen(pszCabPath) : 0;
-  filenamelen = (pszCabinet) ? strlen(pszCabinet) : 0;
+  pathlen = pszCabPath ? strlen(pszCabPath) : 0;
+  filenamelen = pszCabinet ? strlen(pszCabinet) : 0;
 
   /* slight overestimation here to save CPU cycles in the developer's brain */
   if ((pathlen + filenamelen + 3) > MAX_PATH) {
     ERR("MAX_PATH exceeded.\n");
-    PFDI_FREE(hfdi, decomp_state);
-    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
-    PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND;
-    PFDI_INT(hfdi)->perf->fError = TRUE;
-    SetLastError(ERROR_FILE_NOT_FOUND);
+    fdi->free(decomp_state);
+    set_error( fdi, FDIERROR_CABINET_NOT_FOUND, ERROR_FILE_NOT_FOUND );
     return FALSE;
   }
 
   /* paste the path and filename together */
-  idx = 0;
-  if (pathlen) {
-    for (i = 0; i < pathlen; i++) fullpath[idx++] = pszCabPath[i];
-    if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\';
-  }
-  if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = pszCabinet[i];
-  fullpath[idx] = '\0';
+  fullpath[0] = '\0';
+  if (pathlen)
+    strcpy(fullpath, pszCabPath);
+  if (filenamelen)
+    strcat(fullpath, pszCabinet);
 
   TRACE("full cab path/file name: %s\n", debugstr_a(fullpath));
 
   /* get a handle to the cabfile */
-  cabhf = PFDI_OPEN(hfdi, fullpath, _O_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
+  cabhf = fdi->open(fullpath, _O_RDONLY|_O_BINARY, _S_IREAD | _S_IWRITE);
   if (cabhf == -1) {
-    PFDI_FREE(hfdi, decomp_state);
-    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
-    PFDI_INT(hfdi)->perf->fError = TRUE;
-    SetLastError(ERROR_FILE_NOT_FOUND);
-    return FALSE;
-  }
-
-  if (cabhf == 0) {
-    ERR("PFDI_OPEN returned zero for %s.\n", fullpath);
-    PFDI_FREE(hfdi, decomp_state);
-    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
-    PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND;
-    PFDI_INT(hfdi)->perf->fError = TRUE;
+    fdi->free(decomp_state);
+    set_error( fdi, FDIERROR_CABINET_NOT_FOUND, 0 );
     SetLastError(ERROR_FILE_NOT_FOUND);
     return FALSE;
   }
 
   /* check if it's really a cabfile. Note that this doesn't implement the bug */
-  if (!FDI_read_entries(hfdi, cabhf, &fdici, &(CAB(mii)))) {
-    ERR("FDIIsCabinet failed.\n");
-    PFDI_FREE(hfdi, decomp_state);
-    PFDI_CLOSE(hfdi, cabhf);
+  if (!FDI_read_entries(fdi, cabhf, &fdici, &(CAB(mii)))) {
+    WARN("FDI_read_entries failed: %u\n", fdi->perf->erfOper);
+    fdi->free(decomp_state);
+    fdi->close(cabhf);
     return FALSE;
   }
-   
+
   /* cabinet notification */
   ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
   fdin.setID = fdici.setID;
@@ -2575,10 +2509,8 @@ BOOL __cdecl FDICopy(
   fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring;
   fdin.psz3 = pszCabPath;
 
-  if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) {
-    PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
-    PFDI_INT(hfdi)->perf->erfType = 0;
-    PFDI_INT(hfdi)->perf->fError = TRUE;
+  if (pfnfdin(fdintCABINET_INFO, &fdin) == -1) {
+    set_error( fdi, FDIERROR_USER_ABORT, 0 );
     goto bail_and_fail;
   }
 
@@ -2588,23 +2520,18 @@ BOOL __cdecl FDICopy(
 
   /* read folders */
   for (i = 0; i < fdici.cFolders; i++) {
-    if (PFDI_READ(hfdi, cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
+    if (fdi->read(cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) {
+      set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
       goto bail_and_fail;
     }
 
     if (CAB(mii).folder_resv > 0)
-      PFDI_SEEK(hfdi, cabhf, CAB(mii).folder_resv, SEEK_CUR);
+      fdi->seek(cabhf, CAB(mii).folder_resv, SEEK_CUR);
 
-    fol = PFDI_ALLOC(hfdi, sizeof(struct fdi_folder));
+    fol = fdi->alloc(sizeof(struct fdi_folder));
     if (!fol) {
       ERR("out of memory!\n");
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
-      PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
       goto bail_and_fail;
     }
     ZeroMemory(fol, sizeof(struct fdi_folder));
@@ -2621,20 +2548,15 @@ BOOL __cdecl FDICopy(
 
   /* read files */
   for (i = 0; i < fdici.cFiles; i++) {
-    if (PFDI_READ(hfdi, cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
+    if (fdi->read(cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) {
+      set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
       goto bail_and_fail;
     }
 
-    file = PFDI_ALLOC(hfdi, sizeof(struct fdi_file));
+    file = fdi->alloc(sizeof(struct fdi_file));
     if (!file) { 
       ERR("out of memory!\n"); 
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
-      PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
-      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
       goto bail_and_fail;
     }
     ZeroMemory(file, sizeof(struct fdi_file));
@@ -2646,12 +2568,10 @@ BOOL __cdecl FDICopy(
     file->time     = EndGetI16(buf+cffile_Time);
     file->date     = EndGetI16(buf+cffile_Date);
     file->attribs  = EndGetI16(buf+cffile_Attribs);
-    file->filename = FDI_read_string(hfdi, cabhf, fdici.cbCabinet);
+    file->filename = FDI_read_string(fdi, cabhf, fdici.cbCabinet);
 
     if (!file->filename) {
-      PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-      PFDI_INT(hfdi)->perf->erfType = 0;
-      PFDI_INT(hfdi)->perf->fError = TRUE;
+      set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
       goto bail_and_fail;
     }
 
@@ -2675,7 +2595,7 @@ BOOL __cdecl FDICopy(
      * 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
+     * to strictly serialize its 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().
      */
@@ -2706,8 +2626,8 @@ BOOL __cdecl FDICopy(
        * 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
+       * its info from the header of this cabinet.  This provides the right answer in
+       * 95% of the cases; it's worth checking if Microsoft cuts the same corner before
        * we "fix" it.
        */
       ZeroMemory(&fdin, sizeof(FDINOTIFICATION));
@@ -2716,10 +2636,8 @@ BOOL __cdecl FDICopy(
       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;
-        PFDI_INT(hfdi)->perf->erfType = 0;
-        PFDI_INT(hfdi)->perf->fError = TRUE;
+      if (pfnfdin(fdintPARTIAL_FILE, &fdin) == -1) {
+        set_error( fdi, FDIERROR_USER_ABORT, 0 );
         goto bail_and_fail;
       }
       /* I don't think we are supposed to decompress partial files.  This prevents it. */
@@ -2735,10 +2653,9 @@ BOOL __cdecl FDICopy(
       fdin.date = file->date;
       fdin.time = file->time;
       fdin.attribs = file->attribs;
+      fdin.iFolder = file->index;
       if ((filehf = ((*pfnfdin)(fdintCOPY_FILE, &fdin))) == -1) {
-        PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT;
-        PFDI_INT(hfdi)->perf->erfType = 0;
-        PFDI_INT(hfdi)->perf->fError = TRUE;
+        set_error( fdi, FDIERROR_USER_ABORT, 0 );
         filehf = 0;
         goto bail_and_fail;
       }
@@ -2746,13 +2663,13 @@ BOOL __cdecl FDICopy(
 
     /* 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 {
+        unsigned int i2;
+
         for (i2 = 0; (i2 < file->index); i2++)
           if (fol->next) /* bug resistance, should always be true */
             fol = fol->next;
@@ -2768,7 +2685,7 @@ BOOL __cdecl FDICopy(
       TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename));
 
       /* set up decomp_state */
-      CAB(hfdi) = hfdi;
+      CAB(fdi) = fdi;
       CAB(filehf) = filehf;
 
       /* Was there a change of folder?  Compression type?  Did we somehow go backwards? */
@@ -2776,28 +2693,28 @@ BOOL __cdecl FDICopy(
 
         TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename));
 
-        /* free stuff for the old decompresser */
+        /* free stuff for the old decompressor */
         switch (ct2) {
         case cffoldCOMPTYPE_LZX:
           if (LZX(window)) {
-            PFDI_FREE(hfdi, LZX(window));
+            fdi->free(LZX(window));
             LZX(window) = NULL;
           }
           break;
         case cffoldCOMPTYPE_QUANTUM:
           if (QTM(window)) {
-            PFDI_FREE(hfdi, QTM(window));
+            fdi->free(QTM(window));
             QTM(window) = NULL;
           }
           break;
         }
 
         CAB(decomp_cab) = NULL;
-        PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset, SEEK_SET);
+        CAB(fdi)->seek(CAB(cabhf), fol->offset, SEEK_SET);
         CAB(offset) = 0;
         CAB(outlen) = 0;
 
-        /* initialize the new decompresser */
+        /* initialize the new decompressor */
         switch (ct1) {
         case cffoldCOMPTYPE_NONE:
           CAB(decompress) = NONEfdi_decomp;
@@ -2824,15 +2741,10 @@ BOOL __cdecl FDICopy(
         case DECR_OK:
           break;
         case DECR_NOMEMORY:
-          PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
-          PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
-          PFDI_INT(hfdi)->perf->fError = TRUE;
-          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+          set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
           goto bail_and_fail;
         default:
-          PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-          PFDI_INT(hfdi)->perf->erfOper = 0;
-          PFDI_INT(hfdi)->perf->fError = TRUE;
+          set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
           goto bail_and_fail;
       }
 
@@ -2842,20 +2754,13 @@ BOOL __cdecl FDICopy(
           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;
+            set_error( fdi, FDIERROR_USER_ABORT, 0 );
             goto bail_and_fail;
           case DECR_NOMEMORY:
-            PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
-            PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
-            PFDI_INT(hfdi)->perf->fError = TRUE;
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
             goto bail_and_fail;
           default:
-            PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-            PFDI_INT(hfdi)->perf->erfOper = 0;
-            PFDI_INT(hfdi)->perf->fError = TRUE;
+            set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
             goto bail_and_fail;
         }
         CAB(offset) = file->offset;
@@ -2870,10 +2775,11 @@ BOOL __cdecl FDICopy(
       fdin.pv = pvUser;
       fdin.psz1 = (char *)file->filename;
       fdin.hf = filehf;
-      fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */
+      fdin.cb = (file->attribs & cffile_A_EXEC) != 0; /* FIXME: is that right? */
       fdin.date = file->date;
       fdin.time = file->time;
       fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */
+      fdin.iFolder = file->index;
       ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin));
       filehf = 0;
 
@@ -2881,37 +2787,30 @@ BOOL __cdecl FDICopy(
         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;
+          set_error( fdi, FDIERROR_USER_ABORT, 0 );
           goto bail_and_fail;
         case DECR_NOMEMORY:
-          PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL;
-          PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
-          PFDI_INT(hfdi)->perf->fError = TRUE;
-          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+          set_error( fdi, FDIERROR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
           goto bail_and_fail;
         default:
-          PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
-          PFDI_INT(hfdi)->perf->erfOper = 0;
-          PFDI_INT(hfdi)->perf->fError = TRUE;
+          set_error( fdi, FDIERROR_CORRUPT_CABINET, 0 );
           goto bail_and_fail;
       }
     }
   }
 
-  free_decompression_temps(hfdi, fol, decomp_state);
-  free_decompression_mem(hfdi, decomp_state, file);
+  if (fol) free_decompression_temps(fdi, fol, decomp_state);
+  free_decompression_mem(fdi, decomp_state);
  
   return TRUE;
 
   bail_and_fail: /* here we free ram before error returns */
 
-  if (fol) free_decompression_temps(hfdi, fol, decomp_state);
+  if (fol) free_decompression_temps(fdi, fol, decomp_state);
 
-  if (filehf) PFDI_CLOSE(hfdi, filehf);
+  if (filehf) fdi->close(filehf);
 
-  free_decompression_mem(hfdi, decomp_state, file);
+  free_decompression_mem(fdi, decomp_state);
 
   return FALSE;
 }
@@ -2931,15 +2830,13 @@ BOOL __cdecl FDICopy(
  */
 BOOL __cdecl FDIDestroy(HFDI hfdi)
 {
-  TRACE("(hfdi == ^%p)\n", hfdi);
-  if (REALLY_IS_FDI(hfdi)) {
-    PFDI_INT(hfdi)->FDI_Intmagic = 0; /* paranoia */
-    PFDI_FREE(hfdi, hfdi); /* confusing, but correct */
+    FDI_Int *fdi = get_fdi_ptr( hfdi );
+
+    TRACE("(hfdi == ^%p)\n", hfdi);
+    if (!fdi) return FALSE;
+    fdi->magic = 0; /* paranoia */
+    fdi->free(fdi);
     return TRUE;
-  } else {
-    SetLastError(ERROR_INVALID_HANDLE);
-    return FALSE;
-  }
 }
 
 /***********************************************************************
@@ -2966,13 +2863,12 @@ BOOL __cdecl FDITruncateCabinet(
        char   *pszCabinetName,
        USHORT  iFolderToDelete)
 {
+  FDI_Int *fdi = get_fdi_ptr( hfdi );
+
   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;
-  }
+  if (!fdi) return FALSE;
 
   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
   return FALSE;