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);
470 ul |= (((ULONG)(*pb++)) << 8);
481 /* copy all remaining data block to a new temp file */
482 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
483 struct temp_file *temp, PFNFCISTATUS status_callback )
485 struct data_block *block;
488 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
490 set_error( fci, FCIERR_TEMP_FILE, err );
493 if (!create_temp_file( fci, temp )) return FALSE;
495 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
497 if (fci->read( handle, fci->data_out, block->compressed,
498 &err, fci->pv ) != block->compressed)
500 close_temp_file( fci, temp );
501 set_error( fci, FCIERR_TEMP_FILE, err );
504 if (fci->write( temp->handle, fci->data_out, block->compressed,
505 &err, fci->pv ) != block->compressed)
507 close_temp_file( fci, temp );
508 set_error( fci, FCIERR_TEMP_FILE, err );
511 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
512 fci->statusFolderCopied += block->compressed;
514 if (status_callback( statusFolder, fci->statusFolderCopied,
515 fci->statusFolderTotal, fci->pv) == -1)
517 close_temp_file( fci, temp );
518 set_error( fci, FCIERR_USER_ABORT, 0 );
525 /* write all folders to disk and remove them from the list */
526 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
528 struct folder *folder;
530 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
531 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
533 memset( cffolder, 0, folder_size );
535 /* write the folders */
536 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
538 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
539 cffolder->cCFData = fci_endian_uword( folder->data_count );
540 cffolder->typeCompress = fci_endian_uword( folder->compression );
541 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
543 set_error( fci, FCIERR_CAB_FILE, err );
550 /* write all the files to the cabinet file */
551 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
554 struct folder *folder;
557 CFFILE *cffile = (CFFILE *)fci->data_out;
559 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
561 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
563 cffile->cbFile = fci_endian_ulong( file->size );
564 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
565 cffile->iFolder = fci_endian_uword( file->folder );
566 cffile->date = fci_endian_uword( file->date );
567 cffile->time = fci_endian_uword( file->time );
568 cffile->attribs = fci_endian_uword( file->attribs );
569 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
570 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
571 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
573 set_error( fci, FCIERR_CAB_FILE, err );
576 if (!fci->fSplitFolder)
578 fci->statusFolderCopied = 0;
579 /* TODO TEST THIS further */
580 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
582 fci->statusFolderCopied += file_size;
583 /* report status about copied size of folder */
584 if (status_callback( statusFolder, fci->statusFolderCopied,
585 fci->statusFolderTotal, fci->pv ) == -1)
587 set_error( fci, FCIERR_USER_ABORT, 0 );
595 /* write all data blocks to the cabinet file */
596 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
598 struct folder *folder;
599 struct data_block *block;
603 cab_UWORD header_size;
605 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
606 cfdata = (CFDATA *)fci->data_out;
607 memset( cfdata, 0, header_size );
608 data = (char *)cfdata + header_size;
610 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
612 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
614 set_error( fci, FCIERR_CAB_FILE, err );
617 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
619 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
620 if (len != block->compressed) return FALSE;
622 cfdata->cbData = fci_endian_uword( block->compressed );
623 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
624 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
625 header_size - FIELD_OFFSET(CFDATA, cbData),
626 fci_get_checksum( data, len, 0 )));
628 fci->statusFolderCopied += len;
630 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
632 set_error( fci, FCIERR_CAB_FILE, err );
635 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
637 set_error( fci, FCIERR_USER_ABORT, 0 );
645 /* write the cabinet file to disk */
646 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
648 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
652 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
654 cab_ULONG header_size = get_header_size( fci );
655 cab_ULONG total_size = header_size + fci->folders_size +
656 fci->placed_files_size + fci->folders_data_size;
658 assert( header_size <= sizeof(fci->data_out) );
659 memset( cfheader, 0, header_size );
661 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
662 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
663 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
664 flags |= cfheadRESERVE_PRESENT;
666 memcpy( cfheader->signature, "!CAB", 4 );
667 cfheader->cbCabinet = fci_endian_ulong( total_size );
668 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
669 cfheader->versionMinor = 3;
670 cfheader->versionMajor = 1;
671 cfheader->cFolders = fci_endian_uword( fci->cFolders );
672 cfheader->cFiles = fci_endian_uword( fci->cFiles );
673 cfheader->flags = fci_endian_uword( flags );
674 cfheader->setID = fci_endian_uword( fci->ccab.setID );
675 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
676 ptr = (char *)(cfheader + 1);
678 if (flags & cfheadRESERVE_PRESENT)
682 cab_UWORD cbCFHeader;
683 cab_UBYTE cbCFFolder;
685 } *reserve = (void *)ptr;
687 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
688 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
689 reserve->cbCFData = fci->ccab.cbReserveCFData;
690 ptr = (char *)(reserve + 1);
692 ptr += fci->ccab.cbReserveCFHeader;
694 if (flags & cfheadPREV_CABINET)
696 strcpy( ptr, fci->szPrevCab );
697 ptr += strlen( ptr ) + 1;
698 strcpy( ptr, fci->szPrevDisk );
699 ptr += strlen( ptr ) + 1;
702 if (flags & cfheadNEXT_CABINET)
704 strcpy( ptr, fci->pccab->szCab );
705 ptr += strlen( ptr ) + 1;
706 strcpy( ptr, fci->pccab->szDisk );
707 ptr += strlen( ptr ) + 1;
710 assert( ptr - (char *)cfheader == header_size );
712 strcpy( filename, fci->ccab.szCabPath );
713 strcat( filename, fci->ccab.szCab );
715 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
716 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
718 set_error( fci, FCIERR_CAB_FILE, err );
722 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
724 set_error( fci, FCIERR_CAB_FILE, err );
728 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
729 header_size += fci->placed_files_size + fci->folders_size;
730 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
731 if (!write_files( fci, handle, status_callback )) goto failed;
732 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
734 /* update the signature */
735 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
737 set_error( fci, FCIERR_CAB_FILE, err );
740 memcpy( cfheader->signature, "MSCF", 4 );
741 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
743 set_error( fci, FCIERR_CAB_FILE, err );
746 fci->close( handle, &err, fci->pv );
748 reset_cabinet( fci );
749 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
753 fci->close( handle, &err, fci->pv );
754 fci->delete( filename, &err, fci->pv );
758 /* add all pending data blocks folder */
759 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
760 PFNFCISTATUS status_callback )
762 struct data_block *block, *new, *next;
763 BOOL split_block = FALSE;
764 cab_ULONG current_size, start_pos = 0;
767 current_size = get_header_size( fci ) + fci->folders_size +
768 fci->files_size + fci->placed_files_size + fci->folders_data_size;
770 /* move the temp file into the folder structure */
771 folder->data = fci->data;
772 fci->data.handle = -1;
773 fci->pending_data_size = 0;
775 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
777 /* No more CFDATA fits into the cabinet under construction */
778 /* So don't try to store more data into it */
779 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
780 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
783 if (!(new = fci->alloc( sizeof(*new) )))
785 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
788 /* Is cabinet with new CFDATA too large? Then data block has to be split */
790 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
791 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
793 /* Modify the size of the compressed data to store only a part of the */
794 /* data block into the current cabinet. This is done to prevent */
795 /* that the maximum cabinet size will be exceeded. The remainder */
796 /* will be stored into the next following cabinet. */
798 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
799 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
800 new->uncompressed = 0; /* on split blocks of data this is zero */
801 block->compressed -= new->compressed;
806 new->compressed = block->compressed;
807 new->uncompressed = block->uncompressed;
810 start_pos += new->compressed;
811 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
812 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
813 fci->statusFolderCopied += new->compressed;
814 (*payload) += new->uncompressed;
816 list_add_tail( &folder->blocks_list, &new->entry );
817 folder->data_count++;
819 /* report status with pfnfcis about copied size of folder */
820 if (status_callback( statusFolder, fci->statusFolderCopied,
821 fci->statusFolderTotal, fci->pv ) == -1)
823 set_error( fci, FCIERR_USER_ABORT, 0 );
826 if (split_block) break;
827 free_data_block( fci, block );
831 if (list_empty( &fci->blocks_list )) return TRUE;
832 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
835 /* add all pending files to folder */
836 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
838 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
839 cab_ULONG cbFileRemainer = 0;
840 struct file *file, *next;
842 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
844 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
846 /* fnfilfnfildest: placed file on cabinet */
847 fci->fileplaced( &fci->ccab, file->name, file->size,
848 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
850 sizeOfFilesPrev = sizeOfFiles;
851 /* set complete size of all processed files */
852 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
854 sizeOfFiles += fci->cbFileRemainer;
855 fci->cbFileRemainer = 0;
857 else sizeOfFiles += file->size;
859 /* check if spanned file fits into this cabinet folder */
860 if (sizeOfFiles > payload)
862 if (file->folder == cffileCONTINUED_FROM_PREV)
863 file->folder = cffileCONTINUED_PREV_AND_NEXT;
865 file->folder = cffileCONTINUED_TO_NEXT;
868 list_remove( &file->entry );
869 list_add_tail( &folder->files_list, &file->entry );
870 fci->placed_files_size += size;
873 /* This is only true for files which will be written into the */
874 /* next cabinet of the spanning folder */
875 if (sizeOfFiles > payload)
877 /* add a copy back onto the list */
878 if (!(file = copy_file( fci, file ))) return FALSE;
879 list_add_before( &next->entry, &file->entry );
881 /* Files which data will be partially written into the current cabinet */
882 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
884 if (sizeOfFilesPrev <= payload)
886 /* The size of the uncompressed, data of a spanning file in a */
888 cbFileRemainer = sizeOfFiles - payload;
890 file->folder = cffileCONTINUED_FROM_PREV;
892 else file->folder = 0;
896 fci->files_size -= size;
899 fci->cbFileRemainer = cbFileRemainer;
903 static cab_UWORD compress_NONE( FCI_Int *fci )
905 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
906 return fci->cdata_in;
911 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
913 FCI_Int *fci = opaque;
914 return fci->alloc( items * size );
917 static void zfree( void *opaque, void *ptr )
919 FCI_Int *fci = opaque;
920 return fci->free( ptr );
923 static cab_UWORD compress_MSZIP( FCI_Int *fci )
927 stream.zalloc = zalloc;
928 stream.zfree = zfree;
930 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
932 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
935 stream.next_in = fci->data_in;
936 stream.avail_in = fci->cdata_in;
937 stream.next_out = fci->data_out + 2;
938 stream.avail_out = sizeof(fci->data_out) - 2;
939 /* insert the signature */
940 fci->data_out[0] = 'C';
941 fci->data_out[1] = 'K';
942 deflate( &stream, Z_FINISH );
943 deflateEnd( &stream );
944 return stream.total_out + 2;
947 #endif /* HAVE_ZLIB */
950 /***********************************************************************
951 * FCICreate (CABINET.10)
953 * FCICreate is provided with several callbacks and
954 * returns a handle which can be used to create cabinet files.
957 * perf [IO] A pointer to an ERF structure. When FCICreate
958 * returns an error condition, error information may
959 * be found here as well as from GetLastError.
960 * pfnfiledest [I] A pointer to a function which is called when a file
961 * is placed. Only useful for subsequent cabinet files.
962 * pfnalloc [I] A pointer to a function which allocates ram. Uses
963 * the same interface as malloc.
964 * pfnfree [I] A pointer to a function which frees ram. Uses the
965 * same interface as free.
966 * pfnopen [I] A pointer to a function which opens a file. Uses
967 * the same interface as _open.
968 * pfnread [I] A pointer to a function which reads from a file into
969 * a caller-provided buffer. Uses the same interface
971 * pfnwrite [I] A pointer to a function which writes to a file from
972 * a caller-provided buffer. Uses the same interface
974 * pfnclose [I] A pointer to a function which closes a file handle.
975 * Uses the same interface as _close.
976 * pfnseek [I] A pointer to a function which seeks in a file.
977 * Uses the same interface as _lseek.
978 * pfndelete [I] A pointer to a function which deletes a file.
979 * pfnfcigtf [I] A pointer to a function which gets the name of a
981 * pccab [I] A pointer to an initialized CCAB structure.
982 * pv [I] A pointer to an application-defined notification
983 * function which will be passed to other FCI functions
987 * On success, returns an FCI handle of type HFCI.
988 * On failure, the NULL file handle is returned. Error
989 * info can be retrieved from perf.
995 HFCI __cdecl FCICreate(
997 PFNFCIFILEPLACED pfnfiledest,
998 PFNFCIALLOC pfnalloc,
1002 PFNFCIWRITE pfnwrite,
1003 PFNFCICLOSE pfnclose,
1005 PFNFCIDELETE pfndelete,
1006 PFNFCIGETTEMPFILE pfnfcigtf,
1010 FCI_Int *p_fci_internal;
1013 SetLastError(ERROR_BAD_ARGUMENTS);
1016 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1017 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1018 (!pfnfcigtf) || (!pccab)) {
1019 perf->erfOper = FCIERR_NONE;
1020 perf->erfType = ERROR_BAD_ARGUMENTS;
1021 perf->fError = TRUE;
1023 SetLastError(ERROR_BAD_ARGUMENTS);
1027 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1028 perf->erfOper = FCIERR_ALLOC_FAIL;
1029 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1030 perf->fError = TRUE;
1032 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1036 p_fci_internal->magic = FCI_INT_MAGIC;
1037 p_fci_internal->perf = perf;
1038 p_fci_internal->fileplaced = pfnfiledest;
1039 p_fci_internal->alloc = pfnalloc;
1040 p_fci_internal->free = pfnfree;
1041 p_fci_internal->open = pfnopen;
1042 p_fci_internal->read = pfnread;
1043 p_fci_internal->write = pfnwrite;
1044 p_fci_internal->close = pfnclose;
1045 p_fci_internal->seek = pfnseek;
1046 p_fci_internal->delete = pfndelete;
1047 p_fci_internal->gettemp = pfnfcigtf;
1048 p_fci_internal->ccab = *pccab;
1049 p_fci_internal->pccab = pccab;
1050 p_fci_internal->fPrevCab = FALSE;
1051 p_fci_internal->fNextCab = FALSE;
1052 p_fci_internal->fSplitFolder = FALSE;
1053 p_fci_internal->fGetNextCabInVain = FALSE;
1054 p_fci_internal->pv = pv;
1055 p_fci_internal->cdata_in = 0;
1056 p_fci_internal->cCompressedBytesInFolder = 0;
1057 p_fci_internal->cFolders = 0;
1058 p_fci_internal->cFiles = 0;
1059 p_fci_internal->cDataBlocks = 0;
1060 p_fci_internal->data.handle = -1;
1061 p_fci_internal->fNewPrevious = FALSE;
1062 p_fci_internal->estimatedCabinetSize = 0;
1063 p_fci_internal->statusFolderTotal = 0;
1064 p_fci_internal->folders_size = 0;
1065 p_fci_internal->files_size = 0;
1066 p_fci_internal->placed_files_size = 0;
1067 p_fci_internal->pending_data_size = 0;
1068 p_fci_internal->folders_data_size = 0;
1069 p_fci_internal->compression = tcompTYPE_NONE;
1070 p_fci_internal->compress = compress_NONE;
1072 list_init( &p_fci_internal->folders_list );
1073 list_init( &p_fci_internal->files_list );
1074 list_init( &p_fci_internal->blocks_list );
1076 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1077 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1079 return (HFCI)p_fci_internal;
1085 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1087 PFNFCIGETNEXTCABINET pfnfcignc,
1088 PFNFCISTATUS pfnfcis)
1091 cab_ULONG read_result;
1092 struct folder *folder;
1094 if ((!pfnfcignc) || (!pfnfcis)) {
1095 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1099 if( p_fci_internal->fGetNextCabInVain &&
1100 p_fci_internal->fNextCab ){
1101 /* internal error */
1102 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1106 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1107 /* this function will return TRUE */
1108 if( p_fci_internal->files_size == 0 ) {
1109 if ( p_fci_internal->pending_data_size != 0 ) {
1110 /* error handling */
1111 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1117 /* FCIFlushFolder has already been called... */
1118 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1122 /* This can be set already, because it makes only a difference */
1123 /* when the current function exits with return FALSE */
1124 p_fci_internal->fSplitFolder=FALSE;
1127 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1129 /* reset to get the number of data blocks of this folder which are */
1130 /* actually in this cabinet ( at least partially ) */
1131 p_fci_internal->cDataBlocks=0;
1133 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1134 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1135 p_fci_internal->placed_files_size+
1136 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1137 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1138 p_fci_internal->statusFolderCopied = 0;
1140 /* report status with pfnfcis about copied size of folder */
1141 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1142 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1143 p_fci_internal->pv) == -1) {
1144 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1148 /* USE the variable read_result */
1149 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1150 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1152 if(p_fci_internal->files_size!=0) {
1153 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1156 /* Check if multiple cabinets have to be created. */
1158 /* Might be too much data for the maximum allowed cabinet size.*/
1159 /* When any further data will be added later, it might not */
1160 /* be possible to flush the cabinet, because there might */
1161 /* not be enough space to store the name of the following */
1162 /* cabinet and name of the corresponding disk. */
1163 /* So take care of this and get the name of the next cabinet */
1164 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1165 p_fci_internal->fNextCab==FALSE &&
1168 p_fci_internal->ccab.cb < read_result +
1169 p_fci_internal->pending_data_size +
1170 p_fci_internal->files_size +
1171 CB_MAX_CABINET_NAME + /* next cabinet name */
1172 CB_MAX_DISK_NAME /* next disk name */
1176 /* increment cabinet index */
1177 ++(p_fci_internal->pccab->iCab);
1178 /* get name of next cabinet */
1179 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1180 if (!(*pfnfcignc)(p_fci_internal->pccab,
1181 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1182 p_fci_internal->pv)) {
1183 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1187 /* Skip a few lines of code. This is caught by the next if. */
1188 p_fci_internal->fGetNextCabInVain=TRUE;
1191 /* too much data for cabinet */
1192 if( (p_fci_internal->fGetNextCabInVain ||
1193 p_fci_internal->fNextCab ) &&
1196 p_fci_internal->ccab.cb < read_result +
1197 p_fci_internal->pending_data_size +
1198 p_fci_internal->files_size +
1199 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1200 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1204 p_fci_internal->fGetNextCabInVain=FALSE;
1205 p_fci_internal->fNextCab=TRUE;
1207 /* return FALSE if there is not enough space left*/
1208 /* this should never happen */
1209 if (p_fci_internal->ccab.cb <=
1210 p_fci_internal->files_size +
1212 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1213 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1219 /* the folder will be split across cabinets */
1220 p_fci_internal->fSplitFolder=TRUE;
1223 /* this should never happen */
1224 if (p_fci_internal->fNextCab) {
1225 /* internal error */
1226 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1231 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1232 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1233 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1235 /* reset CFFolder specific information */
1236 p_fci_internal->cDataBlocks=0;
1237 p_fci_internal->cCompressedBytesInFolder=0;
1245 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1247 PFNFCIGETNEXTCABINET pfnfcignc,
1248 PFNFCISTATUS pfnfcis)
1250 cab_ULONG read_result=0;
1251 BOOL returntrue=FALSE;
1253 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1255 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1256 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1260 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1261 /* TODO set error */
1265 if(returntrue) return TRUE;
1267 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1268 (p_fci_internal->folders_size==0 &&
1269 (p_fci_internal->files_size!=0 ||
1270 p_fci_internal->placed_files_size!=0 )
1274 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1278 /* create the cabinet */
1279 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1281 p_fci_internal->fPrevCab=TRUE;
1282 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1283 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1285 if (p_fci_internal->fNextCab) {
1286 p_fci_internal->fNextCab=FALSE;
1288 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1289 /* THIS CAN NEVER HAPPEN */
1290 /* set error code */
1291 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1295 if( p_fci_internal->fNewPrevious ) {
1296 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1297 CB_MAX_CABINET_NAME);
1298 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1300 p_fci_internal->fNewPrevious=FALSE;
1302 p_fci_internal->ccab = *p_fci_internal->pccab;
1304 /* REUSE the variable read_result */
1305 read_result=get_header_size( p_fci_internal );
1306 if(p_fci_internal->files_size!=0) {
1307 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1309 read_result+= p_fci_internal->pending_data_size +
1310 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1311 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1312 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1314 /* too much data for the maximum size of a cabinet */
1315 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1316 p_fci_internal->ccab.cb < read_result ) {
1317 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1320 /* Might be too much data for the maximum size of a cabinet.*/
1321 /* When any further data will be added later, it might not */
1322 /* be possible to flush the cabinet, because there might */
1323 /* not be enough space to store the name of the following */
1324 /* cabinet and name of the corresponding disk. */
1325 /* So take care of this and get the name of the next cabinet */
1326 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1327 p_fci_internal->ccab.cb < read_result +
1328 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1330 /* increment cabinet index */
1331 ++(p_fci_internal->pccab->iCab);
1332 /* get name of next cabinet */
1333 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1334 if (!(*pfnfcignc)(p_fci_internal->pccab,
1335 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1336 p_fci_internal->pv)) {
1337 /* error handling */
1338 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1341 /* Skip a few lines of code. This is caught by the next if. */
1342 p_fci_internal->fGetNextCabInVain=TRUE;
1345 /* too much data for cabinet */
1346 if (p_fci_internal->fGetNextCabInVain && (
1347 p_fci_internal->ccab.cb < read_result +
1348 strlen(p_fci_internal->ccab.szCab)+1+
1349 strlen(p_fci_internal->ccab.szDisk)+1
1351 p_fci_internal->fGetNextCabInVain=FALSE;
1352 p_fci_internal->fNextCab=TRUE;
1353 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1356 /* if the FolderThreshold has been reached flush the folder automatically */
1357 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1358 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1360 if( p_fci_internal->files_size>0 ) {
1361 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1362 p_fci_internal->fNewPrevious=TRUE;
1365 p_fci_internal->fNewPrevious=FALSE;
1366 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1367 /* THIS MAY NEVER HAPPEN */
1368 /* set error structures */
1369 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1375 } /* end of fci_flush_cabinet */
1381 /***********************************************************************
1382 * FCIAddFile (CABINET.11)
1384 * FCIAddFile adds a file to the to be created cabinet file
1387 * hfci [I] An HFCI from FCICreate
1388 * pszSourceFile [I] A pointer to a C string which contains the name and
1389 * location of the file which will be added to the cabinet
1390 * pszFileName [I] A pointer to a C string which contains the name under
1391 * which the file will be stored in the cabinet
1392 * fExecute [I] A boolean value which indicates if the file should be
1393 * executed after extraction of self extracting
1395 * pfnfcignc [I] A pointer to a function which gets information about
1397 * pfnfcis [IO] A pointer to a function which will report status
1398 * information about the compression process
1399 * pfnfcioi [I] A pointer to a function which reports file attributes
1400 * and time and date information
1401 * typeCompress [I] Compression type
1404 * On success, returns TRUE
1405 * On failure, returns FALSE
1411 BOOL __cdecl FCIAddFile(
1413 char *pszSourceFile,
1416 PFNFCIGETNEXTCABINET pfnfcignc,
1417 PFNFCISTATUS pfnfcis,
1418 PFNFCIGETOPENINFO pfnfcigoi,
1421 cab_ULONG read_result;
1422 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1424 if (!p_fci_internal) return FALSE;
1426 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1427 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1428 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1432 if (typeCompress != p_fci_internal->compression)
1434 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1435 switch (typeCompress)
1437 case tcompTYPE_MSZIP:
1439 p_fci_internal->compression = tcompTYPE_MSZIP;
1440 p_fci_internal->compress = compress_MSZIP;
1444 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1446 case tcompTYPE_NONE:
1447 p_fci_internal->compression = tcompTYPE_NONE;
1448 p_fci_internal->compress = compress_NONE;
1453 /* TODO check if pszSourceFile??? */
1455 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1456 /* internal error */
1457 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1461 if(p_fci_internal->fNextCab) {
1462 /* internal error */
1463 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1467 /* REUSE the variable read_result */
1468 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1470 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1471 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1472 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1473 sizeof(CFFOLDER); /* size of new CFFolder entry */
1475 /* Might be too much data for the maximum size of a cabinet.*/
1476 /* When any further data will be added later, it might not */
1477 /* be possible to flush the cabinet, because there might */
1478 /* not be enough space to store the name of the following */
1479 /* cabinet and name of the corresponding disk. */
1480 /* So take care of this and get the name of the next cabinet */
1481 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1482 p_fci_internal->fNextCab==FALSE &&
1483 ( p_fci_internal->ccab.cb < read_result +
1484 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1487 /* increment cabinet index */
1488 ++(p_fci_internal->pccab->iCab);
1489 /* get name of next cabinet */
1490 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1491 if (!(*pfnfcignc)(p_fci_internal->pccab,
1492 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1493 p_fci_internal->pv)) {
1494 /* error handling */
1495 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1498 /* Skip a few lines of code. This is caught by the next if. */
1499 p_fci_internal->fGetNextCabInVain=TRUE;
1502 if( p_fci_internal->fGetNextCabInVain &&
1503 p_fci_internal->fNextCab
1505 /* THIS CAN NEVER HAPPEN */
1506 /* set error code */
1507 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1511 /* too much data for cabinet */
1512 if( p_fci_internal->fGetNextCabInVain &&
1514 p_fci_internal->ccab.cb < read_result +
1515 strlen(p_fci_internal->pccab->szCab)+1+
1516 strlen(p_fci_internal->pccab->szDisk)+1
1518 p_fci_internal->fGetNextCabInVain=FALSE;
1519 p_fci_internal->fNextCab=TRUE;
1520 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1523 if( p_fci_internal->fNextCab ) {
1524 /* THIS MAY NEVER HAPPEN */
1525 /* set error code */
1526 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1530 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1533 /* REUSE the variable read_result */
1534 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1535 read_result+= p_fci_internal->pending_data_size +
1536 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1537 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1538 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1540 /* too much data for the maximum size of a cabinet */
1541 /* (ignoring the unflushed data block) */
1542 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1543 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1544 p_fci_internal->ccab.cb < read_result ) {
1545 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1548 /* Might be too much data for the maximum size of a cabinet.*/
1549 /* When any further data will be added later, it might not */
1550 /* be possible to flush the cabinet, because there might */
1551 /* not be enough space to store the name of the following */
1552 /* cabinet and name of the corresponding disk. */
1553 /* So take care of this and get the name of the next cabinet */
1554 /* (ignoring the unflushed data block) */
1555 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1556 p_fci_internal->fNextCab==FALSE &&
1557 ( p_fci_internal->ccab.cb < read_result +
1558 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1561 /* increment cabinet index */
1562 ++(p_fci_internal->pccab->iCab);
1563 /* get name of next cabinet */
1564 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1565 if (!(*pfnfcignc)(p_fci_internal->pccab,
1566 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1567 p_fci_internal->pv)) {
1568 /* error handling */
1569 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1572 /* Skip a few lines of code. This is caught by the next if. */
1573 p_fci_internal->fGetNextCabInVain=TRUE;
1576 if( p_fci_internal->fGetNextCabInVain &&
1577 p_fci_internal->fNextCab
1579 /* THIS CAN NEVER HAPPEN */
1580 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1584 /* too much data for cabinet */
1585 if( (p_fci_internal->fGetNextCabInVain ||
1586 p_fci_internal->fNextCab) && (
1587 p_fci_internal->ccab.cb < read_result +
1588 strlen(p_fci_internal->pccab->szCab)+1+
1589 strlen(p_fci_internal->pccab->szDisk)+1
1592 p_fci_internal->fGetNextCabInVain=FALSE;
1593 p_fci_internal->fNextCab=TRUE;
1594 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1597 if( p_fci_internal->fNextCab ) {
1598 /* THIS MAY NEVER HAPPEN */
1599 /* set error code */
1600 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1604 /* if the FolderThreshold has been reached flush the folder automatically */
1605 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1606 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1609 } /* end of FCIAddFile */
1615 /***********************************************************************
1616 * FCIFlushFolder (CABINET.12)
1618 * FCIFlushFolder completes the CFFolder structure under construction.
1620 * All further data which is added by FCIAddFile will be associated to
1621 * the next CFFolder structure.
1623 * FCIFlushFolder will be called by FCIAddFile automatically if the
1624 * threshold (stored in the member cbFolderThresh of the CCAB structure
1625 * pccab passed to FCICreate) is exceeded.
1627 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1628 * any data will be written into the cabinet file.
1631 * hfci [I] An HFCI from FCICreate
1632 * pfnfcignc [I] A pointer to a function which gets information about
1634 * pfnfcis [IO] A pointer to a function which will report status
1635 * information about the compression process
1638 * On success, returns TRUE
1639 * On failure, returns FALSE
1645 BOOL __cdecl FCIFlushFolder(
1647 PFNFCIGETNEXTCABINET pfnfcignc,
1648 PFNFCISTATUS pfnfcis)
1650 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1652 if (!p_fci_internal) return FALSE;
1653 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1658 /***********************************************************************
1659 * FCIFlushCabinet (CABINET.13)
1661 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1662 * into the cabinet file. If the maximum cabinet size (stored in the
1663 * member cb of the CCAB structure pccab passed to FCICreate) has been
1664 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1665 * The remaining data still has to be flushed manually by calling
1668 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1669 * NOT be called again. Then hfci has to be released by FCIDestroy.
1672 * hfci [I] An HFCI from FCICreate
1673 * fGetNextCab [I] Whether you want to add additional files to a
1674 * cabinet set (TRUE) or whether you want to
1675 * finalize it (FALSE)
1676 * pfnfcignc [I] A pointer to a function which gets information about
1678 * pfnfcis [IO] A pointer to a function which will report status
1679 * information about the compression process
1682 * On success, returns TRUE
1683 * On failure, returns FALSE
1689 BOOL __cdecl FCIFlushCabinet(
1692 PFNFCIGETNEXTCABINET pfnfcignc,
1693 PFNFCISTATUS pfnfcis)
1695 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1697 if (!p_fci_internal) return FALSE;
1699 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1701 while( p_fci_internal->files_size>0 ||
1702 p_fci_internal->placed_files_size>0 ) {
1703 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1710 /***********************************************************************
1711 * FCIDestroy (CABINET.14)
1713 * Frees a handle created by FCICreate.
1714 * Only reason for failure would be an invalid handle.
1717 * hfci [I] The HFCI to free
1723 BOOL __cdecl FCIDestroy(HFCI hfci)
1725 struct folder *folder, *folder_next;
1726 struct file *file, *file_next;
1727 struct data_block *block, *block_next;
1728 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1730 if (!p_fci_internal) return FALSE;
1732 /* before hfci can be removed all temporary files must be closed */
1734 p_fci_internal->magic = 0;
1736 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1738 free_folder( p_fci_internal, folder );
1740 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1742 free_file( p_fci_internal, file );
1744 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1746 free_data_block( p_fci_internal, block );
1749 close_temp_file( p_fci_internal, &p_fci_internal->data );
1751 /* hfci can now be removed */
1752 p_fci_internal->free(hfci);