Sync to Wine-20050628:
authorGé van Geldorp <ge@gse.nl>
Wed, 6 Jul 2005 22:24:04 +0000 (22:24 +0000)
committerGé van Geldorp <ge@gse.nl>
Wed, 6 Jul 2005 22:24:04 +0000 (22:24 +0000)
Thomas Weidenmueller <wine-patches@reactsoft.com>
- Removed local variables only used in TRACE statements.
Gerold Jens Wucherpfennig <gjwucherpfennig@gmx.net>
- Some FCI work.

svn path=/trunk/; revision=16471

reactos/lib/cabinet/cabextract.c
reactos/lib/cabinet/cabinet.h
reactos/lib/cabinet/cabinet_main.c
reactos/lib/cabinet/fci.c

index 3f3517d..e70adfc 100644 (file)
@@ -31,6 +31,7 @@
 #include <stdarg.h>\r
 #include <stdio.h>\r
 #include <stdlib.h>\r
+#include <ctype.h>\r
 \r
 #include "windef.h"\r
 #include "winbase.h"\r
@@ -2523,13 +2524,8 @@ exit_handler:
  * print_fileinfo (internal)\r
  */\r
 void print_fileinfo(struct cab_file *fi) {\r
-  int d;\r
-  int t; \r
   char *fname = NULL;\r
 \r
-  d = fi->date;\r
-  t = fi->time;\r
-\r
   if (fi->attribs & cffile_A_NAME_IS_UTF) {\r
     fname = malloc(strlen(fi->filename) + 1);\r
     if (fname) {\r
@@ -2540,8 +2536,8 @@ void print_fileinfo(struct cab_file *fi) {
 \r
   TRACE("%9u | %02d.%02d.%04d %02d:%02d:%02d | %s\n",\r
     fi->length, \r
-    d & 0x1f, (d>>5) & 0xf, (d>>9) + 1980,\r
-    t >> 11, (t>>5) & 0x3f, (t << 1) & 0x3e,\r
+    fi->date & 0x1f, (fi->date>>5) & 0xf, (fi->date>>9) + 1980,\r
+    fi->time >> 11, (fi->time>>5) & 0x3f, (fi->time << 1) & 0x3e,\r
     fname ? fname : fi->filename\r
   );\r
 \r
index c5b5e60..7e3f1ae 100644 (file)
@@ -305,7 +305,41 @@ typedef struct {
   PFNFCIDELETE       pfndelete;\r
   PFNFCIGETTEMPFILE  pfnfcigtf;\r
   PCCAB              pccab;\r
-  void *pv;\r
+  BOOL               fPrevCab;\r
+  BOOL               fNextCab;\r
+  BOOL               fSplitFolder;\r
+  cab_ULONG          statusFolderCopied;\r
+  cab_ULONG          statusFolderTotal;\r
+  BOOL               fGetNextCabInVain;\r
+  void               *pv;\r
+  char szPrevCab[CB_MAX_CABINET_NAME];    /* previous cabinet name */\r
+  char szPrevDisk[CB_MAX_DISK_NAME];      /* disk name of previous cabinet */\r
+  CCAB               oldCCAB;\r
+  char*              data_in;  /* uncompressed data blocks */\r
+  cab_UWORD          cdata_in;\r
+  char*              data_out; /* compressed data blocks */\r
+  ULONG              cCompressedBytesInFolder;\r
+  cab_UWORD          cFolders;\r
+  cab_UWORD          cFiles;\r
+  cab_ULONG          cDataBlocks;\r
+  cab_ULONG          cbFileRemainer; /* uncompressed, yet to be written data */\r
+               /* of spanned file of a spanning folder of a spanning cabinet */\r
+  cab_UBYTE          szFileNameCFDATA1[CB_MAX_FILENAME];\r
+  int                handleCFDATA1;\r
+  cab_UBYTE          szFileNameCFFILE1[CB_MAX_FILENAME];\r
+  int                handleCFFILE1;\r
+  cab_UBYTE          szFileNameCFDATA2[CB_MAX_FILENAME];\r
+  int                handleCFDATA2;\r
+  cab_UBYTE          szFileNameCFFILE2[CB_MAX_FILENAME];\r
+  int                handleCFFILE2;\r
+  cab_UBYTE          szFileNameCFFOLDER[CB_MAX_FILENAME];\r
+  int                handleCFFOLDER;\r
+  cab_ULONG          sizeFileCFDATA1;\r
+  cab_ULONG          sizeFileCFFILE1;\r
+  cab_ULONG          sizeFileCFDATA2;\r
+  cab_ULONG          sizeFileCFFILE2;\r
+  cab_ULONG          sizeFileCFFOLDER;\r
+  BOOL               fNewPrevious;\r
 } FCI_Int, *PFCI_Int;\r
 \r
 typedef struct {\r
@@ -326,6 +360,18 @@ typedef struct {
 /* cast an HFDI into a PFDI_Int */\r
 #define PFDI_INT(hfdi) ((PFDI_Int)(hfdi))\r
 \r
+/* quick pfci method invokers */\r
+#define PFCI_ALLOC(hfdi, size)            ((*PFCI_INT(hfdi)->pfnalloc) (size))\r
+#define PFCI_FREE(hfdi, ptr)              ((*PFCI_INT(hfdi)->pfnfree)  (ptr))\r
+#define PFCI_GETTEMPFILE(hfci,name,length) ((*PFCI_INT(hfci)->pfnfcigtf)(name,length,PFCI_INT(hfci)->pv))\r
+#define PFCI_DELETE(hfci,name,err,pv)      ((*PFCI_INT(hfci)->pfndelete)(name,err,pv))\r
+#define PFCI_OPEN(hfci,name,oflag,pmode,err,pv) ((*PFCI_INT(hfci)->pfnopen)(name,oflag,pmode,err,pv))\r
+#define PFCI_READ(hfci,hf,memory,cb,err,pv)((*PFCI_INT(hfci)->pfnread)(hf,memory,cb,err,pv))\r
+#define PFCI_WRITE(hfci,hf,memory,cb,err,pv)  ((*PFCI_INT(hfci)->pfnwrite)(hf,memory,cb,err,pv))\r
+#define PFCI_CLOSE(hfci,hf,err,pv)         ((*PFCI_INT(hfci)->pfnclose)(hf,err,pv))\r
+#define PFCI_SEEK(hfci,hf,dist,seektype,err,pv)((*PFCI_INT(hfci)->pfnseek)(hf,dist,seektype,err,pv))\r
+#define PFCI_FILEPLACED(hfci,pccab,name,cb,cont,pv)((*PFCI_INT(hfci)->pfnfiledest)(pccab,name,cb,cont,pv))\r
+\r
 /* quickie pfdi method invokers */\r
 #define PFDI_ALLOC(hfdi, size)            ((*PFDI_INT(hfdi)->pfnalloc) (size))\r
 #define PFDI_FREE(hfdi, ptr)              ((*PFDI_INT(hfdi)->pfnfree)  (ptr))\r
index 2959a6f..9d20968 100644 (file)
@@ -89,15 +89,14 @@ HRESULT WINAPI CABINET_DllGetVersion (DLLVERSIONINFO *pdvi)
 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what)\r
 {\r
 #define DUMPC(idx)      idx >= sizeof(EXTRACTdest) ? ' ' : \\r
-                        ptr[idx] >= 0x20 ? ptr[idx] : '.'\r
+                        ((unsigned char*) dest)[idx] >= 0x20 ? \\r
+                        ((unsigned char*) dest)[idx] : '.'\r
 \r
-#define DUMPH(idx)      idx >= sizeof(EXTRACTdest) ? 0x55 : ptr[idx]\r
+#define DUMPH(idx)      idx >= sizeof(EXTRACTdest) ? 0x55 : ((unsigned char*) dest)[idx]\r
 \r
   LPSTR dir;\r
-  unsigned char *ptr;\r
   unsigned int i;\r
 \r
-   ptr = ((unsigned char*) dest);\r
   TRACE("(dest == %0lx, what == %s)\n", (long) dest, debugstr_a(what));\r
 \r
   if (!dest) {\r
index 88310c2..c46464b 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
  */\r
 \r
+/*\r
+\r
+There is still some work to be done:\r
+\r
+- currently no support for big-endian machines\r
+- the ERF error structure aren't used on error\r
+- no real compression yet\r
+- unknown behaviour if files>4GB or cabinet >4GB\r
+- incorrect status information\r
+- check if the maximum size for a cabinet is too small to store any data\r
+- call pfnfcignc on exactly the same position as MS FCIAddFile in every case\r
+\r
+*/\r
+\r
+\r
+\r
 #include "config.h"\r
 \r
 #include <stdarg.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
 \r
 #include "windef.h"\r
 #include "winbase.h"\r
 \r
 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);\r
 \r
+typedef struct {\r
+  cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */\r
+  cab_ULONG reserved1;\r
+  cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/\r
+  cab_ULONG reserved2;\r
+  cab_ULONG coffFiles;    /* offset to first CFFILE section */\r
+  cab_ULONG reserved3;\r
+  cab_UBYTE versionMinor; /* 3 */\r
+  cab_UBYTE versionMajor; /* 1 */\r
+  cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/\r
+  cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/\r
+  cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved setions*/\r
+  cab_UWORD setID;        /* identification number of all cabinets in a set*/\r
+  cab_UWORD iCabinet;     /* number of the cabinet in a set */\r
+  /* additional area if "flags" were set*/\r
+} CFHEADER; /* minimum 36 bytes */\r
+\r
+typedef struct {\r
+  cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */\r
+  cab_UWORD cCFData;      /* number of this folder's CFDATA sections */\r
+  cab_UWORD typeCompress; /* compression type of data in CFDATA section*/\r
+  /* additional area if reserve flag was set */\r
+} CFFOLDER; /* minumum 8 bytes */\r
+\r
+typedef struct {\r
+  cab_ULONG cbFile;          /* size of the uncompressed file in bytes */\r
+  cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */\r
+  cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */\r
+                             /* for special values see below this structure*/\r
+  cab_UWORD date;            /* last modification date*/\r
+  cab_UWORD time;            /* last modification time*/\r
+  cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */\r
+  /* ... and a C string with the name of the file */\r
+} CFFILE; /* 16 bytes + name of file */\r
+\r
+\r
+typedef struct {\r
+  cab_ULONG csum;          /* checksum of this entry*/\r
+  cab_UWORD cbData;        /* number of compressed bytes  */\r
+  cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */\r
+  /* optional reserved area */\r
+  /* compressed data */\r
+} CFDATA;\r
+\r
+\r
 /***********************************************************************\r
  *             FCICreate (CABINET.10)\r
  *\r
- * Provided with several callbacks,\r
- * returns a handle which can be used to perform operations\r
- * on cabinet files.\r
+ * FCICreate is provided with several callbacks and\r
+ * returns a handle which can be used to create cabinet files.\r
  *\r
  * PARAMS\r
  *   perf       [IO]  A pointer to an ERF structure.  When FCICreate\r
@@ -54,7 +116,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
  *                    the same interface as _open.\r
  *   pfnread     [I]  A pointer to a function which reads from a file into\r
  *                    a caller-provided buffer.  Uses the same interface\r
- *                    as _read\r
+ *                    as _read.\r
  *   pfnwrite    [I]  A pointer to a function which writes to a file from\r
  *                    a caller-provided buffer.  Uses the same interface\r
  *                    as _write.\r
@@ -64,8 +126,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
  *                    Uses the same interface as _lseek.\r
  *   pfndelete   [I]  A pointer to a function which deletes a file.\r
  *   pfnfcigtf   [I]  A pointer to a function which gets the name of a\r
- *                    temporary file; ignored in wine\r
- *   pccab       [I]  A pointer to an initialized CCAB structure\r
+ *                    temporary file.\r
+ *   pccab       [I]  A pointer to an initialized CCAB structure.\r
  *   pv          [I]  A pointer to an application-defined notification\r
  *                    function which will be passed to other FCI functions\r
  *                    as a parameter.\r
@@ -94,9 +156,13 @@ HFCI __cdecl FCICreate(
        PCCAB              pccab,\r
        void *pv)\r
 {\r
-  HFCI rv;\r
+  HFCI hfci;\r
+  int err;\r
+  PFCI_Int p_fci_internal;\r
 \r
-  if ((!pfnalloc) || (!pfnfree)) {\r
+  if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||\r
+      (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||\r
+      (!pfnfcigtf) || (!pccab)) {\r
     perf->erfOper = FCIERR_NONE;\r
     perf->erfType = ERROR_BAD_ARGUMENTS;\r
     perf->fError = TRUE;\r
@@ -105,7 +171,7 @@ HFCI __cdecl FCICreate(
     return NULL;\r
   }\r
 \r
-  if (!(rv = (HFCI) (*pfnalloc)(sizeof(FCI_Int)))) {\r
+  if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) {\r
     perf->erfOper = FCIERR_ALLOC_FAIL;\r
     perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
     perf->fError = TRUE;\r
@@ -114,117 +180,2485 @@ HFCI __cdecl FCICreate(
     return NULL;\r
   }\r
 \r
-  PFCI_INT(rv)->FCI_Intmagic = FCI_INT_MAGIC;\r
-  PFCI_INT(rv)->perf = perf;\r
-  PFCI_INT(rv)->pfnfiledest = pfnfiledest;\r
-  PFCI_INT(rv)->pfnalloc = pfnalloc;\r
-  PFCI_INT(rv)->pfnfree = pfnfree;\r
-  PFCI_INT(rv)->pfnopen = pfnopen;\r
-  PFCI_INT(rv)->pfnread = pfnread;\r
-  PFCI_INT(rv)->pfnwrite = pfnwrite;\r
-  PFCI_INT(rv)->pfnclose = pfnclose;\r
-  PFCI_INT(rv)->pfnseek = pfnseek;\r
-  PFCI_INT(rv)->pfndelete = pfndelete;\r
-  PFCI_INT(rv)->pfnfcigtf = pfnfcigtf;\r
-  PFCI_INT(rv)->pccab = pccab;\r
-  PFCI_INT(rv)->pv = pv;\r
+  p_fci_internal=((PFCI_Int)(hfci));\r
+  p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC;\r
+  p_fci_internal->perf = perf;\r
+  p_fci_internal->pfnfiledest = pfnfiledest;\r
+  p_fci_internal->pfnalloc = pfnalloc;\r
+  p_fci_internal->pfnfree = pfnfree;\r
+  p_fci_internal->pfnopen = pfnopen;\r
+  p_fci_internal->pfnread = pfnread;\r
+  p_fci_internal->pfnwrite = pfnwrite;\r
+  p_fci_internal->pfnclose = pfnclose;\r
+  p_fci_internal->pfnseek = pfnseek;\r
+  p_fci_internal->pfndelete = pfndelete;\r
+  p_fci_internal->pfnfcigtf = pfnfcigtf;\r
+  p_fci_internal->pccab = pccab;\r
+  p_fci_internal->fPrevCab = FALSE;\r
+  p_fci_internal->fNextCab = FALSE;\r
+  p_fci_internal->fSplitFolder = FALSE;\r
+  p_fci_internal->fGetNextCabInVain = FALSE;\r
+  p_fci_internal->pv = pv;\r
+  p_fci_internal->data_in  = NULL;\r
+  p_fci_internal->cdata_in = 0;\r
+  p_fci_internal->data_out = NULL;\r
+  p_fci_internal->cCompressedBytesInFolder = 0;\r
+  p_fci_internal->cFolders = 0;\r
+  p_fci_internal->cFiles = 0;\r
+  p_fci_internal->cDataBlocks = 0;\r
+  p_fci_internal->sizeFileCFDATA1 = 0;\r
+  p_fci_internal->sizeFileCFFILE1 = 0;\r
+  p_fci_internal->sizeFileCFDATA2 = 0;\r
+  p_fci_internal->sizeFileCFFILE2 = 0;\r
+  p_fci_internal->sizeFileCFFOLDER = 0;\r
+  p_fci_internal->sizeFileCFFOLDER = 0;\r
+  p_fci_internal->fNewPrevious = FALSE;\r
 \r
-  /* Still mark as incomplete, because of other missing FCI* APIs */\r
+  memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);\r
+  memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);\r
 \r
-  PFCI_INT(rv)->FCI_Intmagic = 0;\r
-  PFDI_FREE(rv, rv);\r
-  FIXME("(%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p): stub\n",\r
-    perf, pfnfiledest, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose,\r
-    pfnseek, pfndelete, pfnfcigtf, pccab, pv);\r
+  /* CFDATA */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
 \r
-  perf->erfOper = FCIERR_NONE;\r
-  perf->erfType = 0;\r
-  perf->fError = TRUE;\r
+  p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
 \r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
+  /* array of all CFFILE in a folder */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
 \r
-  return NULL;\r
+  /* CFDATA with checksum and ready to be copied into cabinet */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
 \r
-}\r
+  /* array of all CFFILE in a folder, ready to be copied into cabinet */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
 \r
-/***********************************************************************\r
- *             FCIAddFile (CABINET.11)\r
- */\r
-BOOL __cdecl FCIAddFile(\r
-       HFCI                  hfci,\r
-       char                 *pszSourceFile,\r
-       char                 *pszFileName,\r
-       BOOL                  fExecute,\r
-       PFNFCIGETNEXTCABINET  pfnfcignc,\r
-       PFNFCISTATUS          pfnfcis,\r
-       PFNFCIGETOPENINFO     pfnfcigoi,\r
-       TCOMP                 typeCompress)\r
+  /* array of all CFFILE in a folder, ready to be copied into cabinet */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv);\r
+\r
+\r
+  /* TODO close and delete new files when return FALSE */\r
+\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
+\r
+  return hfci;\r
+} /* end of FCICreate */\r
+\r
+\r
+\r
+\r
+\r
+\r
+static BOOL fci_flush_data_block (HFCI hfci, int* err,\r
+    PFNFCISTATUS pfnfcis) {\r
+\r
+  /* attention no hfci checks!!! */\r
+  /* attention no checks if there is data available!!! */\r
+  CFDATA data;\r
+  CFDATA* cfdata=&data;\r
+  char* reserved;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+  UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;\r
+  UINT i;\r
+\r
+  /* TODO compress the data of p_fci_internal->data_in */\r
+  /* and write it to p_fci_internal->data_out */\r
+  memcpy(p_fci_internal->data_out, p_fci_internal->data_in,\r
+    p_fci_internal->cdata_in /* number of bytes to copy */);\r
+\r
+  cfdata->csum=0; /* checksum has to be set later */\r
+  /* TODO set realsize of compressed data */\r
+  cfdata->cbData   = p_fci_internal->cdata_in;\r
+  cfdata->cbUncomp = p_fci_internal->cdata_in;\r
+\r
+  /* write cfdata to p_fci_internal->handleCFDATA1 */\r
+  if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */\r
+      cfdata, sizeof(*cfdata), err, p_fci_internal->pv)\r
+      != sizeof(*cfdata) ) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);\r
+\r
+  /* add optional reserved area */\r
+\r
+  /* This allocation and freeing at each CFData block is a bit */\r
+  /* inefficent, but it's harder to forget about freeing the buffer :-). */\r
+  /* Reserved areas are used seldom besides that... */\r
+  if (cbReserveCFData!=0) {\r
+    if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) {\r
+      p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+      p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+      p_fci_internal->perf->fError = TRUE;\r
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+      return FALSE;\r
+    }\r
+    for(i=0;i<cbReserveCFData;) {\r
+      reserved[i++]='\0';\r
+    }\r
+    if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */\r
+        reserved, /* memory buffer */\r
+        cbReserveCFData, /* number of bytes to copy */\r
+        err, p_fci_internal->pv) != cbReserveCFData ) {\r
+      PFCI_FREE(hfci, reserved);\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err PFCI_FREE(hfci, reserved)*/\r
+\r
+    p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;\r
+    PFCI_FREE(hfci, reserved);\r
+  }\r
+\r
+  /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */\r
+  if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */\r
+      p_fci_internal->data_out, /* memory buffer */\r
+      cfdata->cbData, /* number of bytes to copy */\r
+      err, p_fci_internal->pv) != cfdata->cbData) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;\r
+\r
+  /* reset the offset */\r
+  p_fci_internal->cdata_in = 0;\r
+  p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;\r
+\r
+  /* report status with pfnfcis about uncompressed and compressed file data */\r
+  if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,\r
+      p_fci_internal->pv) == -1) {\r
+    /* TODO set error code and abort */\r
+    return FALSE;\r
+  }\r
+\r
+  ++(p_fci_internal->cDataBlocks);\r
+\r
+  return TRUE;\r
+} /* end of fci_flush_data_block */\r
+\r
+\r
+\r
+\r
+\r
+static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed)\r
+{\r
+  cab_ULONG csum;\r
+  cab_ULONG ul;\r
+  int       cUlong;\r
+  BYTE      *pb;\r
+\r
+  csum = seed;\r
+  cUlong = cb / 4;\r
+  pb = pv;\r
+\r
+  while (cUlong-- > 0) {\r
+    ul = *pb++;\r
+    ul |= (((cab_ULONG)(*pb++)) <<  8);\r
+    ul |= (((cab_ULONG)(*pb++)) << 16);\r
+    ul |= (((cab_ULONG)(*pb++)) << 24);\r
+\r
+    csum ^= ul;\r
+  }\r
+\r
+  ul = 0;\r
+  switch (cb % 4) {\r
+    case 3:\r
+      ul |= (((ULONG)(*pb++)) << 16);\r
+    case 2:\r
+      ul |= (((ULONG)(*pb++)) <<  8);\r
+    case 1:\r
+      ul |= *pb++;\r
+    default:\r
+      break;\r
+  }\r
+  csum ^= ul;\r
+\r
+  return csum;\r
+} /* end of fci_get_checksum */\r
+\r
+\r
+\r
+\r
+\r
+static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData,\r
+  PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,\r
+  cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)\r
+{\r
+  cab_ULONG read_result;\r
+  CFDATA* pcfdata=(CFDATA*)buffer;\r
+  BOOL split_block=FALSE;\r
+  cab_UWORD savedUncomp=0;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  *payload=0;\r
+\r
+  /* while not all CFDATAs have been copied do */\r
+  while(!FALSE) {\r
+    if( p_fci_internal->fNextCab ) {\r
+      if( split_block ) {\r
+        /* TODO internal error should never happen */\r
+        return FALSE;\r
+      }\r
+    }\r
+    /* REUSE the variable read_result */\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      read_result=4;\r
+    } else {\r
+      read_result=0;\r
+    }\r
+    if (p_fci_internal->fPrevCab) {\r
+      read_result+=strlen(p_fci_internal->szPrevCab)+1 +\r
+        strlen(p_fci_internal->szPrevDisk)+1;\r
+    }\r
+    /* No more CFDATA fits into the cabinet under construction */\r
+    /* So don't try to store more data into it */\r
+    if( p_fci_internal->fNextCab &&\r
+        (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +\r
+        p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+        p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+        sizeof(CFHEADER) +\r
+        read_result +\r
+        p_fci_internal->oldCCAB.cbReserveCFHeader +\r
+        sizeof(CFFOLDER) +\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder +\r
+        strlen(p_fci_internal->pccab->szCab)+1 +\r
+        strlen(p_fci_internal->pccab->szDisk)+1\r
+    )) {\r
+      /* This may never be run for the first time the while loop is entered.\r
+      Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/\r
+      split_block=TRUE;  /* In this case split_block is abused to store */\r
+      /* the complete data block into the next cabinet and not into the */\r
+      /* current one. Originally split_block is the indicator that a */\r
+      /* data block has been splitted across different cabinets. */\r
+    } else {\r
+\r
+      /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/\r
+      read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/\r
+          buffer, /* memory buffer */\r
+          sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */\r
+          err, p_fci_internal->pv);\r
+      if (read_result!=sizeof(CFDATA)+cbReserveCFData) {\r
+        if (read_result==0) break; /* ALL DATA has been copied */\r
+        /* TODO read error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      /* REUSE buffer p_fci_internal->data_out !!! */\r
+      /* read data from p_fci_internal->handleCFDATA1 to */\r
+      /*      p_fci_internal->data_out */\r
+      if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,\r
+          p_fci_internal->data_out /* memory buffer */,\r
+          pcfdata->cbData /* number of bytes to copy */,\r
+          err, p_fci_internal->pv) != pcfdata->cbData ) {\r
+        /* TODO read error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      /* if cabinet size is too large */\r
+\r
+      /* REUSE the variable read_result */\r
+      if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+        read_result=4;\r
+      } else {\r
+        read_result=0;\r
+      }\r
+      if (p_fci_internal->fPrevCab) {\r
+        read_result+=strlen(p_fci_internal->szPrevCab)+1 +\r
+          strlen(p_fci_internal->szPrevDisk)+1;\r
+      }\r
+\r
+      /* Is cabinet with new CFDATA too large? Then data block has to be split */\r
+      if( p_fci_internal->fNextCab &&\r
+          (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +\r
+          pcfdata->cbData +\r
+          p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+          p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+          sizeof(CFHEADER) +\r
+          read_result +\r
+          p_fci_internal->oldCCAB.cbReserveCFHeader +\r
+          sizeof(CFFOLDER) + /* size of new CFFolder entry */\r
+          p_fci_internal->oldCCAB.cbReserveCFFolder +\r
+          strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */\r
+          strlen(p_fci_internal->pccab->szDisk)+1  /* name of next disk */\r
+      )) {\r
+        /* REUSE read_result to save the size of the compressed data */\r
+        read_result=pcfdata->cbData;\r
+        /* Modify the size of the compressed data to store only a part of the */\r
+        /* data block into the current cabinet. This is done to prevent */\r
+        /* that the maximum cabinet size will be exceeded. The remainer */\r
+        /* will be stored into the next following cabinet. */\r
+\r
+        /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */\r
+        /* Substract everything except the size of the block of data */\r
+        /* to get it's actual size */\r
+        pcfdata->cbData = p_fci_internal->oldCCAB.cb - (\r
+          sizeof(CFDATA) + cbReserveCFData +\r
+          p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+          p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+          sizeof(CFHEADER) +\r
+          p_fci_internal->oldCCAB.cbReserveCFHeader +\r
+          sizeof(CFFOLDER) + /* set size of new CFFolder entry */\r
+          p_fci_internal->oldCCAB.cbReserveCFFolder );\r
+        /* substract the size of special header fields */\r
+        if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+            p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+            p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+          pcfdata->cbData-=4;\r
+        }\r
+        if (p_fci_internal->fPrevCab) {\r
+          pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +\r
+            strlen(p_fci_internal->szPrevDisk)+1;\r
+        }\r
+        pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +\r
+          strlen(p_fci_internal->pccab->szDisk)+1;\r
+\r
+        savedUncomp = pcfdata->cbUncomp;\r
+        pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */\r
+\r
+        /* if split_block==TRUE then the above while loop won't */\r
+        /* be executed again */\r
+        split_block=TRUE; /* split_block is the indicator that */\r
+                          /* a data block has been splitted across */\r
+                          /* diffentent cabinets.*/\r
+      }\r
+\r
+      /* This should never happen !!! */\r
+      if (pcfdata->cbData==0) {\r
+        /* TODO set error */\r
+        return FALSE;\r
+      }\r
+\r
+      /* get checksum and write to cfdata.csum */\r
+      pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),\r
+        sizeof(CFDATA)+cbReserveCFData -\r
+        sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/\r
+        pcfdata->cbData, 0 ) );\r
+\r
+      /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */\r
+      if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */\r
+          buffer, /* memory buffer */\r
+          sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */\r
+          err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {\r
+          /* TODO write error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;\r
+\r
+      /* write compressed data into p_fci_internal->handleCFDATA2 */\r
+      if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */\r
+          p_fci_internal->data_out, /* memory buffer */\r
+          pcfdata->cbData, /* number of bytes to copy */\r
+          err, p_fci_internal->pv) != pcfdata->cbData) {\r
+        /* TODO write error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;\r
+      ++(p_fci_internal->cDataBlocks);\r
+      p_fci_internal->statusFolderCopied += pcfdata->cbData;\r
+      (*payload)+=pcfdata->cbUncomp;\r
+      /* if cabinet size too large and data has been split */\r
+      /* write the remainer of the data block to the new CFDATA1 file */\r
+      if( split_block  ) { /* This does not include the */\r
+                                  /* abused one (just search for "abused" )*/\r
+      /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */\r
+        if (p_fci_internal->fNextCab==FALSE ) {\r
+          /* TODO internal error */\r
+          return FALSE;\r
+        }\r
+\r
+        /* set cbData the size of the remainer of the data block */\r
+        pcfdata->cbData = read_result - pcfdata->cbData;\r
+        /*recover former value of cfdata.cbData; read_result will be the offset*/\r
+        read_result -= pcfdata->cbData;\r
+        pcfdata->cbUncomp = savedUncomp;\r
+\r
+        /* reset checksum, it will be computed later */\r
+        pcfdata->csum=0;\r
+        /* write cfdata WITHOUT checksum to handleCFDATA1new */\r
+        if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */\r
+            buffer, /* memory buffer */\r
+            sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */\r
+            err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {\r
+            /* TODO write error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */\r
+\r
+        *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;\r
+\r
+        /* write compressed data into handleCFDATA1new */\r
+        if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */\r
+            p_fci_internal->data_out + read_result, /* memory buffer + offset */\r
+                                                /* to last part of split data */\r
+            pcfdata->cbData, /* number of bytes to copy */\r
+            err, p_fci_internal->pv) != pcfdata->cbData) {\r
+          /* TODO write error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err */\r
+\r
+        p_fci_internal->statusFolderCopied += pcfdata->cbData;\r
+\r
+        *psizeFileCFDATA1new += pcfdata->cbData;\r
+        /* the two blocks of the split data block have been written */\r
+        /* dont reset split_data yet, because it is still needed see below */\r
+      }\r
+\r
+      /* report status with pfnfcis about copied size of folder */\r
+      if( (*pfnfcis)(statusFolder,\r
+          p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/\r
+          p_fci_internal->statusFolderTotal, /* total folder size */\r
+          p_fci_internal->pv) == -1) {\r
+        /* TODO set error code and abort */\r
+        return FALSE;\r
+      }\r
+    }\r
+\r
+    /* if cabinet size too large */\r
+    /* write the remaining data blocks to the new CFDATA1 file */\r
+    if ( split_block ) { /* This does include the */\r
+                               /* abused one (just search for "abused" )*/\r
+      if (p_fci_internal->fNextCab==FALSE ) {\r
+        /* TODO internal error */\r
+        return FALSE;\r
+      }\r
+      /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */\r
+      while(!FALSE) {\r
+        /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/\r
+        read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */\r
+            buffer, /* memory buffer */\r
+            sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */\r
+            err, p_fci_internal->pv);\r
+        if (read_result!=sizeof(CFDATA)+cbReserveCFData) {\r
+          if (read_result==0) break; /* ALL DATA has been copied */\r
+          /* TODO read error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err */\r
+\r
+        /* REUSE buffer p_fci_internal->data_out !!! */\r
+        /* read data from p_fci_internal->handleCFDATA1 to */\r
+        /*      p_fci_internal->data_out */\r
+        if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,\r
+            p_fci_internal->data_out /* memory buffer */,\r
+            pcfdata->cbData /* number of bytes to copy */,\r
+            err, p_fci_internal->pv) != pcfdata->cbData ) {\r
+          /* TODO read error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */\r
+\r
+        /* write cfdata with checksum to handleCFDATA1new */\r
+        if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */\r
+            buffer, /* memory buffer */\r
+            sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */\r
+            err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {\r
+            /* TODO write error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */\r
+\r
+        *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;\r
+\r
+        /* write compressed data into handleCFDATA1new */\r
+        if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */\r
+            p_fci_internal->data_out, /* memory buffer */\r
+            pcfdata->cbData, /* number of bytes to copy */\r
+            err, p_fci_internal->pv) != pcfdata->cbData) {\r
+          /* TODO write error */\r
+          return FALSE;\r
+        }\r
+        /* TODO error handling of err */\r
+\r
+        *psizeFileCFDATA1new += pcfdata->cbData;\r
+        p_fci_internal->statusFolderCopied += pcfdata->cbData;\r
+\r
+        /* report status with pfnfcis about copied size of folder */\r
+        if( (*pfnfcis)(statusFolder,\r
+            p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/\r
+            p_fci_internal->statusFolderTotal, /* total folder size */\r
+            p_fci_internal->pv) == -1) {\r
+          /* TODO set error code and abort */\r
+          return FALSE;\r
+        }\r
+\r
+      } /* end of WHILE */\r
+      break; /* jump out of the next while loop */\r
+    } /* end of if( split_data  ) */\r
+  } /* end of WHILE */\r
+  return TRUE;\r
+} /* end of fci_flushfolder_copy_cfdata */\r
+\r
+\r
+\r
+\r
+\r
+static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder,\r
+  cab_ULONG sizeFileCFDATA2old)\r
 {\r
-    FIXME("(%p, %p, %p, %d, %p, %p, %p, %hu): stub\n", hfci, pszSourceFile,\r
-         pszFileName, fExecute, pfnfcignc, pfnfcis, pfnfcigoi, typeCompress);\r
+  CFFOLDER cffolder;\r
+  UINT i;\r
+  char* reserved;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  /* absolute offset cannot be set yet, because the size of cabinet header, */\r
+  /* the number of CFFOLDERs and the number of CFFILEs may change. */\r
+  /* Instead the size of all previous data blocks will be stored and */\r
+  /* the remainer of the offset will be added when the cabinet will be */\r
+  /* flushed to disk. */\r
+  /* This is exactly the way the original CABINET.DLL works!!! */\r
+  cffolder.coffCabStart=sizeFileCFDATA2old;\r
 \r
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
+  /* set the number of this folder's CFDATA sections */\r
+  cffolder.cCFData=p_fci_internal->cDataBlocks;\r
+  /* TODO set compression type */\r
+  cffolder.typeCompress = tcompTYPE_NONE;\r
 \r
+  /* write cffolder to p_fci_internal->handleCFFOLDER */\r
+  if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */\r
+    &cffolder, /* memory buffer */\r
+    sizeof(cffolder), /* number of bytes to copy */\r
+    err, p_fci_internal->pv) != sizeof(cffolder) ) {\r
+    /* TODO write error */\r
     return FALSE;\r
-}\r
+  }\r
+  /* TODO error handling of err */\r
 \r
-/***********************************************************************\r
- *             FCIFlushCabinet (CABINET.13)\r
- */\r
-BOOL __cdecl FCIFlushCabinet(\r
+  p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);\r
+\r
+  /* add optional reserved area */\r
+  if (cbReserveCFFolder!=0) {\r
+    if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) {\r
+      p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+      p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+      p_fci_internal->perf->fError = TRUE;\r
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+      return FALSE;\r
+    }\r
+    for(i=0;i<cbReserveCFFolder;) {\r
+      reserved[i++]='\0';\r
+    }\r
+    if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */\r
+        reserved, /* memory buffer */\r
+        cbReserveCFFolder, /* number of bytes to copy */\r
+        err, p_fci_internal->pv) != cbReserveCFFolder ) {\r
+      PFCI_FREE(hfci, reserved);\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;\r
+\r
+    PFCI_FREE(hfci, reserved);\r
+  }\r
+  return TRUE;\r
+} /* end of fci_flushfolder_copy_cffolder */\r
+\r
+\r
+\r
+\r
+\r
+static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new,\r
+  cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)\r
+{\r
+  CFFILE cffile;\r
+  cab_ULONG read_result;\r
+  cab_ULONG seek=0;\r
+  cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;\r
+  BOOL may_be_prev=TRUE;\r
+  cab_ULONG cbFileRemainer=0;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+  /* set seek of p_fci_internal->handleCFFILE1 to 0 */\r
+  if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err,\r
+    p_fci_internal->pv) !=0 ) {\r
+    /* TODO  wrong return value */\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* while not all CFFILE structures have been copied do */\r
+  while(!FALSE) {\r
+    /* REUSE the variable read_result */\r
+    /* read data from p_fci_internal->handleCFFILE1 to cffile */\r
+    read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */,\r
+      &cffile, /* memory buffer */\r
+      sizeof(cffile), /* number of bytes to copy */\r
+      err, p_fci_internal->pv);\r
+    if( read_result != sizeof(cffile) ) {\r
+      if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */\r
+      /* TODO read error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    /* Microsoft's(R) CABINET.DLL would do a seek to the current! */\r
+    /* position. I don't know why so I'll just omit it */\r
+\r
+    /* read the filename from p_fci_internal->handleCFFILE1 */\r
+    /* REUSE the variable read_result AGAIN */\r
+    /* REUSE the memory buffer PFCI(hfci)->data_out */\r
+    if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/,\r
+        p_fci_internal->data_out, /* memory buffer */\r
+        CB_MAX_FILENAME, /* number of bytes to copy */\r
+        err, p_fci_internal->pv) <2) {\r
+      /* TODO read error */\r
+      return FALSE;\r
+    }\r
+    /* TODO maybe other checks of read_result */\r
+    /* TODO error handling of err */\r
+\r
+    /* safety */\r
+    if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {\r
+      /* TODO set error code internal error */\r
+      return FALSE;\r
+    }\r
+\r
+    seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;\r
+\r
+    /* set seek of p_fci_internal->handleCFFILE1 to end of file name */\r
+    /* i.e. seek to the next CFFILE area */\r
+    if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,\r
+        seek, /* seek position*/\r
+        SEEK_SET ,err,\r
+        p_fci_internal->pv)\r
+        != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) {\r
+      /* TODO  wrong return value */\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    /* fnfilfnfildest: placed file on cabinet */\r
+    if (p_fci_internal->fNextCab ||\r
+        p_fci_internal->fGetNextCabInVain) {\r
+      PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB),\r
+        p_fci_internal->data_out, /* the file name*/\r
+        cffile.cbFile, /* file size */\r
+        (cffile.iFolder==cffileCONTINUED_FROM_PREV),\r
+        p_fci_internal->pv\r
+      );\r
+    } else {\r
+      PFCI_FILEPLACED( hfci, p_fci_internal->pccab,\r
+        p_fci_internal->data_out, /* the file name*/\r
+        cffile.cbFile, /* file size */\r
+        (cffile.iFolder==cffileCONTINUED_FROM_PREV),\r
+        p_fci_internal->pv\r
+      );\r
+    }\r
+\r
+    /* Check special iFolder values */\r
+    if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&\r
+        p_fci_internal->fPrevCab==FALSE ) {\r
+      /* THIS MAY NEVER HAPPEN */\r
+      /* TODO set error code */\r
+      return FALSE;\r
+    }\r
+    if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||\r
+        cffile.iFolder==cffileCONTINUED_TO_NEXT ) {\r
+      /* THIS MAY NEVER HAPPEN */\r
+      /* TODO set error code */\r
+      return FALSE;\r
+    }\r
+    if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {\r
+      may_be_prev=FALSE;\r
+    }\r
+    if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {\r
+      /* THIS MAY NEVER HAPPEN */\r
+      /* TODO set error code */\r
+      return FALSE;\r
+    }\r
+    if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {\r
+      may_be_prev=FALSE;\r
+    }\r
+\r
+    sizeOfFilesPrev=sizeOfFiles;\r
+    /* Set complete size of all processed files */\r
+    if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&\r
+        p_fci_internal->cbFileRemainer!=0\r
+    ) {\r
+      sizeOfFiles+=p_fci_internal->cbFileRemainer;\r
+      p_fci_internal->cbFileRemainer=0;\r
+    } else {\r
+      sizeOfFiles+=cffile.cbFile;\r
+    }\r
+\r
+    /* Check if spanned file fits into this cabinet folder */\r
+    if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) {\r
+      cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT;\r
+    } else\r
+\r
+    /* Check if file doesn't fit into this cabinet folder */\r
+    if( sizeOfFiles>payload ) {\r
+      cffile.iFolder=cffileCONTINUED_TO_NEXT;\r
+    }\r
+\r
+    /* write cffile to p_fci_internal->handleCFFILE2 */\r
+    if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */\r
+      &cffile, /* memory buffer */\r
+      sizeof(cffile), /* number of bytes to copy */\r
+      err, p_fci_internal->pv) != sizeof(cffile) ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    p_fci_internal->sizeFileCFFILE2 += sizeof(cffile);\r
+\r
+    /* write file name to p_fci_internal->handleCFFILE2 */\r
+    if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */\r
+      p_fci_internal->data_out, /* memory buffer */\r
+      strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */\r
+      err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1;\r
+\r
+    /* cFiles is used to count all files of a cabinet */\r
+    ++(p_fci_internal->cFiles);\r
+\r
+    /* This is only true for files which will be written into the */\r
+    /* next cabinet of the spanning folder */\r
+    if( sizeOfFiles>payload ) {\r
+\r
+      /* Files which data will be partially written into the current cabinet */\r
+      if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||\r
+          cffile.iFolder==cffileCONTINUED_TO_NEXT\r
+        ) {\r
+        if( sizeOfFilesPrev<=payload ) {\r
+          /* The size of the uncompressed, data of a spanning file in a */\r
+          /* spanning data */\r
+          cbFileRemainer=sizeOfFiles-payload;\r
+        }\r
+        cffile.iFolder=cffileCONTINUED_FROM_PREV;\r
+      } else {\r
+        cffile.iFolder=0;\r
+      }\r
+\r
+      /* write cffile into handleCFFILE1new */\r
+      if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */\r
+        &cffile, /* memory buffer */\r
+        sizeof(cffile), /* number of bytes to copy */\r
+        err, p_fci_internal->pv) != sizeof(cffile) ) {\r
+        /* TODO write error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      *psizeFileCFFILE1new += sizeof(cffile);\r
+      /* write name of file into handleCFFILE1new */\r
+      if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */\r
+        p_fci_internal->data_out, /* memory buffer */\r
+        strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */\r
+        err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {\r
+        /* TODO write error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1;\r
+    }\r
+\r
+  } /* END OF while */\r
+  p_fci_internal->cbFileRemainer=cbFileRemainer;\r
+  return TRUE;\r
+} /* end of fci_flushfolder_copy_cffile */\r
+\r
+\r
+\r
+\r
+static BOOL fci_flush_folder(\r
        HFCI                  hfci,\r
        BOOL                  fGetNextCab,\r
        PFNFCIGETNEXTCABINET  pfnfcignc,\r
        PFNFCISTATUS          pfnfcis)\r
 {\r
-    FIXME("(%p, %d, %p, %p): stub\n", hfci, fGetNextCab, pfnfcignc, pfnfcis);\r
+  int err;\r
+  int handleCFDATA1new;                         /* handle for new  temp file */\r
+  char szFileNameCFDATA1new[CB_MAX_FILENAME];  /* name buffer for temp file */\r
+  int handleCFFILE1new;                         /* handle for new  temp file */\r
+  char szFileNameCFFILE1new[CB_MAX_FILENAME];  /* name buffer for temp file */\r
+  UINT cbReserveCFData, cbReserveCFFolder;\r
+  char* reserved;\r
+  cab_ULONG sizeFileCFDATA1new=0;\r
+  cab_ULONG sizeFileCFFILE1new=0;\r
+  cab_ULONG sizeFileCFDATA2old;\r
+  cab_ULONG payload;\r
+  cab_ULONG read_result;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  /* test hfci */\r
+  if (!REALLY_IS_FCI(hfci)) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return FALSE;\r
+  }\r
 \r
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
+  if ((!pfnfcignc) || (!pfnfcis)) {\r
+    p_fci_internal->perf->erfOper = FCIERR_NONE;\r
+    p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;\r
+    p_fci_internal->perf->fError = TRUE;\r
 \r
+    SetLastError(ERROR_BAD_ARGUMENTS);\r
     return FALSE;\r
-}\r
+  }\r
 \r
-/***********************************************************************\r
- *             FCIFlushFolder (CABINET.12)\r
- */\r
-BOOL __cdecl FCIFlushFolder(\r
-       HFCI                  hfci,\r
-       PFNFCIGETNEXTCABINET  pfnfcignc,\r
-       PFNFCISTATUS          pfnfcis)\r
-{\r
-    FIXME("(%p, %p, %p): stub\n", hfci, pfnfcignc, pfnfcis);\r
+  if( p_fci_internal->fGetNextCabInVain &&\r
+      p_fci_internal->fNextCab ){\r
+    /* TODO internal error */\r
+    return FALSE;\r
+  }\r
+\r
+  /* If there was no FCIAddFile or FCIFlushFolder has already been called */\r
+  /* this function will return TRUE */\r
+  if( p_fci_internal->sizeFileCFFILE1 == 0 ) {\r
+    if ( p_fci_internal->sizeFileCFDATA1 != 0 ) {\r
+      /* TODO error handling */\r
+      return FALSE;\r
+    }\r
+    return TRUE;\r
+  }\r
 \r
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
+  if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+\r
+  /* FCIFlushFolder has already been called... */\r
+  if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) {\r
+    if (p_fci_internal->sizeFileCFFILE2==0) {\r
+      /* TODO set error code */\r
+      return FALSE;\r
+    }\r
+    return TRUE;\r
+  }\r
+\r
+  /* TODO check what will happen when return FALSE later */\r
+  /* and p_fci_internal->fSplitFolder is set to FALSE */\r
+  p_fci_internal->fSplitFolder=FALSE;\r
+\r
+\r
+  if( p_fci_internal->fGetNextCabInVain ||\r
+      p_fci_internal->fNextCab ){\r
+    cbReserveCFData   = p_fci_internal->oldCCAB.cbReserveCFData;\r
+    cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+  } else {\r
+    cbReserveCFData   = p_fci_internal->pccab->cbReserveCFData;\r
+    cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder;\r
+  }\r
+\r
+  /* START of COPY */\r
+  /* if there is data in p_fci_internal->data_in */\r
+  if (p_fci_internal->cdata_in!=0) {\r
+\r
+    if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;\r
+\r
+  }\r
+  /* reset to get the number of data blocks of this folder which are */\r
+  /* actually in this cabinet ( at least partially ) */\r
+  p_fci_internal->cDataBlocks=0;\r
+\r
+  if ( p_fci_internal->fNextCab ||\r
+       p_fci_internal->fGetNextCabInVain ) {\r
+    read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+\r
+                 p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  } else {\r
+    read_result= p_fci_internal->pccab->cbReserveCFHeader+\r
+                 p_fci_internal->pccab->cbReserveCFFolder;\r
+    if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  }\r
+  if (p_fci_internal->fPrevCab) {\r
+    read_result+=strlen(p_fci_internal->szPrevCab)+1 +\r
+      strlen(p_fci_internal->szPrevDisk)+1;\r
+  }\r
+  if (p_fci_internal->fNextCab) {\r
+    read_result+=strlen(p_fci_internal->pccab->szCab)+1 +\r
+      strlen(p_fci_internal->pccab->szDisk)+1;\r
+  }\r
 \r
+  p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+\r
+      sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+\r
+      p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+\r
+      p_fci_internal->sizeFileCFDATA1;\r
+  p_fci_internal->statusFolderCopied = 0;\r
+\r
+  /* report status with pfnfcis about copied size of folder */\r
+  if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,\r
+      p_fci_internal->statusFolderTotal, /* TODO total folder size */\r
+      p_fci_internal->pv) == -1) {\r
+    /* TODO set error code and abort */\r
     return FALSE;\r
-}\r
+  }\r
 \r
-/***********************************************************************\r
- *             FCIDestroy (CABINET.14)\r
- *\r
- * Frees a handle created by FCICreate.\r
- * Only reason for failure would be an invalid handle.\r
- *\r
- * PARAMS\r
- *   hfci [I] The HFCI to free\r
- *\r
- * RETURNS\r
- *   TRUE for success\r
- *   FALSE for failure\r
- */\r
-BOOL __cdecl FCIDestroy(HFCI hfci)\r
-{\r
-  if (REALLY_IS_FCI(hfci)) {\r
-    PFCI_INT(hfci)->FCI_Intmagic = 0;\r
-    PFDI_FREE(hfci, hfci);\r
-    /*return TRUE; */\r
+  /* get a new temp file */\r
+  if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err,\r
+    p_fci_internal->pv);\r
+\r
+  /* get a new temp file */\r
+  if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+  handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err,\r
+    p_fci_internal->pv);\r
+\r
+  /* USE the variable read_result */\r
+  if ( p_fci_internal->fNextCab ||\r
+       p_fci_internal->fGetNextCabInVain ) {\r
+    read_result= p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  } else {\r
+    read_result= p_fci_internal->pccab->cbReserveCFHeader;\r
+    if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  }\r
+  if (p_fci_internal->fPrevCab) {\r
+    read_result+=strlen(p_fci_internal->szPrevCab)+1 +\r
+      strlen(p_fci_internal->szPrevDisk)+1;\r
+  }\r
+  read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 +\r
+    p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER;\r
+\r
+  if(p_fci_internal->sizeFileCFFILE1!=0) {\r
+    read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder;\r
+  }\r
+\r
+  /* Check if multiple cabinets have to be created. */\r
+\r
+  /* Might be too much data for the maximum allowed cabinet size.*/\r
+  /* When any further data will be added later, it might not */\r
+  /* be possible to flush the cabinet, because there might */\r
+  /* not be enough space to store the name of the following */\r
+  /* cabinet and name of the corresponding disk. */\r
+  /* So take care of this and get the name of the next cabinet */\r
+  if( p_fci_internal->fGetNextCabInVain==FALSE &&\r
+      p_fci_internal->fNextCab==FALSE &&\r
+      (\r
+        (\r
+          p_fci_internal->pccab->cb < read_result +\r
+          p_fci_internal->sizeFileCFDATA1 +\r
+          p_fci_internal->sizeFileCFFILE1 +\r
+          CB_MAX_CABINET_NAME +   /* next cabinet name */\r
+          CB_MAX_DISK_NAME        /* next disk name */\r
+        ) || fGetNextCab\r
+      )\r
+  ) {\r
+    /* save CCAB */\r
+    memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));\r
+    /* increment cabinet index */\r
+    ++(p_fci_internal->pccab->iCab);\r
+    /* get name of next cabinet */\r
+    if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */\r
+        p_fci_internal->pv)) {\r
+      /* TODO error handling */\r
+      PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+      PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+      return FALSE;\r
+    }\r
+\r
+    /* Skip a few lines of code. This is catched by the next if. */\r
+    p_fci_internal->fGetNextCabInVain=TRUE;\r
+  }\r
+\r
+  /* too much data for cabinet */\r
+  if( (p_fci_internal->fGetNextCabInVain ||\r
+        p_fci_internal->fNextCab ) &&\r
+      (\r
+        (\r
+          p_fci_internal->oldCCAB.cb < read_result +\r
+          p_fci_internal->sizeFileCFDATA1 +\r
+          p_fci_internal->sizeFileCFFILE1 +\r
+          strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */\r
+          strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */\r
+        ) || fGetNextCab\r
+      )\r
+  ) {\r
+    p_fci_internal->fGetNextCabInVain=FALSE;\r
+    p_fci_internal->fNextCab=TRUE;\r
+\r
+    /* return FALSE if there is not enough space left*/\r
+    /* this should never happen */\r
+    if (p_fci_internal->oldCCAB.cb <=\r
+        p_fci_internal->sizeFileCFFILE1 +\r
+        read_result +\r
+        strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */\r
+        strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */\r
+    ) {\r
+\r
+      PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+      PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+\r
+      /* close and delete p_fci_internal->handleCFFILE1 */\r
+      PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+      PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);\r
+      /* TODO error handling of err */\r
+\r
+      return FALSE;\r
+    }\r
+\r
+    /* the folder will be split across cabinets */\r
+    p_fci_internal->fSplitFolder=TRUE;\r
+\r
+  } else {\r
+    /* this should never happen */\r
+    if (p_fci_internal->fNextCab) {\r
+      /* TODO internal error */\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  /* set seek of p_fci_internal->handleCFDATA1 to 0 */\r
+  if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err,\r
+    p_fci_internal->pv) !=0 ) {\r
+    /* TODO wrong return value */\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* save size of file CFDATA2 - required for the folder's offset to data */\r
+  sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2;\r
+\r
+  if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) {\r
+    p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+    p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+    p_fci_internal->perf->fError = TRUE;\r
+    SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+\r
+  if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err,\r
+      handleCFDATA1new, &sizeFileCFDATA1new, &payload\r
+  )) {\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_FREE(hfci,reserved);\r
+    return FALSE;\r
+  }\r
+\r
+  PFCI_FREE(hfci,reserved);\r
+\r
+  if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder,\r
+       sizeFileCFDATA2old )) {\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+\r
+  if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new,\r
+      &sizeFileCFFILE1new, payload)) {\r
+    PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    return FALSE;\r
+  }\r
+\r
+  /* close and delete p_fci_internal->handleCFDATA1 */\r
+  PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+\r
+  /* put new CFDATA1 into hfci */\r
+  memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new,\r
+    CB_MAX_FILENAME);\r
+\r
+  /* put CFDATA1 file handle */\r
+  PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new;\r
+  /* set file size */\r
+  PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new;\r
+\r
+  /* close and delete PFCI_INT(hfci)->handleCFFILE1 */\r
+  PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+\r
+  /* put new CFFILE1 into hfci */\r
+  memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new,\r
+    CB_MAX_FILENAME);\r
+\r
+  /* put CFFILE1 file handle */\r
+  p_fci_internal->handleCFFILE1 = handleCFFILE1new;\r
+  /* set file size */\r
+  p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new;\r
+\r
+  ++(p_fci_internal->cFolders);\r
+\r
+  /* reset CFFolder specific information */\r
+  p_fci_internal->cDataBlocks=0;\r
+  p_fci_internal->cCompressedBytesInFolder=0;\r
+\r
+  return TRUE;\r
+}  /* end of fci_flush_folder */\r
+\r
+\r
+\r
+\r
+static BOOL fci_flush_cabinet(\r
+       HFCI                  hfci,\r
+       BOOL                  fGetNextCab,\r
+       PFNFCIGETNEXTCABINET  pfnfcignc,\r
+       PFNFCISTATUS          pfnfcis)\r
+{\r
+  int err;\r
+  CFHEADER cfheader;\r
+  struct {\r
+    cab_UWORD  cbCFHeader;\r
+    cab_UBYTE  cbCFFolder;\r
+    cab_UBYTE  cbCFData;\r
+  } cfreserved;\r
+  CFFOLDER cffolder;\r
+  cab_ULONG read_result;\r
+  int handleCABINET;                            /* file handle for cabinet   */\r
+  char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */\r
+  UINT cbReserveCFHeader, cbReserveCFFolder, i;\r
+  char* reserved;\r
+  BOOL returntrue=FALSE;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */\r
+\r
+  /* when FCIFlushCabinet was or FCIAddFile wasn't called */\r
+  if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) {\r
+    returntrue=TRUE;\r
+  }\r
+\r
+  if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){\r
+    /* TODO set error */\r
+    return FALSE;\r
+  }\r
+\r
+  if(returntrue) return TRUE;\r
+\r
+  if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) {\r
+      /* TODO internal error */\r
+      return FALSE;\r
+  }\r
+\r
+  if( p_fci_internal->fNextCab ||\r
+      p_fci_internal->fGetNextCabInVain ) {\r
+    cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+    cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+    /* safety */\r
+    if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH ||\r
+        strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) {\r
+      /* TODO set error */\r
+      return FALSE;\r
+    }\r
+    /* get the full name of the cabinet */\r
+    memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath,\r
+      CB_MAX_CAB_PATH);\r
+    memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),\r
+      p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME);\r
+  } else {\r
+    cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder;\r
+    cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader;\r
+    /* safety */\r
+    if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH ||\r
+        strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) {\r
+      /* TODO set error */\r
+      return FALSE;\r
+    }\r
+    /* get the full name of the cabinet */\r
+    memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath,\r
+      CB_MAX_CAB_PATH);\r
+    memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),\r
+      p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME);\r
+  }\r
+\r
+  /* create the cabinet */\r
+  handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET,\r
+    33538, 384, &err, p_fci_internal->pv );\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
+\r
+  memcpy(cfheader.signature,"!CAB",4);\r
+  cfheader.reserved1=0;\r
+  cfheader.cbCabinet=   /* size of the cabinet file in bytes */\r
+    sizeof(CFHEADER) +\r
+    p_fci_internal->sizeFileCFFOLDER +\r
+    p_fci_internal->sizeFileCFFILE2 +\r
+    p_fci_internal->sizeFileCFDATA2;\r
+\r
+  if (p_fci_internal->fPrevCab) {\r
+    cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 +\r
+      strlen(p_fci_internal->szPrevDisk)+1;\r
+  }\r
+  if (p_fci_internal->fNextCab) {\r
+    cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 +\r
+      strlen(p_fci_internal->pccab->szDisk)+1;\r
+  }\r
+  if( p_fci_internal->fNextCab ||\r
+      p_fci_internal->fGetNextCabInVain ) {\r
+    cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      cfheader.cbCabinet+=4;\r
+    }\r
+  } else {\r
+    cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader;\r
+    if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      cfheader.cbCabinet+=4;\r
+    }\r
+  }\r
+\r
+  cfheader.reserved2=0;\r
+  cfheader.coffFiles=    /* offset to first CFFILE section */\r
+   cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 -\r
+   p_fci_internal->sizeFileCFDATA2;\r
+\r
+  cfheader.reserved3=0;\r
+  cfheader.versionMinor=3;\r
+  cfheader.versionMajor=1;\r
+  /* number of CFFOLDER entries in the cabinet */\r
+  cfheader.cFolders=p_fci_internal->cFolders;\r
+  /* number of CFFILE entries in the cabinet */\r
+  cfheader.cFiles=p_fci_internal->cFiles;\r
+  cfheader.flags=0;    /* 1=prev cab, 2=next cabinet, 4=reserved setions */\r
+\r
+  if( p_fci_internal->fPrevCab ) {\r
+    cfheader.flags = cfheadPREV_CABINET;\r
+  }\r
+\r
+  if( p_fci_internal->fNextCab ) {\r
+    cfheader.flags |= cfheadNEXT_CABINET;\r
+  }\r
+\r
+  if( p_fci_internal->fNextCab ||\r
+      p_fci_internal->fGetNextCabInVain ) {\r
+    if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      cfheader.flags |= cfheadRESERVE_PRESENT;\r
+    }\r
+    cfheader.setID = p_fci_internal->oldCCAB.setID;\r
+    cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1;\r
+  } else {\r
+    if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      cfheader.flags |= cfheadRESERVE_PRESENT;\r
+    }\r
+    cfheader.setID = p_fci_internal->pccab->setID;\r
+    cfheader.iCabinet = p_fci_internal->pccab->iCab-1;\r
+  }\r
+\r
+  /* write CFHEADER into cabinet file */\r
+  if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+      &cfheader, /* memory buffer */\r
+      sizeof(cfheader), /* number of bytes to copy */\r
+      &err, p_fci_internal->pv) != sizeof(cfheader) ) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  if( cfheader.flags & cfheadRESERVE_PRESENT ) {\r
+    /* NOTE: No checks for maximum value overflows as designed by MS!!! */\r
+    cfreserved.cbCFHeader = cbReserveCFHeader;\r
+    cfreserved.cbCFFolder = cbReserveCFFolder;\r
+    if( p_fci_internal->fNextCab ||\r
+        p_fci_internal->fGetNextCabInVain ) {\r
+      cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData;\r
+    } else {\r
+      cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData;\r
+    }\r
+    /* write reserved info into cabinet file */\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        &cfreserved, /* memory buffer */\r
+        sizeof(cfreserved), /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != sizeof(cfreserved) ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+  }\r
+\r
+  /* add optional reserved area */\r
+  if (cbReserveCFHeader!=0) {\r
+    if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) {\r
+      p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+      p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+      p_fci_internal->perf->fError = TRUE;\r
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+      return FALSE;\r
+    }\r
+    for(i=0;i<cbReserveCFHeader;) {\r
+      reserved[i++]='\0';\r
+    }\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        reserved, /* memory buffer */\r
+        cbReserveCFHeader, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != cbReserveCFHeader ) {\r
+      PFCI_FREE(hfci, reserved);\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+    PFCI_FREE(hfci, reserved);\r
+  }\r
+\r
+  if( cfheader.flags & cfheadPREV_CABINET ) {\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        p_fci_internal->szPrevCab, /* memory buffer */\r
+        strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        p_fci_internal->szPrevDisk, /* memory buffer */\r
+        strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+  }\r
+\r
+  if( cfheader.flags & cfheadNEXT_CABINET ) {\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        p_fci_internal->pccab->szCab, /* memory buffer */\r
+        strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+        p_fci_internal->pccab->szDisk, /* memory buffer */\r
+        strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+  }\r
+\r
+  /* set seek of p_fci_internal->handleCFFOLDER to 0 */\r
+  if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER,\r
+      0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {\r
+    /* TODO  wrong return value */\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* while not all CFFOLDER structures have been copied into the cabinet do */\r
+  while(!FALSE) {\r
+    /* use the variable read_result */\r
+    /* read cffolder of p_fci_internal->handleCFFOLDER */\r
+    read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */\r
+        &cffolder, /* memory buffer */\r
+        sizeof(cffolder), /* number of bytes to copy */\r
+        &err, p_fci_internal->pv);\r
+    if( read_result != sizeof(cffolder) ) {\r
+      if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/\r
+      /* TODO read error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    /* add size of header size of all CFFOLDERs and size of all CFFILEs */\r
+    cffolder.coffCabStart +=\r
+      p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+      sizeof(CFHEADER);\r
+    if( p_fci_internal->fNextCab ||\r
+        p_fci_internal->fGetNextCabInVain ) {\r
+      cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+    } else {\r
+      cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader;\r
+    }\r
+\r
+    if (p_fci_internal->fPrevCab) {\r
+      cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 +\r
+        strlen(p_fci_internal->szPrevDisk)+1;\r
+    }\r
+\r
+    if (p_fci_internal->fNextCab) {\r
+      cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 +\r
+        strlen(p_fci_internal->oldCCAB.szDisk)+1;\r
+    }\r
+\r
+    if( p_fci_internal->fNextCab ||\r
+        p_fci_internal->fGetNextCabInVain ) {\r
+      cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+      if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+        cffolder.coffCabStart += 4;\r
+      }\r
+    } else {\r
+      cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader;\r
+      if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+          p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+          p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+        cffolder.coffCabStart += 4;\r
+      }\r
+    }\r
+\r
+    /* write cffolder to cabinet file */\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+      &cffolder, /* memory buffer */\r
+      sizeof(cffolder), /* number of bytes to copy */\r
+      &err, p_fci_internal->pv) != sizeof(cffolder) ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    /* add optional reserved area */\r
+\r
+    /* This allocation and freeing at each CFFolder block is a bit */\r
+    /* inefficent, but it's harder to forget about freeing the buffer :-). */\r
+    /* Reserved areas are used seldom besides that... */\r
+    if (cbReserveCFFolder!=0) {\r
+      if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) {\r
+        p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+        p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+        p_fci_internal->perf->fError = TRUE;\r
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+        return FALSE;\r
+      }\r
+\r
+      if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */\r
+          reserved, /* memory buffer */\r
+          cbReserveCFFolder, /* number of bytes to copy */\r
+          &err, p_fci_internal->pv) != cbReserveCFFolder ) {\r
+        PFCI_FREE(hfci, reserved);\r
+        /* TODO read error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+          reserved, /* memory buffer */\r
+          cbReserveCFFolder, /* number of bytes to copy */\r
+          &err, p_fci_internal->pv) != cbReserveCFFolder ) {\r
+        PFCI_FREE(hfci, reserved);\r
+        /* TODO read error */\r
+        return FALSE;\r
+      }\r
+      /* TODO error handling of err */\r
+\r
+      PFCI_FREE(hfci, reserved);\r
+    }\r
+\r
+  } /* END OF while */\r
+\r
+  /* set seek of p_fci_internal->handleCFFILE2 to 0 */\r
+  if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2,\r
+      0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {\r
+    /* TODO  wrong return value */\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* while not all CFFILE structures have been copied to the cabinet do */\r
+  while(!FALSE) {\r
+    /* REUSE the variable read_result */\r
+    /* REUSE the buffer p_fci_internal->data_out AGAIN */\r
+    /* read a block from p_fci_internal->handleCFFILE2 */\r
+    read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */,\r
+        p_fci_internal->data_out, /* memory buffer */\r
+        32768, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv);\r
+    if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */\r
+    /* TODO error handling of err */\r
+\r
+    /* write the block to the cabinet file */\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+      p_fci_internal->data_out, /* memory buffer */\r
+      read_result, /* number of bytes to copy */\r
+      &err, p_fci_internal->pv) != read_result ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    if (p_fci_internal->fSplitFolder==FALSE) {\r
+      p_fci_internal->statusFolderCopied = 0;\r
+      p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+\r
+        p_fci_internal->sizeFileCFFILE2;\r
+    }\r
+    p_fci_internal->statusFolderCopied += read_result;\r
+\r
+/* TODO is this correct */\r
+    /* report status with pfnfcis about copied size of folder */\r
+    if( (*pfnfcis)(statusFolder,\r
+      p_fci_internal->statusFolderCopied, /* length of copied blocks */\r
+      p_fci_internal->statusFolderTotal, /* total size of folder */\r
+      p_fci_internal->pv) == -1) {\r
+      /* TODO set error code and abort */\r
+      return FALSE;\r
+    }\r
+\r
+  } /* END OF while */\r
+\r
+  /* set seek of p_fci_internal->handleCFDATA2 to 0 */\r
+  if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2,\r
+      0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {\r
+    /* TODO  wrong return value */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* reset the number of folders for the next cabinet */\r
+  p_fci_internal->cFolders=0;\r
+  /* reset the number of files for the next cabinet */\r
+  p_fci_internal->cFiles=0;\r
+\r
+  /* while not all CFDATA structures have been copied to the cabinet do */\r
+  while(!FALSE) {\r
+    /* REUSE the variable read_result AGAIN */\r
+    /* REUSE the buffer p_fci_internal->data_out AGAIN */\r
+    /* read a block from p_fci_internal->handleCFDATA2 */\r
+    read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */,\r
+        p_fci_internal->data_out, /* memory buffer */\r
+        32768, /* number of bytes to copy */\r
+        &err, p_fci_internal->pv);\r
+    if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */\r
+    /* TODO error handling of err */\r
+\r
+    /* write the block to the cabinet file */\r
+    if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+      p_fci_internal->data_out, /* memory buffer */\r
+      read_result, /* number of bytes to copy */\r
+      &err, p_fci_internal->pv) != read_result ) {\r
+      /* TODO write error */\r
+      return FALSE;\r
+    }\r
+    /* TODO error handling of err */\r
+\r
+    p_fci_internal->statusFolderCopied += read_result;\r
+    /* report status with pfnfcis about copied size of folder */\r
+    if( (*pfnfcis)(statusFolder,\r
+        p_fci_internal->statusFolderCopied, /* length of copied blocks */\r
+        p_fci_internal->statusFolderTotal, /* total size of folder */\r
+        p_fci_internal->pv) == -1) {\r
+      /* TODO set error code and abort */\r
+      return FALSE;\r
+    }\r
+  } /* END OF while */\r
+\r
+  /* set seek of the cabinet file to 0 */\r
+  if( PFCI_SEEK(hfci, handleCABINET,\r
+      0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {\r
+    /* TODO  wrong return value */\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* write the signature "MSCF" into the cabinet file */\r
+  memcpy( cfheader.signature, "MSCF", 4 );\r
+  if( PFCI_WRITE(hfci, handleCABINET, /* file handle */\r
+    &cfheader, /* memory buffer */\r
+    4, /* number of bytes to copy */\r
+    &err, p_fci_internal->pv) != 4 ) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  /* close the cabinet file */\r
+  PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+\r
+\r
+/* COPIED FROM FCIDestroy */\r
+\r
+  PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,\r
+    p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,\r
+    p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+  PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,\r
+    p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+\r
+/* END OF copied from FCIDestroy */\r
+\r
+  /* get 3 temporary files and open them */\r
+  /* write names and handles to hfci */\r
+\r
+\r
+  p_fci_internal->sizeFileCFDATA2  = 0;\r
+  p_fci_internal->sizeFileCFFILE2  = 0;\r
+  p_fci_internal->sizeFileCFFOLDER = 0;\r
+\r
+/* COPIED FROM FCICreate */\r
+\r
+  /* CFDATA with checksum and ready to be copied into cabinet */\r
+  if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
+\r
+  /* array of all CFFILE in a folder, ready to be copied into cabinet */\r
+  if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,\r
+      CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
+\r
+  /* array of all CFFILE in a folder, ready to be copied into cabinet */\r
+  if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) {\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+  /* safety */\r
+  if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,\r
+    p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv);\r
+  /* TODO check handle */\r
+  /* TODO error checking of err */\r
+\r
+/* END OF copied from FCICreate */\r
+\r
+\r
+  /* TODO close and delete new files when return FALSE */\r
+\r
+\r
+  /* report status with pfnfcis about copied size of folder */\r
+  if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */\r
+    cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) {\r
+    /* TODO set error code and abort */\r
+    return FALSE;\r
+  }\r
+\r
+  p_fci_internal->fPrevCab=TRUE;\r
+  /* The sections szPrevCab and szPrevDisk are not being updated, because */\r
+  /* MS CABINET.DLL always puts the first cabinet name and disk into them */\r
+\r
+  if (p_fci_internal->fNextCab) {\r
+    p_fci_internal->fNextCab=FALSE;\r
+\r
+    if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) {\r
+      /* THIS CAN NEVER HAPPEN */\r
+      /* TODO set error code */\r
+      return FALSE;\r
+    }\r
+\r
+/* COPIED FROM FCIAddFile and modified */\r
+\r
+    /* REUSE the variable read_result */\r
+    if (p_fci_internal->fGetNextCabInVain) {\r
+      read_result=p_fci_internal->oldCCAB.cbReserveCFHeader;\r
+      if(p_fci_internal->sizeFileCFFILE1!=0) {\r
+        read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+      }\r
+      if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+          p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+        read_result+=4;\r
+      }\r
+    } else {\r
+      read_result=p_fci_internal->pccab->cbReserveCFHeader;\r
+      if(p_fci_internal->sizeFileCFFILE1!=0) {\r
+        read_result+=p_fci_internal->pccab->cbReserveCFFolder;\r
+      }\r
+      if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+          p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+          p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+        read_result+=4;\r
+      }\r
+    }\r
+    if ( p_fci_internal->fPrevCab ) {\r
+      read_result+= strlen(p_fci_internal->szPrevCab)+1+\r
+        strlen(p_fci_internal->szPrevDisk)+1;\r
+    }\r
+    read_result+= p_fci_internal->sizeFileCFDATA1 +\r
+      p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+      p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+      sizeof(CFHEADER) +\r
+      sizeof(CFFOLDER); /* set size of new CFFolder entry */\r
+\r
+    if( p_fci_internal->fNewPrevious ) {\r
+      memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab,\r
+        CB_MAX_CABINET_NAME);\r
+      memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk,\r
+        CB_MAX_DISK_NAME);\r
+      p_fci_internal->fNewPrevious=FALSE;\r
+    }\r
+\r
+    /* too much data for the maximum size of a cabinet */\r
+    if( p_fci_internal->fGetNextCabInVain==FALSE &&\r
+        p_fci_internal->pccab->cb < read_result ) {\r
+      return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);\r
+    }\r
+\r
+    /* Might be too much data for the maximum size of a cabinet.*/\r
+    /* When any further data will be added later, it might not */\r
+    /* be possible to flush the cabinet, because there might */\r
+    /* not be enough space to store the name of the following */\r
+    /* cabinet and name of the corresponding disk. */\r
+    /* So take care of this and get the name of the next cabinet */\r
+    if (p_fci_internal->fGetNextCabInVain==FALSE && (\r
+      p_fci_internal->pccab->cb < read_result +\r
+      CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME\r
+    )) {\r
+      /* save CCAB */\r
+      memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));\r
+      /* increment cabinet index */\r
+      ++(p_fci_internal->pccab->iCab);\r
+      /* get name of next cabinet */\r
+      if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */\r
+          p_fci_internal->pv)) {\r
+        /* TODO error handling */\r
+        return FALSE;\r
+      }\r
+      /* Skip a few lines of code. This is catched by the next if. */\r
+      p_fci_internal->fGetNextCabInVain=TRUE;\r
+    }\r
+\r
+    /* too much data for cabinet */\r
+    if (p_fci_internal->fGetNextCabInVain && (\r
+        p_fci_internal->oldCCAB.cb < read_result +\r
+        strlen(p_fci_internal->oldCCAB.szCab)+1+\r
+        strlen(p_fci_internal->oldCCAB.szDisk)+1\r
+    )) {\r
+      p_fci_internal->fGetNextCabInVain=FALSE;\r
+      p_fci_internal->fNextCab=TRUE;\r
+      return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);\r
+    }\r
+\r
+    /* if the FolderThreshold has been reached flush the folder automatically */\r
+    if( p_fci_internal->fGetNextCabInVain ) {\r
+      if( p_fci_internal->cCompressedBytesInFolder >=\r
+          p_fci_internal->oldCCAB.cbFolderThresh) {\r
+        return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);\r
+      }\r
+    } else {\r
+      if( p_fci_internal->cCompressedBytesInFolder >=\r
+          p_fci_internal->pccab->cbFolderThresh) {\r
+        return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);\r
+      }\r
+    }\r
+\r
+/* END OF COPIED FROM FCIAddFile and modified */\r
+\r
+    if( p_fci_internal->sizeFileCFFILE1>0 ) {\r
+      if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE;\r
+      p_fci_internal->fNewPrevious=TRUE;\r
+    }\r
+  } else {\r
+    p_fci_internal->fNewPrevious=FALSE;\r
+    if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) {\r
+      /* THIS MAY NEVER HAPPEN */\r
+      /* TODO set error structures */\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+} /* end of fci_flush_cabinet */\r
+\r
+\r
+\r
+\r
+\r
+/***********************************************************************\r
+ *             FCIAddFile (CABINET.11)\r
+ *\r
+ * FCIAddFile adds a file to the to be created cabinet file\r
+ *\r
+ * PARAMS\r
+ *   hfci          [I]  An HFCI from FCICreate\r
+ *   pszSourceFile [I]  A pointer to a C string which contains the name and\r
+ *                      location of the file which will be added to the cabinet\r
+ *   pszFileName   [I]  A pointer to a C string which contains the name under\r
+ *                      which the file will be stored in the cabinet\r
+ *   fExecute      [I]  A boolean value which indicates if the file should be\r
+ *                      executed after extraction of self extracting\r
+ *                      executables\r
+ *   pfnfcignc     [I]  A pointer to a function which gets information about\r
+ *                      the next cabinet\r
+ *   pfnfcis      [IO]  A pointer to a function which will report status\r
+ *                      information about the compression process\r
+ *   pfnfcioi      [I]  A pointer to a function which reports file attributes\r
+ *                      and time and date information\r
+ *   typeCompress  [I]  Compression type\r
+ *\r
+ * RETURNS\r
+ *   On success, returns TRUE\r
+ *   On failure, returns FALSE\r
+ *\r
+ * INCLUDES\r
+ *   fci.h\r
+ *\r
+ */\r
+BOOL __cdecl FCIAddFile(\r
+       HFCI                  hfci,\r
+       char                 *pszSourceFile,\r
+       char                 *pszFileName,\r
+       BOOL                  fExecute,\r
+       PFNFCIGETNEXTCABINET  pfnfcignc,\r
+       PFNFCISTATUS          pfnfcis,\r
+       PFNFCIGETOPENINFO     pfnfcigoi,\r
+       TCOMP                 typeCompress)\r
+{\r
+  int err;\r
+  CFFILE cffile;\r
+  cab_ULONG read_result;\r
+  int file_handle;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  /* test hfci */\r
+  if (!REALLY_IS_FCI(hfci)) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return FALSE;\r
+  }\r
+\r
+  if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||\r
+      (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {\r
+    p_fci_internal->perf->erfOper = FCIERR_NONE;\r
+    p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;\r
+    p_fci_internal->perf->fError = TRUE;\r
+\r
+    SetLastError(ERROR_BAD_ARGUMENTS);\r
+    return FALSE;\r
+  }\r
+\r
+  /* TODO check if pszSourceFile??? */\r
+\r
+  if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {\r
+    /* TODO internal error */\r
+    return FALSE;\r
+  }\r
+\r
+  if(p_fci_internal->fNextCab) {\r
+    /* TODO internal error */\r
+    return FALSE;\r
+  }\r
+\r
+  cffile.cbFile=0; /* size of the to be added file*/\r
+  /* offset of the uncompressed file in the folder */\r
+  cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in;\r
+  /* number of folder in the cabinet or special 0=first  */\r
+  cffile.iFolder = p_fci_internal->cFolders;\r
+\r
+  /* allocation of memory */\r
+  if (p_fci_internal->data_in==NULL) {\r
+    if (p_fci_internal->cdata_in!=0) {\r
+      /* TODO error handling */\r
+      return FALSE;\r
+    }\r
+    if (p_fci_internal->data_out!=NULL) {\r
+      /* TODO error handling */\r
+      return FALSE;\r
+    }\r
+    if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) {\r
+      p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+      p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+      p_fci_internal->perf->fError = TRUE;\r
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+      return FALSE;\r
+    }\r
+    if (p_fci_internal->data_out==NULL) {\r
+      if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){\r
+        p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;\r
+        p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;\r
+        p_fci_internal->perf->fError = TRUE;\r
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (p_fci_internal->data_out==NULL) {\r
+    PFCI_FREE(hfci,p_fci_internal->data_in);\r
+    /* TODO error handling */\r
+    return FALSE;\r
+  }\r
+\r
+  /* get information about the file */\r
+  file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time),\r
+    &(cffile.attribs), &err, p_fci_internal->pv);\r
+  /* TODO check file_handle */\r
+  /* TODO error handling of err */\r
+\r
+  if (fExecute) { cffile.attribs |= _A_EXEC; }\r
+\r
+  /* REUSE the variable read_result */\r
+  if (p_fci_internal->fGetNextCabInVain) {\r
+    read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +\r
+      p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  } else {\r
+    read_result=p_fci_internal->pccab->cbReserveCFHeader +\r
+      p_fci_internal->pccab->cbReserveCFFolder;\r
+    if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  }\r
+  if ( p_fci_internal->fPrevCab ) {\r
+    read_result+= strlen(p_fci_internal->szPrevCab)+1+\r
+      strlen(p_fci_internal->szPrevDisk)+1;\r
+  }\r
+  if ( p_fci_internal->fNextCab ) { /* this is never the case */\r
+    read_result+= strlen(p_fci_internal->pccab->szCab)+1+\r
+      strlen(p_fci_internal->pccab->szDisk)+1;\r
+  }\r
+\r
+  read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +\r
+    p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+    p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+    sizeof(CFHEADER) +\r
+    sizeof(CFFOLDER); /* size of new CFFolder entry */\r
+\r
+  /* Might be too much data for the maximum size of a cabinet.*/\r
+  /* When any further data will be added later, it might not */\r
+  /* be possible to flush the cabinet, because there might */\r
+  /* not be enough space to store the name of the following */\r
+  /* cabinet and name of the corresponding disk. */\r
+  /* So take care of this and get the name of the next cabinet */\r
+  if( p_fci_internal->fGetNextCabInVain==FALSE &&\r
+      p_fci_internal->fNextCab==FALSE &&\r
+      ( p_fci_internal->pccab->cb < read_result +\r
+        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME\r
+      )\r
+  ) {\r
+    /* save CCAB */\r
+    memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));\r
+    /* increment cabinet index */\r
+    ++(p_fci_internal->pccab->iCab);\r
+    /* get name of next cabinet */\r
+    if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */\r
+        p_fci_internal->pv)) {\r
+      /* TODO error handling */\r
+      return FALSE;\r
+    }\r
+    /* Skip a few lines of code. This is catched by the next if. */\r
+    p_fci_internal->fGetNextCabInVain=TRUE;\r
+  }\r
+\r
+  if( p_fci_internal->fGetNextCabInVain &&\r
+      p_fci_internal->fNextCab\r
+  ) {\r
+    /* THIS CAN NEVER HAPPEN */\r
+    /* TODO set error code*/\r
+    return FALSE;\r
+  }\r
+\r
+  /* too much data for cabinet */\r
+  if( p_fci_internal->fGetNextCabInVain &&\r
+     (\r
+      p_fci_internal->oldCCAB.cb < read_result +\r
+      strlen(p_fci_internal->pccab->szCab)+1+\r
+      strlen(p_fci_internal->pccab->szDisk)+1\r
+  )) {\r
+    p_fci_internal->fGetNextCabInVain=FALSE;\r
+    p_fci_internal->fNextCab=TRUE;\r
+    if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE;\r
+  }\r
+\r
+  if( p_fci_internal->fNextCab ) {\r
+    /* THIS MAY NEVER HAPPEN */\r
+    /* TODO set error code*/\r
+    return FALSE;\r
+  }\r
+\r
+  /* read the contents of the file blockwize*/\r
+  while (!FALSE) {\r
+    if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {\r
+      /* TODO internal error */\r
+      return FALSE;\r
+    }\r
+\r
+    read_result = PFCI_READ(hfci, file_handle /* file handle */,\r
+      (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,\r
+      (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,\r
+      &err, p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+\r
+    if( read_result==0 ) break;\r
+\r
+    /* increment the block size */\r
+    p_fci_internal->cdata_in += read_result;\r
+\r
+    /* increment the file size */\r
+    cffile.cbFile += read_result;\r
+\r
+\r
+    if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {\r
+      /* TODO report internal error */\r
+      return FALSE;\r
+    }\r
+    /* write a whole block */\r
+    if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {\r
+\r
+      if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;\r
+    }\r
+  }\r
+\r
+  /* close the file from FCIAddFile */\r
+  PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv);\r
+  /* TODO error handling of err */\r
+\r
+  /* write cffile to p_fci_internal->handleCFFILE1 */\r
+  if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */\r
+      &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  p_fci_internal->sizeFileCFFILE1 += sizeof(cffile);\r
+\r
+  /* append the name of file*/\r
+  if (strlen(pszFileName)>=CB_MAX_FILENAME) {\r
+    /* IMPOSSIBLE */\r
+    /* TODO set error code */\r
+    return FALSE;\r
+  }\r
+  if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */\r
+      pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv)\r
+      != strlen(pszFileName)+1 ) {\r
+    /* TODO write error */\r
+    return FALSE;\r
+  }\r
+  /* TODO error handling of err */\r
+\r
+  p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1;\r
+\r
+  /* REUSE the variable read_result */\r
+  if (p_fci_internal->fGetNextCabInVain ||\r
+      p_fci_internal->fNextCab\r
+     ) {\r
+    read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +\r
+      p_fci_internal->oldCCAB.cbReserveCFFolder;\r
+    if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||\r
+        p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  } else {\r
+    read_result=p_fci_internal->pccab->cbReserveCFHeader +\r
+      p_fci_internal->pccab->cbReserveCFFolder;\r
+    if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFFolder != 0 ||\r
+        p_fci_internal->pccab->cbReserveCFData   != 0 ) {\r
+      read_result+=4;\r
+    }\r
+  }\r
+  if ( p_fci_internal->fPrevCab ) {\r
+    read_result+= strlen(p_fci_internal->szPrevCab)+1+\r
+      strlen(p_fci_internal->szPrevDisk)+1;\r
+  }\r
+  if ( p_fci_internal->fNextCab ) { /* this is never the case */\r
+    read_result+= strlen(p_fci_internal->pccab->szCab)+1+\r
+      strlen(p_fci_internal->pccab->szDisk)+1;\r
+  }\r
+  read_result+= p_fci_internal->sizeFileCFDATA1 +\r
+    p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +\r
+    p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +\r
+    sizeof(CFHEADER) +\r
+    sizeof(CFFOLDER); /* set size of new CFFolder entry */\r
+\r
+  /* too much data for the maximum size of a cabinet */\r
+  /* (ignoring the unflushed data block) */\r
+  if( p_fci_internal->fGetNextCabInVain==FALSE &&\r
+      p_fci_internal->fNextCab==FALSE && /* this is always the case */\r
+      p_fci_internal->pccab->cb < read_result ) {\r
+    return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);\r
+  }\r
+\r
+  /* Might be too much data for the maximum size of a cabinet.*/\r
+  /* When any further data will be added later, it might not */\r
+  /* be possible to flush the cabinet, because there might */\r
+  /* not be enough space to store the name of the following */\r
+  /* cabinet and name of the corresponding disk. */\r
+  /* So take care of this and get the name of the next cabinet */\r
+  /* (ignoring the unflushed data block) */\r
+  if( p_fci_internal->fGetNextCabInVain==FALSE &&\r
+      p_fci_internal->fNextCab==FALSE &&\r
+      ( p_fci_internal->pccab->cb < read_result +\r
+        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME\r
+      )\r
+  ) {\r
+    /* save CCAB */\r
+    memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));\r
+    /* increment cabinet index */\r
+    ++(p_fci_internal->pccab->iCab);\r
+    /* get name of next cabinet */\r
+    if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */\r
+        p_fci_internal->pv)) {\r
+      /* TODO error handling */\r
+      return FALSE;\r
+    }\r
+    /* Skip a few lines of code. This is catched by the next if. */\r
+    p_fci_internal->fGetNextCabInVain=TRUE;\r
+  }\r
+\r
+  if( p_fci_internal->fGetNextCabInVain &&\r
+      p_fci_internal->fNextCab\r
+  ) {\r
+    /* THIS CAN NEVER HAPPEN */\r
+    /* TODO set error code*/\r
+    return FALSE;\r
+  }\r
+\r
+  /* too much data for cabinet */\r
+  if( (p_fci_internal->fGetNextCabInVain ||\r
+      p_fci_internal->fNextCab) && (\r
+      p_fci_internal->oldCCAB.cb < read_result +\r
+      strlen(p_fci_internal->pccab->szCab)+1+\r
+      strlen(p_fci_internal->pccab->szDisk)+1\r
+  )) {\r
+\r
+    p_fci_internal->fGetNextCabInVain=FALSE;\r
+    p_fci_internal->fNextCab=TRUE;\r
+    return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);\r
+  }\r
+\r
+  if( p_fci_internal->fNextCab ) {\r
+    /* THIS MAY NEVER HAPPEN */\r
+    /* TODO set error code*/\r
+    return FALSE;\r
+  }\r
+\r
+  /* if the FolderThreshold has been reached flush the folder automatically */\r
+  if( p_fci_internal->fGetNextCabInVain ) {\r
+    if( p_fci_internal->cCompressedBytesInFolder >=\r
+        p_fci_internal->oldCCAB.cbFolderThresh) {\r
+      return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);\r
+    }\r
+  } else {\r
+    if( p_fci_internal->cCompressedBytesInFolder >=\r
+        p_fci_internal->pccab->cbFolderThresh) {\r
+      return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+} /* end of FCIAddFile */\r
+\r
+\r
+\r
+\r
+\r
+/***********************************************************************\r
+ *             FCIFlushFolder (CABINET.12)\r
+ *\r
+ * FCIFlushFolder completes the CFFolder structure under construction.\r
+ *\r
+ * All further data which is added by FCIAddFile will be associateed to\r
+ * the next CFFolder structure.\r
+ *\r
+ * FCIFlushFolder will be called by FCIAddFile automatically if the\r
+ * threshold (stored in the member cbFolderThresh of the CCAB structure\r
+ * pccab passed to FCICreate) is exceeded.\r
+ *\r
+ * FCIFlushFolder will be called by FCIFlushFolder automatically before\r
+ * any data will be written into the cabinet file.\r
+ *\r
+ * PARAMS\r
+ *   hfci          [I]  An HFCI from FCICreate\r
+ *   pfnfcignc     [I]  A pointer to a function which gets information about\r
+ *                      the next cabinet\r
+ *   pfnfcis      [IO]  A pointer to a function which will report status\r
+ *                      information about the compression process\r
+ *\r
+ * RETURNS\r
+ *   On success, returns TRUE\r
+ *   On failure, returns FALSE\r
+ *\r
+ * INCLUDES\r
+ *   fci.h\r
+ *\r
+ */\r
+BOOL __cdecl FCIFlushFolder(\r
+       HFCI                  hfci,\r
+       PFNFCIGETNEXTCABINET  pfnfcignc,\r
+       PFNFCISTATUS          pfnfcis)\r
+{\r
+  return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis);\r
+} /* end of FCIFlushFolder */\r
+\r
+\r
+\r
+/***********************************************************************\r
+ *             FCIFlushCabinet (CABINET.13)\r
+ *\r
+ * FCIFlushCabinet stores the data which has been added by FCIAddFile\r
+ * into the cabinet file. If the maximum cabinet size (stored in the\r
+ * member cb of the CCAB structure pccab passed to FCICreate) has been\r
+ * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.\r
+ * The remaining data still has to be flushed manually by calling\r
+ * FCIFlushCabinet.\r
+ *\r
+ * After FCIFlushCabinet has been called (manually) FCIAddFile must\r
+ * NOT be called again. Then hfci has to be released by FCIDestroy.\r
+ *\r
+ * PARAMS\r
+ *   hfci          [I]  An HFCI from FCICreate\r
+ *   fGetNextCab   [I]  Whether you want to add additional files to a\r
+ *                      cabinet set (TRUE) or whether you want to\r
+ *                      finalize it (FALSE)\r
+ *   pfnfcignc     [I]  A pointer to a function which gets information about\r
+ *                      the next cabinet\r
+ *   pfnfcis      [IO]  A pointer to a function which will report status\r
+ *                      information about the compression process\r
+ *\r
+ * RETURNS\r
+ *   On success, returns TRUE\r
+ *   On failure, returns FALSE\r
+ *\r
+ * INCLUDES\r
+ *   fci.h\r
+ *\r
+ */\r
+BOOL __cdecl FCIFlushCabinet(\r
+       HFCI                  hfci,\r
+       BOOL                  fGetNextCab,\r
+       PFNFCIGETNEXTCABINET  pfnfcignc,\r
+       PFNFCISTATUS          pfnfcis)\r
+{\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+\r
+  if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;\r
+\r
+  while( p_fci_internal->sizeFileCFFILE1>0 ||\r
+         p_fci_internal->sizeFileCFFILE2>0 ) {\r
+    if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+} /* end of FCIFlushCabinet */\r
+\r
+\r
+/***********************************************************************\r
+ *             FCIDestroy (CABINET.14)\r
+ *\r
+ * Frees a handle created by FCICreate.\r
+ * Only reason for failure would be an invalid handle.\r
+ *\r
+ * PARAMS\r
+ *   hfci [I] The HFCI to free\r
+ *\r
+ * RETURNS\r
+ *   TRUE for success\r
+ *   FALSE for failure\r
+ */\r
+BOOL __cdecl FCIDestroy(HFCI hfci)\r
+{\r
+  int err;\r
+  PFCI_Int p_fci_internal=((PFCI_Int)(hfci));\r
+  if (REALLY_IS_FCI(hfci)) {\r
+\r
+    /* before hfci can be removed all temporary files must be closed */\r
+    /* and deleted */\r
+    p_fci_internal->FCI_Intmagic = 0;\r
+\r
+    PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err,\r
+      p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err,\r
+      p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,\r
+      p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,\r
+      p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+    PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,\r
+      p_fci_internal->pv);\r
+    /* TODO error handling of err */\r
+\r
+    /* data in and out buffers have to be removed */\r
+    if (p_fci_internal->data_in!=NULL)\r
+      PFCI_FREE(hfci, p_fci_internal->data_in);\r
+    if (p_fci_internal->data_out!=NULL)\r
+      PFCI_FREE(hfci, p_fci_internal->data_out);\r
+\r
+    /* hfci can now be removed */\r
+    PFCI_FREE(hfci, hfci);\r
+    return TRUE;\r
   } else {\r
     SetLastError(ERROR_INVALID_HANDLE);\r
     return FALSE;\r
   }\r
 \r
-  /* Still mark as incomplete, because of other missing FCI* APIs */\r
-  FIXME("(%p): stub\n", hfci);\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return FALSE;\r
-}\r
+} /* end of FCIDestroy */\r