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