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