gphoto2.ds: Set supported groups.
[wine.git] / dlls / cabinet / fci.c
blob03fbf4676bddcf5eb40113270ccf1e5177a92a40
1 /*
2 * File Compression Interface
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
6 * Copyright 2011 Alexandre Julliard
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.
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.
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
25 There is still some work to be done:
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
35 #include "config.h"
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
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"
54 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
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
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 */
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 */
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 */
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;
109 struct temp_file
111 INT_PTR handle;
112 char name[CB_MAX_FILENAME];
115 struct folder
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;
126 struct file
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];
138 struct data_block
140 struct list entry;
141 cab_UWORD compressed;
142 cab_UWORD uncompressed;
145 typedef struct FCI_Int
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;
194 #define FCI_INT_MAGIC 0xfcfcfc05
196 static void set_error( FCI_Int *fci, int oper, int err )
198 fci->perf->erfOper = oper;
199 fci->perf->erfType = err;
200 fci->perf->fError = TRUE;
201 if (err) SetLastError( err );
204 static FCI_Int *get_fci_ptr( HFCI hfci )
206 FCI_Int *fci= (FCI_Int *)hfci;
208 if (!fci || fci->magic != FCI_INT_MAGIC)
210 SetLastError( ERROR_INVALID_HANDLE );
211 return NULL;
213 return fci;
216 /* compute the cabinet header size */
217 static cab_ULONG get_header_size( FCI_Int *fci )
219 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
221 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
222 ret += 4;
224 if (fci->fPrevCab)
225 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
227 if (fci->fNextCab)
228 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
230 return ret;
233 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
235 int err;
237 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
239 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
240 return FALSE;
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)
245 set_error( fci, FCIERR_TEMP_FILE, err );
246 return FALSE;
248 return TRUE;
251 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
253 int err;
255 if (file->handle == -1) return TRUE;
256 if (fci->close( file->handle, &err, fci->pv ) == -1)
258 set_error( fci, FCIERR_TEMP_FILE, err );
259 return FALSE;
261 file->handle = -1;
262 if (fci->delete( file->name, &err, fci->pv ) == -1)
264 set_error( fci, FCIERR_TEMP_FILE, err );
265 return FALSE;
267 return TRUE;
270 static struct file *add_file( FCI_Int *fci, const char *filename )
272 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
273 struct file *file = fci->alloc( size );
275 if (!file)
277 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
278 return NULL;
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;
292 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
294 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
295 struct file *file = fci->alloc( size );
297 if (!file)
299 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
300 return NULL;
302 memcpy( file, orig, size );
303 return file;
306 static void free_file( FCI_Int *fci, struct file *file )
308 list_remove( &file->entry );
309 fci->free( file );
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 )
315 int err;
316 struct data_block *block;
318 if (!fci->cdata_in) return TRUE;
320 if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
322 if (!(block = fci->alloc( sizeof(*block) )))
324 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
325 return FALSE;
327 block->uncompressed = fci->cdata_in;
328 block->compressed = fci->compress( fci );
330 if (fci->write( fci->data.handle, fci->data_out,
331 block->compressed, &err, fci->pv ) != block->compressed)
333 set_error( fci, FCIERR_TEMP_FILE, err );
334 fci->free( block );
335 return FALSE;
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 );
344 if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
346 set_error( fci, FCIERR_USER_ABORT, 0 );
347 return FALSE;
349 return TRUE;
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 )
356 int err, len;
357 INT_PTR handle;
358 struct file *file;
360 if (!(file = add_file( fci, filename ))) return FALSE;
362 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
363 if (handle == -1)
365 free_file( fci, file );
366 set_error( fci, FCIERR_OPEN_SRC, err );
367 return FALSE;
369 if (execute) file->attribs |= _A_EXEC;
371 for (;;)
373 len = fci->read( handle, fci->data_in + fci->cdata_in,
374 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
375 if (!len) break;
377 if (len == -1)
379 set_error( fci, FCIERR_READ_SRC, err );
380 return FALSE;
382 file->size += len;
383 fci->cdata_in += len;
384 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
386 fci->close( handle, &err, fci->pv );
387 return TRUE;
390 static void free_data_block( FCI_Int *fci, struct data_block *block )
392 list_remove( &block->entry );
393 fci->free( block );
396 static struct folder *add_folder( FCI_Int *fci )
398 struct folder *folder = fci->alloc( sizeof(*folder) );
400 if (!folder)
402 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
403 return NULL;
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;
417 static void free_folder( FCI_Int *fci, struct folder *folder )
419 struct file *file, *file_next;
420 struct data_block *block, *block_next;
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 );
431 /* reset state for the next cabinet file once the current one has been flushed */
432 static void reset_cabinet( FCI_Int *fci )
434 struct folder *folder, *folder_next;
436 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
437 free_folder( fci, folder );
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;
446 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
448 cab_ULONG csum;
449 cab_ULONG ul;
450 int cUlong;
451 const BYTE *pb;
453 csum = seed;
454 cUlong = cb / 4;
455 pb = pv;
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;
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;
479 csum ^= ul;
481 return csum;
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 )
488 struct data_block *block;
489 int err;
491 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
493 set_error( fci, FCIERR_TEMP_FILE, err );
494 return FALSE;
496 if (!create_temp_file( fci, temp )) return FALSE;
498 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
500 if (fci->read( handle, fci->data_out, block->compressed,
501 &err, fci->pv ) != block->compressed)
503 close_temp_file( fci, temp );
504 set_error( fci, FCIERR_TEMP_FILE, err );
505 return FALSE;
507 if (fci->write( temp->handle, fci->data_out, block->compressed,
508 &err, fci->pv ) != block->compressed)
510 close_temp_file( fci, temp );
511 set_error( fci, FCIERR_TEMP_FILE, err );
512 return FALSE;
514 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
515 fci->statusFolderCopied += block->compressed;
517 if (status_callback( statusFolder, fci->statusFolderCopied,
518 fci->statusFolderTotal, fci->pv) == -1)
520 close_temp_file( fci, temp );
521 set_error( fci, FCIERR_USER_ABORT, 0 );
522 return FALSE;
525 return TRUE;
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 )
531 struct folder *folder;
532 int err;
533 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
534 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
536 memset( cffolder, 0, folder_size );
538 /* write the folders */
539 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
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)
546 set_error( fci, FCIERR_CAB_FILE, err );
547 return FALSE;
550 return TRUE;
553 /* write all the files to the cabinet file */
554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
556 cab_ULONG file_size;
557 struct folder *folder;
558 struct file *file;
559 int err;
560 CFFILE *cffile = (CFFILE *)fci->data_out;
562 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
564 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
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)
576 set_error( fci, FCIERR_CAB_FILE, err );
577 return FALSE;
579 if (!fci->fSplitFolder)
581 fci->statusFolderCopied = 0;
582 /* TODO TEST THIS further */
583 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
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)
590 set_error( fci, FCIERR_USER_ABORT, 0 );
591 return FALSE;
595 return TRUE;
598 /* write all data blocks to the cabinet file */
599 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
601 struct folder *folder;
602 struct data_block *block;
603 int err, len;
604 CFDATA *cfdata;
605 void *data;
606 cab_UWORD header_size;
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;
613 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
615 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
617 set_error( fci, FCIERR_CAB_FILE, err );
618 return FALSE;
620 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
622 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
623 if (len != block->compressed) return FALSE;
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 )));
631 fci->statusFolderCopied += len;
632 len += header_size;
633 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
635 set_error( fci, FCIERR_CAB_FILE, err );
636 return FALSE;
638 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
640 set_error( fci, FCIERR_USER_ABORT, 0 );
641 return FALSE;
645 return TRUE;
648 /* write the cabinet file to disk */
649 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
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;
661 assert( header_size <= sizeof(fci->data_out) );
662 memset( cfheader, 0, header_size );
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;
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);
681 if (flags & cfheadRESERVE_PRESENT)
683 struct
685 cab_UWORD cbCFHeader;
686 cab_UBYTE cbCFFolder;
687 cab_UBYTE cbCFData;
688 } *reserve = (void *)ptr;
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);
695 ptr += fci->ccab.cbReserveCFHeader;
697 if (flags & cfheadPREV_CABINET)
699 strcpy( ptr, fci->szPrevCab );
700 ptr += strlen( ptr ) + 1;
701 strcpy( ptr, fci->szPrevDisk );
702 ptr += strlen( ptr ) + 1;
705 if (flags & cfheadNEXT_CABINET)
707 strcpy( ptr, fci->pccab->szCab );
708 ptr += strlen( ptr ) + 1;
709 strcpy( ptr, fci->pccab->szDisk );
710 ptr += strlen( ptr ) + 1;
713 assert( ptr - (char *)cfheader == header_size );
715 strcpy( filename, fci->ccab.szCabPath );
716 strcat( filename, fci->ccab.szCab );
718 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
719 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
721 set_error( fci, FCIERR_CAB_FILE, err );
722 return FALSE;
725 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
727 set_error( fci, FCIERR_CAB_FILE, err );
728 goto failed;
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;
737 /* update the signature */
738 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
740 set_error( fci, FCIERR_CAB_FILE, err );
741 goto failed;
743 memcpy( cfheader->signature, "MSCF", 4 );
744 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
746 set_error( fci, FCIERR_CAB_FILE, err );
747 goto failed;
749 fci->close( handle, &err, fci->pv );
751 reset_cabinet( fci );
752 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
753 return TRUE;
755 failed:
756 fci->close( handle, &err, fci->pv );
757 fci->delete( filename, &err, fci->pv );
758 return FALSE;
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 )
765 struct data_block *block, *new, *next;
766 BOOL split_block = FALSE;
767 cab_ULONG current_size, start_pos = 0;
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;
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;
778 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
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;
786 if (!(new = fci->alloc( sizeof(*new) )))
788 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
789 return FALSE;
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))
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. */
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;
807 else
809 new->compressed = block->compressed;
810 new->uncompressed = block->uncompressed;
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;
819 list_add_tail( &folder->blocks_list, &new->entry );
820 folder->data_count++;
822 /* report status with pfnfcis about copied size of folder */
823 if (status_callback( statusFolder, fci->statusFolderCopied,
824 fci->statusFolderTotal, fci->pv ) == -1)
826 set_error( fci, FCIERR_USER_ABORT, 0 );
827 return FALSE;
829 if (split_block) break;
830 free_data_block( fci, block );
831 fci->cDataBlocks--;
834 if (list_empty( &fci->blocks_list )) return TRUE;
835 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
838 /* add all pending files to folder */
839 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
841 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
842 cab_ULONG cbFileRemainer = 0;
843 struct file *file, *next;
845 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
847 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
849 /* fnfilfnfildest: placed file on cabinet */
850 fci->fileplaced( &fci->ccab, file->name, file->size,
851 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
853 sizeOfFilesPrev = sizeOfFiles;
854 /* set complete size of all processed files */
855 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
857 sizeOfFiles += fci->cbFileRemainer;
858 fci->cbFileRemainer = 0;
860 else sizeOfFiles += file->size;
862 /* check if spanned file fits into this cabinet folder */
863 if (sizeOfFiles > payload)
865 if (file->folder == cffileCONTINUED_FROM_PREV)
866 file->folder = cffileCONTINUED_PREV_AND_NEXT;
867 else
868 file->folder = cffileCONTINUED_TO_NEXT;
871 list_remove( &file->entry );
872 list_add_tail( &folder->files_list, &file->entry );
873 fci->placed_files_size += size;
874 fci->cFiles++;
876 /* This is only true for files which will be written into the */
877 /* next cabinet of the spanning folder */
878 if (sizeOfFiles > payload)
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 );
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)
887 if (sizeOfFilesPrev <= payload)
889 /* The size of the uncompressed, data of a spanning file in a */
890 /* spanning data */
891 cbFileRemainer = sizeOfFiles - payload;
893 file->folder = cffileCONTINUED_FROM_PREV;
895 else file->folder = 0;
897 else
899 fci->files_size -= size;
902 fci->cbFileRemainer = cbFileRemainer;
903 return TRUE;
906 static cab_UWORD compress_NONE( FCI_Int *fci )
908 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
909 return fci->cdata_in;
912 #ifdef HAVE_ZLIB
914 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
916 FCI_Int *fci = opaque;
917 return fci->alloc( items * size );
920 static void zfree( void *opaque, void *ptr )
922 FCI_Int *fci = opaque;
923 fci->free( ptr );
926 static cab_UWORD compress_MSZIP( FCI_Int *fci )
928 z_stream stream;
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)
935 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
936 return 0;
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;
950 #endif /* HAVE_ZLIB */
953 /***********************************************************************
954 * FCICreate (CABINET.10)
956 * FCICreate is provided with several callbacks and
957 * returns a handle which can be used to create cabinet files.
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.
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.
994 * INCLUDES
995 * fci.h
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)
1013 FCI_Int *p_fci_internal;
1015 if (!perf) {
1016 SetLastError(ERROR_BAD_ARGUMENTS);
1017 return NULL;
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;
1026 SetLastError(ERROR_BAD_ARGUMENTS);
1027 return NULL;
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;
1035 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1036 return NULL;
1039 memset(p_fci_internal, 0, sizeof(FCI_Int));
1040 p_fci_internal->magic = FCI_INT_MAGIC;
1041 p_fci_internal->perf = perf;
1042 p_fci_internal->fileplaced = pfnfiledest;
1043 p_fci_internal->alloc = pfnalloc;
1044 p_fci_internal->free = pfnfree;
1045 p_fci_internal->open = pfnopen;
1046 p_fci_internal->read = pfnread;
1047 p_fci_internal->write = pfnwrite;
1048 p_fci_internal->close = pfnclose;
1049 p_fci_internal->seek = pfnseek;
1050 p_fci_internal->delete = pfndelete;
1051 p_fci_internal->gettemp = pfnfcigtf;
1052 p_fci_internal->ccab = *pccab;
1053 p_fci_internal->pccab = pccab;
1054 p_fci_internal->pv = pv;
1055 p_fci_internal->data.handle = -1;
1056 p_fci_internal->compress = compress_NONE;
1058 list_init( &p_fci_internal->folders_list );
1059 list_init( &p_fci_internal->files_list );
1060 list_init( &p_fci_internal->blocks_list );
1062 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1063 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1065 return (HFCI)p_fci_internal;
1071 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1072 BOOL fGetNextCab,
1073 PFNFCIGETNEXTCABINET pfnfcignc,
1074 PFNFCISTATUS pfnfcis)
1076 cab_ULONG payload;
1077 cab_ULONG read_result;
1078 struct folder *folder;
1080 if ((!pfnfcignc) || (!pfnfcis)) {
1081 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1082 return FALSE;
1085 if( p_fci_internal->fGetNextCabInVain &&
1086 p_fci_internal->fNextCab ){
1087 /* internal error */
1088 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1089 return FALSE;
1092 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1093 /* this function will return TRUE */
1094 if( p_fci_internal->files_size == 0 ) {
1095 if ( p_fci_internal->pending_data_size != 0 ) {
1096 /* error handling */
1097 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1098 return FALSE;
1100 return TRUE;
1103 /* FCIFlushFolder has already been called... */
1104 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1105 return TRUE;
1108 /* This can be set already, because it makes only a difference */
1109 /* when the current function exits with return FALSE */
1110 p_fci_internal->fSplitFolder=FALSE;
1112 /* START of COPY */
1113 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1115 /* reset to get the number of data blocks of this folder which are */
1116 /* actually in this cabinet ( at least partially ) */
1117 p_fci_internal->cDataBlocks=0;
1119 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1120 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1121 p_fci_internal->placed_files_size+
1122 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1123 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1124 p_fci_internal->statusFolderCopied = 0;
1126 /* report status with pfnfcis about copied size of folder */
1127 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1128 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1129 p_fci_internal->pv) == -1) {
1130 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1131 return FALSE;
1134 /* USE the variable read_result */
1135 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1136 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1138 if(p_fci_internal->files_size!=0) {
1139 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1142 /* Check if multiple cabinets have to be created. */
1144 /* Might be too much data for the maximum allowed cabinet size.*/
1145 /* When any further data will be added later, it might not */
1146 /* be possible to flush the cabinet, because there might */
1147 /* not be enough space to store the name of the following */
1148 /* cabinet and name of the corresponding disk. */
1149 /* So take care of this and get the name of the next cabinet */
1150 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1151 p_fci_internal->fNextCab==FALSE &&
1154 p_fci_internal->ccab.cb < read_result +
1155 p_fci_internal->pending_data_size +
1156 p_fci_internal->files_size +
1157 CB_MAX_CABINET_NAME + /* next cabinet name */
1158 CB_MAX_DISK_NAME /* next disk name */
1159 ) || fGetNextCab
1162 /* increment cabinet index */
1163 ++(p_fci_internal->pccab->iCab);
1164 /* get name of next cabinet */
1165 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1166 if (!(*pfnfcignc)(p_fci_internal->pccab,
1167 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1168 p_fci_internal->pv)) {
1169 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1170 return FALSE;
1173 /* Skip a few lines of code. This is caught by the next if. */
1174 p_fci_internal->fGetNextCabInVain=TRUE;
1177 /* too much data for cabinet */
1178 if( (p_fci_internal->fGetNextCabInVain ||
1179 p_fci_internal->fNextCab ) &&
1182 p_fci_internal->ccab.cb < read_result +
1183 p_fci_internal->pending_data_size +
1184 p_fci_internal->files_size +
1185 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1186 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1187 ) || fGetNextCab
1190 p_fci_internal->fGetNextCabInVain=FALSE;
1191 p_fci_internal->fNextCab=TRUE;
1193 /* return FALSE if there is not enough space left*/
1194 /* this should never happen */
1195 if (p_fci_internal->ccab.cb <=
1196 p_fci_internal->files_size +
1197 read_result +
1198 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1199 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1202 return FALSE;
1205 /* the folder will be split across cabinets */
1206 p_fci_internal->fSplitFolder=TRUE;
1208 } else {
1209 /* this should never happen */
1210 if (p_fci_internal->fNextCab) {
1211 /* internal error */
1212 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1213 return FALSE;
1217 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1218 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1219 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1221 /* reset CFFolder specific information */
1222 p_fci_internal->cDataBlocks=0;
1223 p_fci_internal->cCompressedBytesInFolder=0;
1225 return TRUE;
1231 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1232 BOOL fGetNextCab,
1233 PFNFCIGETNEXTCABINET pfnfcignc,
1234 PFNFCISTATUS pfnfcis)
1236 cab_ULONG read_result=0;
1237 BOOL returntrue=FALSE;
1239 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1241 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1242 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1243 returntrue=TRUE;
1246 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1247 /* TODO set error */
1248 return FALSE;
1251 if(returntrue) return TRUE;
1253 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1254 (p_fci_internal->folders_size==0 &&
1255 (p_fci_internal->files_size!=0 ||
1256 p_fci_internal->placed_files_size!=0 )
1259 /* error */
1260 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1261 return FALSE;
1264 /* create the cabinet */
1265 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1267 p_fci_internal->fPrevCab=TRUE;
1268 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1269 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1271 if (p_fci_internal->fNextCab) {
1272 p_fci_internal->fNextCab=FALSE;
1274 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1275 /* THIS CAN NEVER HAPPEN */
1276 /* set error code */
1277 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1278 return FALSE;
1281 if( p_fci_internal->fNewPrevious ) {
1282 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1283 CB_MAX_CABINET_NAME);
1284 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1285 CB_MAX_DISK_NAME);
1286 p_fci_internal->fNewPrevious=FALSE;
1288 p_fci_internal->ccab = *p_fci_internal->pccab;
1290 /* REUSE the variable read_result */
1291 read_result=get_header_size( p_fci_internal );
1292 if(p_fci_internal->files_size!=0) {
1293 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1295 read_result+= p_fci_internal->pending_data_size +
1296 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1297 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1298 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1300 /* too much data for the maximum size of a cabinet */
1301 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1302 p_fci_internal->ccab.cb < read_result ) {
1303 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1306 /* Might be too much data for the maximum size of a cabinet.*/
1307 /* When any further data will be added later, it might not */
1308 /* be possible to flush the cabinet, because there might */
1309 /* not be enough space to store the name of the following */
1310 /* cabinet and name of the corresponding disk. */
1311 /* So take care of this and get the name of the next cabinet */
1312 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1313 p_fci_internal->ccab.cb < read_result +
1314 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1315 )) {
1316 /* increment cabinet index */
1317 ++(p_fci_internal->pccab->iCab);
1318 /* get name of next cabinet */
1319 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1320 if (!(*pfnfcignc)(p_fci_internal->pccab,
1321 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1322 p_fci_internal->pv)) {
1323 /* error handling */
1324 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1325 return FALSE;
1327 /* Skip a few lines of code. This is caught by the next if. */
1328 p_fci_internal->fGetNextCabInVain=TRUE;
1331 /* too much data for cabinet */
1332 if (p_fci_internal->fGetNextCabInVain && (
1333 p_fci_internal->ccab.cb < read_result +
1334 strlen(p_fci_internal->ccab.szCab)+1+
1335 strlen(p_fci_internal->ccab.szDisk)+1
1336 )) {
1337 p_fci_internal->fGetNextCabInVain=FALSE;
1338 p_fci_internal->fNextCab=TRUE;
1339 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1342 /* if the FolderThreshold has been reached flush the folder automatically */
1343 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1344 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1346 if( p_fci_internal->files_size>0 ) {
1347 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1348 p_fci_internal->fNewPrevious=TRUE;
1350 } else {
1351 p_fci_internal->fNewPrevious=FALSE;
1352 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1353 /* THIS MAY NEVER HAPPEN */
1354 /* set error structures */
1355 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1356 return FALSE;
1360 return TRUE;
1361 } /* end of fci_flush_cabinet */
1367 /***********************************************************************
1368 * FCIAddFile (CABINET.11)
1370 * FCIAddFile adds a file to the to be created cabinet file
1372 * PARAMS
1373 * hfci [I] An HFCI from FCICreate
1374 * pszSourceFile [I] A pointer to a C string which contains the name and
1375 * location of the file which will be added to the cabinet
1376 * pszFileName [I] A pointer to a C string which contains the name under
1377 * which the file will be stored in the cabinet
1378 * fExecute [I] A boolean value which indicates if the file should be
1379 * executed after extraction of self extracting
1380 * executables
1381 * pfnfcignc [I] A pointer to a function which gets information about
1382 * the next cabinet
1383 * pfnfcis [IO] A pointer to a function which will report status
1384 * information about the compression process
1385 * pfnfcioi [I] A pointer to a function which reports file attributes
1386 * and time and date information
1387 * typeCompress [I] Compression type
1389 * RETURNS
1390 * On success, returns TRUE
1391 * On failure, returns FALSE
1393 * INCLUDES
1394 * fci.h
1397 BOOL __cdecl FCIAddFile(
1398 HFCI hfci,
1399 char *pszSourceFile,
1400 char *pszFileName,
1401 BOOL fExecute,
1402 PFNFCIGETNEXTCABINET pfnfcignc,
1403 PFNFCISTATUS pfnfcis,
1404 PFNFCIGETOPENINFO pfnfcigoi,
1405 TCOMP typeCompress)
1407 cab_ULONG read_result;
1408 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1410 if (!p_fci_internal) return FALSE;
1412 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1413 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1414 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1415 return FALSE;
1418 if (typeCompress != p_fci_internal->compression)
1420 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1421 switch (typeCompress)
1423 case tcompTYPE_MSZIP:
1424 #ifdef HAVE_ZLIB
1425 p_fci_internal->compression = tcompTYPE_MSZIP;
1426 p_fci_internal->compress = compress_MSZIP;
1427 break;
1428 #endif
1429 default:
1430 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1431 /* fall through */
1432 case tcompTYPE_NONE:
1433 p_fci_internal->compression = tcompTYPE_NONE;
1434 p_fci_internal->compress = compress_NONE;
1435 break;
1439 /* TODO check if pszSourceFile??? */
1441 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1442 /* internal error */
1443 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1444 return FALSE;
1447 if(p_fci_internal->fNextCab) {
1448 /* internal error */
1449 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1450 return FALSE;
1453 /* REUSE the variable read_result */
1454 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1456 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1457 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1458 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1459 sizeof(CFFOLDER); /* size of new CFFolder entry */
1461 /* Might be too much data for the maximum size of a cabinet.*/
1462 /* When any further data will be added later, it might not */
1463 /* be possible to flush the cabinet, because there might */
1464 /* not be enough space to store the name of the following */
1465 /* cabinet and name of the corresponding disk. */
1466 /* So take care of this and get the name of the next cabinet */
1467 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1468 p_fci_internal->fNextCab==FALSE &&
1469 ( p_fci_internal->ccab.cb < read_result +
1470 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1473 /* increment cabinet index */
1474 ++(p_fci_internal->pccab->iCab);
1475 /* get name of next cabinet */
1476 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1477 if (!(*pfnfcignc)(p_fci_internal->pccab,
1478 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1479 p_fci_internal->pv)) {
1480 /* error handling */
1481 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1482 return FALSE;
1484 /* Skip a few lines of code. This is caught by the next if. */
1485 p_fci_internal->fGetNextCabInVain=TRUE;
1488 if( p_fci_internal->fGetNextCabInVain &&
1489 p_fci_internal->fNextCab
1491 /* THIS CAN NEVER HAPPEN */
1492 /* set error code */
1493 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1494 return FALSE;
1497 /* too much data for cabinet */
1498 if( p_fci_internal->fGetNextCabInVain &&
1500 p_fci_internal->ccab.cb < read_result +
1501 strlen(p_fci_internal->pccab->szCab)+1+
1502 strlen(p_fci_internal->pccab->szDisk)+1
1503 )) {
1504 p_fci_internal->fGetNextCabInVain=FALSE;
1505 p_fci_internal->fNextCab=TRUE;
1506 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1509 if( p_fci_internal->fNextCab ) {
1510 /* THIS MAY NEVER HAPPEN */
1511 /* set error code */
1512 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1513 return FALSE;
1516 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1517 return FALSE;
1519 /* REUSE the variable read_result */
1520 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1521 read_result+= p_fci_internal->pending_data_size +
1522 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1523 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1524 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1526 /* too much data for the maximum size of a cabinet */
1527 /* (ignoring the unflushed data block) */
1528 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1529 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1530 p_fci_internal->ccab.cb < read_result ) {
1531 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1534 /* Might be too much data for the maximum size of a cabinet.*/
1535 /* When any further data will be added later, it might not */
1536 /* be possible to flush the cabinet, because there might */
1537 /* not be enough space to store the name of the following */
1538 /* cabinet and name of the corresponding disk. */
1539 /* So take care of this and get the name of the next cabinet */
1540 /* (ignoring the unflushed data block) */
1541 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1542 p_fci_internal->fNextCab==FALSE &&
1543 ( p_fci_internal->ccab.cb < read_result +
1544 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1547 /* increment cabinet index */
1548 ++(p_fci_internal->pccab->iCab);
1549 /* get name of next cabinet */
1550 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1551 if (!(*pfnfcignc)(p_fci_internal->pccab,
1552 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1553 p_fci_internal->pv)) {
1554 /* error handling */
1555 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1556 return FALSE;
1558 /* Skip a few lines of code. This is caught by the next if. */
1559 p_fci_internal->fGetNextCabInVain=TRUE;
1562 if( p_fci_internal->fGetNextCabInVain &&
1563 p_fci_internal->fNextCab
1565 /* THIS CAN NEVER HAPPEN */
1566 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1567 return FALSE;
1570 /* too much data for cabinet */
1571 if( (p_fci_internal->fGetNextCabInVain ||
1572 p_fci_internal->fNextCab) && (
1573 p_fci_internal->ccab.cb < read_result +
1574 strlen(p_fci_internal->pccab->szCab)+1+
1575 strlen(p_fci_internal->pccab->szDisk)+1
1576 )) {
1578 p_fci_internal->fGetNextCabInVain=FALSE;
1579 p_fci_internal->fNextCab=TRUE;
1580 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1583 if( p_fci_internal->fNextCab ) {
1584 /* THIS MAY NEVER HAPPEN */
1585 /* set error code */
1586 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1587 return FALSE;
1590 /* if the FolderThreshold has been reached flush the folder automatically */
1591 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1592 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1594 return TRUE;
1595 } /* end of FCIAddFile */
1601 /***********************************************************************
1602 * FCIFlushFolder (CABINET.12)
1604 * FCIFlushFolder completes the CFFolder structure under construction.
1606 * All further data which is added by FCIAddFile will be associated to
1607 * the next CFFolder structure.
1609 * FCIFlushFolder will be called by FCIAddFile automatically if the
1610 * threshold (stored in the member cbFolderThresh of the CCAB structure
1611 * pccab passed to FCICreate) is exceeded.
1613 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1614 * any data will be written into the cabinet file.
1616 * PARAMS
1617 * hfci [I] An HFCI from FCICreate
1618 * pfnfcignc [I] A pointer to a function which gets information about
1619 * the next cabinet
1620 * pfnfcis [IO] A pointer to a function which will report status
1621 * information about the compression process
1623 * RETURNS
1624 * On success, returns TRUE
1625 * On failure, returns FALSE
1627 * INCLUDES
1628 * fci.h
1631 BOOL __cdecl FCIFlushFolder(
1632 HFCI hfci,
1633 PFNFCIGETNEXTCABINET pfnfcignc,
1634 PFNFCISTATUS pfnfcis)
1636 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1638 if (!p_fci_internal) return FALSE;
1639 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1644 /***********************************************************************
1645 * FCIFlushCabinet (CABINET.13)
1647 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1648 * into the cabinet file. If the maximum cabinet size (stored in the
1649 * member cb of the CCAB structure pccab passed to FCICreate) has been
1650 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1651 * The remaining data still has to be flushed manually by calling
1652 * FCIFlushCabinet.
1654 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1655 * NOT be called again. Then hfci has to be released by FCIDestroy.
1657 * PARAMS
1658 * hfci [I] An HFCI from FCICreate
1659 * fGetNextCab [I] Whether you want to add additional files to a
1660 * cabinet set (TRUE) or whether you want to
1661 * finalize it (FALSE)
1662 * pfnfcignc [I] A pointer to a function which gets information about
1663 * the next cabinet
1664 * pfnfcis [IO] A pointer to a function which will report status
1665 * information about the compression process
1667 * RETURNS
1668 * On success, returns TRUE
1669 * On failure, returns FALSE
1671 * INCLUDES
1672 * fci.h
1675 BOOL __cdecl FCIFlushCabinet(
1676 HFCI hfci,
1677 BOOL fGetNextCab,
1678 PFNFCIGETNEXTCABINET pfnfcignc,
1679 PFNFCISTATUS pfnfcis)
1681 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1683 if (!p_fci_internal) return FALSE;
1685 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1687 while( p_fci_internal->files_size>0 ||
1688 p_fci_internal->placed_files_size>0 ) {
1689 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1692 return TRUE;
1696 /***********************************************************************
1697 * FCIDestroy (CABINET.14)
1699 * Frees a handle created by FCICreate.
1700 * Only reason for failure would be an invalid handle.
1702 * PARAMS
1703 * hfci [I] The HFCI to free
1705 * RETURNS
1706 * TRUE for success
1707 * FALSE for failure
1709 BOOL __cdecl FCIDestroy(HFCI hfci)
1711 struct folder *folder, *folder_next;
1712 struct file *file, *file_next;
1713 struct data_block *block, *block_next;
1714 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1716 if (!p_fci_internal) return FALSE;
1718 /* before hfci can be removed all temporary files must be closed */
1719 /* and deleted */
1720 p_fci_internal->magic = 0;
1722 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1724 free_folder( p_fci_internal, folder );
1726 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1728 free_file( p_fci_internal, file );
1730 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1732 free_data_block( p_fci_internal, block );
1735 close_temp_file( p_fci_internal, &p_fci_internal->data );
1737 /* hfci can now be removed */
1738 p_fci_internal->free(hfci);
1739 return TRUE;