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