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