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
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)
60 #define fci_endian_ulong(x) (x)
61 #define fci_endian_uword(x) (x)
66 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
68 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
70 cab_ULONG coffFiles; /* offset to first CFFILE section */
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 */
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 */
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 */
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 */
112 char name[CB_MAX_FILENAME];
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;
129 cab_ULONG size; /* uncompressed size */
130 cab_ULONG offset; /* offset in folder */
131 cab_UWORD folder; /* index of folder */
141 cab_UWORD compressed;
142 cab_UWORD uncompressed;
145 typedef struct FCI_Int
149 PFNFCIFILEPLACED fileplaced;
158 PFNFCIGETTEMPFILE gettemp;
164 cab_ULONG statusFolderCopied;
165 cab_ULONG statusFolderTotal;
166 BOOL fGetNextCabInVain;
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 */
173 ULONG cCompressedBytesInFolder;
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;
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 */
191 cab_UWORD (*compress)(struct 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 );
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)
225 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
228 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
233 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
237 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
239 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
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 );
251 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
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 );
262 if (fci->delete( file->name, &err, fci->pv ) == -1)
264 set_error( fci, FCIERR_TEMP_FILE, err );
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 );
277 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
281 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
282 file->folder = fci->cFolders;
286 strcpy( file->name, filename );
287 list_add_tail( &fci->files_list, &file->entry );
288 fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
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 );
299 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
302 memcpy( file, orig, size );
306 static void free_file( FCI_Int *fci, struct file *file )
308 list_remove( &file->entry );
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 )
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 );
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 );
339 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
340 fci->cCompressedBytesInFolder += block->compressed;
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 );
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 )
360 if (!(file = add_file( fci, filename ))) return FALSE;
362 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
365 free_file( fci, file );
366 set_error( fci, FCIERR_OPEN_SRC, err );
369 if (execute) file->attribs |= _A_EXEC;
373 len = fci->read( handle, fci->data_in + fci->cdata_in,
374 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
379 set_error( fci, FCIERR_READ_SRC, err );
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 );
390 static void free_data_block( FCI_Int *fci, struct data_block *block )
392 list_remove( &block->entry );
396 static struct folder *add_folder( FCI_Int *fci )
398 struct folder *folder = fci->alloc( sizeof(*folder) );
402 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
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;
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 );
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 );
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 )
457 while (cUlong-- > 0) {
459 ul |= (((cab_ULONG)(*pb++)) << 8);
460 ul |= (((cab_ULONG)(*pb++)) << 16);
461 ul |= (((cab_ULONG)(*pb++)) << 24);
468 ul |= (((ULONG)(*pb++)) << 16);
471 ul |= (((ULONG)(*pb++)) << 8);
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;
491 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
493 set_error( fci, FCIERR_TEMP_FILE, err );
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 );
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 );
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 );
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;
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 );
553 /* write all the files to the cabinet file */
554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
557 struct folder *folder;
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 );
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 );
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;
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 );
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;
633 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
635 set_error( fci, FCIERR_CAB_FILE, err );
638 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
640 set_error( fci, FCIERR_USER_ABORT, 0 );
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];
655 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
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)
685 cab_UWORD cbCFHeader;
686 cab_UBYTE cbCFFolder;
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 );
725 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
727 set_error( fci, FCIERR_CAB_FILE, err );
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 );
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 );
749 fci->close( handle, &err, fci->pv );
751 reset_cabinet( fci );
752 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
756 fci->close( handle, &err, fci->pv );
757 fci->delete( filename, &err, fci->pv );
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;
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))
786 if (!(new = fci->alloc( sizeof(*new) )))
788 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
791 /* Is cabinet with new CFDATA too large? Then data block has to be split */
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;
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 );
829 if (split_block) break;
830 free_data_block( fci, block );
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;
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;
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 */
891 cbFileRemainer = sizeOfFiles - payload;
893 file->folder = cffileCONTINUED_FROM_PREV;
895 else file->folder = 0;
899 fci->files_size -= size;
902 fci->cbFileRemainer = cbFileRemainer;
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;
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;
926 static cab_UWORD compress_MSZIP( FCI_Int *fci )
930 stream.zalloc = zalloc;
931 stream.zfree = zfree;
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 );
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.
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
974 * pfnwrite [I] A pointer to a function which writes to a file from
975 * a caller-provided buffer. Uses the same interface
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
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
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.
998 HFCI __cdecl FCICreate(
1000 PFNFCIFILEPLACED pfnfiledest,
1001 PFNFCIALLOC pfnalloc,
1005 PFNFCIWRITE pfnwrite,
1006 PFNFCICLOSE pfnclose,
1008 PFNFCIDELETE pfndelete,
1009 PFNFCIGETTEMPFILE pfnfcigtf,
1013 FCI_Int *p_fci_internal;
1016 SetLastError(ERROR_BAD_ARGUMENTS);
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);
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);
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;
1075 list_init( &p_fci_internal->folders_list );
1076 list_init( &p_fci_internal->files_list );
1077 list_init( &p_fci_internal->blocks_list );
1079 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1080 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1082 return (HFCI)p_fci_internal;
1088 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1090 PFNFCIGETNEXTCABINET pfnfcignc,
1091 PFNFCISTATUS pfnfcis)
1094 cab_ULONG read_result;
1095 struct folder *folder;
1097 if ((!pfnfcignc) || (!pfnfcis)) {
1098 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
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 );
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 );
1120 /* FCIFlushFolder has already been called... */
1121 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
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;
1130 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
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;
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;
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 );
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;
1155 if(p_fci_internal->files_size!=0) {
1156 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1159 /* Check if multiple cabinets have to be created. */
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 &&
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 */
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 );
1190 /* Skip a few lines of code. This is caught by the next if. */
1191 p_fci_internal->fGetNextCabInVain=TRUE;
1194 /* too much data for cabinet */
1195 if( (p_fci_internal->fGetNextCabInVain ||
1196 p_fci_internal->fNextCab ) &&
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 */
1207 p_fci_internal->fGetNextCabInVain=FALSE;
1208 p_fci_internal->fNextCab=TRUE;
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 +
1215 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1216 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1222 /* the folder will be split across cabinets */
1223 p_fci_internal->fSplitFolder=TRUE;
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 );
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;
1238 /* reset CFFolder specific information */
1239 p_fci_internal->cDataBlocks=0;
1240 p_fci_internal->cCompressedBytesInFolder=0;
1248 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1250 PFNFCIGETNEXTCABINET pfnfcignc,
1251 PFNFCISTATUS pfnfcis)
1253 cab_ULONG read_result=0;
1254 BOOL returntrue=FALSE;
1256 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1258 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1259 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1263 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1264 /* TODO set error */
1268 if(returntrue) return TRUE;
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 )
1277 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1281 /* create the cabinet */
1282 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
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 */
1288 if (p_fci_internal->fNextCab) {
1289 p_fci_internal->fNextCab=FALSE;
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 );
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,
1303 p_fci_internal->fNewPrevious=FALSE;
1305 p_fci_internal->ccab = *p_fci_internal->pccab;
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;
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 */
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);
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
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 );
1344 /* Skip a few lines of code. This is caught by the next if. */
1345 p_fci_internal->fGetNextCabInVain=TRUE;
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
1354 p_fci_internal->fGetNextCabInVain=FALSE;
1355 p_fci_internal->fNextCab=TRUE;
1356 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
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);
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;
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 );
1378 } /* end of fci_flush_cabinet */
1384 /***********************************************************************
1385 * FCIAddFile (CABINET.11)
1387 * FCIAddFile adds a file to the to be created cabinet file
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
1398 * pfnfcignc [I] A pointer to a function which gets information about
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
1407 * On success, returns TRUE
1408 * On failure, returns FALSE
1414 BOOL __cdecl FCIAddFile(
1416 char *pszSourceFile,
1419 PFNFCIGETNEXTCABINET pfnfcignc,
1420 PFNFCISTATUS pfnfcis,
1421 PFNFCIGETOPENINFO pfnfcigoi,
1424 cab_ULONG read_result;
1425 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1427 if (!p_fci_internal) return FALSE;
1429 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1430 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1431 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1435 if (typeCompress != p_fci_internal->compression)
1437 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1438 switch (typeCompress)
1440 case tcompTYPE_MSZIP:
1442 p_fci_internal->compression = tcompTYPE_MSZIP;
1443 p_fci_internal->compress = compress_MSZIP;
1447 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1449 case tcompTYPE_NONE:
1450 p_fci_internal->compression = tcompTYPE_NONE;
1451 p_fci_internal->compress = compress_NONE;
1456 /* TODO check if pszSourceFile??? */
1458 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1459 /* internal error */
1460 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1464 if(p_fci_internal->fNextCab) {
1465 /* internal error */
1466 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1470 /* REUSE the variable read_result */
1471 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
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 */
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
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 );
1501 /* Skip a few lines of code. This is caught by the next if. */
1502 p_fci_internal->fGetNextCabInVain=TRUE;
1505 if( p_fci_internal->fGetNextCabInVain &&
1506 p_fci_internal->fNextCab
1508 /* THIS CAN NEVER HAPPEN */
1509 /* set error code */
1510 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1514 /* too much data for cabinet */
1515 if( p_fci_internal->fGetNextCabInVain &&
1517 p_fci_internal->ccab.cb < read_result +
1518 strlen(p_fci_internal->pccab->szCab)+1+
1519 strlen(p_fci_internal->pccab->szDisk)+1
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;
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 );
1533 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
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 */
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);
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
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 );
1575 /* Skip a few lines of code. This is caught by the next if. */
1576 p_fci_internal->fGetNextCabInVain=TRUE;
1579 if( p_fci_internal->fGetNextCabInVain &&
1580 p_fci_internal->fNextCab
1582 /* THIS CAN NEVER HAPPEN */
1583 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
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
1595 p_fci_internal->fGetNextCabInVain=FALSE;
1596 p_fci_internal->fNextCab=TRUE;
1597 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
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 );
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);
1612 } /* end of FCIAddFile */
1618 /***********************************************************************
1619 * FCIFlushFolder (CABINET.12)
1621 * FCIFlushFolder completes the CFFolder structure under construction.
1623 * All further data which is added by FCIAddFile will be associated to
1624 * the next CFFolder structure.
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.
1630 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1631 * any data will be written into the cabinet file.
1634 * hfci [I] An HFCI from FCICreate
1635 * pfnfcignc [I] A pointer to a function which gets information about
1637 * pfnfcis [IO] A pointer to a function which will report status
1638 * information about the compression process
1641 * On success, returns TRUE
1642 * On failure, returns FALSE
1648 BOOL __cdecl FCIFlushFolder(
1650 PFNFCIGETNEXTCABINET pfnfcignc,
1651 PFNFCISTATUS pfnfcis)
1653 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1655 if (!p_fci_internal) return FALSE;
1656 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1661 /***********************************************************************
1662 * FCIFlushCabinet (CABINET.13)
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
1671 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1672 * NOT be called again. Then hfci has to be released by FCIDestroy.
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
1681 * pfnfcis [IO] A pointer to a function which will report status
1682 * information about the compression process
1685 * On success, returns TRUE
1686 * On failure, returns FALSE
1692 BOOL __cdecl FCIFlushCabinet(
1695 PFNFCIGETNEXTCABINET pfnfcignc,
1696 PFNFCISTATUS pfnfcis)
1698 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1700 if (!p_fci_internal) return FALSE;
1702 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
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;
1713 /***********************************************************************
1714 * FCIDestroy (CABINET.14)
1716 * Frees a handle created by FCICreate.
1717 * Only reason for failure would be an invalid handle.
1720 * hfci [I] The HFCI to free
1726 BOOL __cdecl FCIDestroy(HFCI hfci)
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 );
1733 if (!p_fci_internal) return FALSE;
1735 /* before hfci can be removed all temporary files must be closed */
1737 p_fci_internal->magic = 0;
1739 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1741 free_folder( p_fci_internal, folder );
1743 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1745 free_file( p_fci_internal, file );
1747 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1749 free_data_block( p_fci_internal, block );
1752 close_temp_file( p_fci_internal, &p_fci_internal->data );
1754 /* hfci can now be removed */
1755 p_fci_internal->free(hfci);