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