ws2_32/tests: Add SO_ERROR [set|get]sockopt tests.
[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       /* fall through */
470     case 2:
471       ul |= (((ULONG)(*pb++)) <<  8);
472       /* fall through */
473     case 1:
474       ul |= *pb;
475       /* fall through */
476     default:
477       break;
478   }
479   csum ^= ul;
480
481   return csum;
482 }
483
484 /* copy all remaining data block to a new temp file */
485 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
486                               struct temp_file *temp, PFNFCISTATUS status_callback )
487 {
488     struct data_block *block;
489     int err;
490
491     if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
492     {
493         set_error( fci, FCIERR_TEMP_FILE, err );
494         return FALSE;
495     }
496     if (!create_temp_file( fci, temp )) return FALSE;
497
498     LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
499     {
500         if (fci->read( handle, fci->data_out, block->compressed,
501                        &err, fci->pv ) != block->compressed)
502         {
503             close_temp_file( fci, temp );
504             set_error( fci, FCIERR_TEMP_FILE, err );
505             return FALSE;
506         }
507         if (fci->write( temp->handle, fci->data_out, block->compressed,
508                         &err, fci->pv ) != block->compressed)
509         {
510             close_temp_file( fci, temp );
511             set_error( fci, FCIERR_TEMP_FILE, err );
512             return FALSE;
513         }
514         fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
515         fci->statusFolderCopied += block->compressed;
516
517         if (status_callback( statusFolder, fci->statusFolderCopied,
518                              fci->statusFolderTotal, fci->pv) == -1)
519         {
520             close_temp_file( fci, temp );
521             set_error( fci, FCIERR_USER_ABORT, 0 );
522             return FALSE;
523         }
524     }
525     return TRUE;
526 }
527
528 /* write all folders to disk and remove them from the list */
529 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
530 {
531     struct folder *folder;
532     int err;
533     CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
534     cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
535
536     memset( cffolder, 0, folder_size );
537
538     /* write the folders */
539     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
540     {
541         cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
542         cffolder->cCFData      = fci_endian_uword( folder->data_count );
543         cffolder->typeCompress = fci_endian_uword( folder->compression );
544         if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
545         {
546             set_error( fci, FCIERR_CAB_FILE, err );
547             return FALSE;
548         }
549     }
550     return TRUE;
551 }
552
553 /* write all the files to the cabinet file */
554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
555 {
556     cab_ULONG file_size;
557     struct folder *folder;
558     struct file *file;
559     int err;
560     CFFILE *cffile = (CFFILE *)fci->data_out;
561
562     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
563     {
564         LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
565         {
566             cffile->cbFile          = fci_endian_ulong( file->size );
567             cffile->uoffFolderStart = fci_endian_ulong( file->offset );
568             cffile->iFolder         = fci_endian_uword( file->folder );
569             cffile->date            = fci_endian_uword( file->date );
570             cffile->time            = fci_endian_uword( file->time );
571             cffile->attribs         = fci_endian_uword( file->attribs );
572             lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
573             file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
574             if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
575             {
576                 set_error( fci, FCIERR_CAB_FILE, err );
577                 return FALSE;
578             }
579             if (!fci->fSplitFolder)
580             {
581                 fci->statusFolderCopied = 0;
582                 /* TODO TEST THIS further */
583                 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
584             }
585             fci->statusFolderCopied += file_size;
586             /* report status about copied size of folder */
587             if (status_callback( statusFolder, fci->statusFolderCopied,
588                                  fci->statusFolderTotal, fci->pv ) == -1)
589             {
590                 set_error( fci, FCIERR_USER_ABORT, 0 );
591                 return FALSE;
592             }
593         }
594     }
595     return TRUE;
596 }
597
598 /* write all data blocks to the cabinet file */
599 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
600 {
601     struct folder *folder;
602     struct data_block *block;
603     int err, len;
604     CFDATA *cfdata;
605     void *data;
606     cab_UWORD header_size;
607
608     header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
609     cfdata = (CFDATA *)fci->data_out;
610     memset( cfdata, 0, header_size );
611     data = (char *)cfdata + header_size;
612
613     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
614     {
615         if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
616         {
617             set_error( fci, FCIERR_CAB_FILE, err );
618             return FALSE;
619         }
620         LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
621         {
622             len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
623             if (len != block->compressed) return FALSE;
624
625             cfdata->cbData = fci_endian_uword( block->compressed );
626             cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
627             cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
628                                                                header_size - FIELD_OFFSET(CFDATA, cbData),
629                                                                fci_get_checksum( data, len, 0 )));
630
631             fci->statusFolderCopied += len;
632             len += header_size;
633             if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
634             {
635                 set_error( fci, FCIERR_CAB_FILE, err );
636                 return FALSE;
637             }
638             if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
639             {
640                 set_error( fci, FCIERR_USER_ABORT, 0 );
641                 return FALSE;
642             }
643         }
644     }
645     return TRUE;
646 }
647
648 /* write the cabinet file to disk */
649 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
650 {
651     char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
652     int err;
653     char *ptr;
654     INT_PTR handle;
655     CFHEADER *cfheader = (CFHEADER *)fci->data_out;
656     cab_UWORD flags = 0;
657     cab_ULONG header_size = get_header_size( fci );
658     cab_ULONG total_size = header_size + fci->folders_size +
659                            fci->placed_files_size + fci->folders_data_size;
660
661     assert( header_size <= sizeof(fci->data_out) );
662     memset( cfheader, 0, header_size );
663
664     if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
665     if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
666     if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
667       flags |= cfheadRESERVE_PRESENT;
668
669     memcpy( cfheader->signature, "!CAB", 4 );
670     cfheader->cbCabinet    = fci_endian_ulong( total_size );
671     cfheader->coffFiles    = fci_endian_ulong( header_size + fci->folders_size );
672     cfheader->versionMinor = 3;
673     cfheader->versionMajor = 1;
674     cfheader->cFolders     = fci_endian_uword( fci->cFolders );
675     cfheader->cFiles       = fci_endian_uword( fci->cFiles );
676     cfheader->flags        = fci_endian_uword( flags );
677     cfheader->setID        = fci_endian_uword( fci->ccab.setID );
678     cfheader->iCabinet     = fci_endian_uword( fci->ccab.iCab );
679     ptr = (char *)(cfheader + 1);
680
681     if (flags & cfheadRESERVE_PRESENT)
682     {
683         struct
684         {
685             cab_UWORD cbCFHeader;
686             cab_UBYTE cbCFFolder;
687             cab_UBYTE cbCFData;
688         } *reserve = (void *)ptr;
689
690         reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
691         reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
692         reserve->cbCFData   = fci->ccab.cbReserveCFData;
693         ptr = (char *)(reserve + 1);
694     }
695     ptr += fci->ccab.cbReserveCFHeader;
696
697     if (flags & cfheadPREV_CABINET)
698     {
699         strcpy( ptr, fci->szPrevCab );
700         ptr += strlen( ptr ) + 1;
701         strcpy( ptr, fci->szPrevDisk );
702         ptr += strlen( ptr ) + 1;
703     }
704
705     if (flags & cfheadNEXT_CABINET)
706     {
707         strcpy( ptr, fci->pccab->szCab );
708         ptr += strlen( ptr ) + 1;
709         strcpy( ptr, fci->pccab->szDisk );
710         ptr += strlen( ptr ) + 1;
711     }
712
713     assert( ptr - (char *)cfheader == header_size );
714
715     strcpy( filename, fci->ccab.szCabPath );
716     strcat( filename, fci->ccab.szCab );
717
718     if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
719                              _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
720     {
721         set_error( fci, FCIERR_CAB_FILE, err );
722         return FALSE;
723     }
724
725     if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
726     {
727         set_error( fci, FCIERR_CAB_FILE, err );
728         goto failed;
729     }
730
731     /* add size of header size of all CFFOLDERs and size of all CFFILEs */
732     header_size += fci->placed_files_size + fci->folders_size;
733     if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
734     if (!write_files( fci, handle, status_callback )) goto failed;
735     if (!write_data_blocks( fci, handle, status_callback )) goto failed;
736
737     /* update the signature */
738     if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
739     {
740         set_error( fci, FCIERR_CAB_FILE, err );
741         goto failed;
742     }
743     memcpy( cfheader->signature, "MSCF", 4 );
744     if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
745     {
746         set_error( fci, FCIERR_CAB_FILE, err );
747         goto failed;
748     }
749     fci->close( handle, &err, fci->pv );
750
751     reset_cabinet( fci );
752     status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
753     return TRUE;
754
755 failed:
756     fci->close( handle, &err, fci->pv );
757     fci->delete( filename, &err, fci->pv );
758     return FALSE;
759 }
760
761 /* add all pending data blocks folder */
762 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
763                                 PFNFCISTATUS status_callback )
764 {
765     struct data_block *block, *new, *next;
766     BOOL split_block = FALSE;
767     cab_ULONG current_size, start_pos = 0;
768
769     *payload = 0;
770     current_size = get_header_size( fci ) + fci->folders_size +
771                    fci->files_size + fci->placed_files_size + fci->folders_data_size;
772
773     /* move the temp file into the folder structure */
774     folder->data = fci->data;
775     fci->data.handle = -1;
776     fci->pending_data_size = 0;
777
778     LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
779     {
780         /* No more CFDATA fits into the cabinet under construction */
781         /* So don't try to store more data into it */
782         if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
783                               current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
784             break;
785
786         if (!(new = fci->alloc( sizeof(*new) )))
787         {
788             set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
789             return FALSE;
790         }
791         /* Is cabinet with new CFDATA too large? Then data block has to be split */
792         if( fci->fNextCab &&
793             (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
794              block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
795         {
796             /* Modify the size of the compressed data to store only a part of the */
797             /* data block into the current cabinet. This is done to prevent */
798             /* that the maximum cabinet size will be exceeded. The remainder */
799             /* will be stored into the next following cabinet. */
800
801             new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
802                                               sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
803             new->uncompressed = 0; /* on split blocks of data this is zero */
804             block->compressed -= new->compressed;
805             split_block = TRUE;
806         }
807         else
808         {
809             new->compressed   = block->compressed;
810             new->uncompressed = block->uncompressed;
811         }
812
813         start_pos += new->compressed;
814         current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
815         fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
816         fci->statusFolderCopied += new->compressed;
817         (*payload) += new->uncompressed;
818
819         list_add_tail( &folder->blocks_list, &new->entry );
820         folder->data_count++;
821
822         /* report status with pfnfcis about copied size of folder */
823         if (status_callback( statusFolder, fci->statusFolderCopied,
824                              fci->statusFolderTotal, fci->pv ) == -1)
825         {
826             set_error( fci, FCIERR_USER_ABORT, 0 );
827             return FALSE;
828         }
829         if (split_block) break;
830         free_data_block( fci, block );
831         fci->cDataBlocks--;
832     }
833
834     if (list_empty( &fci->blocks_list )) return TRUE;
835     return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
836 }
837
838 /* add all pending files to folder */
839 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
840 {
841     cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
842     cab_ULONG cbFileRemainer = 0;
843     struct file *file, *next;
844
845     LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
846     {
847         cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
848
849         /* fnfilfnfildest: placed file on cabinet */
850         fci->fileplaced( &fci->ccab, file->name, file->size,
851                          (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
852
853         sizeOfFilesPrev = sizeOfFiles;
854         /* set complete size of all processed files */
855         if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
856         {
857             sizeOfFiles += fci->cbFileRemainer;
858             fci->cbFileRemainer = 0;
859         }
860         else sizeOfFiles += file->size;
861
862         /* check if spanned file fits into this cabinet folder */
863         if (sizeOfFiles > payload)
864         {
865             if (file->folder == cffileCONTINUED_FROM_PREV)
866                 file->folder = cffileCONTINUED_PREV_AND_NEXT;
867             else
868                 file->folder = cffileCONTINUED_TO_NEXT;
869         }
870
871         list_remove( &file->entry );
872         list_add_tail( &folder->files_list, &file->entry );
873         fci->placed_files_size += size;
874         fci->cFiles++;
875
876         /* This is only true for files which will be written into the */
877         /* next cabinet of the spanning folder */
878         if (sizeOfFiles > payload)
879         {
880             /* add a copy back onto the list */
881             if (!(file = copy_file( fci, file ))) return FALSE;
882             list_add_before( &next->entry, &file->entry );
883
884             /* Files which data will be partially written into the current cabinet */
885             if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
886             {
887                 if (sizeOfFilesPrev <= payload)
888                 {
889                     /* The size of the uncompressed, data of a spanning file in a */
890                     /* spanning data */
891                     cbFileRemainer = sizeOfFiles - payload;
892                 }
893                 file->folder = cffileCONTINUED_FROM_PREV;
894             }
895             else file->folder = 0;
896         }
897         else
898         {
899             fci->files_size -= size;
900         }
901     }
902     fci->cbFileRemainer = cbFileRemainer;
903     return TRUE;
904 }
905
906 static cab_UWORD compress_NONE( FCI_Int *fci )
907 {
908     memcpy( fci->data_out, fci->data_in, fci->cdata_in );
909     return fci->cdata_in;
910 }
911
912 #ifdef HAVE_ZLIB
913
914 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
915 {
916     FCI_Int *fci = opaque;
917     return fci->alloc( items * size );
918 }
919
920 static void zfree( void *opaque, void *ptr )
921 {
922     FCI_Int *fci = opaque;
923     fci->free( ptr );
924 }
925
926 static cab_UWORD compress_MSZIP( FCI_Int *fci )
927 {
928     z_stream stream;
929
930     stream.zalloc = zalloc;
931     stream.zfree  = zfree;
932     stream.opaque = fci;
933     if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
934     {
935         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
936         return 0;
937     }
938     stream.next_in   = fci->data_in;
939     stream.avail_in  = fci->cdata_in;
940     stream.next_out  = fci->data_out + 2;
941     stream.avail_out = sizeof(fci->data_out) - 2;
942     /* insert the signature */
943     fci->data_out[0] = 'C';
944     fci->data_out[1] = 'K';
945     deflate( &stream, Z_FINISH );
946     deflateEnd( &stream );
947     return stream.total_out + 2;
948 }
949
950 #endif  /* HAVE_ZLIB */
951
952
953 /***********************************************************************
954  *              FCICreate (CABINET.10)
955  *
956  * FCICreate is provided with several callbacks and
957  * returns a handle which can be used to create cabinet files.
958  *
959  * PARAMS
960  *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
961  *                    returns an error condition, error information may
962  *                    be found here as well as from GetLastError.
963  *   pfnfiledest [I]  A pointer to a function which is called when a file
964  *                    is placed. Only useful for subsequent cabinet files.
965  *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
966  *                    the same interface as malloc.
967  *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
968  *                    same interface as free.
969  *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
970  *                    the same interface as _open.
971  *   pfnread     [I]  A pointer to a function which reads from a file into
972  *                    a caller-provided buffer.  Uses the same interface
973  *                    as _read.
974  *   pfnwrite    [I]  A pointer to a function which writes to a file from
975  *                    a caller-provided buffer.  Uses the same interface
976  *                    as _write.
977  *   pfnclose    [I]  A pointer to a function which closes a file handle.
978  *                    Uses the same interface as _close.
979  *   pfnseek     [I]  A pointer to a function which seeks in a file.
980  *                    Uses the same interface as _lseek.
981  *   pfndelete   [I]  A pointer to a function which deletes a file.
982  *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
983  *                    temporary file.
984  *   pccab       [I]  A pointer to an initialized CCAB structure.
985  *   pv          [I]  A pointer to an application-defined notification
986  *                    function which will be passed to other FCI functions
987  *                    as a parameter.
988  *
989  * RETURNS
990  *   On success, returns an FCI handle of type HFCI.
991  *   On failure, the NULL file handle is returned. Error
992  *   info can be retrieved from perf.
993  *
994  * INCLUDES
995  *   fci.h
996  *
997  */
998 HFCI __cdecl FCICreate(
999         PERF perf,
1000         PFNFCIFILEPLACED   pfnfiledest,
1001         PFNFCIALLOC        pfnalloc,
1002         PFNFCIFREE         pfnfree,
1003         PFNFCIOPEN         pfnopen,
1004         PFNFCIREAD         pfnread,
1005         PFNFCIWRITE        pfnwrite,
1006         PFNFCICLOSE        pfnclose,
1007         PFNFCISEEK         pfnseek,
1008         PFNFCIDELETE       pfndelete,
1009         PFNFCIGETTEMPFILE  pfnfcigtf,
1010         PCCAB              pccab,
1011         void *pv)
1012 {
1013   FCI_Int *p_fci_internal;
1014
1015   if (!perf) {
1016     SetLastError(ERROR_BAD_ARGUMENTS);
1017     return NULL;
1018   }
1019   if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1020       (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1021       (!pfnfcigtf) || (!pccab)) {
1022     perf->erfOper = FCIERR_NONE;
1023     perf->erfType = ERROR_BAD_ARGUMENTS;
1024     perf->fError = TRUE;
1025
1026     SetLastError(ERROR_BAD_ARGUMENTS);
1027     return NULL;
1028   }
1029
1030   if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1031     perf->erfOper = FCIERR_ALLOC_FAIL;
1032     perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1033     perf->fError = TRUE;
1034
1035     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1036     return NULL;
1037   }
1038
1039   p_fci_internal->magic = FCI_INT_MAGIC;
1040   p_fci_internal->perf = perf;
1041   p_fci_internal->fileplaced = pfnfiledest;
1042   p_fci_internal->alloc = pfnalloc;
1043   p_fci_internal->free = pfnfree;
1044   p_fci_internal->open = pfnopen;
1045   p_fci_internal->read = pfnread;
1046   p_fci_internal->write = pfnwrite;
1047   p_fci_internal->close = pfnclose;
1048   p_fci_internal->seek = pfnseek;
1049   p_fci_internal->delete = pfndelete;
1050   p_fci_internal->gettemp = pfnfcigtf;
1051   p_fci_internal->ccab = *pccab;
1052   p_fci_internal->pccab = pccab;
1053   p_fci_internal->fPrevCab = FALSE;
1054   p_fci_internal->fNextCab = FALSE;
1055   p_fci_internal->fSplitFolder = FALSE;
1056   p_fci_internal->fGetNextCabInVain = FALSE;
1057   p_fci_internal->pv = pv;
1058   p_fci_internal->cdata_in = 0;
1059   p_fci_internal->cCompressedBytesInFolder = 0;
1060   p_fci_internal->cFolders = 0;
1061   p_fci_internal->cFiles = 0;
1062   p_fci_internal->cDataBlocks = 0;
1063   p_fci_internal->data.handle = -1;
1064   p_fci_internal->fNewPrevious = FALSE;
1065   p_fci_internal->estimatedCabinetSize = 0;
1066   p_fci_internal->statusFolderTotal = 0;
1067   p_fci_internal->folders_size = 0;
1068   p_fci_internal->files_size = 0;
1069   p_fci_internal->placed_files_size = 0;
1070   p_fci_internal->pending_data_size = 0;
1071   p_fci_internal->folders_data_size = 0;
1072   p_fci_internal->compression = tcompTYPE_NONE;
1073   p_fci_internal->compress = compress_NONE;
1074
1075   list_init( &p_fci_internal->folders_list );
1076   list_init( &p_fci_internal->files_list );
1077   list_init( &p_fci_internal->blocks_list );
1078
1079   memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1080   memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1081
1082   return (HFCI)p_fci_internal;
1083 }
1084
1085
1086
1087
1088 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1089         BOOL                  fGetNextCab,
1090         PFNFCIGETNEXTCABINET  pfnfcignc,
1091         PFNFCISTATUS          pfnfcis)
1092 {
1093   cab_ULONG payload;
1094   cab_ULONG read_result;
1095   struct folder *folder;
1096
1097   if ((!pfnfcignc) || (!pfnfcis)) {
1098     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1099     return FALSE;
1100   }
1101
1102   if( p_fci_internal->fGetNextCabInVain &&
1103       p_fci_internal->fNextCab ){
1104     /* internal error */
1105     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1106     return FALSE;
1107   }
1108
1109   /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1110   /* this function will return TRUE */
1111   if( p_fci_internal->files_size == 0 ) {
1112     if ( p_fci_internal->pending_data_size != 0 ) {
1113       /* error handling */
1114       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1115       return FALSE;
1116     }
1117     return TRUE;
1118   }
1119
1120   /* FCIFlushFolder has already been called... */
1121   if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1122     return TRUE;
1123   }
1124
1125   /* This can be set already, because it makes only a difference */
1126   /* when the current function exits with return FALSE */
1127   p_fci_internal->fSplitFolder=FALSE;
1128
1129   /* START of COPY */
1130   if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1131
1132   /* reset to get the number of data blocks of this folder which are */
1133   /* actually in this cabinet ( at least partially ) */
1134   p_fci_internal->cDataBlocks=0;
1135
1136   p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1137       sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1138       p_fci_internal->placed_files_size+
1139       p_fci_internal->folders_data_size + p_fci_internal->files_size+
1140       p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1141   p_fci_internal->statusFolderCopied = 0;
1142
1143   /* report status with pfnfcis about copied size of folder */
1144   if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1145       p_fci_internal->statusFolderTotal, /* TODO total folder size */
1146       p_fci_internal->pv) == -1) {
1147     set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1148     return FALSE;
1149   }
1150
1151   /* USE the variable read_result */
1152   read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1153       p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1154
1155   if(p_fci_internal->files_size!=0) {
1156     read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1157   }
1158
1159   /* Check if multiple cabinets have to be created. */
1160
1161   /* Might be too much data for the maximum allowed cabinet size.*/
1162   /* When any further data will be added later, it might not */
1163   /* be possible to flush the cabinet, because there might */
1164   /* not be enough space to store the name of the following */
1165   /* cabinet and name of the corresponding disk. */
1166   /* So take care of this and get the name of the next cabinet */
1167   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1168       p_fci_internal->fNextCab==FALSE &&
1169       (
1170         (
1171           p_fci_internal->ccab.cb < read_result +
1172           p_fci_internal->pending_data_size +
1173           p_fci_internal->files_size +
1174           CB_MAX_CABINET_NAME +   /* next cabinet name */
1175           CB_MAX_DISK_NAME        /* next disk name */
1176         ) || fGetNextCab
1177       )
1178   ) {
1179     /* increment cabinet index */
1180     ++(p_fci_internal->pccab->iCab);
1181     /* get name of next cabinet */
1182     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1183     if (!(*pfnfcignc)(p_fci_internal->pccab,
1184         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1185         p_fci_internal->pv)) {
1186       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1187       return FALSE;
1188     }
1189
1190     /* Skip a few lines of code. This is caught by the next if. */
1191     p_fci_internal->fGetNextCabInVain=TRUE;
1192   }
1193
1194   /* too much data for cabinet */
1195   if( (p_fci_internal->fGetNextCabInVain ||
1196         p_fci_internal->fNextCab ) &&
1197       (
1198         (
1199           p_fci_internal->ccab.cb < read_result +
1200           p_fci_internal->pending_data_size +
1201           p_fci_internal->files_size +
1202           strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
1203           strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
1204         ) || fGetNextCab
1205       )
1206   ) {
1207     p_fci_internal->fGetNextCabInVain=FALSE;
1208     p_fci_internal->fNextCab=TRUE;
1209
1210     /* return FALSE if there is not enough space left*/
1211     /* this should never happen */
1212     if (p_fci_internal->ccab.cb <=
1213         p_fci_internal->files_size +
1214         read_result +
1215         strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1216         strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
1217     ) {
1218
1219       return FALSE;
1220     }
1221
1222     /* the folder will be split across cabinets */
1223     p_fci_internal->fSplitFolder=TRUE;
1224
1225   } else {
1226     /* this should never happen */
1227     if (p_fci_internal->fNextCab) {
1228       /* internal error */
1229       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1230       return FALSE;
1231     }
1232   }
1233
1234   if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1235   if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1236   if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1237
1238   /* reset CFFolder specific information */
1239   p_fci_internal->cDataBlocks=0;
1240   p_fci_internal->cCompressedBytesInFolder=0;
1241
1242   return TRUE;
1243 }
1244
1245
1246
1247
1248 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1249         BOOL                  fGetNextCab,
1250         PFNFCIGETNEXTCABINET  pfnfcignc,
1251         PFNFCISTATUS          pfnfcis)
1252 {
1253   cab_ULONG read_result=0;
1254   BOOL returntrue=FALSE;
1255
1256   /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1257
1258   /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1259   if( p_fci_internal->files_size==0 && fGetNextCab ) {
1260     returntrue=TRUE;
1261   }
1262
1263   if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1264     /* TODO set error */
1265     return FALSE;
1266   }
1267
1268   if(returntrue) return TRUE;
1269
1270   if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1271        (p_fci_internal->folders_size==0 &&
1272          (p_fci_internal->files_size!=0 ||
1273           p_fci_internal->placed_files_size!=0 )
1274      ) )
1275   {
1276       /* error */
1277       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1278       return FALSE;
1279   }
1280
1281   /* create the cabinet */
1282   if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1283
1284   p_fci_internal->fPrevCab=TRUE;
1285   /* The sections szPrevCab and szPrevDisk are not being updated, because */
1286   /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1287
1288   if (p_fci_internal->fNextCab) {
1289     p_fci_internal->fNextCab=FALSE;
1290
1291     if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1292       /* THIS CAN NEVER HAPPEN */
1293       /* set error code */
1294       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1295       return FALSE;
1296     }
1297
1298     if( p_fci_internal->fNewPrevious ) {
1299       memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1300         CB_MAX_CABINET_NAME);
1301       memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1302         CB_MAX_DISK_NAME);
1303       p_fci_internal->fNewPrevious=FALSE;
1304     }
1305     p_fci_internal->ccab = *p_fci_internal->pccab;
1306
1307     /* REUSE the variable read_result */
1308     read_result=get_header_size( p_fci_internal );
1309     if(p_fci_internal->files_size!=0) {
1310         read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1311     }
1312     read_result+= p_fci_internal->pending_data_size +
1313       p_fci_internal->files_size + p_fci_internal->folders_data_size +
1314       p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1315       sizeof(CFFOLDER); /* set size of new CFFolder entry */
1316
1317     /* too much data for the maximum size of a cabinet */
1318     if( p_fci_internal->fGetNextCabInVain==FALSE &&
1319         p_fci_internal->ccab.cb < read_result ) {
1320       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1321     }
1322
1323     /* Might be too much data for the maximum size of a cabinet.*/
1324     /* When any further data will be added later, it might not */
1325     /* be possible to flush the cabinet, because there might */
1326     /* not be enough space to store the name of the following */
1327     /* cabinet and name of the corresponding disk. */
1328     /* So take care of this and get the name of the next cabinet */
1329     if (p_fci_internal->fGetNextCabInVain==FALSE && (
1330       p_fci_internal->ccab.cb < read_result +
1331       CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1332     )) {
1333       /* increment cabinet index */
1334       ++(p_fci_internal->pccab->iCab);
1335       /* get name of next cabinet */
1336       p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1337       if (!(*pfnfcignc)(p_fci_internal->pccab,
1338           p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1339           p_fci_internal->pv)) {
1340         /* error handling */
1341         set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1342         return FALSE;
1343       }
1344       /* Skip a few lines of code. This is caught by the next if. */
1345       p_fci_internal->fGetNextCabInVain=TRUE;
1346     }
1347
1348     /* too much data for cabinet */
1349     if (p_fci_internal->fGetNextCabInVain && (
1350         p_fci_internal->ccab.cb < read_result +
1351         strlen(p_fci_internal->ccab.szCab)+1+
1352         strlen(p_fci_internal->ccab.szDisk)+1
1353     )) {
1354       p_fci_internal->fGetNextCabInVain=FALSE;
1355       p_fci_internal->fNextCab=TRUE;
1356       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1357     }
1358
1359     /* if the FolderThreshold has been reached flush the folder automatically */
1360     if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1361         return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1362
1363     if( p_fci_internal->files_size>0 ) {
1364       if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1365       p_fci_internal->fNewPrevious=TRUE;
1366     }
1367   } else {
1368     p_fci_internal->fNewPrevious=FALSE;
1369     if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1370       /* THIS MAY NEVER HAPPEN */
1371       /* set error structures */
1372       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1373       return FALSE;
1374     }
1375   }
1376
1377   return TRUE;
1378 } /* end of fci_flush_cabinet */
1379
1380
1381
1382
1383
1384 /***********************************************************************
1385  *              FCIAddFile (CABINET.11)
1386  *
1387  * FCIAddFile adds a file to the to be created cabinet file
1388  *
1389  * PARAMS
1390  *   hfci          [I]  An HFCI from FCICreate
1391  *   pszSourceFile [I]  A pointer to a C string which contains the name and
1392  *                      location of the file which will be added to the cabinet
1393  *   pszFileName   [I]  A pointer to a C string which contains the name under
1394  *                      which the file will be stored in the cabinet
1395  *   fExecute      [I]  A boolean value which indicates if the file should be
1396  *                      executed after extraction of self extracting
1397  *                      executables
1398  *   pfnfcignc     [I]  A pointer to a function which gets information about
1399  *                      the next cabinet
1400  *   pfnfcis      [IO]  A pointer to a function which will report status
1401  *                      information about the compression process
1402  *   pfnfcioi      [I]  A pointer to a function which reports file attributes
1403  *                      and time and date information
1404  *   typeCompress  [I]  Compression type
1405  *
1406  * RETURNS
1407  *   On success, returns TRUE
1408  *   On failure, returns FALSE
1409  *
1410  * INCLUDES
1411  *   fci.h
1412  *
1413  */
1414 BOOL __cdecl FCIAddFile(
1415         HFCI                  hfci,
1416         char                 *pszSourceFile,
1417         char                 *pszFileName,
1418         BOOL                  fExecute,
1419         PFNFCIGETNEXTCABINET  pfnfcignc,
1420         PFNFCISTATUS          pfnfcis,
1421         PFNFCIGETOPENINFO     pfnfcigoi,
1422         TCOMP                 typeCompress)
1423 {
1424   cab_ULONG read_result;
1425   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1426
1427   if (!p_fci_internal) return FALSE;
1428
1429   if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1430       (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1431     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1432     return FALSE;
1433   }
1434
1435   if (typeCompress != p_fci_internal->compression)
1436   {
1437       if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1438       switch (typeCompress)
1439       {
1440       case tcompTYPE_MSZIP:
1441 #ifdef HAVE_ZLIB
1442           p_fci_internal->compression = tcompTYPE_MSZIP;
1443           p_fci_internal->compress    = compress_MSZIP;
1444           break;
1445 #endif
1446       default:
1447           FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1448           /* fall through */
1449       case tcompTYPE_NONE:
1450           p_fci_internal->compression = tcompTYPE_NONE;
1451           p_fci_internal->compress    = compress_NONE;
1452           break;
1453       }
1454   }
1455
1456   /* TODO check if pszSourceFile??? */
1457
1458   if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1459     /* internal error */
1460     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1461     return FALSE;
1462   }
1463
1464   if(p_fci_internal->fNextCab) {
1465     /* internal error */
1466     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1467     return FALSE;
1468   }
1469
1470   /* REUSE the variable read_result */
1471   read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1472
1473   read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1474     p_fci_internal->files_size + p_fci_internal->folders_data_size +
1475     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1476     sizeof(CFFOLDER); /* size of new CFFolder entry */
1477
1478   /* Might be too much data for the maximum size of a cabinet.*/
1479   /* When any further data will be added later, it might not */
1480   /* be possible to flush the cabinet, because there might */
1481   /* not be enough space to store the name of the following */
1482   /* cabinet and name of the corresponding disk. */
1483   /* So take care of this and get the name of the next cabinet */
1484   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1485       p_fci_internal->fNextCab==FALSE &&
1486       ( p_fci_internal->ccab.cb < read_result +
1487         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1488       )
1489   ) {
1490     /* increment cabinet index */
1491     ++(p_fci_internal->pccab->iCab);
1492     /* get name of next cabinet */
1493     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1494     if (!(*pfnfcignc)(p_fci_internal->pccab,
1495         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1496         p_fci_internal->pv)) {
1497       /* error handling */
1498       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1499       return FALSE;
1500     }
1501     /* Skip a few lines of code. This is caught by the next if. */
1502     p_fci_internal->fGetNextCabInVain=TRUE;
1503   }
1504
1505   if( p_fci_internal->fGetNextCabInVain &&
1506       p_fci_internal->fNextCab
1507   ) {
1508     /* THIS CAN NEVER HAPPEN */
1509     /* set error code */
1510     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1511     return FALSE;
1512   }
1513
1514   /* too much data for cabinet */
1515   if( p_fci_internal->fGetNextCabInVain &&
1516      (
1517       p_fci_internal->ccab.cb < read_result +
1518       strlen(p_fci_internal->pccab->szCab)+1+
1519       strlen(p_fci_internal->pccab->szDisk)+1
1520   )) {
1521     p_fci_internal->fGetNextCabInVain=FALSE;
1522     p_fci_internal->fNextCab=TRUE;
1523     if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1524   }
1525
1526   if( p_fci_internal->fNextCab ) {
1527     /* THIS MAY NEVER HAPPEN */
1528     /* set error code */
1529     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1530     return FALSE;
1531   }
1532
1533   if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1534       return FALSE;
1535
1536   /* REUSE the variable read_result */
1537   read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1538   read_result+= p_fci_internal->pending_data_size +
1539     p_fci_internal->files_size + p_fci_internal->folders_data_size +
1540     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1541     sizeof(CFFOLDER); /* set size of new CFFolder entry */
1542
1543   /* too much data for the maximum size of a cabinet */
1544   /* (ignoring the unflushed data block) */
1545   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1546       p_fci_internal->fNextCab==FALSE && /* this is always the case */
1547       p_fci_internal->ccab.cb < read_result ) {
1548     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1549   }
1550
1551   /* Might be too much data for the maximum size of a cabinet.*/
1552   /* When any further data will be added later, it might not */
1553   /* be possible to flush the cabinet, because there might */
1554   /* not be enough space to store the name of the following */
1555   /* cabinet and name of the corresponding disk. */
1556   /* So take care of this and get the name of the next cabinet */
1557   /* (ignoring the unflushed data block) */
1558   if( p_fci_internal->fGetNextCabInVain==FALSE &&
1559       p_fci_internal->fNextCab==FALSE &&
1560       ( p_fci_internal->ccab.cb < read_result +
1561         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1562       )
1563   ) {
1564     /* increment cabinet index */
1565     ++(p_fci_internal->pccab->iCab);
1566     /* get name of next cabinet */
1567     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1568     if (!(*pfnfcignc)(p_fci_internal->pccab,
1569         p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1570         p_fci_internal->pv)) {
1571       /* error handling */
1572       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1573       return FALSE;
1574     }
1575     /* Skip a few lines of code. This is caught by the next if. */
1576     p_fci_internal->fGetNextCabInVain=TRUE;
1577   }
1578
1579   if( p_fci_internal->fGetNextCabInVain &&
1580       p_fci_internal->fNextCab
1581   ) {
1582     /* THIS CAN NEVER HAPPEN */
1583     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1584     return FALSE;
1585   }
1586
1587   /* too much data for cabinet */
1588   if( (p_fci_internal->fGetNextCabInVain ||
1589       p_fci_internal->fNextCab) && (
1590       p_fci_internal->ccab.cb < read_result +
1591       strlen(p_fci_internal->pccab->szCab)+1+
1592       strlen(p_fci_internal->pccab->szDisk)+1
1593   )) {
1594
1595     p_fci_internal->fGetNextCabInVain=FALSE;
1596     p_fci_internal->fNextCab=TRUE;
1597     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1598   }
1599
1600   if( p_fci_internal->fNextCab ) {
1601     /* THIS MAY NEVER HAPPEN */
1602     /* set error code */
1603     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1604     return FALSE;
1605   }
1606
1607   /* if the FolderThreshold has been reached flush the folder automatically */
1608   if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1609       return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1610
1611   return TRUE;
1612 } /* end of FCIAddFile */
1613
1614
1615
1616
1617
1618 /***********************************************************************
1619  *              FCIFlushFolder (CABINET.12)
1620  *
1621  * FCIFlushFolder completes the CFFolder structure under construction.
1622  *
1623  * All further data which is added by FCIAddFile will be associated to
1624  * the next CFFolder structure.
1625  *
1626  * FCIFlushFolder will be called by FCIAddFile automatically if the
1627  * threshold (stored in the member cbFolderThresh of the CCAB structure
1628  * pccab passed to FCICreate) is exceeded.
1629  *
1630  * FCIFlushFolder will be called by FCIFlushFolder automatically before
1631  * any data will be written into the cabinet file.
1632  *
1633  * PARAMS
1634  *   hfci          [I]  An HFCI from FCICreate
1635  *   pfnfcignc     [I]  A pointer to a function which gets information about
1636  *                      the next cabinet
1637  *   pfnfcis      [IO]  A pointer to a function which will report status
1638  *                      information about the compression process
1639  *
1640  * RETURNS
1641  *   On success, returns TRUE
1642  *   On failure, returns FALSE
1643  *
1644  * INCLUDES
1645  *   fci.h
1646  *
1647  */
1648 BOOL __cdecl FCIFlushFolder(
1649         HFCI                  hfci,
1650         PFNFCIGETNEXTCABINET  pfnfcignc,
1651         PFNFCISTATUS          pfnfcis)
1652 {
1653     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1654
1655     if (!p_fci_internal) return FALSE;
1656     return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1657 }
1658
1659
1660
1661 /***********************************************************************
1662  *              FCIFlushCabinet (CABINET.13)
1663  *
1664  * FCIFlushCabinet stores the data which has been added by FCIAddFile
1665  * into the cabinet file. If the maximum cabinet size (stored in the
1666  * member cb of the CCAB structure pccab passed to FCICreate) has been
1667  * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1668  * The remaining data still has to be flushed manually by calling
1669  * FCIFlushCabinet.
1670  *
1671  * After FCIFlushCabinet has been called (manually) FCIAddFile must
1672  * NOT be called again. Then hfci has to be released by FCIDestroy.
1673  *
1674  * PARAMS
1675  *   hfci          [I]  An HFCI from FCICreate
1676  *   fGetNextCab   [I]  Whether you want to add additional files to a
1677  *                      cabinet set (TRUE) or whether you want to
1678  *                      finalize it (FALSE)
1679  *   pfnfcignc     [I]  A pointer to a function which gets information about
1680  *                      the next cabinet
1681  *   pfnfcis      [IO]  A pointer to a function which will report status
1682  *                      information about the compression process
1683  *
1684  * RETURNS
1685  *   On success, returns TRUE
1686  *   On failure, returns FALSE
1687  *
1688  * INCLUDES
1689  *   fci.h
1690  *
1691  */
1692 BOOL __cdecl FCIFlushCabinet(
1693         HFCI                  hfci,
1694         BOOL                  fGetNextCab,
1695         PFNFCIGETNEXTCABINET  pfnfcignc,
1696         PFNFCISTATUS          pfnfcis)
1697 {
1698   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1699
1700   if (!p_fci_internal) return FALSE;
1701
1702   if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1703
1704   while( p_fci_internal->files_size>0 ||
1705          p_fci_internal->placed_files_size>0 ) {
1706     if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1707   }
1708
1709   return TRUE;
1710 }
1711
1712
1713 /***********************************************************************
1714  *              FCIDestroy (CABINET.14)
1715  *
1716  * Frees a handle created by FCICreate.
1717  * Only reason for failure would be an invalid handle.
1718  *
1719  * PARAMS
1720  *   hfci [I] The HFCI to free
1721  *
1722  * RETURNS
1723  *   TRUE for success
1724  *   FALSE for failure
1725  */
1726 BOOL __cdecl FCIDestroy(HFCI hfci)
1727 {
1728     struct folder *folder, *folder_next;
1729     struct file *file, *file_next;
1730     struct data_block *block, *block_next;
1731     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1732
1733     if (!p_fci_internal) return FALSE;
1734
1735     /* before hfci can be removed all temporary files must be closed */
1736     /* and deleted */
1737     p_fci_internal->magic = 0;
1738
1739     LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1740     {
1741         free_folder( p_fci_internal, folder );
1742     }
1743     LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1744     {
1745         free_file( p_fci_internal, file );
1746     }
1747     LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1748     {
1749         free_data_block( p_fci_internal, block );
1750     }
1751
1752     close_temp_file( p_fci_internal, &p_fci_internal->data );
1753
1754     /* hfci can now be removed */
1755     p_fci_internal->free(hfci);
1756     return TRUE;
1757 }