kernel32: Remove a useless error message.
[wine] / dlls / cabinet / fci.c
1 /*
2  * File Compression Interface
3  *
4  * Copyright 2002 Patrik Stridvall
5  * Copyright 2005 Gerold Jens Wucherpfennig
6  * Copyright 2011 Alexandre Julliard
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 /*
24
25 There is still some work to be done:
26
27 - no real compression yet
28 - unknown behaviour if files>=2GB or cabinet >=4GB
29 - check if the maximum size for a cabinet is too small to store any data
30 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
31 - probably check err
32
33 */
34
35
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winerror.h"
47 #include "winternl.h"
48 #include "fci.h"
49 #include "cabinet.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
52
53
54 #ifdef WORDS_BIGENDIAN
55 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
56 #define fci_endian_uword(x) RtlUshortByteSwap(x)
57 #else
58 #define fci_endian_ulong(x) (x)
59 #define fci_endian_uword(x) (x)
60 #endif
61
62
63 typedef struct {
64   cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
65   cab_ULONG reserved1;
66   cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/
67   cab_ULONG reserved2;
68   cab_ULONG coffFiles;    /* offset to first CFFILE section */
69   cab_ULONG reserved3;
70   cab_UBYTE versionMinor; /* 3 */
71   cab_UBYTE versionMajor; /* 1 */
72   cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/
73   cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/
74   cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
75   cab_UWORD setID;        /* identification number of all cabinets in a set*/
76   cab_UWORD iCabinet;     /* number of the cabinet in a set */
77   /* additional area if "flags" were set*/
78 } CFHEADER; /* minimum 36 bytes */
79
80 typedef struct {
81   cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
82   cab_UWORD cCFData;      /* number of this folder's CFDATA sections */
83   cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
84   /* additional area if reserve flag was set */
85 } CFFOLDER; /* minimum 8 bytes */
86
87 typedef struct {
88   cab_ULONG cbFile;          /* size of the uncompressed file in bytes */
89   cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
90   cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */
91                              /* for special values see below this structure*/
92   cab_UWORD date;            /* last modification date*/
93   cab_UWORD time;            /* last modification time*/
94   cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */
95   /* ... and a C string with the name of the file */
96 } CFFILE; /* 16 bytes + name of file */
97
98
99 typedef struct {
100   cab_ULONG csum;          /* checksum of this entry*/
101   cab_UWORD cbData;        /* number of compressed bytes  */
102   cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */
103   /* optional reserved area */
104   /* compressed data */
105 } CFDATA;
106
107 struct temp_file
108 {
109     INT_PTR   handle;
110     cab_ULONG size;
111     char      name[CB_MAX_FILENAME];
112 };
113
114 struct folder
115 {
116     struct list entry;
117     struct list files_list;
118     cab_ULONG   data_start;
119     cab_UWORD   data_count;
120     cab_UWORD   compression;
121 };
122
123 struct file
124 {
125     struct list entry;
126     cab_ULONG   size;    /* uncompressed size */
127     cab_ULONG   offset;  /* offset in folder */
128     cab_UWORD   folder;  /* index of folder */
129     cab_UWORD   date;
130     cab_UWORD   time;
131     cab_UWORD   attribs;
132     char        name[1];
133 };
134
135 struct data_block
136 {
137     struct list entry;
138     cab_UWORD   compressed;
139     cab_UWORD   uncompressed;
140 };
141
142 typedef struct
143 {
144   unsigned int       magic;
145   PERF               perf;
146   PFNFCIFILEPLACED   fileplaced;
147   PFNFCIALLOC        alloc;
148   PFNFCIFREE         free;
149   PFNFCIOPEN         open;
150   PFNFCIREAD         read;
151   PFNFCIWRITE        write;
152   PFNFCICLOSE        close;
153   PFNFCISEEK         seek;
154   PFNFCIDELETE       delete;
155   PFNFCIGETTEMPFILE  gettemp;
156   CCAB               ccab;
157   PCCAB              pccab;
158   BOOL               fPrevCab;
159   BOOL               fNextCab;
160   BOOL               fSplitFolder;
161   cab_ULONG          statusFolderCopied;
162   cab_ULONG          statusFolderTotal;
163   BOOL               fGetNextCabInVain;
164   void               *pv;
165   char szPrevCab[CB_MAX_CABINET_NAME];    /* previous cabinet name */
166   char szPrevDisk[CB_MAX_DISK_NAME];      /* disk name of previous cabinet */
167   char*              data_in;  /* uncompressed data blocks */
168   cab_UWORD          cdata_in;
169   char*              data_out; /* compressed data blocks */
170   ULONG              cCompressedBytesInFolder;
171   cab_UWORD          cFolders;
172   cab_UWORD          cFiles;
173   cab_ULONG          cDataBlocks;
174   cab_ULONG          cbFileRemainer; /* uncompressed, yet to be written data */
175                /* of spanned file of a spanning folder of a spanning cabinet */
176   struct temp_file   data1;
177   struct temp_file   data2;
178   BOOL               fNewPrevious;
179   cab_ULONG          estimatedCabinetSize;
180   struct list        folders_list;
181   struct list        files_list;
182   struct list        blocks_list;
183   cab_ULONG          folders_size;
184   cab_ULONG          files_size;
185   cab_ULONG          placed_files_size;
186 } FCI_Int;
187
188 #define FCI_INT_MAGIC 0xfcfcfc05
189
190 static void set_error( FCI_Int *fci, int oper, int err )
191 {
192     fci->perf->erfOper = oper;
193     fci->perf->erfType = err;
194     fci->perf->fError = TRUE;
195     if (err) SetLastError( err );
196 }
197
198 static FCI_Int *get_fci_ptr( HFCI hfci )
199 {
200     FCI_Int *fci= (FCI_Int *)hfci;
201
202     if (!fci || !fci->magic == FCI_INT_MAGIC)
203     {
204         SetLastError( ERROR_INVALID_HANDLE );
205         return NULL;
206     }
207     return fci;
208 }
209
210 /* compute the cabinet header size */
211 static cab_ULONG get_header_size( FCI_Int *fci )
212 {
213     cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
214
215     if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
216         ret += 4;
217
218     if (fci->fPrevCab)
219         ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
220
221     if (fci->fNextCab)
222         ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
223
224     return ret;
225 }
226
227 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
228 {
229     int err;
230
231     if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
232     {
233         set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
234         return FALSE;
235     }
236     if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
237                                    _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
238     {
239         set_error( fci, FCIERR_TEMP_FILE, err );
240         return FALSE;
241     }
242     file->size = 0;
243     return TRUE;
244 }
245
246 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
247 {
248     int err;
249
250     if (file->handle == -1) return TRUE;
251     if (fci->close( file->handle, &err, fci->pv ) == -1)
252     {
253         set_error( fci, FCIERR_TEMP_FILE, err );
254         return FALSE;
255     }
256     file->handle = -1;
257     if (fci->delete( file->name, &err, fci->pv ) == -1)
258     {
259         set_error( fci, FCIERR_TEMP_FILE, err );
260         return FALSE;
261     }
262     return TRUE;
263 }
264
265 static struct file *add_file( FCI_Int *fci, const char *filename )
266 {
267     unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
268     struct file *file = fci->alloc( size );
269
270     if (!file)
271     {
272         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
273         return NULL;
274     }
275     file->size    = 0;
276     file->offset  = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
277     file->folder  = fci->cFolders;
278     file->date    = 0;
279     file->time    = 0;
280     file->attribs = 0;
281     strcpy( file->name, filename );
282     list_add_tail( &fci->files_list, &file->entry );
283     return file;
284 }
285
286 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
287 {
288     unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
289     struct file *file = fci->alloc( size );
290
291     if (!file)
292     {
293         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
294         return NULL;
295     }
296     memcpy( file, orig, size );
297     return file;
298 }
299
300 static void free_file( FCI_Int *fci, struct file *file )
301 {
302     list_remove( &file->entry );
303     fci->free( file );
304 }
305
306 static struct folder *add_folder( FCI_Int *fci )
307 {
308     struct folder *folder = fci->alloc( sizeof(*folder) );
309
310     if (!folder)
311     {
312         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
313         return NULL;
314     }
315     folder->data_start  = fci->data2.size;
316     folder->compression = tcompTYPE_NONE;  /* FIXME */
317     list_init( &folder->files_list );
318     list_add_tail( &fci->folders_list, &folder->entry );
319     fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
320     fci->cFolders++;
321     return folder;
322 }
323
324 static void free_folder( FCI_Int *fci, struct folder *folder )
325 {
326     struct file *file, *next;
327
328     LIST_FOR_EACH_ENTRY_SAFE( file, next, &folder->files_list, struct file, entry ) free_file( fci, file );
329     list_remove( &folder->entry );
330     fci->free( folder );
331 }
332
333 static struct data_block *add_data_block( FCI_Int *fci, cab_UWORD compressed, cab_UWORD uncompressed )
334 {
335     struct data_block *block = fci->alloc( sizeof(*block) );
336
337     if (!block)
338     {
339         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
340         return NULL;
341     }
342     block->compressed   = compressed;
343     block->uncompressed = uncompressed;
344     list_add_tail( &fci->blocks_list, &block->entry );
345     fci->data2.size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + compressed;
346     fci->cDataBlocks++;
347     return block;
348 }
349
350 static void free_data_block( FCI_Int *fci, struct data_block *block )
351 {
352     list_remove( &block->entry );
353     fci->free( block );
354 }
355
356 /* reset state for the next cabinet file once the current one has been flushed */
357 static void reset_cabinet( FCI_Int *fci )
358 {
359     struct folder *folder, *folder_next;
360     struct data_block *block, *block_next;
361
362     LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
363         free_folder( fci, folder );
364
365     LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &fci->blocks_list, struct data_block, entry )
366         free_data_block( fci, block );
367
368     close_temp_file( fci, &fci->data2 );
369
370     fci->cFolders          = 0;
371     fci->cFiles            = 0;
372     fci->folders_size      = 0;
373     fci->placed_files_size = 0;
374     fci->data2.size        = 0;
375 }
376
377 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
378 {
379   cab_ULONG     csum;
380   cab_ULONG     ul;
381   int           cUlong;
382   const BYTE    *pb;
383
384   csum = seed;
385   cUlong = cb / 4;
386   pb = pv;
387
388   while (cUlong-- > 0) {
389     ul = *pb++;
390     ul |= (((cab_ULONG)(*pb++)) <<  8);
391     ul |= (((cab_ULONG)(*pb++)) << 16);
392     ul |= (((cab_ULONG)(*pb++)) << 24);
393     csum ^= ul;
394   }
395
396   ul = 0;
397   switch (cb % 4) {
398     case 3:
399       ul |= (((ULONG)(*pb++)) << 16);
400     case 2:
401       ul |= (((ULONG)(*pb++)) <<  8);
402     case 1:
403       ul |= *pb;
404     default:
405       break;
406   }
407   csum ^= ul;
408
409   return csum;
410 }
411
412 /* write all folders to disk and remove them from the list */
413 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
414 {
415     struct folder *folder;
416     int err;
417     BOOL ret = TRUE;
418     CFFOLDER *cffolder;
419     cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
420
421     if (!(cffolder = fci->alloc( folder_size )))
422     {
423         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
424         return FALSE;
425     }
426     memset( cffolder, 0, folder_size );
427
428     /* write the folders */
429     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
430     {
431         cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
432         cffolder->cCFData      = fci_endian_uword( folder->data_count );
433         cffolder->typeCompress = fci_endian_uword( folder->compression );
434         if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
435         {
436             set_error( fci, FCIERR_CAB_FILE, err );
437             ret = FALSE;
438             break;
439         }
440     }
441
442     fci->free( cffolder );
443     return ret;
444 }
445
446 /* write all the files to the cabinet file */
447 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
448 {
449     cab_ULONG file_size;
450     struct folder *folder;
451     struct file *file;
452     int err;
453     BOOL ret = TRUE;
454     CFFILE *cffile;
455
456     if (!(cffile = fci->alloc( sizeof(CFFILE) + CB_MAX_FILENAME )))
457     {
458         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
459         return FALSE;
460     }
461
462     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
463     {
464         LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
465         {
466             cffile->cbFile          = fci_endian_ulong( file->size );
467             cffile->uoffFolderStart = fci_endian_ulong( file->offset );
468             cffile->iFolder         = fci_endian_uword( file->folder );
469             cffile->date            = fci_endian_uword( file->date );
470             cffile->time            = fci_endian_uword( file->time );
471             cffile->attribs         = fci_endian_uword( file->attribs );
472             lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
473             file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
474             if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
475             {
476                 set_error( fci, FCIERR_CAB_FILE, err );
477                 ret = FALSE;
478                 break;
479             }
480             if (!fci->fSplitFolder)
481             {
482                 fci->statusFolderCopied = 0;
483                 /* TODO TEST THIS further */
484                 fci->statusFolderTotal = fci->data2.size + fci->placed_files_size;
485             }
486             fci->statusFolderCopied += file_size;
487             /* report status about copied size of folder */
488             if (status_callback( statusFolder, fci->statusFolderCopied,
489                                  fci->statusFolderTotal, fci->pv ) == -1)
490             {
491                 set_error( fci, FCIERR_USER_ABORT, 0 );
492                 ret = FALSE;
493                 break;
494             }
495         }
496     }
497
498     fci->free( cffile );
499     return ret;
500 }
501
502 /* write all data blocks to the cabinet file */
503 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
504 {
505     struct data_block *block;
506     int err, len;
507     CFDATA *cfdata;
508     void *data;
509     cab_UWORD header_size;
510
511     if (!fci->data_out) return TRUE;
512
513     if (fci->seek( fci->data2.handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
514     {
515         set_error( fci, FCIERR_CAB_FILE, err );
516         return FALSE;
517     }
518
519     header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
520     cfdata = (CFDATA *)fci->data_out;
521     memset( cfdata, 0, header_size );
522     data = (char *)cfdata + header_size;
523
524     LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
525     {
526         len = fci->read( fci->data2.handle, data, block->compressed, &err, fci->pv );
527         if (len != block->compressed) return FALSE;
528
529         cfdata->cbData = fci_endian_uword( block->compressed );
530         cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
531         cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
532                                                            header_size - FIELD_OFFSET( CFDATA, cbData ),
533                                                            fci_get_checksum( data, len, 0 )));
534
535         fci->statusFolderCopied += len;
536         len += header_size;
537         if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
538         {
539             set_error( fci, FCIERR_CAB_FILE, err );
540             return FALSE;
541         }
542         if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
543         {
544             set_error( fci, FCIERR_USER_ABORT, 0 );
545             return FALSE;
546         }
547     }
548     return TRUE;
549 }
550
551 /* write the cabinet file to disk */
552 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
553 {
554     char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
555     int err;
556     char *ptr;
557     INT_PTR handle;
558     CFHEADER *cfheader;
559     cab_UWORD flags = 0;
560     cab_ULONG header_size = get_header_size( fci );
561     cab_ULONG total_size = header_size + fci->folders_size + fci->placed_files_size + fci->data2.size;
562
563     if (!(cfheader = fci->alloc( header_size )))
564     {
565         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
566         return FALSE;
567     }
568     memset( cfheader, 0, header_size );
569
570     if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
571     if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
572     if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
573       flags |= cfheadRESERVE_PRESENT;
574
575     memcpy( cfheader->signature, "!CAB", 4 );
576     cfheader->cbCabinet    = fci_endian_ulong( total_size );
577     cfheader->coffFiles    = fci_endian_ulong( header_size + fci->folders_size );
578     cfheader->versionMinor = 3;
579     cfheader->versionMajor = 1;
580     cfheader->cFolders     = fci_endian_uword( fci->cFolders );
581     cfheader->cFiles       = fci_endian_uword( fci->cFiles );
582     cfheader->flags        = fci_endian_uword( flags );
583     cfheader->setID        = fci_endian_uword( fci->ccab.setID );
584     cfheader->iCabinet     = fci_endian_uword( fci->ccab.iCab - 1 );
585     ptr = (char *)(cfheader + 1);
586
587     if (flags & cfheadRESERVE_PRESENT)
588     {
589         struct
590         {
591             cab_UWORD cbCFHeader;
592             cab_UBYTE cbCFFolder;
593             cab_UBYTE cbCFData;
594         } *reserve = (void *)ptr;
595
596         reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
597         reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
598         reserve->cbCFData   = fci->ccab.cbReserveCFData;
599         ptr = (char *)(reserve + 1);
600     }
601     ptr += fci->ccab.cbReserveCFHeader;
602
603     if (flags & cfheadPREV_CABINET)
604     {
605         strcpy( ptr, fci->szPrevCab );
606         ptr += strlen( ptr ) + 1;
607         strcpy( ptr, fci->szPrevDisk );
608         ptr += strlen( ptr ) + 1;
609     }
610
611     if (flags & cfheadNEXT_CABINET)
612     {
613         strcpy( ptr, fci->pccab->szCab );
614         ptr += strlen( ptr ) + 1;
615         strcpy( ptr, fci->pccab->szDisk );
616         ptr += strlen( ptr ) + 1;
617     }
618
619     assert( ptr - (char *)cfheader == header_size );
620
621     strcpy( filename, fci->ccab.szCabPath );
622     strcat( filename, fci->ccab.szCab );
623
624     if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
625                              _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
626     {
627         set_error( fci, FCIERR_CAB_FILE, err );
628         fci->free( cfheader );
629         return FALSE;
630     }
631
632     if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
633     {
634         set_error( fci, FCIERR_CAB_FILE, err );
635         goto failed;
636     }
637
638     /* add size of header size of all CFFOLDERs and size of all CFFILEs */
639     header_size += fci->placed_files_size + fci->folders_size;
640     if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
641     if (!write_files( fci, handle, status_callback )) goto failed;
642     if (!write_data_blocks( fci, handle, status_callback )) goto failed;
643
644     /* update the signature */
645     if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
646     {
647         set_error( fci, FCIERR_CAB_FILE, err );
648         goto failed;
649     }
650     memcpy( cfheader->signature, "MSCF", 4 );
651     if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
652     {
653         set_error( fci, FCIERR_CAB_FILE, err );
654         goto failed;
655     }
656     fci->close( handle, &err, fci->pv );
657     fci->free( cfheader );
658
659     reset_cabinet( fci );
660     status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
661     return TRUE;
662
663 failed:
664     fci->close( handle, &err, fci->pv );
665     fci->delete( filename, &err, fci->pv );
666     fci->free( cfheader );
667     return FALSE;
668 }
669
670 /* add all pending files to folder */
671 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
672 {
673     cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
674     cab_ULONG cbFileRemainer = 0;
675     struct file *file, *next;
676
677     LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
678     {
679         cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
680
681         /* fnfilfnfildest: placed file on cabinet */
682         fci->fileplaced( &fci->ccab, file->name, file->size,
683                          (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
684
685         sizeOfFilesPrev = sizeOfFiles;
686         /* set complete size of all processed files */
687         if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
688         {
689             sizeOfFiles += fci->cbFileRemainer;
690             fci->cbFileRemainer = 0;
691         }
692         else sizeOfFiles += file->size;
693
694         /* check if spanned file fits into this cabinet folder */
695         if (sizeOfFiles > payload)
696         {
697             if (file->folder == cffileCONTINUED_FROM_PREV)
698                 file->folder = cffileCONTINUED_PREV_AND_NEXT;
699             else
700                 file->folder = cffileCONTINUED_TO_NEXT;
701         }
702
703         list_remove( &file->entry );
704         list_add_tail( &folder->files_list, &file->entry );
705         fci->placed_files_size += size;
706         fci->cFiles++;
707
708         /* This is only true for files which will be written into the */
709         /* next cabinet of the spanning folder */
710         if (sizeOfFiles > payload)
711         {
712             /* add a copy back onto the list */
713             if (!(file = copy_file( fci, file ))) return FALSE;
714             list_add_before( &next->entry, &file->entry );
715
716             /* Files which data will be partially written into the current cabinet */
717             if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
718             {
719                 if (sizeOfFilesPrev <= payload)
720                 {
721                     /* The size of the uncompressed, data of a spanning file in a */
722                     /* spanning data */
723                     cbFileRemainer = sizeOfFiles - payload;
724                 }
725                 file->folder = cffileCONTINUED_FROM_PREV;
726             }
727             else file->folder = 0;
728         }
729         else
730         {
731             fci->files_size -= size;
732         }
733     }
734     fci->cbFileRemainer = cbFileRemainer;
735     return TRUE;
736 }
737
738 /***********************************************************************
739  *              FCICreate (CABINET.10)
740  *
741  * FCICreate is provided with several callbacks and
742  * returns a handle which can be used to create cabinet files.
743  *
744  * PARAMS
745  *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
746  *                    returns an error condition, error information may
747  *                    be found here as well as from GetLastError.
748  *   pfnfiledest [I]  A pointer to a function which is called when a file
749  *                    is placed. Only useful for subsequent cabinet files.
750  *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
751  *                    the same interface as malloc.
752  *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
753  *                    same interface as free.
754  *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
755  *                    the same interface as _open.
756  *   pfnread     [I]  A pointer to a function which reads from a file into
757  *                    a caller-provided buffer.  Uses the same interface
758  *                    as _read.
759  *   pfnwrite    [I]  A pointer to a function which writes to a file from
760  *                    a caller-provided buffer.  Uses the same interface
761  *                    as _write.
762  *   pfnclose    [I]  A pointer to a function which closes a file handle.
763  *                    Uses the same interface as _close.
764  *   pfnseek     [I]  A pointer to a function which seeks in a file.
765  *                    Uses the same interface as _lseek.
766  *   pfndelete   [I]  A pointer to a function which deletes a file.
767  *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
768  *                    temporary file.
769  *   pccab       [I]  A pointer to an initialized CCAB structure.
770  *   pv          [I]  A pointer to an application-defined notification
771  *                    function which will be passed to other FCI functions
772  *                    as a parameter.
773  *
774  * RETURNS
775  *   On success, returns an FCI handle of type HFCI.
776  *   On failure, the NULL file handle is returned. Error
777  *   info can be retrieved from perf.
778  *
779  * INCLUDES
780  *   fci.h
781  *
782  */
783 HFCI __cdecl FCICreate(
784         PERF perf,
785         PFNFCIFILEPLACED   pfnfiledest,
786         PFNFCIALLOC        pfnalloc,
787         PFNFCIFREE         pfnfree,
788         PFNFCIOPEN         pfnopen,
789         PFNFCIREAD         pfnread,
790         PFNFCIWRITE        pfnwrite,
791         PFNFCICLOSE        pfnclose,
792         PFNFCISEEK         pfnseek,
793         PFNFCIDELETE       pfndelete,
794         PFNFCIGETTEMPFILE  pfnfcigtf,
795         PCCAB              pccab,
796         void *pv)
797 {
798   FCI_Int *p_fci_internal;
799
800   if (!perf) {
801     SetLastError(ERROR_BAD_ARGUMENTS);
802     return NULL;
803   }
804   if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
805       (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
806       (!pfnfcigtf) || (!pccab)) {
807     perf->erfOper = FCIERR_NONE;
808     perf->erfType = ERROR_BAD_ARGUMENTS;
809     perf->fError = TRUE;
810
811     SetLastError(ERROR_BAD_ARGUMENTS);
812     return NULL;
813   }
814
815   if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
816     perf->erfOper = FCIERR_ALLOC_FAIL;
817     perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
818     perf->fError = TRUE;
819
820     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
821     return NULL;
822   }
823
824   p_fci_internal->magic = FCI_INT_MAGIC;
825   p_fci_internal->perf = perf;
826   p_fci_internal->fileplaced = pfnfiledest;
827   p_fci_internal->alloc = pfnalloc;
828   p_fci_internal->free = pfnfree;
829   p_fci_internal->open = pfnopen;
830   p_fci_internal->read = pfnread;
831   p_fci_internal->write = pfnwrite;
832   p_fci_internal->close = pfnclose;
833   p_fci_internal->seek = pfnseek;
834   p_fci_internal->delete = pfndelete;
835   p_fci_internal->gettemp = pfnfcigtf;
836   p_fci_internal->ccab = *pccab;
837   p_fci_internal->pccab = pccab;
838   p_fci_internal->fPrevCab = FALSE;
839   p_fci_internal->fNextCab = FALSE;
840   p_fci_internal->fSplitFolder = FALSE;
841   p_fci_internal->fGetNextCabInVain = FALSE;
842   p_fci_internal->pv = pv;
843   p_fci_internal->data_in  = NULL;
844   p_fci_internal->cdata_in = 0;
845   p_fci_internal->data_out = NULL;
846   p_fci_internal->cCompressedBytesInFolder = 0;
847   p_fci_internal->cFolders = 0;
848   p_fci_internal->cFiles = 0;
849   p_fci_internal->cDataBlocks = 0;
850   p_fci_internal->data1.handle = -1;
851   p_fci_internal->data2.handle = -1;
852   p_fci_internal->fNewPrevious = FALSE;
853   p_fci_internal->estimatedCabinetSize = 0;
854   p_fci_internal->statusFolderTotal = 0;
855   p_fci_internal->folders_size = 0;
856   p_fci_internal->files_size = 0;
857   p_fci_internal->placed_files_size = 0;
858
859   list_init( &p_fci_internal->folders_list );
860   list_init( &p_fci_internal->files_list );
861   list_init( &p_fci_internal->blocks_list );
862
863   memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
864   memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
865
866   if (!create_temp_file( p_fci_internal, &p_fci_internal->data1 )) goto failed;
867   if (!create_temp_file( p_fci_internal, &p_fci_internal->data2 )) goto failed;
868   return (HFCI)p_fci_internal;
869
870 failed:
871   close_temp_file( p_fci_internal, &p_fci_internal->data1 );
872   close_temp_file( p_fci_internal, &p_fci_internal->data2 );
873   return NULL;
874 }
875
876
877
878
879
880
881 static BOOL fci_flush_data_block (FCI_Int *p_fci_internal, int* err,
882     PFNFCISTATUS pfnfcis) {
883
884   /* attention no checks if there is data available!!! */
885   CFDATA data;
886   CFDATA* cfdata=&data;
887   char* reserved;
888   UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
889   UINT i;
890
891   /* TODO compress the data of p_fci_internal->data_in */
892   /* and write it to p_fci_internal->data_out */
893   memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
894     p_fci_internal->cdata_in /* number of bytes to copy */);
895
896   cfdata->csum=0; /* checksum has to be set later */
897   /* TODO set realsize of compressed data */
898   cfdata->cbData   = p_fci_internal->cdata_in;
899   cfdata->cbUncomp = p_fci_internal->cdata_in;
900
901   /* write cfdata to p_fci_internal->data1.handle */
902   if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
903       cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
904       != sizeof(*cfdata) ) {
905     set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
906     return FALSE;
907   }
908   /* TODO error handling of err */
909
910   p_fci_internal->data1.size += sizeof(*cfdata);
911
912   /* add optional reserved area */
913
914   /* This allocation and freeing at each CFData block is a bit */
915   /* inefficient, but it's harder to forget about freeing the buffer :-). */
916   /* Reserved areas are used seldom besides that... */
917   if (cbReserveCFData!=0) {
918     if(!(reserved = p_fci_internal->alloc( cbReserveCFData))) {
919       set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
920       return FALSE;
921     }
922     for(i=0;i<cbReserveCFData;) {
923       reserved[i++]='\0';
924     }
925     if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
926         reserved, /* memory buffer */
927         cbReserveCFData, /* number of bytes to copy */
928         err, p_fci_internal->pv) != cbReserveCFData ) {
929       p_fci_internal->free(reserved);
930       set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
931       return FALSE;
932     }
933     /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
934
935     p_fci_internal->data1.size += cbReserveCFData;
936     p_fci_internal->free( reserved);
937   }
938
939   /* write p_fci_internal->data_out to p_fci_internal->data1.handle */
940   if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
941       p_fci_internal->data_out, /* memory buffer */
942       cfdata->cbData, /* number of bytes to copy */
943       err, p_fci_internal->pv) != cfdata->cbData) {
944     set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
945     return FALSE;
946   }
947   /* TODO error handling of err */
948
949   p_fci_internal->data1.size += cfdata->cbData;
950
951   /* reset the offset */
952   p_fci_internal->cdata_in = 0;
953   p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
954
955   /* report status with pfnfcis about uncompressed and compressed file data */
956   if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
957       p_fci_internal->pv) == -1) {
958     set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
959     return FALSE;
960   }
961
962   ++(p_fci_internal->cDataBlocks);
963
964   return TRUE;
965 } /* end of fci_flush_data_block */
966
967
968
969
970
971 static BOOL fci_flushfolder_copy_cfdata(FCI_Int *p_fci_internal, char* buffer, UINT cbReserveCFData,
972                                         PFNFCISTATUS pfnfcis, int* err, struct temp_file *data1new,
973                                         cab_ULONG* payload)
974 {
975   struct data_block *block;
976   cab_ULONG read_result;
977   CFDATA* pcfdata=(CFDATA*)buffer;
978   BOOL split_block=FALSE;
979   cab_UWORD savedUncomp=0;
980
981   *payload=0;
982
983   /* while not all CFDATAs have been copied do */
984   while(!FALSE) {
985     if( p_fci_internal->fNextCab ) {
986       if( split_block ) {
987         /* internal error should never happen */
988         set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
989         return FALSE;
990       }
991     }
992
993     /* No more CFDATA fits into the cabinet under construction */
994     /* So don't try to store more data into it */
995     if( p_fci_internal->fNextCab &&
996         (p_fci_internal->ccab.cb <= sizeof(CFDATA) + cbReserveCFData +
997         p_fci_internal->files_size + p_fci_internal->data2.size +
998         p_fci_internal->placed_files_size + p_fci_internal->folders_size +
999         get_header_size( p_fci_internal ) +
1000         sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder
1001     )) {
1002       /* This may never be run for the first time the while loop is entered.
1003       Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
1004       split_block=TRUE;  /* In this case split_block is abused to store */
1005       /* the complete data block into the next cabinet and not into the */
1006       /* current one. Originally split_block is the indicator that a */
1007       /* data block has been split across different cabinets. */
1008     } else {
1009
1010       /* read CFDATA from p_fci_internal->data1.handle to cfdata*/
1011       read_result= p_fci_internal->read( p_fci_internal->data1.handle,/*file handle*/
1012           buffer, /* memory buffer */
1013           sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1014           err, p_fci_internal->pv);
1015       if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
1016         if (read_result==0) break; /* ALL DATA has been copied */
1017         /* read error */
1018         set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1019         return FALSE;
1020       }
1021       /* TODO error handling of err */
1022
1023       /* REUSE buffer p_fci_internal->data_out !!! */
1024       /* read data from p_fci_internal->data1.handle to */
1025       /*      p_fci_internal->data_out */
1026       if( p_fci_internal->read( p_fci_internal->data1.handle /* file handle */,
1027           p_fci_internal->data_out /* memory buffer */,
1028           pcfdata->cbData /* number of bytes to copy */,
1029           err, p_fci_internal->pv) != pcfdata->cbData ) {
1030         /* read error */
1031         set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1032         return FALSE;
1033       }
1034       /* TODO error handling of err */
1035
1036       /* if cabinet size is too large */
1037
1038       /* Is cabinet with new CFDATA too large? Then data block has to be split */
1039       if( p_fci_internal->fNextCab &&
1040           (p_fci_internal->ccab.cb < sizeof(CFDATA) + cbReserveCFData +
1041           pcfdata->cbData +
1042           p_fci_internal->files_size + p_fci_internal->data2.size +
1043           p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1044           get_header_size( p_fci_internal ) +
1045           sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder
1046       )) {
1047         /* REUSE read_result to save the size of the compressed data */
1048         read_result=pcfdata->cbData;
1049         /* Modify the size of the compressed data to store only a part of the */
1050         /* data block into the current cabinet. This is done to prevent */
1051         /* that the maximum cabinet size will be exceeded. The remainder */
1052         /* will be stored into the next following cabinet. */
1053
1054         /* The cabinet will be of size "p_fci_internal->ccab.cb". */
1055         /* Substract everything except the size of the block of data */
1056         /* to get it's actual size */
1057         pcfdata->cbData = p_fci_internal->ccab.cb - (
1058           sizeof(CFDATA) + cbReserveCFData +
1059           p_fci_internal->files_size + p_fci_internal->data2.size +
1060           p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1061           get_header_size( p_fci_internal ) +
1062           sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder );
1063
1064         savedUncomp = pcfdata->cbUncomp;
1065         pcfdata->cbUncomp = 0; /* on split blocks of data this is zero */
1066
1067         /* if split_block==TRUE then the above while loop won't */
1068         /* be executed again */
1069         split_block=TRUE; /* split_block is the indicator that */
1070                           /* a data block has been split across */
1071                           /* different cabinets.*/
1072       }
1073
1074       /* This should never happen !!! */
1075       if (pcfdata->cbData==0) {
1076         /* set error */
1077         set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1078         return FALSE;
1079       }
1080
1081       if (!(block = add_data_block( p_fci_internal, pcfdata->cbData, pcfdata->cbUncomp ))) return FALSE;
1082
1083       /* write compressed data into p_fci_internal->data2.handle */
1084       if( p_fci_internal->write( p_fci_internal->data2.handle, /* file handle */
1085           p_fci_internal->data_out, /* memory buffer */
1086           pcfdata->cbData, /* number of bytes to copy */
1087           err, p_fci_internal->pv) != pcfdata->cbData) {
1088         set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1089         return FALSE;
1090       }
1091       /* TODO error handling of err */
1092
1093       p_fci_internal->statusFolderCopied += pcfdata->cbData;
1094       (*payload)+=pcfdata->cbUncomp;
1095       /* if cabinet size too large and data has been split */
1096       /* write the remainder of the data block to the new CFDATA1 file */
1097       if( split_block  ) { /* This does not include the */
1098                                   /* abused one (just search for "abused" )*/
1099       /* copy all CFDATA structures from data1.handle to data1new->handle */
1100         if (p_fci_internal->fNextCab==FALSE ) {
1101           /* internal error */
1102           set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1103           return FALSE;
1104         }
1105
1106         /* set cbData to the size of the remainder of the data block */
1107         pcfdata->cbData = read_result - pcfdata->cbData;
1108         /*recover former value of cfdata.cbData; read_result will be the offset*/
1109         read_result -= pcfdata->cbData;
1110         pcfdata->cbUncomp = savedUncomp;
1111
1112         /* reset checksum, it will be computed later */
1113         pcfdata->csum=0;
1114
1115         /* write cfdata WITHOUT checksum to data1new->handle */
1116         if( p_fci_internal->write( data1new->handle, /* file handle */
1117             buffer, /* memory buffer */
1118             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1119             err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
1120           set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1121           return FALSE;
1122         }
1123         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1124
1125         data1new->size += sizeof(CFDATA)+cbReserveCFData;
1126
1127         /* write compressed data into data1new->handle */
1128         if( p_fci_internal->write( data1new->handle, /* file handle */
1129             p_fci_internal->data_out + read_result, /* memory buffer + offset */
1130                                                 /* to last part of split data */
1131             pcfdata->cbData, /* number of bytes to copy */
1132             err, p_fci_internal->pv) != pcfdata->cbData) {
1133           set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1134           return FALSE;
1135         }
1136         /* TODO error handling of err */
1137
1138         p_fci_internal->statusFolderCopied += pcfdata->cbData;
1139
1140         data1new->size += pcfdata->cbData;
1141         /* the two blocks of the split data block have been written */
1142         /* don't reset split_data yet, because it is still needed see below */
1143       }
1144
1145       /* report status with pfnfcis about copied size of folder */
1146       if( (*pfnfcis)(statusFolder,
1147           p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
1148           p_fci_internal->statusFolderTotal, /* total folder size */
1149           p_fci_internal->pv) == -1) {
1150         set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1151         return FALSE;
1152       }
1153     }
1154
1155     /* if cabinet size too large */
1156     /* write the remaining data blocks to the new CFDATA1 file */
1157     if ( split_block ) { /* This does include the */
1158                                /* abused one (just search for "abused" )*/
1159       if (p_fci_internal->fNextCab==FALSE ) {
1160         /* internal error */
1161         set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1162         return FALSE;
1163       }
1164       /* copy all CFDATA structures from data1.handle to data1new->handle */
1165       while(!FALSE) {
1166         /* read CFDATA from p_fci_internal->data1.handle to cfdata*/
1167         read_result= p_fci_internal->read( p_fci_internal->data1.handle,/* handle */
1168             buffer, /* memory buffer */
1169             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1170             err, p_fci_internal->pv);
1171         if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
1172           if (read_result==0) break; /* ALL DATA has been copied */
1173           /* read error */
1174           set_error( p_fci_internal,FCIERR_NONE, ERROR_READ_FAULT );
1175           return FALSE;
1176         }
1177         /* TODO error handling of err */
1178
1179         /* REUSE buffer p_fci_internal->data_out !!! */
1180         /* read data from p_fci_internal->data1.handle to */
1181         /*      p_fci_internal->data_out */
1182         if( p_fci_internal->read( p_fci_internal->data1.handle /* file handle */,
1183             p_fci_internal->data_out /* memory buffer */,
1184             pcfdata->cbData /* number of bytes to copy */,
1185             err, p_fci_internal->pv) != pcfdata->cbData ) {
1186           /* read error */
1187           set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1188           return FALSE;
1189         }
1190         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1191
1192         /* write cfdata with checksum to data1new->handle */
1193         if( p_fci_internal->write( data1new->handle, /* file handle */
1194             buffer, /* memory buffer */
1195             sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1196             err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
1197           set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1198           return FALSE;
1199         }
1200         /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1201
1202         data1new->size += sizeof(CFDATA)+cbReserveCFData;
1203
1204         /* write compressed data into data1new->handle */
1205         if( p_fci_internal->write( data1new->handle, /* file handle */
1206             p_fci_internal->data_out, /* memory buffer */
1207             pcfdata->cbData, /* number of bytes to copy */
1208             err, p_fci_internal->pv) != pcfdata->cbData) {
1209           set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1210           return FALSE;
1211         }
1212         /* TODO error handling of err */
1213
1214         data1new->size += pcfdata->cbData;
1215         p_fci_internal->statusFolderCopied += pcfdata->cbData;
1216
1217         /* report status with pfnfcis about copied size of folder */
1218         if( (*pfnfcis)(statusFolder,
1219             p_fci_internal->statusFolderCopied,/*cfdata.cbData(+previous ones)*/
1220             p_fci_internal->statusFolderTotal, /* total folder size */
1221             p_fci_internal->pv) == -1) {
1222           set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1223           return FALSE;
1224         }
1225
1226       } /* end of WHILE */
1227       break; /* jump out of the next while loop */
1228     } /* end of if( split_data  ) */
1229   } /* end of WHILE */
1230   return TRUE;
1231 } /* end of fci_flushfolder_copy_cfdata */
1232
1233
1234
1235
1236
1237 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1238         BOOL                  fGetNextCab,
1239         PFNFCIGETNEXTCABINET  pfnfcignc,
1240         PFNFCISTATUS          pfnfcis)
1241 {
1242   int err;
1243   struct temp_file data1new;
1244   UINT cbReserveCFData, cbReserveCFFolder;
1245   char* reserved;
1246   cab_ULONG payload;
1247   cab_ULONG read_result;
1248   struct folder *folder;
1249
1250   if ((!pfnfcignc) || (!pfnfcis)) {
1251     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1252     return FALSE;
1253   }
1254
1255   if( p_fci_internal->fGetNextCabInVain &&
1256       p_fci_internal->fNextCab ){
1257     /* internal error */
1258     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1259     return FALSE;
1260   }
1261
1262   /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1263   /* this function will return TRUE */
1264   if( p_fci_internal->files_size == 0 ) {
1265     if ( p_fci_internal->data1.size != 0 ) {
1266       /* error handling */
1267       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1268       return FALSE;
1269     }
1270     return TRUE;
1271   }
1272
1273   if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1274     /* error handling */
1275     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1276     return FALSE;
1277   }
1278
1279   /* FCIFlushFolder has already been called... */
1280   if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1281     return TRUE;
1282   }
1283
1284   /* This can be set already, because it makes only a difference */
1285   /* when the current function exits with return FALSE */
1286   p_fci_internal->fSplitFolder=FALSE;
1287
1288   cbReserveCFData   = p_fci_internal->ccab.cbReserveCFData;
1289   cbReserveCFFolder = p_fci_internal->ccab.cbReserveCFFolder;
1290
1291   /* START of COPY */
1292   /* if there is data in p_fci_internal->data_in */
1293   if (p_fci_internal->cdata_in!=0) {
1294
1295     if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
1296
1297   }
1298   /* reset to get the number of data blocks of this folder which are */
1299   /* actually in this cabinet ( at least partially ) */
1300   p_fci_internal->cDataBlocks=0;
1301
1302   p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1303       sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1304       p_fci_internal->placed_files_size+
1305       p_fci_internal->data2.size + p_fci_internal->files_size+
1306       p_fci_internal->data1.size + p_fci_internal->folders_size;
1307   p_fci_internal->statusFolderCopied = 0;
1308
1309   /* report status with pfnfcis about copied size of folder */
1310   if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1311       p_fci_internal->statusFolderTotal, /* TODO total folder size */
1312       p_fci_internal->pv) == -1) {
1313     set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1314     return FALSE;
1315   }
1316
1317   /* get a new temp file */
1318   if (!create_temp_file( p_fci_internal, &data1new )) return FALSE;
1319
1320   /* USE the variable read_result */
1321   read_result = get_header_size( p_fci_internal ) + p_fci_internal->data2.size +
1322       p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1323
1324   if(p_fci_internal->files_size!=0) {
1325     read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1326   }
1327
1328   /* Check if multiple cabinets have to be created. */
1329
1330   /* Might be too much data for the maximum allowed cabinet size.*/
1331   /* When any further data will be added later, it might not */
1332   /* be possible to flush the cabinet, because there might */
1333   /* not be enough space to store the name of the following */
1334   /* cabinet and name of the corresponding disk. */
1335   /* So take care of this and get the name of the next cabinet */
1336   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1337       p_fci_internal->fNextCab==FALSE &&
1338       (
1339         (
1340           p_fci_internal->ccab.cb < read_result +
1341           p_fci_internal->data1.size +
1342           p_fci_internal->files_size +
1343           CB_MAX_CABINET_NAME +   /* next cabinet name */
1344           CB_MAX_DISK_NAME        /* next disk name */
1345         ) || fGetNextCab
1346       )
1347   ) {
1348     /* increment cabinet index */
1349     ++(p_fci_internal->pccab->iCab);
1350     /* get name of next cabinet */
1351     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1352     if (!(*pfnfcignc)(p_fci_internal->pccab,
1353         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1354         p_fci_internal->pv)) {
1355       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1356       close_temp_file( p_fci_internal, &data1new );
1357       return FALSE;
1358     }
1359
1360     /* Skip a few lines of code. This is caught by the next if. */
1361     p_fci_internal->fGetNextCabInVain=TRUE;
1362   }
1363
1364   /* too much data for cabinet */
1365   if( (p_fci_internal->fGetNextCabInVain ||
1366         p_fci_internal->fNextCab ) &&
1367       (
1368         (
1369           p_fci_internal->ccab.cb < read_result +
1370           p_fci_internal->data1.size +
1371           p_fci_internal->files_size +
1372           strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
1373           strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
1374         ) || fGetNextCab
1375       )
1376   ) {
1377     p_fci_internal->fGetNextCabInVain=FALSE;
1378     p_fci_internal->fNextCab=TRUE;
1379
1380     /* return FALSE if there is not enough space left*/
1381     /* this should never happen */
1382     if (p_fci_internal->ccab.cb <=
1383         p_fci_internal->files_size +
1384         read_result +
1385         strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1386         strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
1387     ) {
1388
1389       close_temp_file( p_fci_internal, &data1new );
1390       return FALSE;
1391     }
1392
1393     /* the folder will be split across cabinets */
1394     p_fci_internal->fSplitFolder=TRUE;
1395
1396   } else {
1397     /* this should never happen */
1398     if (p_fci_internal->fNextCab) {
1399       /* internal error */
1400       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1401       return FALSE;
1402     }
1403   }
1404
1405   /* set seek of p_fci_internal->data1.handle to 0 */
1406   if( p_fci_internal->seek(p_fci_internal->data1.handle,0,SEEK_SET,&err,
1407     p_fci_internal->pv) !=0 ) {
1408     /* wrong return value */
1409     set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
1410     close_temp_file( p_fci_internal, &data1new );
1411     return FALSE;
1412   }
1413   /* TODO error handling of err */
1414
1415   if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1416
1417   if(!(reserved = p_fci_internal->alloc( cbReserveCFData+sizeof(CFDATA)))) {
1418     set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1419     close_temp_file( p_fci_internal, &data1new );
1420     return FALSE;
1421   }
1422
1423   if(!fci_flushfolder_copy_cfdata(p_fci_internal, reserved, cbReserveCFData, pfnfcis, &err,
1424                                   &data1new, &payload ))
1425   {
1426     close_temp_file( p_fci_internal, &data1new );
1427     p_fci_internal->free(reserved);
1428     return FALSE;
1429   }
1430
1431   p_fci_internal->free(reserved);
1432
1433   folder->data_count = p_fci_internal->cDataBlocks;
1434
1435   if (!add_files_to_folder( p_fci_internal, folder, payload ))
1436   {
1437     close_temp_file( p_fci_internal, &data1new );
1438     return FALSE;
1439   }
1440
1441   close_temp_file( p_fci_internal, &p_fci_internal->data1 );
1442   p_fci_internal->data1 = data1new;
1443
1444   /* reset CFFolder specific information */
1445   p_fci_internal->cDataBlocks=0;
1446   p_fci_internal->cCompressedBytesInFolder=0;
1447
1448   return TRUE;
1449 }
1450
1451
1452
1453
1454 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1455         BOOL                  fGetNextCab,
1456         PFNFCIGETNEXTCABINET  pfnfcignc,
1457         PFNFCISTATUS          pfnfcis)
1458 {
1459   cab_ULONG read_result=0;
1460   BOOL returntrue=FALSE;
1461
1462   /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1463
1464   /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1465   if( p_fci_internal->files_size==0 && fGetNextCab ) {
1466     returntrue=TRUE;
1467   }
1468
1469   if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1470     /* TODO set error */
1471     return FALSE;
1472   }
1473
1474   if(returntrue) return TRUE;
1475
1476   if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1477        (p_fci_internal->folders_size==0 &&
1478          (p_fci_internal->files_size!=0 ||
1479           p_fci_internal->placed_files_size!=0 )
1480      ) )
1481   {
1482       /* error */
1483       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1484       return FALSE;
1485   }
1486
1487   /* create the cabinet */
1488   if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1489
1490   if (!create_temp_file( p_fci_internal, &p_fci_internal->data2 )) return FALSE;
1491
1492   p_fci_internal->fPrevCab=TRUE;
1493   /* The sections szPrevCab and szPrevDisk are not being updated, because */
1494   /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1495
1496   if (p_fci_internal->fNextCab) {
1497     p_fci_internal->fNextCab=FALSE;
1498
1499     if (p_fci_internal->files_size==0 && p_fci_internal->data1.size!=0) {
1500       /* THIS CAN NEVER HAPPEN */
1501       /* set error code */
1502       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1503       return FALSE;
1504     }
1505
1506     if( p_fci_internal->fNewPrevious ) {
1507       memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1508         CB_MAX_CABINET_NAME);
1509       memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1510         CB_MAX_DISK_NAME);
1511       p_fci_internal->fNewPrevious=FALSE;
1512     }
1513     p_fci_internal->ccab = *p_fci_internal->pccab;
1514
1515     /* REUSE the variable read_result */
1516     read_result=get_header_size( p_fci_internal );
1517     if(p_fci_internal->files_size!=0) {
1518         read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1519     }
1520     read_result+= p_fci_internal->data1.size +
1521       p_fci_internal->files_size + p_fci_internal->data2.size +
1522       p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1523       sizeof(CFFOLDER); /* set size of new CFFolder entry */
1524
1525     /* too much data for the maximum size of a cabinet */
1526     if( p_fci_internal->fGetNextCabInVain==FALSE &&
1527         p_fci_internal->ccab.cb < read_result ) {
1528       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1529     }
1530
1531     /* Might be too much data for the maximum size of a cabinet.*/
1532     /* When any further data will be added later, it might not */
1533     /* be possible to flush the cabinet, because there might */
1534     /* not be enough space to store the name of the following */
1535     /* cabinet and name of the corresponding disk. */
1536     /* So take care of this and get the name of the next cabinet */
1537     if (p_fci_internal->fGetNextCabInVain==FALSE && (
1538       p_fci_internal->ccab.cb < read_result +
1539       CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1540     )) {
1541       /* increment cabinet index */
1542       ++(p_fci_internal->pccab->iCab);
1543       /* get name of next cabinet */
1544       p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1545       if (!(*pfnfcignc)(p_fci_internal->pccab,
1546           p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1547           p_fci_internal->pv)) {
1548         /* error handling */
1549         set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1550         return FALSE;
1551       }
1552       /* Skip a few lines of code. This is caught by the next if. */
1553       p_fci_internal->fGetNextCabInVain=TRUE;
1554     }
1555
1556     /* too much data for cabinet */
1557     if (p_fci_internal->fGetNextCabInVain && (
1558         p_fci_internal->ccab.cb < read_result +
1559         strlen(p_fci_internal->ccab.szCab)+1+
1560         strlen(p_fci_internal->ccab.szDisk)+1
1561     )) {
1562       p_fci_internal->fGetNextCabInVain=FALSE;
1563       p_fci_internal->fNextCab=TRUE;
1564       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1565     }
1566
1567     /* if the FolderThreshold has been reached flush the folder automatically */
1568     if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1569         return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1570
1571     if( p_fci_internal->files_size>0 ) {
1572       if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1573       p_fci_internal->fNewPrevious=TRUE;
1574     }
1575   } else {
1576     p_fci_internal->fNewPrevious=FALSE;
1577     if( p_fci_internal->files_size>0 || p_fci_internal->data1.size) {
1578       /* THIS MAY NEVER HAPPEN */
1579       /* set error structures */
1580       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1581       return FALSE;
1582     }
1583   }
1584
1585   return TRUE;
1586 } /* end of fci_flush_cabinet */
1587
1588
1589
1590
1591
1592 /***********************************************************************
1593  *              FCIAddFile (CABINET.11)
1594  *
1595  * FCIAddFile adds a file to the to be created cabinet file
1596  *
1597  * PARAMS
1598  *   hfci          [I]  An HFCI from FCICreate
1599  *   pszSourceFile [I]  A pointer to a C string which contains the name and
1600  *                      location of the file which will be added to the cabinet
1601  *   pszFileName   [I]  A pointer to a C string which contains the name under
1602  *                      which the file will be stored in the cabinet
1603  *   fExecute      [I]  A boolean value which indicates if the file should be
1604  *                      executed after extraction of self extracting
1605  *                      executables
1606  *   pfnfcignc     [I]  A pointer to a function which gets information about
1607  *                      the next cabinet
1608  *   pfnfcis      [IO]  A pointer to a function which will report status
1609  *                      information about the compression process
1610  *   pfnfcioi      [I]  A pointer to a function which reports file attributes
1611  *                      and time and date information
1612  *   typeCompress  [I]  Compression type
1613  *
1614  * RETURNS
1615  *   On success, returns TRUE
1616  *   On failure, returns FALSE
1617  *
1618  * INCLUDES
1619  *   fci.h
1620  *
1621  */
1622 BOOL __cdecl FCIAddFile(
1623         HFCI                  hfci,
1624         char                 *pszSourceFile,
1625         char                 *pszFileName,
1626         BOOL                  fExecute,
1627         PFNFCIGETNEXTCABINET  pfnfcignc,
1628         PFNFCISTATUS          pfnfcis,
1629         PFNFCIGETOPENINFO     pfnfcigoi,
1630         TCOMP                 typeCompress)
1631 {
1632   int err;
1633   cab_ULONG read_result;
1634   int file_handle;
1635   struct file *file;
1636   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1637
1638   if (!p_fci_internal) return FALSE;
1639
1640   if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1641       (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1642     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1643     return FALSE;
1644   }
1645
1646   /* TODO check if pszSourceFile??? */
1647
1648   if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1649     /* internal error */
1650     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1651     return FALSE;
1652   }
1653
1654   if(p_fci_internal->fNextCab) {
1655     /* internal error */
1656     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1657     return FALSE;
1658   }
1659
1660   if (!(file = add_file( p_fci_internal, pszFileName ))) return FALSE;
1661
1662   /* allocation of memory */
1663   if (p_fci_internal->data_in==NULL) {
1664     if (p_fci_internal->cdata_in!=0) {
1665       /* error handling */
1666       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1667       return FALSE;
1668     }
1669     if (p_fci_internal->data_out!=NULL) {
1670       /* error handling */
1671       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1672       return FALSE;
1673     }
1674     if(!(p_fci_internal->data_in = p_fci_internal->alloc(CB_MAX_CHUNK))) {
1675       set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1676       return FALSE;
1677     }
1678     if (p_fci_internal->data_out==NULL) {
1679       if(!(p_fci_internal->data_out = p_fci_internal->alloc( 2 * CB_MAX_CHUNK))){
1680         set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1681         return FALSE;
1682       }
1683     }
1684   }
1685
1686   if (p_fci_internal->data_out==NULL) {
1687     p_fci_internal->free(p_fci_internal->data_in);
1688     /* error handling */
1689     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1690     return FALSE;
1691   }
1692
1693   /* get information about the file */
1694   /* set defaults in case callback doesn't set one or more fields */
1695   file_handle = pfnfcigoi( pszSourceFile, &file->date, &file->time, &file->attribs,
1696                            &err, p_fci_internal->pv );
1697   /* check file_handle */
1698   if(file_handle==0){
1699     set_error( p_fci_internal, FCIERR_OPEN_SRC, ERROR_OPEN_FAILED );
1700   }
1701   /* TODO error handling of err */
1702
1703   if (fExecute) { file->attribs |= _A_EXEC; }
1704
1705   /* REUSE the variable read_result */
1706   read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1707
1708   read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1709     p_fci_internal->files_size + p_fci_internal->data2.size +
1710     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1711     sizeof(CFFOLDER); /* size of new CFFolder entry */
1712
1713   /* Might be too much data for the maximum size of a cabinet.*/
1714   /* When any further data will be added later, it might not */
1715   /* be possible to flush the cabinet, because there might */
1716   /* not be enough space to store the name of the following */
1717   /* cabinet and name of the corresponding disk. */
1718   /* So take care of this and get the name of the next cabinet */
1719   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1720       p_fci_internal->fNextCab==FALSE &&
1721       ( p_fci_internal->ccab.cb < read_result +
1722         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1723       )
1724   ) {
1725     /* increment cabinet index */
1726     ++(p_fci_internal->pccab->iCab);
1727     /* get name of next cabinet */
1728     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1729     if (!(*pfnfcignc)(p_fci_internal->pccab,
1730         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1731         p_fci_internal->pv)) {
1732       /* error handling */
1733       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1734       return FALSE;
1735     }
1736     /* Skip a few lines of code. This is caught by the next if. */
1737     p_fci_internal->fGetNextCabInVain=TRUE;
1738   }
1739
1740   if( p_fci_internal->fGetNextCabInVain &&
1741       p_fci_internal->fNextCab
1742   ) {
1743     /* THIS CAN NEVER HAPPEN */
1744     /* set error code */
1745     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1746     return FALSE;
1747   }
1748
1749   /* too much data for cabinet */
1750   if( p_fci_internal->fGetNextCabInVain &&
1751      (
1752       p_fci_internal->ccab.cb < read_result +
1753       strlen(p_fci_internal->pccab->szCab)+1+
1754       strlen(p_fci_internal->pccab->szDisk)+1
1755   )) {
1756     p_fci_internal->fGetNextCabInVain=FALSE;
1757     p_fci_internal->fNextCab=TRUE;
1758     if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1759   }
1760
1761   if( p_fci_internal->fNextCab ) {
1762     /* THIS MAY NEVER HAPPEN */
1763     /* set error code */
1764     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1765     return FALSE;
1766   }
1767
1768   /* read the contents of the file blockwise */
1769   while (!FALSE) {
1770     if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
1771       /* internal error */
1772       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1773       return FALSE;
1774     }
1775
1776     read_result = p_fci_internal->read( file_handle /* file handle */,
1777       (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
1778       (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
1779       &err, p_fci_internal->pv);
1780     /* TODO error handling of err */
1781
1782     if( read_result==0 ) break;
1783
1784     /* increment the block size */
1785     p_fci_internal->cdata_in += read_result;
1786
1787     /* increment the file size */
1788     file->size += read_result;
1789
1790     if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
1791       /* report internal error */
1792       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1793       return FALSE;
1794     }
1795     /* write a whole block */
1796     if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
1797
1798       if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
1799     }
1800   }
1801
1802   /* close the file from FCIAddFile */
1803   p_fci_internal->close(file_handle,&err,p_fci_internal->pv);
1804   /* TODO error handling of err */
1805
1806   p_fci_internal->files_size += sizeof(CFFILE) + strlen(pszFileName)+1;
1807
1808   /* REUSE the variable read_result */
1809   read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1810   read_result+= p_fci_internal->data1.size +
1811     p_fci_internal->files_size + p_fci_internal->data2.size +
1812     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1813     sizeof(CFFOLDER); /* set size of new CFFolder entry */
1814
1815   /* too much data for the maximum size of a cabinet */
1816   /* (ignoring the unflushed data block) */
1817   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1818       p_fci_internal->fNextCab==FALSE && /* this is always the case */
1819       p_fci_internal->ccab.cb < read_result ) {
1820     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1821   }
1822
1823   /* Might be too much data for the maximum size of a cabinet.*/
1824   /* When any further data will be added later, it might not */
1825   /* be possible to flush the cabinet, because there might */
1826   /* not be enough space to store the name of the following */
1827   /* cabinet and name of the corresponding disk. */
1828   /* So take care of this and get the name of the next cabinet */
1829   /* (ignoring the unflushed data block) */
1830   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1831       p_fci_internal->fNextCab==FALSE &&
1832       ( p_fci_internal->ccab.cb < read_result +
1833         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1834       )
1835   ) {
1836     /* increment cabinet index */
1837     ++(p_fci_internal->pccab->iCab);
1838     /* get name of next cabinet */
1839     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1840     if (!(*pfnfcignc)(p_fci_internal->pccab,
1841         p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1842         p_fci_internal->pv)) {
1843       /* error handling */
1844       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1845       return FALSE;
1846     }
1847     /* Skip a few lines of code. This is caught by the next if. */
1848     p_fci_internal->fGetNextCabInVain=TRUE;
1849   }
1850
1851   if( p_fci_internal->fGetNextCabInVain &&
1852       p_fci_internal->fNextCab
1853   ) {
1854     /* THIS CAN NEVER HAPPEN */
1855     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1856     return FALSE;
1857   }
1858
1859   /* too much data for cabinet */
1860   if( (p_fci_internal->fGetNextCabInVain ||
1861       p_fci_internal->fNextCab) && (
1862       p_fci_internal->ccab.cb < read_result +
1863       strlen(p_fci_internal->pccab->szCab)+1+
1864       strlen(p_fci_internal->pccab->szDisk)+1
1865   )) {
1866
1867     p_fci_internal->fGetNextCabInVain=FALSE;
1868     p_fci_internal->fNextCab=TRUE;
1869     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1870   }
1871
1872   if( p_fci_internal->fNextCab ) {
1873     /* THIS MAY NEVER HAPPEN */
1874     /* set error code */
1875     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1876     return FALSE;
1877   }
1878
1879   /* if the FolderThreshold has been reached flush the folder automatically */
1880   if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1881       return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1882
1883   return TRUE;
1884 } /* end of FCIAddFile */
1885
1886
1887
1888
1889
1890 /***********************************************************************
1891  *              FCIFlushFolder (CABINET.12)
1892  *
1893  * FCIFlushFolder completes the CFFolder structure under construction.
1894  *
1895  * All further data which is added by FCIAddFile will be associated to
1896  * the next CFFolder structure.
1897  *
1898  * FCIFlushFolder will be called by FCIAddFile automatically if the
1899  * threshold (stored in the member cbFolderThresh of the CCAB structure
1900  * pccab passed to FCICreate) is exceeded.
1901  *
1902  * FCIFlushFolder will be called by FCIFlushFolder automatically before
1903  * any data will be written into the cabinet file.
1904  *
1905  * PARAMS
1906  *   hfci          [I]  An HFCI from FCICreate
1907  *   pfnfcignc     [I]  A pointer to a function which gets information about
1908  *                      the next cabinet
1909  *   pfnfcis      [IO]  A pointer to a function which will report status
1910  *                      information about the compression process
1911  *
1912  * RETURNS
1913  *   On success, returns TRUE
1914  *   On failure, returns FALSE
1915  *
1916  * INCLUDES
1917  *   fci.h
1918  *
1919  */
1920 BOOL __cdecl FCIFlushFolder(
1921         HFCI                  hfci,
1922         PFNFCIGETNEXTCABINET  pfnfcignc,
1923         PFNFCISTATUS          pfnfcis)
1924 {
1925     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1926
1927     if (!p_fci_internal) return FALSE;
1928     return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1929 }
1930
1931
1932
1933 /***********************************************************************
1934  *              FCIFlushCabinet (CABINET.13)
1935  *
1936  * FCIFlushCabinet stores the data which has been added by FCIAddFile
1937  * into the cabinet file. If the maximum cabinet size (stored in the
1938  * member cb of the CCAB structure pccab passed to FCICreate) has been
1939  * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1940  * The remaining data still has to be flushed manually by calling
1941  * FCIFlushCabinet.
1942  *
1943  * After FCIFlushCabinet has been called (manually) FCIAddFile must
1944  * NOT be called again. Then hfci has to be released by FCIDestroy.
1945  *
1946  * PARAMS
1947  *   hfci          [I]  An HFCI from FCICreate
1948  *   fGetNextCab   [I]  Whether you want to add additional files to a
1949  *                      cabinet set (TRUE) or whether you want to
1950  *                      finalize it (FALSE)
1951  *   pfnfcignc     [I]  A pointer to a function which gets information about
1952  *                      the next cabinet
1953  *   pfnfcis      [IO]  A pointer to a function which will report status
1954  *                      information about the compression process
1955  *
1956  * RETURNS
1957  *   On success, returns TRUE
1958  *   On failure, returns FALSE
1959  *
1960  * INCLUDES
1961  *   fci.h
1962  *
1963  */
1964 BOOL __cdecl FCIFlushCabinet(
1965         HFCI                  hfci,
1966         BOOL                  fGetNextCab,
1967         PFNFCIGETNEXTCABINET  pfnfcignc,
1968         PFNFCISTATUS          pfnfcis)
1969 {
1970   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1971
1972   if (!p_fci_internal) return FALSE;
1973
1974   if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1975
1976   while( p_fci_internal->files_size>0 ||
1977          p_fci_internal->placed_files_size>0 ) {
1978     if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1979   }
1980
1981   return TRUE;
1982 }
1983
1984
1985 /***********************************************************************
1986  *              FCIDestroy (CABINET.14)
1987  *
1988  * Frees a handle created by FCICreate.
1989  * Only reason for failure would be an invalid handle.
1990  *
1991  * PARAMS
1992  *   hfci [I] The HFCI to free
1993  *
1994  * RETURNS
1995  *   TRUE for success
1996  *   FALSE for failure
1997  */
1998 BOOL __cdecl FCIDestroy(HFCI hfci)
1999 {
2000     struct folder *folder, *folder_next;
2001     struct file *file, *file_next;
2002     struct data_block *block, *block_next;
2003     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2004
2005     if (!p_fci_internal) return FALSE;
2006
2007     /* before hfci can be removed all temporary files must be closed */
2008     /* and deleted */
2009     p_fci_internal->magic = 0;
2010
2011     LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
2012     {
2013         free_folder( p_fci_internal, folder );
2014     }
2015     LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
2016     {
2017         free_file( p_fci_internal, file );
2018     }
2019     LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
2020     {
2021         free_data_block( p_fci_internal, block );
2022     }
2023
2024     close_temp_file( p_fci_internal, &p_fci_internal->data1 );
2025     close_temp_file( p_fci_internal, &p_fci_internal->data2 );
2026
2027     /* data in and out buffers have to be removed */
2028     if (p_fci_internal->data_in!=NULL)
2029       p_fci_internal->free(p_fci_internal->data_in);
2030     if (p_fci_internal->data_out!=NULL)
2031       p_fci_internal->free(p_fci_internal->data_out);
2032
2033     /* hfci can now be removed */
2034     p_fci_internal->free(hfci);
2035     return TRUE;
2036 }