Fix gcc 4.0 -Wpointer-sign warnings.
[wine] / dlls / cabinet / fci.c
1 /*
2  * File Compression Interface
3  *
4  * Copyright 2002 Patrik Stridvall
5  * Copyright 2005 Gerold Jens Wucherpfennig
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23
24 There is still some work to be done:
25
26 - the ERF error structure aren't used on error
27 - no real compression yet
28 - unknown behaviour if files>4GB or cabinet >4GB
29 - incorrect status information
30 - check if the maximum size for a cabinet is too small to store any data
31 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
32
33 */
34
35
36
37 #include "config.h"
38
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winerror.h"
46 #include "winternl.h"
47 #include "fci.h"
48 #include "cabinet.h"
49
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
53
54 typedef struct {
55   cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
56   cab_ULONG reserved1;
57   cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/
58   cab_ULONG reserved2;
59   cab_ULONG coffFiles;    /* offset to first CFFILE section */
60   cab_ULONG reserved3;
61   cab_UBYTE versionMinor; /* 3 */
62   cab_UBYTE versionMajor; /* 1 */
63   cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/
64   cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/
65   cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved setions*/
66   cab_UWORD setID;        /* identification number of all cabinets in a set*/
67   cab_UWORD iCabinet;     /* number of the cabinet in a set */
68   /* additional area if "flags" were set*/
69 } CFHEADER; /* minimum 36 bytes */
70
71 typedef struct {
72   cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
73   cab_UWORD cCFData;      /* number of this folder's CFDATA sections */
74   cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
75   /* additional area if reserve flag was set */
76 } CFFOLDER; /* minumum 8 bytes */
77
78 typedef struct {
79   cab_ULONG cbFile;          /* size of the uncompressed file in bytes */
80   cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
81   cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */
82                              /* for special values see below this structure*/
83   cab_UWORD date;            /* last modification date*/
84   cab_UWORD time;            /* last modification time*/
85   cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */
86   /* ... and a C string with the name of the file */
87 } CFFILE; /* 16 bytes + name of file */
88
89
90 typedef struct {
91   cab_ULONG csum;          /* checksum of this entry*/
92   cab_UWORD cbData;        /* number of compressed bytes  */
93   cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */
94   /* optional reserved area */
95   /* compressed data */
96 } CFDATA;
97
98
99 /***********************************************************************
100  *              FCICreate (CABINET.10)
101  *
102  * FCICreate is provided with several callbacks and
103  * returns a handle which can be used to create cabinet files.
104  *
105  * PARAMS
106  *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
107  *                    returns an error condition, error information may
108  *                    be found here as well as from GetLastError.
109  *   pfnfiledest [I]  A pointer to a function which is called when a file
110  *                    is placed. Only useful for subsequent cabinet files.
111  *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
112  *                    the same interface as malloc.
113  *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
114  *                    same interface as free.
115  *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
116  *                    the same interface as _open.
117  *   pfnread     [I]  A pointer to a function which reads from a file into
118  *                    a caller-provided buffer.  Uses the same interface
119  *                    as _read.
120  *   pfnwrite    [I]  A pointer to a function which writes to a file from
121  *                    a caller-provided buffer.  Uses the same interface
122  *                    as _write.
123  *   pfnclose    [I]  A pointer to a function which closes a file handle.
124  *                    Uses the same interface as _close.
125  *   pfnseek     [I]  A pointer to a function which seeks in a file.
126  *                    Uses the same interface as _lseek.
127  *   pfndelete   [I]  A pointer to a function which deletes a file.
128  *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
129  *                    temporary file.
130  *   pccab       [I]  A pointer to an initialized CCAB structure.
131  *   pv          [I]  A pointer to an application-defined notification
132  *                    function which will be passed to other FCI functions
133  *                    as a parameter.
134  *
135  * RETURNS
136  *   On success, returns an FCI handle of type HFCI.
137  *   On failure, the NULL file handle is returned. Error
138  *   info can be retrieved from perf.
139  *
140  * INCLUDES
141  *   fci.h
142  *
143  */
144 HFCI __cdecl FCICreate(
145         PERF perf,
146         PFNFCIFILEPLACED   pfnfiledest,
147         PFNFCIALLOC        pfnalloc,
148         PFNFCIFREE         pfnfree,
149         PFNFCIOPEN         pfnopen,
150         PFNFCIREAD         pfnread,
151         PFNFCIWRITE        pfnwrite,
152         PFNFCICLOSE        pfnclose,
153         PFNFCISEEK         pfnseek,
154         PFNFCIDELETE       pfndelete,
155         PFNFCIGETTEMPFILE  pfnfcigtf,
156         PCCAB              pccab,
157         void *pv)
158 {
159   HFCI hfci;
160   int err;
161   PFCI_Int p_fci_internal;
162
163   if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
164       (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
165       (!pfnfcigtf) || (!pccab)) {
166     perf->erfOper = FCIERR_NONE;
167     perf->erfType = ERROR_BAD_ARGUMENTS;
168     perf->fError = TRUE;
169
170     SetLastError(ERROR_BAD_ARGUMENTS);
171     return NULL;
172   }
173
174   if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) {
175     perf->erfOper = FCIERR_ALLOC_FAIL;
176     perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
177     perf->fError = TRUE;
178
179     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
180     return NULL;
181   }
182
183   p_fci_internal=((PFCI_Int)(hfci));
184   p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC;
185   p_fci_internal->perf = perf;
186   p_fci_internal->pfnfiledest = pfnfiledest;
187   p_fci_internal->pfnalloc = pfnalloc;
188   p_fci_internal->pfnfree = pfnfree;
189   p_fci_internal->pfnopen = pfnopen;
190   p_fci_internal->pfnread = pfnread;
191   p_fci_internal->pfnwrite = pfnwrite;
192   p_fci_internal->pfnclose = pfnclose;
193   p_fci_internal->pfnseek = pfnseek;
194   p_fci_internal->pfndelete = pfndelete;
195   p_fci_internal->pfnfcigtf = pfnfcigtf;
196   p_fci_internal->pccab = pccab;
197   p_fci_internal->fPrevCab = FALSE;
198   p_fci_internal->fNextCab = FALSE;
199   p_fci_internal->fSplitFolder = FALSE;
200   p_fci_internal->fGetNextCabInVain = FALSE;
201   p_fci_internal->pv = pv;
202   p_fci_internal->data_in  = NULL;
203   p_fci_internal->cdata_in = 0;
204   p_fci_internal->data_out = NULL;
205   p_fci_internal->cCompressedBytesInFolder = 0;
206   p_fci_internal->cFolders = 0;
207   p_fci_internal->cFiles = 0;
208   p_fci_internal->cDataBlocks = 0;
209   p_fci_internal->sizeFileCFDATA1 = 0;
210   p_fci_internal->sizeFileCFFILE1 = 0;
211   p_fci_internal->sizeFileCFDATA2 = 0;
212   p_fci_internal->sizeFileCFFILE2 = 0;
213   p_fci_internal->sizeFileCFFOLDER = 0;
214   p_fci_internal->sizeFileCFFOLDER = 0;
215   p_fci_internal->fNewPrevious = FALSE;
216
217   memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
218   memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
219
220   /* CFDATA */
221   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1,
222       CB_MAX_FILENAME)) {
223     /* TODO error handling */
224     return FALSE;
225   }
226   /* safety */
227   if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {
228     /* TODO set error code */
229     return FALSE;
230   }
231
232   p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci,
233     p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv);
234   /* TODO check handle */
235   /* TODO error checking of err */
236
237   /* array of all CFFILE in a folder */
238   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1,
239       CB_MAX_FILENAME)) {
240     /* TODO error handling */
241     return FALSE;
242   }
243   /* safety */
244   if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {
245     /* TODO set error code */
246     return FALSE;
247   }
248   p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci,
249     p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv);
250   /* TODO check handle */
251   /* TODO error checking of err */
252
253   /* CFDATA with checksum and ready to be copied into cabinet */
254   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2,
255       CB_MAX_FILENAME)) {
256     /* TODO error handling */
257     return FALSE;
258   }
259   /* safety */
260   if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
261     /* TODO set error code */
262     return FALSE;
263   }
264   p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
265     p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv);
266   /* TODO check handle */
267   /* TODO error checking of err */
268
269   /* array of all CFFILE in a folder, ready to be copied into cabinet */
270   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
271       CB_MAX_FILENAME)) {
272     /* TODO error handling */
273     return FALSE;
274   }
275   /* safety */
276   if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
277     /* TODO set error code */
278     return FALSE;
279   }
280   p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
281     p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv);
282   /* TODO check handle */
283   /* TODO error checking of err */
284
285   /* array of all CFFILE in a folder, ready to be copied into cabinet */
286   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,
287       CB_MAX_FILENAME)) {
288     /* TODO error handling */
289     return FALSE;
290   }
291   /* safety */
292   if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
293     /* TODO set error code */
294     return FALSE;
295   }
296   p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
297     p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv);
298
299
300   /* TODO close and delete new files when return FALSE */
301
302   /* TODO check handle */
303   /* TODO error checking of err */
304
305   return hfci;
306 } /* end of FCICreate */
307
308
309
310
311
312
313 static BOOL fci_flush_data_block (HFCI hfci, int* err,
314     PFNFCISTATUS pfnfcis) {
315
316   /* attention no hfci checks!!! */
317   /* attention no checks if there is data available!!! */
318   CFDATA data;
319   CFDATA* cfdata=&data;
320   char* reserved;
321   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
322   UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
323   UINT i;
324
325   /* TODO compress the data of p_fci_internal->data_in */
326   /* and write it to p_fci_internal->data_out */
327   memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
328     p_fci_internal->cdata_in /* number of bytes to copy */);
329
330   cfdata->csum=0; /* checksum has to be set later */
331   /* TODO set realsize of compressed data */
332   cfdata->cbData   = p_fci_internal->cdata_in;
333   cfdata->cbUncomp = p_fci_internal->cdata_in;
334
335   /* write cfdata to p_fci_internal->handleCFDATA1 */
336   if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
337       cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
338       != sizeof(*cfdata) ) {
339     /* TODO write error */
340     return FALSE;
341   }
342   /* TODO error handling of err */
343
344   p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);
345
346   /* add optional reserved area */
347
348   /* This allocation and freeing at each CFData block is a bit */
349   /* inefficent, but it's harder to forget about freeing the buffer :-). */
350   /* Reserved areas are used seldom besides that... */
351   if (cbReserveCFData!=0) {
352     if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) {
353       p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
354       p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
355       p_fci_internal->perf->fError = TRUE;
356       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
357       return FALSE;
358     }
359     for(i=0;i<cbReserveCFData;) {
360       reserved[i++]='\0';
361     }
362     if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
363         reserved, /* memory buffer */
364         cbReserveCFData, /* number of bytes to copy */
365         err, p_fci_internal->pv) != cbReserveCFData ) {
366       PFCI_FREE(hfci, reserved);
367       /* TODO write error */
368       return FALSE;
369     }
370     /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
371
372     p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;
373     PFCI_FREE(hfci, reserved);
374   }
375
376   /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
377   if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */
378       p_fci_internal->data_out, /* memory buffer */
379       cfdata->cbData, /* number of bytes to copy */
380       err, p_fci_internal->pv) != cfdata->cbData) {
381     /* TODO write error */
382     return FALSE;
383   }
384   /* TODO error handling of err */
385
386   p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;
387
388   /* reset the offset */
389   p_fci_internal->cdata_in = 0;
390   p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
391
392   /* report status with pfnfcis about uncompressed and compressed file data */
393   if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
394       p_fci_internal->pv) == -1) {
395     /* TODO set error code and abort */
396     return FALSE;
397   }
398
399   ++(p_fci_internal->cDataBlocks);
400
401   return TRUE;
402 } /* end of fci_flush_data_block */
403
404
405
406
407
408 static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed)
409 {
410   cab_ULONG csum;
411   cab_ULONG ul;
412   int       cUlong;
413   BYTE      *pb;
414
415   csum = seed;
416   cUlong = cb / 4;
417   pb = pv;
418
419   while (cUlong-- > 0) {
420     ul = *pb++;
421     ul |= (((cab_ULONG)(*pb++)) <<  8);
422     ul |= (((cab_ULONG)(*pb++)) << 16);
423     ul |= (((cab_ULONG)(*pb++)) << 24);
424
425     csum ^= ul;
426   }
427
428   ul = 0;
429   switch (cb % 4) {
430     case 3:
431       ul |= (((ULONG)(*pb++)) << 16);
432     case 2:
433       ul |= (((ULONG)(*pb++)) <<  8);
434     case 1:
435       ul |= *pb++;
436     default:
437       break;
438   }
439   csum ^= ul;
440
441   return csum;
442 } /* end of fci_get_checksum */
443
444
445 static inline cab_ULONG fci_set_little_endian_ulong( cab_ULONG i )
446 {
447 #ifdef WORDS_BIGENDIAN
448     return RtlUlongByteSwap( i );
449 #else
450     return i;
451 #endif
452 }
453
454 static inline cab_ULONG fci_get_little_endian_ulong( cab_ULONG i )
455 {
456 #ifdef WORDS_BIGENDIAN
457     return RtlUlongByteSwap( i );
458 #else
459     return i;
460 #endif
461 }
462
463 static inline cab_UWORD fci_set_little_endian_uword( cab_UWORD i )
464 {
465 #ifdef WORDS_BIGENDIAN
466     return RtlUshortByteSwap( i );
467 #else
468     return i;
469 #endif
470 }
471
472 static inline cab_UWORD fci_get_little_endian_uword( cab_UWORD i )
473 {
474 #ifdef WORDS_BIGENDIAN
475     return RtlUshortByteSwap( i );
476 #else
477     return i;
478 #endif
479 }
480
481
482 static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData,
483   PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,
484   cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)
485 {
486   cab_ULONG read_result;
487   CFDATA* pcfdata=(CFDATA*)buffer;
488   BOOL split_block=FALSE;
489   cab_UWORD savedUncomp=0;
490   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
491
492   *payload=0;
493
494   /* while not all CFDATAs have been copied do */
495   while(!FALSE) {
496     if( p_fci_internal->fNextCab ) {
497       if( split_block ) {
498         /* TODO internal error should never happen */
499         return FALSE;
500       }
501     }
502     /* REUSE the variable read_result */
503     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
504         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
505         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
506       read_result=4;
507     } else {
508       read_result=0;
509     }
510     if (p_fci_internal->fPrevCab) {
511       read_result+=strlen(p_fci_internal->szPrevCab)+1 +
512         strlen(p_fci_internal->szPrevDisk)+1;
513     }
514     /* No more CFDATA fits into the cabinet under construction */
515     /* So don't try to store more data into it */
516     if( p_fci_internal->fNextCab &&
517         (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +
518         p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
519         p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
520         sizeof(CFHEADER) +
521         read_result +
522         p_fci_internal->oldCCAB.cbReserveCFHeader +
523         sizeof(CFFOLDER) +
524         p_fci_internal->oldCCAB.cbReserveCFFolder +
525         strlen(p_fci_internal->pccab->szCab)+1 +
526         strlen(p_fci_internal->pccab->szDisk)+1
527     )) {
528       /* This may never be run for the first time the while loop is entered.
529       Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
530       split_block=TRUE;  /* In this case split_block is abused to store */
531       /* the complete data block into the next cabinet and not into the */
532       /* current one. Originally split_block is the indicator that a */
533       /* data block has been splitted across different cabinets. */
534     } else {
535
536       /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
537       read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/
538           buffer, /* memory buffer */
539           sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
540           err, p_fci_internal->pv);
541       if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
542         if (read_result==0) break; /* ALL DATA has been copied */
543         /* TODO read error */
544         return FALSE;
545       }
546       /* TODO error handling of err */
547
548       /* REUSE buffer p_fci_internal->data_out !!! */
549       /* read data from p_fci_internal->handleCFDATA1 to */
550       /*      p_fci_internal->data_out */
551       if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
552           p_fci_internal->data_out /* memory buffer */,
553           pcfdata->cbData /* number of bytes to copy */,
554           err, p_fci_internal->pv) != pcfdata->cbData ) {
555         /* TODO read error */
556         return FALSE;
557       }
558       /* TODO error handling of err */
559
560       /* if cabinet size is too large */
561
562       /* REUSE the variable read_result */
563       if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
564           p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
565           p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
566         read_result=4;
567       } else {
568         read_result=0;
569       }
570       if (p_fci_internal->fPrevCab) {
571         read_result+=strlen(p_fci_internal->szPrevCab)+1 +
572           strlen(p_fci_internal->szPrevDisk)+1;
573       }
574
575       /* Is cabinet with new CFDATA too large? Then data block has to be split */
576       if( p_fci_internal->fNextCab &&
577           (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +
578           pcfdata->cbData +
579           p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
580           p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
581           sizeof(CFHEADER) +
582           read_result +
583           p_fci_internal->oldCCAB.cbReserveCFHeader +
584           sizeof(CFFOLDER) + /* size of new CFFolder entry */
585           p_fci_internal->oldCCAB.cbReserveCFFolder +
586           strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */
587           strlen(p_fci_internal->pccab->szDisk)+1  /* name of next disk */
588       )) {
589         /* REUSE read_result to save the size of the compressed data */
590         read_result=pcfdata->cbData;
591         /* Modify the size of the compressed data to store only a part of the */
592         /* data block into the current cabinet. This is done to prevent */
593         /* that the maximum cabinet size will be exceeded. The remainder */
594         /* will be stored into the next following cabinet. */
595
596         /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
597         /* Substract everything except the size of the block of data */
598         /* to get it's actual size */
599         pcfdata->cbData = p_fci_internal->oldCCAB.cb - (
600           sizeof(CFDATA) + cbReserveCFData +
601           p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
602           p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
603           sizeof(CFHEADER) +
604           p_fci_internal->oldCCAB.cbReserveCFHeader +
605           sizeof(CFFOLDER) + /* set size of new CFFolder entry */
606           p_fci_internal->oldCCAB.cbReserveCFFolder );
607         /* substract the size of special header fields */
608         if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
609             p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
610             p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
611           pcfdata->cbData-=4;
612         }
613         if (p_fci_internal->fPrevCab) {
614           pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +
615             strlen(p_fci_internal->szPrevDisk)+1;
616         }
617         pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +
618           strlen(p_fci_internal->pccab->szDisk)+1;
619
620         savedUncomp = pcfdata->cbUncomp;
621         pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */
622
623         /* if split_block==TRUE then the above while loop won't */
624         /* be executed again */
625         split_block=TRUE; /* split_block is the indicator that */
626                           /* a data block has been splitted across */
627                           /* diffentent cabinets.*/
628       }
629
630       /* This should never happen !!! */
631       if (pcfdata->cbData==0) {
632         /* TODO set error */
633         return FALSE;
634       }
635
636       /* set little endian */
637       pcfdata->cbData=fci_set_little_endian_uword(pcfdata->cbData);
638       pcfdata->cbUncomp=fci_set_little_endian_uword(pcfdata->cbUncomp);
639
640       /* get checksum and write to cfdata.csum */
641       pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
642         sizeof(CFDATA)+cbReserveCFData -
643         sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
644         pcfdata->cbData, 0 ) );
645
646       /* set little endian */
647       pcfdata->csum=fci_set_little_endian_ulong(pcfdata->csum);
648
649       /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
650       if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
651           buffer, /* memory buffer */
652           sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
653           err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
654           /* TODO write error */
655         return FALSE;
656       }
657       /* TODO error handling of err */
658
659       p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;
660
661       /* reset little endian */
662       pcfdata->cbData=fci_get_little_endian_uword(pcfdata->cbData);
663       pcfdata->cbUncomp=fci_get_little_endian_uword(pcfdata->cbUncomp);
664       pcfdata->csum=fci_get_little_endian_ulong(pcfdata->csum);
665
666       /* write compressed data into p_fci_internal->handleCFDATA2 */
667       if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */
668           p_fci_internal->data_out, /* memory buffer */
669           pcfdata->cbData, /* number of bytes to copy */
670           err, p_fci_internal->pv) != pcfdata->cbData) {
671         /* TODO write error */
672         return FALSE;
673       }
674       /* TODO error handling of err */
675
676       p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;
677       ++(p_fci_internal->cDataBlocks);
678       p_fci_internal->statusFolderCopied += pcfdata->cbData;
679       (*payload)+=pcfdata->cbUncomp;
680       /* if cabinet size too large and data has been split */
681       /* write the remainder of the data block to the new CFDATA1 file */
682       if( split_block  ) { /* This does not include the */
683                                   /* abused one (just search for "abused" )*/
684       /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
685         if (p_fci_internal->fNextCab==FALSE ) {
686           /* TODO internal error */
687           return FALSE;
688         }
689
690         /* set cbData to the size of the remainder of the data block */
691         pcfdata->cbData = read_result - pcfdata->cbData;
692         /*recover former value of cfdata.cbData; read_result will be the offset*/
693         read_result -= pcfdata->cbData;
694         pcfdata->cbUncomp = savedUncomp;
695
696         /* reset checksum, it will be computed later */
697         pcfdata->csum=0;
698
699         /* write cfdata WITHOUT checksum to handleCFDATA1new */
700         if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
701             buffer, /* memory buffer */
702             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
703             err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
704             /* TODO write error */
705           return FALSE;
706         }
707         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
708
709         *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
710
711         /* write compressed data into handleCFDATA1new */
712         if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
713             p_fci_internal->data_out + read_result, /* memory buffer + offset */
714                                                 /* to last part of split data */
715             pcfdata->cbData, /* number of bytes to copy */
716             err, p_fci_internal->pv) != pcfdata->cbData) {
717           /* TODO write error */
718           return FALSE;
719         }
720         /* TODO error handling of err */
721
722         p_fci_internal->statusFolderCopied += pcfdata->cbData;
723
724         *psizeFileCFDATA1new += pcfdata->cbData;
725         /* the two blocks of the split data block have been written */
726         /* don't reset split_data yet, because it is still needed see below */
727       }
728
729       /* report status with pfnfcis about copied size of folder */
730       if( (*pfnfcis)(statusFolder,
731           p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
732           p_fci_internal->statusFolderTotal, /* total folder size */
733           p_fci_internal->pv) == -1) {
734         /* TODO set error code and abort */
735         return FALSE;
736       }
737     }
738
739     /* if cabinet size too large */
740     /* write the remaining data blocks to the new CFDATA1 file */
741     if ( split_block ) { /* This does include the */
742                                /* abused one (just search for "abused" )*/
743       if (p_fci_internal->fNextCab==FALSE ) {
744         /* TODO internal error */
745         return FALSE;
746       }
747       /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
748       while(!FALSE) {
749         /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
750         read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */
751             buffer, /* memory buffer */
752             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
753             err, p_fci_internal->pv);
754         if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
755           if (read_result==0) break; /* ALL DATA has been copied */
756           /* TODO read error */
757           return FALSE;
758         }
759         /* TODO error handling of err */
760
761         /* REUSE buffer p_fci_internal->data_out !!! */
762         /* read data from p_fci_internal->handleCFDATA1 to */
763         /*      p_fci_internal->data_out */
764         if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */,
765             p_fci_internal->data_out /* memory buffer */,
766             pcfdata->cbData /* number of bytes to copy */,
767             err, p_fci_internal->pv) != pcfdata->cbData ) {
768           /* TODO read error */
769           return FALSE;
770         }
771         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
772
773         /* write cfdata with checksum to handleCFDATA1new */
774         if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
775             buffer, /* memory buffer */
776             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
777             err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
778             /* TODO write error */
779           return FALSE;
780         }
781         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
782
783         *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
784
785         /* write compressed data into handleCFDATA1new */
786         if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */
787             p_fci_internal->data_out, /* memory buffer */
788             pcfdata->cbData, /* number of bytes to copy */
789             err, p_fci_internal->pv) != pcfdata->cbData) {
790           /* TODO write error */
791           return FALSE;
792         }
793         /* TODO error handling of err */
794
795         *psizeFileCFDATA1new += pcfdata->cbData;
796         p_fci_internal->statusFolderCopied += pcfdata->cbData;
797
798         /* report status with pfnfcis about copied size of folder */
799         if( (*pfnfcis)(statusFolder,
800             p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/
801             p_fci_internal->statusFolderTotal, /* total folder size */
802             p_fci_internal->pv) == -1) {
803           /* TODO set error code and abort */
804           return FALSE;
805         }
806
807       } /* end of WHILE */
808       break; /* jump out of the next while loop */
809     } /* end of if( split_data  ) */
810   } /* end of WHILE */
811   return TRUE;
812 } /* end of fci_flushfolder_copy_cfdata */
813
814
815
816
817
818 static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder,
819   cab_ULONG sizeFileCFDATA2old)
820 {
821   CFFOLDER cffolder;
822   UINT i;
823   char* reserved;
824   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
825
826   /* absolute offset cannot be set yet, because the size of cabinet header, */
827   /* the number of CFFOLDERs and the number of CFFILEs may change. */
828   /* Instead the size of all previous data blocks will be stored and */
829   /* the remainder of the offset will be added when the cabinet will be */
830   /* flushed to disk. */
831   /* This is exactly the way the original CABINET.DLL works!!! */
832   cffolder.coffCabStart=sizeFileCFDATA2old;
833
834   /* set the number of this folder's CFDATA sections */
835   cffolder.cCFData=p_fci_internal->cDataBlocks;
836   /* TODO set compression type */
837   cffolder.typeCompress = tcompTYPE_NONE;
838
839   /* write cffolder to p_fci_internal->handleCFFOLDER */
840   if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
841     &cffolder, /* memory buffer */
842     sizeof(cffolder), /* number of bytes to copy */
843     err, p_fci_internal->pv) != sizeof(cffolder) ) {
844     /* TODO write error */
845     return FALSE;
846   }
847   /* TODO error handling of err */
848
849   p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);
850
851   /* add optional reserved area */
852   if (cbReserveCFFolder!=0) {
853     if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) {
854       p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
855       p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
856       p_fci_internal->perf->fError = TRUE;
857       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
858       return FALSE;
859     }
860     for(i=0;i<cbReserveCFFolder;) {
861       reserved[i++]='\0';
862     }
863     if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
864         reserved, /* memory buffer */
865         cbReserveCFFolder, /* number of bytes to copy */
866         err, p_fci_internal->pv) != cbReserveCFFolder ) {
867       PFCI_FREE(hfci, reserved);
868       /* TODO write error */
869       return FALSE;
870     }
871     /* TODO error handling of err */
872
873     p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;
874
875     PFCI_FREE(hfci, reserved);
876   }
877   return TRUE;
878 } /* end of fci_flushfolder_copy_cffolder */
879
880
881
882
883
884 static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new,
885   cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)
886 {
887   CFFILE cffile;
888   cab_ULONG read_result;
889   cab_ULONG seek=0;
890   cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;
891   BOOL may_be_prev=TRUE;
892   cab_ULONG cbFileRemainer=0;
893   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
894   /* set seek of p_fci_internal->handleCFFILE1 to 0 */
895   if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err,
896     p_fci_internal->pv) !=0 ) {
897     /* TODO  wrong return value */
898   }
899   /* TODO error handling of err */
900
901   /* while not all CFFILE structures have been copied do */
902   while(!FALSE) {
903     /* REUSE the variable read_result */
904     /* read data from p_fci_internal->handleCFFILE1 to cffile */
905     read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */,
906       &cffile, /* memory buffer */
907       sizeof(cffile), /* number of bytes to copy */
908       err, p_fci_internal->pv);
909     if( read_result != sizeof(cffile) ) {
910       if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
911       /* TODO read error */
912       return FALSE;
913     }
914     /* TODO error handling of err */
915
916     /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
917     /* position. I don't know why so I'll just omit it */
918
919     /* read the filename from p_fci_internal->handleCFFILE1 */
920     /* REUSE the variable read_result AGAIN */
921     /* REUSE the memory buffer PFCI(hfci)->data_out */
922     if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/,
923         p_fci_internal->data_out, /* memory buffer */
924         CB_MAX_FILENAME, /* number of bytes to copy */
925         err, p_fci_internal->pv) <2) {
926       /* TODO read error */
927       return FALSE;
928     }
929     /* TODO maybe other checks of read_result */
930     /* TODO error handling of err */
931
932     /* safety */
933     if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {
934       /* TODO set error code internal error */
935       return FALSE;
936     }
937
938     seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;
939
940     /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
941     /* i.e. seek to the next CFFILE area */
942     if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,
943         seek, /* seek position*/
944         SEEK_SET ,err,
945         p_fci_internal->pv)
946         != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) {
947       /* TODO  wrong return value */
948     }
949     /* TODO error handling of err */
950
951     /* fnfilfnfildest: placed file on cabinet */
952     if (p_fci_internal->fNextCab ||
953         p_fci_internal->fGetNextCabInVain) {
954       PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB),
955         p_fci_internal->data_out, /* the file name*/
956         cffile.cbFile, /* file size */
957         (cffile.iFolder==cffileCONTINUED_FROM_PREV),
958         p_fci_internal->pv
959       );
960     } else {
961       PFCI_FILEPLACED( hfci, p_fci_internal->pccab,
962         p_fci_internal->data_out, /* the file name*/
963         cffile.cbFile, /* file size */
964         (cffile.iFolder==cffileCONTINUED_FROM_PREV),
965         p_fci_internal->pv
966       );
967     }
968
969     /* Check special iFolder values */
970     if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
971         p_fci_internal->fPrevCab==FALSE ) {
972       /* THIS MAY NEVER HAPPEN */
973       /* TODO set error code */
974       return FALSE;
975     }
976     if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
977         cffile.iFolder==cffileCONTINUED_TO_NEXT ) {
978       /* THIS MAY NEVER HAPPEN */
979       /* TODO set error code */
980       return FALSE;
981     }
982     if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
983       may_be_prev=FALSE;
984     }
985     if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {
986       /* THIS MAY NEVER HAPPEN */
987       /* TODO set error code */
988       return FALSE;
989     }
990     if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
991       may_be_prev=FALSE;
992     }
993
994     sizeOfFilesPrev=sizeOfFiles;
995     /* Set complete size of all processed files */
996     if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
997         p_fci_internal->cbFileRemainer!=0
998     ) {
999       sizeOfFiles+=p_fci_internal->cbFileRemainer;
1000       p_fci_internal->cbFileRemainer=0;
1001     } else {
1002       sizeOfFiles+=cffile.cbFile;
1003     }
1004
1005     /* Check if spanned file fits into this cabinet folder */
1006     if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) {
1007       cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT;
1008     } else
1009
1010     /* Check if file doesn't fit into this cabinet folder */
1011     if( sizeOfFiles>payload ) {
1012       cffile.iFolder=cffileCONTINUED_TO_NEXT;
1013     }
1014
1015     /* set little endian */
1016     cffile.cbFile=fci_set_little_endian_ulong(cffile.cbFile);
1017     cffile.uoffFolderStart=fci_set_little_endian_ulong(cffile.uoffFolderStart);
1018     cffile.iFolder=fci_set_little_endian_uword(cffile.iFolder);
1019     cffile.date=fci_set_little_endian_uword(cffile.date);
1020     cffile.time=fci_set_little_endian_uword(cffile.time);
1021     cffile.attribs=fci_set_little_endian_uword(cffile.attribs);
1022
1023     /* write cffile to p_fci_internal->handleCFFILE2 */
1024     if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
1025       &cffile, /* memory buffer */
1026       sizeof(cffile), /* number of bytes to copy */
1027       err, p_fci_internal->pv) != sizeof(cffile) ) {
1028       /* TODO write error */
1029       return FALSE;
1030     }
1031     /* TODO error handling of err */
1032
1033     p_fci_internal->sizeFileCFFILE2 += sizeof(cffile);
1034
1035     /* reset little endian */
1036     cffile.cbFile=fci_get_little_endian_ulong(cffile.cbFile);
1037     cffile.uoffFolderStart=fci_get_little_endian_ulong(cffile.uoffFolderStart);
1038     cffile.iFolder=fci_get_little_endian_uword(cffile.iFolder);
1039     cffile.date=fci_get_little_endian_uword(cffile.date);
1040     cffile.time=fci_get_little_endian_uword(cffile.time);
1041     cffile.attribs=fci_get_little_endian_uword(cffile.attribs);
1042
1043     /* write file name to p_fci_internal->handleCFFILE2 */
1044     if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */
1045       p_fci_internal->data_out, /* memory buffer */
1046       strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1047       err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1048       /* TODO write error */
1049       return FALSE;
1050     }
1051     /* TODO error handling of err */
1052
1053     p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1;
1054
1055     /* cFiles is used to count all files of a cabinet */
1056     ++(p_fci_internal->cFiles);
1057
1058     /* This is only true for files which will be written into the */
1059     /* next cabinet of the spanning folder */
1060     if( sizeOfFiles>payload ) {
1061
1062       /* Files which data will be partially written into the current cabinet */
1063       if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
1064           cffile.iFolder==cffileCONTINUED_TO_NEXT
1065         ) {
1066         if( sizeOfFilesPrev<=payload ) {
1067           /* The size of the uncompressed, data of a spanning file in a */
1068           /* spanning data */
1069           cbFileRemainer=sizeOfFiles-payload;
1070         }
1071         cffile.iFolder=cffileCONTINUED_FROM_PREV;
1072       } else {
1073         cffile.iFolder=0;
1074       }
1075
1076       /* write cffile into handleCFFILE1new */
1077       if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1078         &cffile, /* memory buffer */
1079         sizeof(cffile), /* number of bytes to copy */
1080         err, p_fci_internal->pv) != sizeof(cffile) ) {
1081         /* TODO write error */
1082         return FALSE;
1083       }
1084       /* TODO error handling of err */
1085
1086       *psizeFileCFFILE1new += sizeof(cffile);
1087       /* write name of file into handleCFFILE1new */
1088       if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */
1089         p_fci_internal->data_out, /* memory buffer */
1090         strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1091         err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1092         /* TODO write error */
1093         return FALSE;
1094       }
1095       /* TODO error handling of err */
1096
1097       *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1;
1098     }
1099
1100   } /* END OF while */
1101   p_fci_internal->cbFileRemainer=cbFileRemainer;
1102   return TRUE;
1103 } /* end of fci_flushfolder_copy_cffile */
1104
1105
1106
1107
1108 static BOOL fci_flush_folder(
1109         HFCI                  hfci,
1110         BOOL                  fGetNextCab,
1111         PFNFCIGETNEXTCABINET  pfnfcignc,
1112         PFNFCISTATUS          pfnfcis)
1113 {
1114   int err;
1115   int handleCFDATA1new;                         /* handle for new  temp file */
1116   char szFileNameCFDATA1new[CB_MAX_FILENAME];  /* name buffer for temp file */
1117   int handleCFFILE1new;                         /* handle for new  temp file */
1118   char szFileNameCFFILE1new[CB_MAX_FILENAME];  /* name buffer for temp file */
1119   UINT cbReserveCFData, cbReserveCFFolder;
1120   char* reserved;
1121   cab_ULONG sizeFileCFDATA1new=0;
1122   cab_ULONG sizeFileCFFILE1new=0;
1123   cab_ULONG sizeFileCFDATA2old;
1124   cab_ULONG payload;
1125   cab_ULONG read_result;
1126   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1127
1128   /* test hfci */
1129   if (!REALLY_IS_FCI(hfci)) {
1130     SetLastError(ERROR_INVALID_HANDLE);
1131     return FALSE;
1132   }
1133
1134   if ((!pfnfcignc) || (!pfnfcis)) {
1135     p_fci_internal->perf->erfOper = FCIERR_NONE;
1136     p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
1137     p_fci_internal->perf->fError = TRUE;
1138
1139     SetLastError(ERROR_BAD_ARGUMENTS);
1140     return FALSE;
1141   }
1142
1143   if( p_fci_internal->fGetNextCabInVain &&
1144       p_fci_internal->fNextCab ){
1145     /* TODO internal error */
1146     return FALSE;
1147   }
1148
1149   /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1150   /* this function will return TRUE */
1151   if( p_fci_internal->sizeFileCFFILE1 == 0 ) {
1152     if ( p_fci_internal->sizeFileCFDATA1 != 0 ) {
1153       /* TODO error handling */
1154       return FALSE;
1155     }
1156     return TRUE;
1157   }
1158
1159   if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1160     /* TODO error handling */
1161     return FALSE;
1162   }
1163
1164   /* FCIFlushFolder has already been called... */
1165   if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) {
1166     if (p_fci_internal->sizeFileCFFILE2==0) {
1167       /* TODO set error code */
1168       return FALSE;
1169     }
1170     return TRUE;
1171   }
1172
1173   /* TODO check what will happen when return FALSE later */
1174   /* and p_fci_internal->fSplitFolder is set to FALSE */
1175   p_fci_internal->fSplitFolder=FALSE;
1176
1177
1178   if( p_fci_internal->fGetNextCabInVain ||
1179       p_fci_internal->fNextCab ){
1180     cbReserveCFData   = p_fci_internal->oldCCAB.cbReserveCFData;
1181     cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder;
1182   } else {
1183     cbReserveCFData   = p_fci_internal->pccab->cbReserveCFData;
1184     cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder;
1185   }
1186
1187   /* START of COPY */
1188   /* if there is data in p_fci_internal->data_in */
1189   if (p_fci_internal->cdata_in!=0) {
1190
1191     if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
1192
1193   }
1194   /* reset to get the number of data blocks of this folder which are */
1195   /* actually in this cabinet ( at least partially ) */
1196   p_fci_internal->cDataBlocks=0;
1197
1198   if ( p_fci_internal->fNextCab ||
1199        p_fci_internal->fGetNextCabInVain ) {
1200     read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+
1201                  p_fci_internal->oldCCAB.cbReserveCFFolder;
1202     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1203         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1204         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
1205       read_result+=4;
1206     }
1207   } else {
1208     read_result= p_fci_internal->pccab->cbReserveCFHeader+
1209                  p_fci_internal->pccab->cbReserveCFFolder;
1210     if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1211         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1212         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
1213       read_result+=4;
1214     }
1215   }
1216   if (p_fci_internal->fPrevCab) {
1217     read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1218       strlen(p_fci_internal->szPrevDisk)+1;
1219   }
1220   if (p_fci_internal->fNextCab) {
1221     read_result+=strlen(p_fci_internal->pccab->szCab)+1 +
1222       strlen(p_fci_internal->pccab->szDisk)+1;
1223   }
1224
1225   p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+
1226       sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+
1227       p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+
1228       p_fci_internal->sizeFileCFDATA1;
1229   p_fci_internal->statusFolderCopied = 0;
1230
1231   /* report status with pfnfcis about copied size of folder */
1232   if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1233       p_fci_internal->statusFolderTotal, /* TODO total folder size */
1234       p_fci_internal->pv) == -1) {
1235     /* TODO set error code and abort */
1236     return FALSE;
1237   }
1238
1239   /* get a new temp file */
1240   if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) {
1241     /* TODO error handling */
1242     return FALSE;
1243   }
1244   /* safety */
1245   if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) {
1246     /* TODO set error code */
1247     return FALSE;
1248   }
1249   handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err,
1250     p_fci_internal->pv);
1251
1252   /* get a new temp file */
1253   if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) {
1254     /* TODO error handling */
1255     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1256     /* TODO error handling of err */
1257     return FALSE;
1258   }
1259   /* safety */
1260   if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) {
1261     /* TODO set error code */
1262     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1263     /* TODO error handling of err */
1264     return FALSE;
1265   }
1266   handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err,
1267     p_fci_internal->pv);
1268
1269   /* USE the variable read_result */
1270   if ( p_fci_internal->fNextCab ||
1271        p_fci_internal->fGetNextCabInVain ) {
1272     read_result= p_fci_internal->oldCCAB.cbReserveCFHeader;
1273     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1274         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1275         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
1276       read_result+=4;
1277     }
1278   } else {
1279     read_result= p_fci_internal->pccab->cbReserveCFHeader;
1280     if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1281         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1282         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
1283       read_result+=4;
1284     }
1285   }
1286   if (p_fci_internal->fPrevCab) {
1287     read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1288       strlen(p_fci_internal->szPrevDisk)+1;
1289   }
1290   read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 +
1291     p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER;
1292
1293   if(p_fci_internal->sizeFileCFFILE1!=0) {
1294     read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder;
1295   }
1296
1297   /* Check if multiple cabinets have to be created. */
1298
1299   /* Might be too much data for the maximum allowed cabinet size.*/
1300   /* When any further data will be added later, it might not */
1301   /* be possible to flush the cabinet, because there might */
1302   /* not be enough space to store the name of the following */
1303   /* cabinet and name of the corresponding disk. */
1304   /* So take care of this and get the name of the next cabinet */
1305   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1306       p_fci_internal->fNextCab==FALSE &&
1307       (
1308         (
1309           p_fci_internal->pccab->cb < read_result +
1310           p_fci_internal->sizeFileCFDATA1 +
1311           p_fci_internal->sizeFileCFFILE1 +
1312           CB_MAX_CABINET_NAME +   /* next cabinet name */
1313           CB_MAX_DISK_NAME        /* next disk name */
1314         ) || fGetNextCab
1315       )
1316   ) {
1317     /* save CCAB */
1318     memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
1319     /* increment cabinet index */
1320     ++(p_fci_internal->pccab->iCab);
1321     /* get name of next cabinet */
1322     if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
1323         p_fci_internal->pv)) {
1324       /* TODO error handling */
1325       PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1326       /* TODO error handling of err */
1327       PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1328       /* TODO error handling of err */
1329       return FALSE;
1330     }
1331
1332     /* Skip a few lines of code. This is catched by the next if. */
1333     p_fci_internal->fGetNextCabInVain=TRUE;
1334   }
1335
1336   /* too much data for cabinet */
1337   if( (p_fci_internal->fGetNextCabInVain ||
1338         p_fci_internal->fNextCab ) &&
1339       (
1340         (
1341           p_fci_internal->oldCCAB.cb < read_result +
1342           p_fci_internal->sizeFileCFDATA1 +
1343           p_fci_internal->sizeFileCFFILE1 +
1344           strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
1345           strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
1346         ) || fGetNextCab
1347       )
1348   ) {
1349     p_fci_internal->fGetNextCabInVain=FALSE;
1350     p_fci_internal->fNextCab=TRUE;
1351
1352     /* return FALSE if there is not enough space left*/
1353     /* this should never happen */
1354     if (p_fci_internal->oldCCAB.cb <=
1355         p_fci_internal->sizeFileCFFILE1 +
1356         read_result +
1357         strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1358         strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
1359     ) {
1360
1361       PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1362       /* TODO error handling of err */
1363       PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1364       /* TODO error handling of err */
1365
1366       /* close and delete p_fci_internal->handleCFFILE1 */
1367       PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1368       /* TODO error handling of err */
1369       PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1370       /* TODO error handling of err */
1371
1372       return FALSE;
1373     }
1374
1375     /* the folder will be split across cabinets */
1376     p_fci_internal->fSplitFolder=TRUE;
1377
1378   } else {
1379     /* this should never happen */
1380     if (p_fci_internal->fNextCab) {
1381       /* TODO internal error */
1382       return FALSE;
1383     }
1384   }
1385
1386   /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1387   if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err,
1388     p_fci_internal->pv) !=0 ) {
1389     /* TODO wrong return value */
1390     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1391     /* TODO error handling of err */
1392     PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1393     /* TODO error handling of err */
1394     return FALSE;
1395   }
1396   /* TODO error handling of err */
1397
1398   /* save size of file CFDATA2 - required for the folder's offset to data */
1399   sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2;
1400
1401   if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) {
1402     p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1403     p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1404     p_fci_internal->perf->fError = TRUE;
1405     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1406     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1407     /* TODO error handling of err */
1408     PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1409     /* TODO error handling of err */
1410     return FALSE;
1411   }
1412
1413   if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err,
1414       handleCFDATA1new, &sizeFileCFDATA1new, &payload
1415   )) {
1416     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1417     /* TODO error handling of err */
1418     PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1419     /* TODO error handling of err */
1420     PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1421     /* TODO error handling of err */
1422     PFCI_FREE(hfci,reserved);
1423     return FALSE;
1424   }
1425
1426   PFCI_FREE(hfci,reserved);
1427
1428   if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder,
1429        sizeFileCFDATA2old )) {
1430     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1431     /* TODO error handling of err */
1432     PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1433     /* TODO error handling of err */
1434     PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1435     /* TODO error handling of err */
1436     return FALSE;
1437   }
1438
1439   if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new,
1440       &sizeFileCFFILE1new, payload)) {
1441     PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv);
1442     /* TODO error handling of err */
1443     PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv);
1444     /* TODO error handling of err */
1445     PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv);
1446     /* TODO error handling of err */
1447     PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv);
1448     /* TODO error handling of err */
1449     return FALSE;
1450   }
1451
1452   /* close and delete p_fci_internal->handleCFDATA1 */
1453   PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
1454   /* TODO error handling of err */
1455   PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv);
1456   /* TODO error handling of err */
1457
1458   /* put new CFDATA1 into hfci */
1459   memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new,
1460     CB_MAX_FILENAME);
1461
1462   /* put CFDATA1 file handle */
1463   PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new;
1464   /* set file size */
1465   PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new;
1466
1467   /* close and delete PFCI_INT(hfci)->handleCFFILE1 */
1468   PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv);
1469   /* TODO error handling of err */
1470   PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv);
1471   /* TODO error handling of err */
1472
1473   /* put new CFFILE1 into hfci */
1474   memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new,
1475     CB_MAX_FILENAME);
1476
1477   /* put CFFILE1 file handle */
1478   p_fci_internal->handleCFFILE1 = handleCFFILE1new;
1479   /* set file size */
1480   p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new;
1481
1482   ++(p_fci_internal->cFolders);
1483
1484   /* reset CFFolder specific information */
1485   p_fci_internal->cDataBlocks=0;
1486   p_fci_internal->cCompressedBytesInFolder=0;
1487
1488   return TRUE;
1489 }  /* end of fci_flush_folder */
1490
1491
1492
1493
1494 static BOOL fci_flush_cabinet(
1495         HFCI                  hfci,
1496         BOOL                  fGetNextCab,
1497         PFNFCIGETNEXTCABINET  pfnfcignc,
1498         PFNFCISTATUS          pfnfcis)
1499 {
1500   int err;
1501   CFHEADER cfheader;
1502   struct {
1503     cab_UWORD  cbCFHeader;
1504     cab_UBYTE  cbCFFolder;
1505     cab_UBYTE  cbCFData;
1506   } cfreserved;
1507   CFFOLDER cffolder;
1508   cab_ULONG read_result;
1509   int handleCABINET;                            /* file handle for cabinet   */
1510   char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */
1511   UINT cbReserveCFHeader, cbReserveCFFolder, i;
1512   char* reserved;
1513   BOOL returntrue=FALSE;
1514   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
1515
1516   /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1517
1518   /* when FCIFlushCabinet was or FCIAddFile wasn't called */
1519   if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) {
1520     returntrue=TRUE;
1521   }
1522
1523   if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){
1524     /* TODO set error */
1525     return FALSE;
1526   }
1527
1528   if(returntrue) return TRUE;
1529
1530   if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) {
1531       /* TODO internal error */
1532       return FALSE;
1533   }
1534
1535   if( p_fci_internal->fNextCab ||
1536       p_fci_internal->fGetNextCabInVain ) {
1537     cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder;
1538     cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader;
1539     /* safety */
1540     if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH ||
1541         strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) {
1542       /* TODO set error */
1543       return FALSE;
1544     }
1545     /* get the full name of the cabinet */
1546     memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath,
1547       CB_MAX_CAB_PATH);
1548     memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1549       p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME);
1550   } else {
1551     cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder;
1552     cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader;
1553     /* safety */
1554     if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH ||
1555         strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) {
1556       /* TODO set error */
1557       return FALSE;
1558     }
1559     /* get the full name of the cabinet */
1560     memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath,
1561       CB_MAX_CAB_PATH);
1562     memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET),
1563       p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME);
1564   }
1565
1566   /* create the cabinet */
1567   handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET,
1568     33538, 384, &err, p_fci_internal->pv );
1569   /* TODO check handle */
1570   /* TODO error checking of err */
1571
1572   memcpy(cfheader.signature,"!CAB",4);
1573   cfheader.reserved1=0;
1574   cfheader.cbCabinet=   /* size of the cabinet file in bytes */
1575     sizeof(CFHEADER) +
1576     p_fci_internal->sizeFileCFFOLDER +
1577     p_fci_internal->sizeFileCFFILE2 +
1578     p_fci_internal->sizeFileCFDATA2;
1579
1580   if (p_fci_internal->fPrevCab) {
1581     cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 +
1582       strlen(p_fci_internal->szPrevDisk)+1;
1583   }
1584   if (p_fci_internal->fNextCab) {
1585     cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 +
1586       strlen(p_fci_internal->pccab->szDisk)+1;
1587   }
1588   if( p_fci_internal->fNextCab ||
1589       p_fci_internal->fGetNextCabInVain ) {
1590     cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1591     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1592         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1593         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
1594       cfheader.cbCabinet+=4;
1595     }
1596   } else {
1597     cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader;
1598     if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1599         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1600         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
1601       cfheader.cbCabinet+=4;
1602     }
1603   }
1604
1605   cfheader.reserved2=0;
1606   cfheader.coffFiles=    /* offset to first CFFILE section */
1607    cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 -
1608    p_fci_internal->sizeFileCFDATA2;
1609
1610   cfheader.reserved3=0;
1611   cfheader.versionMinor=3;
1612   cfheader.versionMajor=1;
1613   /* number of CFFOLDER entries in the cabinet */
1614   cfheader.cFolders=p_fci_internal->cFolders;
1615   /* number of CFFILE entries in the cabinet */
1616   cfheader.cFiles=p_fci_internal->cFiles;
1617   cfheader.flags=0;    /* 1=prev cab, 2=next cabinet, 4=reserved setions */
1618
1619   if( p_fci_internal->fPrevCab ) {
1620     cfheader.flags = cfheadPREV_CABINET;
1621   }
1622
1623   if( p_fci_internal->fNextCab ) {
1624     cfheader.flags |= cfheadNEXT_CABINET;
1625   }
1626
1627   if( p_fci_internal->fNextCab ||
1628       p_fci_internal->fGetNextCabInVain ) {
1629     if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1630         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1631         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
1632       cfheader.flags |= cfheadRESERVE_PRESENT;
1633     }
1634     cfheader.setID = p_fci_internal->oldCCAB.setID;
1635     cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1;
1636   } else {
1637     if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1638         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1639         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
1640       cfheader.flags |= cfheadRESERVE_PRESENT;
1641     }
1642     cfheader.setID = p_fci_internal->pccab->setID;
1643     cfheader.iCabinet = p_fci_internal->pccab->iCab-1;
1644   }
1645
1646   /* set little endian */
1647   cfheader.reserved1=fci_set_little_endian_ulong(cfheader.reserved1);
1648   cfheader.cbCabinet=fci_set_little_endian_ulong(cfheader.cbCabinet);
1649   cfheader.reserved2=fci_set_little_endian_ulong(cfheader.reserved2);
1650   cfheader.coffFiles=fci_set_little_endian_ulong(cfheader.coffFiles);
1651   cfheader.reserved3=fci_set_little_endian_ulong(cfheader.reserved3);
1652   cfheader.cFolders=fci_set_little_endian_uword(cfheader.cFolders);
1653   cfheader.cFiles=fci_set_little_endian_uword(cfheader.cFiles);
1654   cfheader.flags=fci_set_little_endian_uword(cfheader.flags);
1655   cfheader.setID=fci_set_little_endian_uword(cfheader.setID);
1656   cfheader.iCabinet=fci_set_little_endian_uword(cfheader.iCabinet);
1657
1658   /* write CFHEADER into cabinet file */
1659   if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1660       &cfheader, /* memory buffer */
1661       sizeof(cfheader), /* number of bytes to copy */
1662       &err, p_fci_internal->pv) != sizeof(cfheader) ) {
1663     /* TODO write error */
1664     return FALSE;
1665   }
1666   /* TODO error handling of err */
1667
1668   /* reset little endian */
1669   cfheader.reserved1=fci_get_little_endian_ulong(cfheader.reserved1);
1670   cfheader.cbCabinet=fci_get_little_endian_ulong(cfheader.cbCabinet);
1671   cfheader.reserved2=fci_get_little_endian_ulong(cfheader.reserved2);
1672   cfheader.coffFiles=fci_get_little_endian_ulong(cfheader.coffFiles);
1673   cfheader.reserved3=fci_get_little_endian_ulong(cfheader.reserved3);
1674   cfheader.cFolders=fci_get_little_endian_uword(cfheader.cFolders);
1675   cfheader.cFiles=fci_get_little_endian_uword(cfheader.cFiles);
1676   cfheader.flags=fci_get_little_endian_uword(cfheader.flags);
1677   cfheader.setID=fci_get_little_endian_uword(cfheader.setID);
1678   cfheader.iCabinet=fci_get_little_endian_uword(cfheader.iCabinet);
1679
1680   if( cfheader.flags & cfheadRESERVE_PRESENT ) {
1681     /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1682     cfreserved.cbCFHeader = cbReserveCFHeader;
1683     cfreserved.cbCFFolder = cbReserveCFFolder;
1684     if( p_fci_internal->fNextCab ||
1685         p_fci_internal->fGetNextCabInVain ) {
1686       cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1687     } else {
1688       cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData;
1689     }
1690
1691     /* set little endian */
1692     cfreserved.cbCFHeader=fci_set_little_endian_uword(cfreserved.cbCFHeader);
1693
1694     /* write reserved info into cabinet file */
1695     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1696         &cfreserved, /* memory buffer */
1697         sizeof(cfreserved), /* number of bytes to copy */
1698         &err, p_fci_internal->pv) != sizeof(cfreserved) ) {
1699       /* TODO write error */
1700       return FALSE;
1701     }
1702     /* TODO error handling of err */
1703
1704     /* reset little endian */
1705     cfreserved.cbCFHeader=fci_get_little_endian_uword(cfreserved.cbCFHeader);
1706   }
1707
1708   /* add optional reserved area */
1709   if (cbReserveCFHeader!=0) {
1710     if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) {
1711       p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1712       p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1713       p_fci_internal->perf->fError = TRUE;
1714       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1715       return FALSE;
1716     }
1717     for(i=0;i<cbReserveCFHeader;) {
1718       reserved[i++]='\0';
1719     }
1720     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1721         reserved, /* memory buffer */
1722         cbReserveCFHeader, /* number of bytes to copy */
1723         &err, p_fci_internal->pv) != cbReserveCFHeader ) {
1724       PFCI_FREE(hfci, reserved);
1725       /* TODO write error */
1726       return FALSE;
1727     }
1728     /* TODO error handling of err */
1729     PFCI_FREE(hfci, reserved);
1730   }
1731
1732   if( cfheader.flags & cfheadPREV_CABINET ) {
1733     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1734         p_fci_internal->szPrevCab, /* memory buffer */
1735         strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */
1736         &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) {
1737       /* TODO write error */
1738       return FALSE;
1739     }
1740     /* TODO error handling of err */
1741
1742     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1743         p_fci_internal->szPrevDisk, /* memory buffer */
1744         strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */
1745         &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) {
1746       /* TODO write error */
1747       return FALSE;
1748     }
1749     /* TODO error handling of err */
1750   }
1751
1752   if( cfheader.flags & cfheadNEXT_CABINET ) {
1753     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1754         p_fci_internal->pccab->szCab, /* memory buffer */
1755         strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */
1756         &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) {
1757       /* TODO write error */
1758       return FALSE;
1759     }
1760     /* TODO error handling of err */
1761
1762     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1763         p_fci_internal->pccab->szDisk, /* memory buffer */
1764         strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */
1765         &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) {
1766       /* TODO write error */
1767       return FALSE;
1768     }
1769     /* TODO error handling of err */
1770   }
1771
1772   /* set seek of p_fci_internal->handleCFFOLDER to 0 */
1773   if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER,
1774       0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1775     /* TODO  wrong return value */
1776   }
1777   /* TODO error handling of err */
1778
1779   /* while not all CFFOLDER structures have been copied into the cabinet do */
1780   while(!FALSE) {
1781     /* use the variable read_result */
1782     /* read cffolder of p_fci_internal->handleCFFOLDER */
1783     read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */
1784         &cffolder, /* memory buffer */
1785         sizeof(cffolder), /* number of bytes to copy */
1786         &err, p_fci_internal->pv);
1787     if( read_result != sizeof(cffolder) ) {
1788       if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/
1789       /* TODO read error */
1790       return FALSE;
1791     }
1792     /* TODO error handling of err */
1793
1794     /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1795     cffolder.coffCabStart +=
1796       p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
1797       sizeof(CFHEADER);
1798     if( p_fci_internal->fNextCab ||
1799         p_fci_internal->fGetNextCabInVain ) {
1800       cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1801     } else {
1802       cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader;
1803     }
1804
1805     if (p_fci_internal->fPrevCab) {
1806       cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 +
1807         strlen(p_fci_internal->szPrevDisk)+1;
1808     }
1809
1810     if (p_fci_internal->fNextCab) {
1811       cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 +
1812         strlen(p_fci_internal->oldCCAB.szDisk)+1;
1813     }
1814
1815     if( p_fci_internal->fNextCab ||
1816         p_fci_internal->fGetNextCabInVain ) {
1817       cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader;
1818       if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1819           p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1820           p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
1821         cffolder.coffCabStart += 4;
1822       }
1823     } else {
1824       cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader;
1825       if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1826           p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1827           p_fci_internal->pccab->cbReserveCFData   != 0 ) {
1828         cffolder.coffCabStart += 4;
1829       }
1830     }
1831
1832     /* set little endian */
1833     cffolder.coffCabStart=fci_set_little_endian_ulong(cffolder.coffCabStart);
1834     cffolder.cCFData=fci_set_little_endian_uword(cffolder.cCFData);
1835     cffolder.typeCompress=fci_set_little_endian_uword(cffolder.typeCompress);
1836
1837     /* write cffolder to cabinet file */
1838     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1839       &cffolder, /* memory buffer */
1840       sizeof(cffolder), /* number of bytes to copy */
1841       &err, p_fci_internal->pv) != sizeof(cffolder) ) {
1842       /* TODO write error */
1843       return FALSE;
1844     }
1845     /* TODO error handling of err */
1846
1847     /* reset little endian */
1848     cffolder.coffCabStart=fci_get_little_endian_ulong(cffolder.coffCabStart);
1849     cffolder.cCFData=fci_get_little_endian_uword(cffolder.cCFData);
1850     cffolder.typeCompress=fci_get_little_endian_uword(cffolder.typeCompress);
1851
1852     /* add optional reserved area */
1853
1854     /* This allocation and freeing at each CFFolder block is a bit */
1855     /* inefficent, but it's harder to forget about freeing the buffer :-). */
1856     /* Reserved areas are used seldom besides that... */
1857     if (cbReserveCFFolder!=0) {
1858       if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) {
1859         p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
1860         p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1861         p_fci_internal->perf->fError = TRUE;
1862         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1863         return FALSE;
1864       }
1865
1866       if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */
1867           reserved, /* memory buffer */
1868           cbReserveCFFolder, /* number of bytes to copy */
1869           &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1870         PFCI_FREE(hfci, reserved);
1871         /* TODO read error */
1872         return FALSE;
1873       }
1874       /* TODO error handling of err */
1875
1876       if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1877           reserved, /* memory buffer */
1878           cbReserveCFFolder, /* number of bytes to copy */
1879           &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1880         PFCI_FREE(hfci, reserved);
1881         /* TODO read error */
1882         return FALSE;
1883       }
1884       /* TODO error handling of err */
1885
1886       PFCI_FREE(hfci, reserved);
1887     }
1888
1889   } /* END OF while */
1890
1891   /* set seek of p_fci_internal->handleCFFILE2 to 0 */
1892   if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2,
1893       0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1894     /* TODO  wrong return value */
1895   }
1896   /* TODO error handling of err */
1897
1898   /* while not all CFFILE structures have been copied to the cabinet do */
1899   while(!FALSE) {
1900     /* REUSE the variable read_result */
1901     /* REUSE the buffer p_fci_internal->data_out AGAIN */
1902     /* read a block from p_fci_internal->handleCFFILE2 */
1903     read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */,
1904         p_fci_internal->data_out, /* memory buffer */
1905         32768, /* number of bytes to copy */
1906         &err, p_fci_internal->pv);
1907     if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
1908     /* TODO error handling of err */
1909
1910     /* write the block to the cabinet file */
1911     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1912       p_fci_internal->data_out, /* memory buffer */
1913       read_result, /* number of bytes to copy */
1914       &err, p_fci_internal->pv) != read_result ) {
1915       /* TODO write error */
1916       return FALSE;
1917     }
1918     /* TODO error handling of err */
1919
1920     if (p_fci_internal->fSplitFolder==FALSE) {
1921       p_fci_internal->statusFolderCopied = 0;
1922       p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+
1923         p_fci_internal->sizeFileCFFILE2;
1924     }
1925     p_fci_internal->statusFolderCopied += read_result;
1926
1927 /* TODO is this correct */
1928     /* report status with pfnfcis about copied size of folder */
1929     if( (*pfnfcis)(statusFolder,
1930       p_fci_internal->statusFolderCopied, /* length of copied blocks */
1931       p_fci_internal->statusFolderTotal, /* total size of folder */
1932       p_fci_internal->pv) == -1) {
1933       /* TODO set error code and abort */
1934       return FALSE;
1935     }
1936
1937   } /* END OF while */
1938
1939   /* set seek of p_fci_internal->handleCFDATA2 to 0 */
1940   if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2,
1941       0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1942     /* TODO  wrong return value */
1943     return FALSE;
1944   }
1945   /* TODO error handling of err */
1946
1947   /* reset the number of folders for the next cabinet */
1948   p_fci_internal->cFolders=0;
1949   /* reset the number of files for the next cabinet */
1950   p_fci_internal->cFiles=0;
1951
1952   /* while not all CFDATA structures have been copied to the cabinet do */
1953   while(!FALSE) {
1954     /* REUSE the variable read_result AGAIN */
1955     /* REUSE the buffer p_fci_internal->data_out AGAIN */
1956     /* read a block from p_fci_internal->handleCFDATA2 */
1957     read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */,
1958         p_fci_internal->data_out, /* memory buffer */
1959         32768, /* number of bytes to copy */
1960         &err, p_fci_internal->pv);
1961     if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */
1962     /* TODO error handling of err */
1963
1964     /* write the block to the cabinet file */
1965     if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1966       p_fci_internal->data_out, /* memory buffer */
1967       read_result, /* number of bytes to copy */
1968       &err, p_fci_internal->pv) != read_result ) {
1969       /* TODO write error */
1970       return FALSE;
1971     }
1972     /* TODO error handling of err */
1973
1974     p_fci_internal->statusFolderCopied += read_result;
1975     /* report status with pfnfcis about copied size of folder */
1976     if( (*pfnfcis)(statusFolder,
1977         p_fci_internal->statusFolderCopied, /* length of copied blocks */
1978         p_fci_internal->statusFolderTotal, /* total size of folder */
1979         p_fci_internal->pv) == -1) {
1980       /* TODO set error code and abort */
1981       return FALSE;
1982     }
1983   } /* END OF while */
1984
1985   /* set seek of the cabinet file to 0 */
1986   if( PFCI_SEEK(hfci, handleCABINET,
1987       0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1988     /* TODO  wrong return value */
1989   }
1990   /* TODO error handling of err */
1991
1992   /* write the signature "MSCF" into the cabinet file */
1993   memcpy( cfheader.signature, "MSCF", 4 );
1994   if( PFCI_WRITE(hfci, handleCABINET, /* file handle */
1995     &cfheader, /* memory buffer */
1996     4, /* number of bytes to copy */
1997     &err, p_fci_internal->pv) != 4 ) {
1998     /* TODO write error */
1999     return FALSE;
2000   }
2001   /* TODO error handling of err */
2002
2003   /* close the cabinet file */
2004   PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv);
2005   /* TODO error handling of err */
2006
2007
2008 /* COPIED FROM FCIDestroy */
2009
2010   PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2011   /* TODO error handling of err */
2012   PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
2013     p_fci_internal->pv);
2014   /* TODO error handling of err */
2015   PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2016   /* TODO error handling of err */
2017   PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
2018     p_fci_internal->pv);
2019   /* TODO error handling of err */
2020   PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2021   /* TODO error handling of err */
2022   PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
2023     p_fci_internal->pv);
2024   /* TODO error handling of err */
2025
2026 /* END OF copied from FCIDestroy */
2027
2028   /* get 3 temporary files and open them */
2029   /* write names and handles to hfci */
2030
2031
2032   p_fci_internal->sizeFileCFDATA2  = 0;
2033   p_fci_internal->sizeFileCFFILE2  = 0;
2034   p_fci_internal->sizeFileCFFOLDER = 0;
2035
2036 /* COPIED FROM FCICreate */
2037
2038   /* CFDATA with checksum and ready to be copied into cabinet */
2039   if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2,
2040       CB_MAX_FILENAME)) {
2041     /* TODO error handling */
2042     return FALSE;
2043   }
2044   /* safety */
2045   if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
2046     /* TODO set error code */
2047     return FALSE;
2048   }
2049   p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci,
2050     p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv);
2051   /* TODO check handle */
2052   /* TODO error checking of err */
2053
2054   /* array of all CFFILE in a folder, ready to be copied into cabinet */
2055   if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2,
2056       CB_MAX_FILENAME)) {
2057     /* TODO error handling */
2058     return FALSE;
2059   }
2060   /* safety */
2061   if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
2062     /* TODO set error code */
2063     return FALSE;
2064   }
2065   p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci,
2066     p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv);
2067   /* TODO check handle */
2068   /* TODO error checking of err */
2069
2070   /* array of all CFFILE in a folder, ready to be copied into cabinet */
2071   if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) {
2072     /* TODO error handling */
2073     return FALSE;
2074   }
2075   /* safety */
2076   if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
2077     /* TODO set error code */
2078     return FALSE;
2079   }
2080   p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci,
2081     p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv);
2082   /* TODO check handle */
2083   /* TODO error checking of err */
2084
2085 /* END OF copied from FCICreate */
2086
2087
2088   /* TODO close and delete new files when return FALSE */
2089
2090
2091   /* report status with pfnfcis about copied size of folder */
2092   if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */
2093     cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) {
2094     /* TODO set error code and abort */
2095     return FALSE;
2096   }
2097
2098   p_fci_internal->fPrevCab=TRUE;
2099   /* The sections szPrevCab and szPrevDisk are not being updated, because */
2100   /* MS CABINET.DLL always puts the first cabinet name and disk into them */
2101
2102   if (p_fci_internal->fNextCab) {
2103     p_fci_internal->fNextCab=FALSE;
2104
2105     if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) {
2106       /* THIS CAN NEVER HAPPEN */
2107       /* TODO set error code */
2108       return FALSE;
2109     }
2110
2111 /* COPIED FROM FCIAddFile and modified */
2112
2113     /* REUSE the variable read_result */
2114     if (p_fci_internal->fGetNextCabInVain) {
2115       read_result=p_fci_internal->oldCCAB.cbReserveCFHeader;
2116       if(p_fci_internal->sizeFileCFFILE1!=0) {
2117         read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder;
2118       }
2119       if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2120           p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2121           p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
2122         read_result+=4;
2123       }
2124     } else {
2125       read_result=p_fci_internal->pccab->cbReserveCFHeader;
2126       if(p_fci_internal->sizeFileCFFILE1!=0) {
2127         read_result+=p_fci_internal->pccab->cbReserveCFFolder;
2128       }
2129       if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2130           p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2131           p_fci_internal->pccab->cbReserveCFData   != 0 ) {
2132         read_result+=4;
2133       }
2134     }
2135     if ( p_fci_internal->fPrevCab ) {
2136       read_result+= strlen(p_fci_internal->szPrevCab)+1+
2137         strlen(p_fci_internal->szPrevDisk)+1;
2138     }
2139     read_result+= p_fci_internal->sizeFileCFDATA1 +
2140       p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2141       p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2142       sizeof(CFHEADER) +
2143       sizeof(CFFOLDER); /* set size of new CFFolder entry */
2144
2145     if( p_fci_internal->fNewPrevious ) {
2146       memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab,
2147         CB_MAX_CABINET_NAME);
2148       memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk,
2149         CB_MAX_DISK_NAME);
2150       p_fci_internal->fNewPrevious=FALSE;
2151     }
2152
2153     /* too much data for the maximum size of a cabinet */
2154     if( p_fci_internal->fGetNextCabInVain==FALSE &&
2155         p_fci_internal->pccab->cb < read_result ) {
2156       return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2157     }
2158
2159     /* Might be too much data for the maximum size of a cabinet.*/
2160     /* When any further data will be added later, it might not */
2161     /* be possible to flush the cabinet, because there might */
2162     /* not be enough space to store the name of the following */
2163     /* cabinet and name of the corresponding disk. */
2164     /* So take care of this and get the name of the next cabinet */
2165     if (p_fci_internal->fGetNextCabInVain==FALSE && (
2166       p_fci_internal->pccab->cb < read_result +
2167       CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2168     )) {
2169       /* save CCAB */
2170       memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2171       /* increment cabinet index */
2172       ++(p_fci_internal->pccab->iCab);
2173       /* get name of next cabinet */
2174       if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */
2175           p_fci_internal->pv)) {
2176         /* TODO error handling */
2177         return FALSE;
2178       }
2179       /* Skip a few lines of code. This is catched by the next if. */
2180       p_fci_internal->fGetNextCabInVain=TRUE;
2181     }
2182
2183     /* too much data for cabinet */
2184     if (p_fci_internal->fGetNextCabInVain && (
2185         p_fci_internal->oldCCAB.cb < read_result +
2186         strlen(p_fci_internal->oldCCAB.szCab)+1+
2187         strlen(p_fci_internal->oldCCAB.szDisk)+1
2188     )) {
2189       p_fci_internal->fGetNextCabInVain=FALSE;
2190       p_fci_internal->fNextCab=TRUE;
2191       return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2192     }
2193
2194     /* if the FolderThreshold has been reached flush the folder automatically */
2195     if( p_fci_internal->fGetNextCabInVain ) {
2196       if( p_fci_internal->cCompressedBytesInFolder >=
2197           p_fci_internal->oldCCAB.cbFolderThresh) {
2198         return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2199       }
2200     } else {
2201       if( p_fci_internal->cCompressedBytesInFolder >=
2202           p_fci_internal->pccab->cbFolderThresh) {
2203         return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2204       }
2205     }
2206
2207 /* END OF COPIED FROM FCIAddFile and modified */
2208
2209     if( p_fci_internal->sizeFileCFFILE1>0 ) {
2210       if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE;
2211       p_fci_internal->fNewPrevious=TRUE;
2212     }
2213   } else {
2214     p_fci_internal->fNewPrevious=FALSE;
2215     if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) {
2216       /* THIS MAY NEVER HAPPEN */
2217       /* TODO set error structures */
2218       return FALSE;
2219     }
2220   }
2221
2222   return TRUE;
2223 } /* end of fci_flush_cabinet */
2224
2225
2226
2227
2228
2229 /***********************************************************************
2230  *              FCIAddFile (CABINET.11)
2231  *
2232  * FCIAddFile adds a file to the to be created cabinet file
2233  *
2234  * PARAMS
2235  *   hfci          [I]  An HFCI from FCICreate
2236  *   pszSourceFile [I]  A pointer to a C string which contains the name and
2237  *                      location of the file which will be added to the cabinet
2238  *   pszFileName   [I]  A pointer to a C string which contains the name under
2239  *                      which the file will be stored in the cabinet
2240  *   fExecute      [I]  A boolean value which indicates if the file should be
2241  *                      executed after extraction of self extracting
2242  *                      executables
2243  *   pfnfcignc     [I]  A pointer to a function which gets information about
2244  *                      the next cabinet
2245  *   pfnfcis      [IO]  A pointer to a function which will report status
2246  *                      information about the compression process
2247  *   pfnfcioi      [I]  A pointer to a function which reports file attributes
2248  *                      and time and date information
2249  *   typeCompress  [I]  Compression type
2250  *
2251  * RETURNS
2252  *   On success, returns TRUE
2253  *   On failure, returns FALSE
2254  *
2255  * INCLUDES
2256  *   fci.h
2257  *
2258  */
2259 BOOL __cdecl FCIAddFile(
2260         HFCI                  hfci,
2261         char                 *pszSourceFile,
2262         char                 *pszFileName,
2263         BOOL                  fExecute,
2264         PFNFCIGETNEXTCABINET  pfnfcignc,
2265         PFNFCISTATUS          pfnfcis,
2266         PFNFCIGETOPENINFO     pfnfcigoi,
2267         TCOMP                 typeCompress)
2268 {
2269   int err;
2270   CFFILE cffile;
2271   cab_ULONG read_result;
2272   int file_handle;
2273   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2274
2275   /* test hfci */
2276   if (!REALLY_IS_FCI(hfci)) {
2277     SetLastError(ERROR_INVALID_HANDLE);
2278     return FALSE;
2279   }
2280
2281   if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
2282       (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
2283     p_fci_internal->perf->erfOper = FCIERR_NONE;
2284     p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS;
2285     p_fci_internal->perf->fError = TRUE;
2286
2287     SetLastError(ERROR_BAD_ARGUMENTS);
2288     return FALSE;
2289   }
2290
2291   /* TODO check if pszSourceFile??? */
2292
2293   if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
2294     /* TODO internal error */
2295     return FALSE;
2296   }
2297
2298   if(p_fci_internal->fNextCab) {
2299     /* TODO internal error */
2300     return FALSE;
2301   }
2302
2303   cffile.cbFile=0; /* size of the to be added file*/
2304   /* offset of the uncompressed file in the folder */
2305   cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in;
2306   /* number of folder in the cabinet or special 0=first  */
2307   cffile.iFolder = p_fci_internal->cFolders;
2308
2309   /* allocation of memory */
2310   if (p_fci_internal->data_in==NULL) {
2311     if (p_fci_internal->cdata_in!=0) {
2312       /* TODO error handling */
2313       return FALSE;
2314     }
2315     if (p_fci_internal->data_out!=NULL) {
2316       /* TODO error handling */
2317       return FALSE;
2318     }
2319     if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) {
2320       p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2321       p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2322       p_fci_internal->perf->fError = TRUE;
2323       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2324       return FALSE;
2325     }
2326     if (p_fci_internal->data_out==NULL) {
2327       if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){
2328         p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL;
2329         p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
2330         p_fci_internal->perf->fError = TRUE;
2331         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2332         return FALSE;
2333       }
2334     }
2335   }
2336
2337   if (p_fci_internal->data_out==NULL) {
2338     PFCI_FREE(hfci,p_fci_internal->data_in);
2339     /* TODO error handling */
2340     return FALSE;
2341   }
2342
2343   /* get information about the file */
2344   file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time),
2345     &(cffile.attribs), &err, p_fci_internal->pv);
2346   /* TODO check file_handle */
2347   /* TODO error handling of err */
2348
2349   if (fExecute) { cffile.attribs |= _A_EXEC; }
2350
2351   /* REUSE the variable read_result */
2352   if (p_fci_internal->fGetNextCabInVain) {
2353     read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2354       p_fci_internal->oldCCAB.cbReserveCFFolder;
2355     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2356         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2357         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
2358       read_result+=4;
2359     }
2360   } else {
2361     read_result=p_fci_internal->pccab->cbReserveCFHeader +
2362       p_fci_internal->pccab->cbReserveCFFolder;
2363     if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2364         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2365         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
2366       read_result+=4;
2367     }
2368   }
2369   if ( p_fci_internal->fPrevCab ) {
2370     read_result+= strlen(p_fci_internal->szPrevCab)+1+
2371       strlen(p_fci_internal->szPrevDisk)+1;
2372   }
2373   if ( p_fci_internal->fNextCab ) { /* this is never the case */
2374     read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2375       strlen(p_fci_internal->pccab->szDisk)+1;
2376   }
2377
2378   read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
2379     p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2380     p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2381     sizeof(CFHEADER) +
2382     sizeof(CFFOLDER); /* size of new CFFolder entry */
2383
2384   /* Might be too much data for the maximum size of a cabinet.*/
2385   /* When any further data will be added later, it might not */
2386   /* be possible to flush the cabinet, because there might */
2387   /* not be enough space to store the name of the following */
2388   /* cabinet and name of the corresponding disk. */
2389   /* So take care of this and get the name of the next cabinet */
2390   if( p_fci_internal->fGetNextCabInVain==FALSE &&
2391       p_fci_internal->fNextCab==FALSE &&
2392       ( p_fci_internal->pccab->cb < read_result +
2393         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2394       )
2395   ) {
2396     /* save CCAB */
2397     memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2398     /* increment cabinet index */
2399     ++(p_fci_internal->pccab->iCab);
2400     /* get name of next cabinet */
2401     if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2402         p_fci_internal->pv)) {
2403       /* TODO error handling */
2404       return FALSE;
2405     }
2406     /* Skip a few lines of code. This is catched by the next if. */
2407     p_fci_internal->fGetNextCabInVain=TRUE;
2408   }
2409
2410   if( p_fci_internal->fGetNextCabInVain &&
2411       p_fci_internal->fNextCab
2412   ) {
2413     /* THIS CAN NEVER HAPPEN */
2414     /* TODO set error code*/
2415     return FALSE;
2416   }
2417
2418   /* too much data for cabinet */
2419   if( p_fci_internal->fGetNextCabInVain &&
2420      (
2421       p_fci_internal->oldCCAB.cb < read_result +
2422       strlen(p_fci_internal->pccab->szCab)+1+
2423       strlen(p_fci_internal->pccab->szDisk)+1
2424   )) {
2425     p_fci_internal->fGetNextCabInVain=FALSE;
2426     p_fci_internal->fNextCab=TRUE;
2427     if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE;
2428   }
2429
2430   if( p_fci_internal->fNextCab ) {
2431     /* THIS MAY NEVER HAPPEN */
2432     /* TODO set error code*/
2433     return FALSE;
2434   }
2435
2436   /* read the contents of the file blockwize*/
2437   while (!FALSE) {
2438     if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
2439       /* TODO internal error */
2440       return FALSE;
2441     }
2442
2443     read_result = PFCI_READ(hfci, file_handle /* file handle */,
2444       (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
2445       (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
2446       &err, p_fci_internal->pv);
2447     /* TODO error handling of err */
2448
2449     if( read_result==0 ) break;
2450
2451     /* increment the block size */
2452     p_fci_internal->cdata_in += read_result;
2453
2454     /* increment the file size */
2455     cffile.cbFile += read_result;
2456
2457
2458     if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
2459       /* TODO report internal error */
2460       return FALSE;
2461     }
2462     /* write a whole block */
2463     if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
2464
2465       if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE;
2466     }
2467   }
2468
2469   /* close the file from FCIAddFile */
2470   PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv);
2471   /* TODO error handling of err */
2472
2473   /* write cffile to p_fci_internal->handleCFFILE1 */
2474   if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2475       &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) {
2476     /* TODO write error */
2477     return FALSE;
2478   }
2479   /* TODO error handling of err */
2480
2481   p_fci_internal->sizeFileCFFILE1 += sizeof(cffile);
2482
2483   /* append the name of file*/
2484   if (strlen(pszFileName)>=CB_MAX_FILENAME) {
2485     /* IMPOSSIBLE */
2486     /* TODO set error code */
2487     return FALSE;
2488   }
2489   if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */
2490       pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv)
2491       != strlen(pszFileName)+1 ) {
2492     /* TODO write error */
2493     return FALSE;
2494   }
2495   /* TODO error handling of err */
2496
2497   p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1;
2498
2499   /* REUSE the variable read_result */
2500   if (p_fci_internal->fGetNextCabInVain ||
2501       p_fci_internal->fNextCab
2502      ) {
2503     read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2504       p_fci_internal->oldCCAB.cbReserveCFFolder;
2505     if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2506         p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2507         p_fci_internal->oldCCAB.cbReserveCFData   != 0 ) {
2508       read_result+=4;
2509     }
2510   } else {
2511     read_result=p_fci_internal->pccab->cbReserveCFHeader +
2512       p_fci_internal->pccab->cbReserveCFFolder;
2513     if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2514         p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2515         p_fci_internal->pccab->cbReserveCFData   != 0 ) {
2516       read_result+=4;
2517     }
2518   }
2519   if ( p_fci_internal->fPrevCab ) {
2520     read_result+= strlen(p_fci_internal->szPrevCab)+1+
2521       strlen(p_fci_internal->szPrevDisk)+1;
2522   }
2523   if ( p_fci_internal->fNextCab ) { /* this is never the case */
2524     read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2525       strlen(p_fci_internal->pccab->szDisk)+1;
2526   }
2527   read_result+= p_fci_internal->sizeFileCFDATA1 +
2528     p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2529     p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2530     sizeof(CFHEADER) +
2531     sizeof(CFFOLDER); /* set size of new CFFolder entry */
2532
2533   /* too much data for the maximum size of a cabinet */
2534   /* (ignoring the unflushed data block) */
2535   if( p_fci_internal->fGetNextCabInVain==FALSE &&
2536       p_fci_internal->fNextCab==FALSE && /* this is always the case */
2537       p_fci_internal->pccab->cb < read_result ) {
2538     return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2539   }
2540
2541   /* Might be too much data for the maximum size of a cabinet.*/
2542   /* When any further data will be added later, it might not */
2543   /* be possible to flush the cabinet, because there might */
2544   /* not be enough space to store the name of the following */
2545   /* cabinet and name of the corresponding disk. */
2546   /* So take care of this and get the name of the next cabinet */
2547   /* (ignoring the unflushed data block) */
2548   if( p_fci_internal->fGetNextCabInVain==FALSE &&
2549       p_fci_internal->fNextCab==FALSE &&
2550       ( p_fci_internal->pccab->cb < read_result +
2551         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2552       )
2553   ) {
2554     /* save CCAB */
2555     memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB));
2556     /* increment cabinet index */
2557     ++(p_fci_internal->pccab->iCab);
2558     /* get name of next cabinet */
2559     if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */
2560         p_fci_internal->pv)) {
2561       /* TODO error handling */
2562       return FALSE;
2563     }
2564     /* Skip a few lines of code. This is catched by the next if. */
2565     p_fci_internal->fGetNextCabInVain=TRUE;
2566   }
2567
2568   if( p_fci_internal->fGetNextCabInVain &&
2569       p_fci_internal->fNextCab
2570   ) {
2571     /* THIS CAN NEVER HAPPEN */
2572     /* TODO set error code*/
2573     return FALSE;
2574   }
2575
2576   /* too much data for cabinet */
2577   if( (p_fci_internal->fGetNextCabInVain ||
2578       p_fci_internal->fNextCab) && (
2579       p_fci_internal->oldCCAB.cb < read_result +
2580       strlen(p_fci_internal->pccab->szCab)+1+
2581       strlen(p_fci_internal->pccab->szDisk)+1
2582   )) {
2583
2584     p_fci_internal->fGetNextCabInVain=FALSE;
2585     p_fci_internal->fNextCab=TRUE;
2586     return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis);
2587   }
2588
2589   if( p_fci_internal->fNextCab ) {
2590     /* THIS MAY NEVER HAPPEN */
2591     /* TODO set error code*/
2592     return FALSE;
2593   }
2594
2595   /* if the FolderThreshold has been reached flush the folder automatically */
2596   if( p_fci_internal->fGetNextCabInVain ) {
2597     if( p_fci_internal->cCompressedBytesInFolder >=
2598         p_fci_internal->oldCCAB.cbFolderThresh) {
2599       return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2600     }
2601   } else {
2602     if( p_fci_internal->cCompressedBytesInFolder >=
2603         p_fci_internal->pccab->cbFolderThresh) {
2604       return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2605     }
2606   }
2607
2608   return TRUE;
2609 } /* end of FCIAddFile */
2610
2611
2612
2613
2614
2615 /***********************************************************************
2616  *              FCIFlushFolder (CABINET.12)
2617  *
2618  * FCIFlushFolder completes the CFFolder structure under construction.
2619  *
2620  * All further data which is added by FCIAddFile will be associateed to
2621  * the next CFFolder structure.
2622  *
2623  * FCIFlushFolder will be called by FCIAddFile automatically if the
2624  * threshold (stored in the member cbFolderThresh of the CCAB structure
2625  * pccab passed to FCICreate) is exceeded.
2626  *
2627  * FCIFlushFolder will be called by FCIFlushFolder automatically before
2628  * any data will be written into the cabinet file.
2629  *
2630  * PARAMS
2631  *   hfci          [I]  An HFCI from FCICreate
2632  *   pfnfcignc     [I]  A pointer to a function which gets information about
2633  *                      the next cabinet
2634  *   pfnfcis      [IO]  A pointer to a function which will report status
2635  *                      information about the compression process
2636  *
2637  * RETURNS
2638  *   On success, returns TRUE
2639  *   On failure, returns FALSE
2640  *
2641  * INCLUDES
2642  *   fci.h
2643  *
2644  */
2645 BOOL __cdecl FCIFlushFolder(
2646         HFCI                  hfci,
2647         PFNFCIGETNEXTCABINET  pfnfcignc,
2648         PFNFCISTATUS          pfnfcis)
2649 {
2650   return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis);
2651 } /* end of FCIFlushFolder */
2652
2653
2654
2655 /***********************************************************************
2656  *              FCIFlushCabinet (CABINET.13)
2657  *
2658  * FCIFlushCabinet stores the data which has been added by FCIAddFile
2659  * into the cabinet file. If the maximum cabinet size (stored in the
2660  * member cb of the CCAB structure pccab passed to FCICreate) has been
2661  * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2662  * The remaining data still has to be flushed manually by calling
2663  * FCIFlushCabinet.
2664  *
2665  * After FCIFlushCabinet has been called (manually) FCIAddFile must
2666  * NOT be called again. Then hfci has to be released by FCIDestroy.
2667  *
2668  * PARAMS
2669  *   hfci          [I]  An HFCI from FCICreate
2670  *   fGetNextCab   [I]  Whether you want to add additional files to a
2671  *                      cabinet set (TRUE) or whether you want to
2672  *                      finalize it (FALSE)
2673  *   pfnfcignc     [I]  A pointer to a function which gets information about
2674  *                      the next cabinet
2675  *   pfnfcis      [IO]  A pointer to a function which will report status
2676  *                      information about the compression process
2677  *
2678  * RETURNS
2679  *   On success, returns TRUE
2680  *   On failure, returns FALSE
2681  *
2682  * INCLUDES
2683  *   fci.h
2684  *
2685  */
2686 BOOL __cdecl FCIFlushCabinet(
2687         HFCI                  hfci,
2688         BOOL                  fGetNextCab,
2689         PFNFCIGETNEXTCABINET  pfnfcignc,
2690         PFNFCISTATUS          pfnfcis)
2691 {
2692   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2693
2694   if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2695
2696   while( p_fci_internal->sizeFileCFFILE1>0 ||
2697          p_fci_internal->sizeFileCFFILE2>0 ) {
2698     if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2699   }
2700
2701   return TRUE;
2702 } /* end of FCIFlushCabinet */
2703
2704
2705 /***********************************************************************
2706  *              FCIDestroy (CABINET.14)
2707  *
2708  * Frees a handle created by FCICreate.
2709  * Only reason for failure would be an invalid handle.
2710  *
2711  * PARAMS
2712  *   hfci [I] The HFCI to free
2713  *
2714  * RETURNS
2715  *   TRUE for success
2716  *   FALSE for failure
2717  */
2718 BOOL __cdecl FCIDestroy(HFCI hfci)
2719 {
2720   int err;
2721   PFCI_Int p_fci_internal=((PFCI_Int)(hfci));
2722   if (REALLY_IS_FCI(hfci)) {
2723
2724     /* before hfci can be removed all temporary files must be closed */
2725     /* and deleted */
2726     p_fci_internal->FCI_Intmagic = 0;
2727
2728     PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
2729     /* TODO error handling of err */
2730     PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err,
2731       p_fci_internal->pv);
2732     /* TODO error handling of err */
2733     PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);
2734     /* TODO error handling of err */
2735     PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err,
2736       p_fci_internal->pv);
2737     /* TODO error handling of err */
2738     PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2739     /* TODO error handling of err */
2740     PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err,
2741       p_fci_internal->pv);
2742     /* TODO error handling of err */
2743     PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2744     /* TODO error handling of err */
2745     PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err,
2746       p_fci_internal->pv);
2747     /* TODO error handling of err */
2748     PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2749     /* TODO error handling of err */
2750     PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err,
2751       p_fci_internal->pv);
2752     /* TODO error handling of err */
2753
2754     /* data in and out buffers have to be removed */
2755     if (p_fci_internal->data_in!=NULL)
2756       PFCI_FREE(hfci, p_fci_internal->data_in);
2757     if (p_fci_internal->data_out!=NULL)
2758       PFCI_FREE(hfci, p_fci_internal->data_out);
2759
2760     /* hfci can now be removed */
2761     PFCI_FREE(hfci, hfci);
2762     return TRUE;
2763   } else {
2764     SetLastError(ERROR_INVALID_HANDLE);
2765     return FALSE;
2766   }
2767
2768 } /* end of FCIDestroy */