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