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