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 - no real compression yet
28 - unknown behaviour if files>=2GB or cabinet >=4GB
29 - check if the maximum size for a cabinet is too small to store any data
30 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
50 #include "wine/list.h"
51 #include "wine/debug.h"
54 #ifdef WORDS_BIGENDIAN
55 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
56 #define fci_endian_uword(x) RtlUshortByteSwap(x)
58 #define fci_endian_ulong(x) (x)
59 #define fci_endian_uword(x) (x)
64 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
66 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
68 cab_ULONG coffFiles; /* offset to first CFFILE section */
70 cab_UBYTE versionMinor; /* 3 */
71 cab_UBYTE versionMajor; /* 1 */
72 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
73 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
74 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
75 cab_UWORD setID; /* identification number of all cabinets in a set*/
76 cab_UWORD iCabinet; /* number of the cabinet in a set */
77 /* additional area if "flags" were set*/
78 } CFHEADER; /* minimum 36 bytes */
81 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
82 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
83 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
84 /* additional area if reserve flag was set */
85 } CFFOLDER; /* minimum 8 bytes */
88 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
89 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
90 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
91 /* for special values see below this structure*/
92 cab_UWORD date; /* last modification date*/
93 cab_UWORD time; /* last modification time*/
94 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
95 /* ... and a C string with the name of the file */
96 } CFFILE; /* 16 bytes + name of file */
100 cab_ULONG csum; /* checksum of this entry*/
101 cab_UWORD cbData; /* number of compressed bytes */
102 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
103 /* optional reserved area */
104 /* compressed data */
111 char name[CB_MAX_FILENAME];
117 struct list files_list;
118 cab_ULONG data_start;
119 cab_UWORD data_count;
120 cab_UWORD compression;
126 cab_ULONG size; /* uncompressed size */
127 cab_ULONG offset; /* offset in folder */
128 cab_UWORD folder; /* index of folder */
138 cab_UWORD compressed;
139 cab_UWORD uncompressed;
146 PFNFCIFILEPLACED fileplaced;
155 PFNFCIGETTEMPFILE gettemp;
161 cab_ULONG statusFolderCopied;
162 cab_ULONG statusFolderTotal;
163 BOOL fGetNextCabInVain;
165 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
166 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
167 char* data_in; /* uncompressed data blocks */
169 char* data_out; /* compressed data blocks */
170 ULONG cCompressedBytesInFolder;
173 cab_ULONG cDataBlocks;
174 cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */
175 /* of spanned file of a spanning folder of a spanning cabinet */
176 struct temp_file data1;
177 struct temp_file data2;
179 cab_ULONG estimatedCabinetSize;
180 struct list folders_list;
181 struct list files_list;
182 struct list blocks_list;
183 cab_ULONG folders_size;
184 cab_ULONG files_size;
185 cab_ULONG placed_files_size;
188 #define FCI_INT_MAGIC 0xfcfcfc05
190 static void set_error( FCI_Int *fci, int oper, int err )
192 fci->perf->erfOper = oper;
193 fci->perf->erfType = err;
194 fci->perf->fError = TRUE;
195 if (err) SetLastError( err );
198 static FCI_Int *get_fci_ptr( HFCI hfci )
200 FCI_Int *fci= (FCI_Int *)hfci;
202 if (!fci || !fci->magic == FCI_INT_MAGIC)
204 SetLastError( ERROR_INVALID_HANDLE );
210 /* compute the cabinet header size */
211 static cab_ULONG get_header_size( FCI_Int *fci )
213 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
215 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
219 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
222 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
227 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
231 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
233 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
236 if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
237 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
239 set_error( fci, FCIERR_TEMP_FILE, err );
246 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
250 if (file->handle == -1) return TRUE;
251 if (fci->close( file->handle, &err, fci->pv ) == -1)
253 set_error( fci, FCIERR_TEMP_FILE, err );
257 if (fci->delete( file->name, &err, fci->pv ) == -1)
259 set_error( fci, FCIERR_TEMP_FILE, err );
265 static struct file *add_file( FCI_Int *fci, const char *filename )
267 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
268 struct file *file = fci->alloc( size );
272 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
276 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
277 file->folder = fci->cFolders;
281 strcpy( file->name, filename );
282 list_add_tail( &fci->files_list, &file->entry );
286 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
288 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
289 struct file *file = fci->alloc( size );
293 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
296 memcpy( file, orig, size );
300 static void free_file( FCI_Int *fci, struct file *file )
302 list_remove( &file->entry );
306 static struct folder *add_folder( FCI_Int *fci )
308 struct folder *folder = fci->alloc( sizeof(*folder) );
312 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
315 folder->data_start = fci->data2.size;
316 folder->compression = tcompTYPE_NONE; /* FIXME */
317 list_init( &folder->files_list );
318 list_add_tail( &fci->folders_list, &folder->entry );
319 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
324 static void free_folder( FCI_Int *fci, struct folder *folder )
326 struct file *file, *next;
328 LIST_FOR_EACH_ENTRY_SAFE( file, next, &folder->files_list, struct file, entry ) free_file( fci, file );
329 list_remove( &folder->entry );
333 static struct data_block *add_data_block( FCI_Int *fci, cab_UWORD compressed, cab_UWORD uncompressed )
335 struct data_block *block = fci->alloc( sizeof(*block) );
339 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
342 block->compressed = compressed;
343 block->uncompressed = uncompressed;
344 list_add_tail( &fci->blocks_list, &block->entry );
345 fci->data2.size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + compressed;
350 static void free_data_block( FCI_Int *fci, struct data_block *block )
352 list_remove( &block->entry );
356 /* reset state for the next cabinet file once the current one has been flushed */
357 static void reset_cabinet( FCI_Int *fci )
359 struct folder *folder, *folder_next;
360 struct data_block *block, *block_next;
362 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
363 free_folder( fci, folder );
365 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &fci->blocks_list, struct data_block, entry )
366 free_data_block( fci, block );
368 close_temp_file( fci, &fci->data2 );
372 fci->folders_size = 0;
373 fci->placed_files_size = 0;
377 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
388 while (cUlong-- > 0) {
390 ul |= (((cab_ULONG)(*pb++)) << 8);
391 ul |= (((cab_ULONG)(*pb++)) << 16);
392 ul |= (((cab_ULONG)(*pb++)) << 24);
399 ul |= (((ULONG)(*pb++)) << 16);
401 ul |= (((ULONG)(*pb++)) << 8);
412 /* write all folders to disk and remove them from the list */
413 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
415 struct folder *folder;
419 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
421 if (!(cffolder = fci->alloc( folder_size )))
423 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
426 memset( cffolder, 0, folder_size );
428 /* write the folders */
429 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
431 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
432 cffolder->cCFData = fci_endian_uword( folder->data_count );
433 cffolder->typeCompress = fci_endian_uword( folder->compression );
434 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
436 set_error( fci, FCIERR_CAB_FILE, err );
442 fci->free( cffolder );
446 /* write all the files to the cabinet file */
447 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
450 struct folder *folder;
456 if (!(cffile = fci->alloc( sizeof(CFFILE) + CB_MAX_FILENAME )))
458 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
462 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
464 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
466 cffile->cbFile = fci_endian_ulong( file->size );
467 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
468 cffile->iFolder = fci_endian_uword( file->folder );
469 cffile->date = fci_endian_uword( file->date );
470 cffile->time = fci_endian_uword( file->time );
471 cffile->attribs = fci_endian_uword( file->attribs );
472 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
473 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
474 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
476 set_error( fci, FCIERR_CAB_FILE, err );
480 if (!fci->fSplitFolder)
482 fci->statusFolderCopied = 0;
483 /* TODO TEST THIS further */
484 fci->statusFolderTotal = fci->data2.size + fci->placed_files_size;
486 fci->statusFolderCopied += file_size;
487 /* report status about copied size of folder */
488 if (status_callback( statusFolder, fci->statusFolderCopied,
489 fci->statusFolderTotal, fci->pv ) == -1)
491 set_error( fci, FCIERR_USER_ABORT, 0 );
502 /* write all data blocks to the cabinet file */
503 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
505 struct data_block *block;
509 cab_UWORD header_size;
511 if (!fci->data_out) return TRUE;
513 if (fci->seek( fci->data2.handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
515 set_error( fci, FCIERR_CAB_FILE, err );
519 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
520 cfdata = (CFDATA *)fci->data_out;
521 memset( cfdata, 0, header_size );
522 data = (char *)cfdata + header_size;
524 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
526 len = fci->read( fci->data2.handle, data, block->compressed, &err, fci->pv );
527 if (len != block->compressed) return FALSE;
529 cfdata->cbData = fci_endian_uword( block->compressed );
530 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
531 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
532 header_size - FIELD_OFFSET( CFDATA, cbData ),
533 fci_get_checksum( data, len, 0 )));
535 fci->statusFolderCopied += len;
537 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
539 set_error( fci, FCIERR_CAB_FILE, err );
542 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
544 set_error( fci, FCIERR_USER_ABORT, 0 );
551 /* write the cabinet file to disk */
552 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
554 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
560 cab_ULONG header_size = get_header_size( fci );
561 cab_ULONG total_size = header_size + fci->folders_size + fci->placed_files_size + fci->data2.size;
563 if (!(cfheader = fci->alloc( header_size )))
565 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
568 memset( cfheader, 0, header_size );
570 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
571 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
572 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
573 flags |= cfheadRESERVE_PRESENT;
575 memcpy( cfheader->signature, "!CAB", 4 );
576 cfheader->cbCabinet = fci_endian_ulong( total_size );
577 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
578 cfheader->versionMinor = 3;
579 cfheader->versionMajor = 1;
580 cfheader->cFolders = fci_endian_uword( fci->cFolders );
581 cfheader->cFiles = fci_endian_uword( fci->cFiles );
582 cfheader->flags = fci_endian_uword( flags );
583 cfheader->setID = fci_endian_uword( fci->ccab.setID );
584 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab - 1 );
585 ptr = (char *)(cfheader + 1);
587 if (flags & cfheadRESERVE_PRESENT)
591 cab_UWORD cbCFHeader;
592 cab_UBYTE cbCFFolder;
594 } *reserve = (void *)ptr;
596 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
597 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
598 reserve->cbCFData = fci->ccab.cbReserveCFData;
599 ptr = (char *)(reserve + 1);
601 ptr += fci->ccab.cbReserveCFHeader;
603 if (flags & cfheadPREV_CABINET)
605 strcpy( ptr, fci->szPrevCab );
606 ptr += strlen( ptr ) + 1;
607 strcpy( ptr, fci->szPrevDisk );
608 ptr += strlen( ptr ) + 1;
611 if (flags & cfheadNEXT_CABINET)
613 strcpy( ptr, fci->pccab->szCab );
614 ptr += strlen( ptr ) + 1;
615 strcpy( ptr, fci->pccab->szDisk );
616 ptr += strlen( ptr ) + 1;
619 assert( ptr - (char *)cfheader == header_size );
621 strcpy( filename, fci->ccab.szCabPath );
622 strcat( filename, fci->ccab.szCab );
624 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
625 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
627 set_error( fci, FCIERR_CAB_FILE, err );
628 fci->free( cfheader );
632 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
634 set_error( fci, FCIERR_CAB_FILE, err );
638 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
639 header_size += fci->placed_files_size + fci->folders_size;
640 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
641 if (!write_files( fci, handle, status_callback )) goto failed;
642 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
644 /* update the signature */
645 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
647 set_error( fci, FCIERR_CAB_FILE, err );
650 memcpy( cfheader->signature, "MSCF", 4 );
651 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
653 set_error( fci, FCIERR_CAB_FILE, err );
656 fci->close( handle, &err, fci->pv );
657 fci->free( cfheader );
659 reset_cabinet( fci );
660 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
664 fci->close( handle, &err, fci->pv );
665 fci->delete( filename, &err, fci->pv );
666 fci->free( cfheader );
670 /* add all pending files to folder */
671 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
673 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
674 cab_ULONG cbFileRemainer = 0;
675 struct file *file, *next;
677 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
679 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
681 /* fnfilfnfildest: placed file on cabinet */
682 fci->fileplaced( &fci->ccab, file->name, file->size,
683 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
685 sizeOfFilesPrev = sizeOfFiles;
686 /* set complete size of all processed files */
687 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
689 sizeOfFiles += fci->cbFileRemainer;
690 fci->cbFileRemainer = 0;
692 else sizeOfFiles += file->size;
694 /* check if spanned file fits into this cabinet folder */
695 if (sizeOfFiles > payload)
697 if (file->folder == cffileCONTINUED_FROM_PREV)
698 file->folder = cffileCONTINUED_PREV_AND_NEXT;
700 file->folder = cffileCONTINUED_TO_NEXT;
703 list_remove( &file->entry );
704 list_add_tail( &folder->files_list, &file->entry );
705 fci->placed_files_size += size;
708 /* This is only true for files which will be written into the */
709 /* next cabinet of the spanning folder */
710 if (sizeOfFiles > payload)
712 /* add a copy back onto the list */
713 if (!(file = copy_file( fci, file ))) return FALSE;
714 list_add_before( &next->entry, &file->entry );
716 /* Files which data will be partially written into the current cabinet */
717 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
719 if (sizeOfFilesPrev <= payload)
721 /* The size of the uncompressed, data of a spanning file in a */
723 cbFileRemainer = sizeOfFiles - payload;
725 file->folder = cffileCONTINUED_FROM_PREV;
727 else file->folder = 0;
731 fci->files_size -= size;
734 fci->cbFileRemainer = cbFileRemainer;
738 /***********************************************************************
739 * FCICreate (CABINET.10)
741 * FCICreate is provided with several callbacks and
742 * returns a handle which can be used to create cabinet files.
745 * perf [IO] A pointer to an ERF structure. When FCICreate
746 * returns an error condition, error information may
747 * be found here as well as from GetLastError.
748 * pfnfiledest [I] A pointer to a function which is called when a file
749 * is placed. Only useful for subsequent cabinet files.
750 * pfnalloc [I] A pointer to a function which allocates ram. Uses
751 * the same interface as malloc.
752 * pfnfree [I] A pointer to a function which frees ram. Uses the
753 * same interface as free.
754 * pfnopen [I] A pointer to a function which opens a file. Uses
755 * the same interface as _open.
756 * pfnread [I] A pointer to a function which reads from a file into
757 * a caller-provided buffer. Uses the same interface
759 * pfnwrite [I] A pointer to a function which writes to a file from
760 * a caller-provided buffer. Uses the same interface
762 * pfnclose [I] A pointer to a function which closes a file handle.
763 * Uses the same interface as _close.
764 * pfnseek [I] A pointer to a function which seeks in a file.
765 * Uses the same interface as _lseek.
766 * pfndelete [I] A pointer to a function which deletes a file.
767 * pfnfcigtf [I] A pointer to a function which gets the name of a
769 * pccab [I] A pointer to an initialized CCAB structure.
770 * pv [I] A pointer to an application-defined notification
771 * function which will be passed to other FCI functions
775 * On success, returns an FCI handle of type HFCI.
776 * On failure, the NULL file handle is returned. Error
777 * info can be retrieved from perf.
783 HFCI __cdecl FCICreate(
785 PFNFCIFILEPLACED pfnfiledest,
786 PFNFCIALLOC pfnalloc,
790 PFNFCIWRITE pfnwrite,
791 PFNFCICLOSE pfnclose,
793 PFNFCIDELETE pfndelete,
794 PFNFCIGETTEMPFILE pfnfcigtf,
798 FCI_Int *p_fci_internal;
801 SetLastError(ERROR_BAD_ARGUMENTS);
804 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
805 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
806 (!pfnfcigtf) || (!pccab)) {
807 perf->erfOper = FCIERR_NONE;
808 perf->erfType = ERROR_BAD_ARGUMENTS;
811 SetLastError(ERROR_BAD_ARGUMENTS);
815 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
816 perf->erfOper = FCIERR_ALLOC_FAIL;
817 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
820 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
824 p_fci_internal->magic = FCI_INT_MAGIC;
825 p_fci_internal->perf = perf;
826 p_fci_internal->fileplaced = pfnfiledest;
827 p_fci_internal->alloc = pfnalloc;
828 p_fci_internal->free = pfnfree;
829 p_fci_internal->open = pfnopen;
830 p_fci_internal->read = pfnread;
831 p_fci_internal->write = pfnwrite;
832 p_fci_internal->close = pfnclose;
833 p_fci_internal->seek = pfnseek;
834 p_fci_internal->delete = pfndelete;
835 p_fci_internal->gettemp = pfnfcigtf;
836 p_fci_internal->ccab = *pccab;
837 p_fci_internal->pccab = pccab;
838 p_fci_internal->fPrevCab = FALSE;
839 p_fci_internal->fNextCab = FALSE;
840 p_fci_internal->fSplitFolder = FALSE;
841 p_fci_internal->fGetNextCabInVain = FALSE;
842 p_fci_internal->pv = pv;
843 p_fci_internal->data_in = NULL;
844 p_fci_internal->cdata_in = 0;
845 p_fci_internal->data_out = NULL;
846 p_fci_internal->cCompressedBytesInFolder = 0;
847 p_fci_internal->cFolders = 0;
848 p_fci_internal->cFiles = 0;
849 p_fci_internal->cDataBlocks = 0;
850 p_fci_internal->data1.handle = -1;
851 p_fci_internal->data2.handle = -1;
852 p_fci_internal->fNewPrevious = FALSE;
853 p_fci_internal->estimatedCabinetSize = 0;
854 p_fci_internal->statusFolderTotal = 0;
855 p_fci_internal->folders_size = 0;
856 p_fci_internal->files_size = 0;
857 p_fci_internal->placed_files_size = 0;
859 list_init( &p_fci_internal->folders_list );
860 list_init( &p_fci_internal->files_list );
861 list_init( &p_fci_internal->blocks_list );
863 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
864 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
866 if (!create_temp_file( p_fci_internal, &p_fci_internal->data1 )) goto failed;
867 if (!create_temp_file( p_fci_internal, &p_fci_internal->data2 )) goto failed;
868 return (HFCI)p_fci_internal;
871 close_temp_file( p_fci_internal, &p_fci_internal->data1 );
872 close_temp_file( p_fci_internal, &p_fci_internal->data2 );
881 static BOOL fci_flush_data_block (FCI_Int *p_fci_internal, int* err,
882 PFNFCISTATUS pfnfcis) {
884 /* attention no checks if there is data available!!! */
886 CFDATA* cfdata=&data;
888 UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
891 /* TODO compress the data of p_fci_internal->data_in */
892 /* and write it to p_fci_internal->data_out */
893 memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
894 p_fci_internal->cdata_in /* number of bytes to copy */);
896 cfdata->csum=0; /* checksum has to be set later */
897 /* TODO set realsize of compressed data */
898 cfdata->cbData = p_fci_internal->cdata_in;
899 cfdata->cbUncomp = p_fci_internal->cdata_in;
901 /* write cfdata to p_fci_internal->data1.handle */
902 if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
903 cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
904 != sizeof(*cfdata) ) {
905 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
908 /* TODO error handling of err */
910 p_fci_internal->data1.size += sizeof(*cfdata);
912 /* add optional reserved area */
914 /* This allocation and freeing at each CFData block is a bit */
915 /* inefficient, but it's harder to forget about freeing the buffer :-). */
916 /* Reserved areas are used seldom besides that... */
917 if (cbReserveCFData!=0) {
918 if(!(reserved = p_fci_internal->alloc( cbReserveCFData))) {
919 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
922 for(i=0;i<cbReserveCFData;) {
925 if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
926 reserved, /* memory buffer */
927 cbReserveCFData, /* number of bytes to copy */
928 err, p_fci_internal->pv) != cbReserveCFData ) {
929 p_fci_internal->free(reserved);
930 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
933 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
935 p_fci_internal->data1.size += cbReserveCFData;
936 p_fci_internal->free( reserved);
939 /* write p_fci_internal->data_out to p_fci_internal->data1.handle */
940 if( p_fci_internal->write( p_fci_internal->data1.handle, /* file handle */
941 p_fci_internal->data_out, /* memory buffer */
942 cfdata->cbData, /* number of bytes to copy */
943 err, p_fci_internal->pv) != cfdata->cbData) {
944 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
947 /* TODO error handling of err */
949 p_fci_internal->data1.size += cfdata->cbData;
951 /* reset the offset */
952 p_fci_internal->cdata_in = 0;
953 p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
955 /* report status with pfnfcis about uncompressed and compressed file data */
956 if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
957 p_fci_internal->pv) == -1) {
958 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
962 ++(p_fci_internal->cDataBlocks);
965 } /* end of fci_flush_data_block */
971 static BOOL fci_flushfolder_copy_cfdata(FCI_Int *p_fci_internal, char* buffer, UINT cbReserveCFData,
972 PFNFCISTATUS pfnfcis, int* err, struct temp_file *data1new,
975 struct data_block *block;
976 cab_ULONG read_result;
977 CFDATA* pcfdata=(CFDATA*)buffer;
978 BOOL split_block=FALSE;
979 cab_UWORD savedUncomp=0;
983 /* while not all CFDATAs have been copied do */
985 if( p_fci_internal->fNextCab ) {
987 /* internal error should never happen */
988 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
993 /* No more CFDATA fits into the cabinet under construction */
994 /* So don't try to store more data into it */
995 if( p_fci_internal->fNextCab &&
996 (p_fci_internal->ccab.cb <= sizeof(CFDATA) + cbReserveCFData +
997 p_fci_internal->files_size + p_fci_internal->data2.size +
998 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
999 get_header_size( p_fci_internal ) +
1000 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder
1002 /* This may never be run for the first time the while loop is entered.
1003 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
1004 split_block=TRUE; /* In this case split_block is abused to store */
1005 /* the complete data block into the next cabinet and not into the */
1006 /* current one. Originally split_block is the indicator that a */
1007 /* data block has been split across different cabinets. */
1010 /* read CFDATA from p_fci_internal->data1.handle to cfdata*/
1011 read_result= p_fci_internal->read( p_fci_internal->data1.handle,/*file handle*/
1012 buffer, /* memory buffer */
1013 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1014 err, p_fci_internal->pv);
1015 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
1016 if (read_result==0) break; /* ALL DATA has been copied */
1018 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1021 /* TODO error handling of err */
1023 /* REUSE buffer p_fci_internal->data_out !!! */
1024 /* read data from p_fci_internal->data1.handle to */
1025 /* p_fci_internal->data_out */
1026 if( p_fci_internal->read( p_fci_internal->data1.handle /* file handle */,
1027 p_fci_internal->data_out /* memory buffer */,
1028 pcfdata->cbData /* number of bytes to copy */,
1029 err, p_fci_internal->pv) != pcfdata->cbData ) {
1031 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1034 /* TODO error handling of err */
1036 /* if cabinet size is too large */
1038 /* Is cabinet with new CFDATA too large? Then data block has to be split */
1039 if( p_fci_internal->fNextCab &&
1040 (p_fci_internal->ccab.cb < sizeof(CFDATA) + cbReserveCFData +
1042 p_fci_internal->files_size + p_fci_internal->data2.size +
1043 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1044 get_header_size( p_fci_internal ) +
1045 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder
1047 /* REUSE read_result to save the size of the compressed data */
1048 read_result=pcfdata->cbData;
1049 /* Modify the size of the compressed data to store only a part of the */
1050 /* data block into the current cabinet. This is done to prevent */
1051 /* that the maximum cabinet size will be exceeded. The remainder */
1052 /* will be stored into the next following cabinet. */
1054 /* The cabinet will be of size "p_fci_internal->ccab.cb". */
1055 /* Substract everything except the size of the block of data */
1056 /* to get it's actual size */
1057 pcfdata->cbData = p_fci_internal->ccab.cb - (
1058 sizeof(CFDATA) + cbReserveCFData +
1059 p_fci_internal->files_size + p_fci_internal->data2.size +
1060 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1061 get_header_size( p_fci_internal ) +
1062 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder );
1064 savedUncomp = pcfdata->cbUncomp;
1065 pcfdata->cbUncomp = 0; /* on split blocks of data this is zero */
1067 /* if split_block==TRUE then the above while loop won't */
1068 /* be executed again */
1069 split_block=TRUE; /* split_block is the indicator that */
1070 /* a data block has been split across */
1071 /* different cabinets.*/
1074 /* This should never happen !!! */
1075 if (pcfdata->cbData==0) {
1077 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1081 if (!(block = add_data_block( p_fci_internal, pcfdata->cbData, pcfdata->cbUncomp ))) return FALSE;
1083 /* write compressed data into p_fci_internal->data2.handle */
1084 if( p_fci_internal->write( p_fci_internal->data2.handle, /* file handle */
1085 p_fci_internal->data_out, /* memory buffer */
1086 pcfdata->cbData, /* number of bytes to copy */
1087 err, p_fci_internal->pv) != pcfdata->cbData) {
1088 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1091 /* TODO error handling of err */
1093 p_fci_internal->statusFolderCopied += pcfdata->cbData;
1094 (*payload)+=pcfdata->cbUncomp;
1095 /* if cabinet size too large and data has been split */
1096 /* write the remainder of the data block to the new CFDATA1 file */
1097 if( split_block ) { /* This does not include the */
1098 /* abused one (just search for "abused" )*/
1099 /* copy all CFDATA structures from data1.handle to data1new->handle */
1100 if (p_fci_internal->fNextCab==FALSE ) {
1101 /* internal error */
1102 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1106 /* set cbData to the size of the remainder of the data block */
1107 pcfdata->cbData = read_result - pcfdata->cbData;
1108 /*recover former value of cfdata.cbData; read_result will be the offset*/
1109 read_result -= pcfdata->cbData;
1110 pcfdata->cbUncomp = savedUncomp;
1112 /* reset checksum, it will be computed later */
1115 /* write cfdata WITHOUT checksum to data1new->handle */
1116 if( p_fci_internal->write( data1new->handle, /* file handle */
1117 buffer, /* memory buffer */
1118 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1119 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
1120 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1123 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1125 data1new->size += sizeof(CFDATA)+cbReserveCFData;
1127 /* write compressed data into data1new->handle */
1128 if( p_fci_internal->write( data1new->handle, /* file handle */
1129 p_fci_internal->data_out + read_result, /* memory buffer + offset */
1130 /* to last part of split data */
1131 pcfdata->cbData, /* number of bytes to copy */
1132 err, p_fci_internal->pv) != pcfdata->cbData) {
1133 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1136 /* TODO error handling of err */
1138 p_fci_internal->statusFolderCopied += pcfdata->cbData;
1140 data1new->size += pcfdata->cbData;
1141 /* the two blocks of the split data block have been written */
1142 /* don't reset split_data yet, because it is still needed see below */
1145 /* report status with pfnfcis about copied size of folder */
1146 if( (*pfnfcis)(statusFolder,
1147 p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
1148 p_fci_internal->statusFolderTotal, /* total folder size */
1149 p_fci_internal->pv) == -1) {
1150 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1155 /* if cabinet size too large */
1156 /* write the remaining data blocks to the new CFDATA1 file */
1157 if ( split_block ) { /* This does include the */
1158 /* abused one (just search for "abused" )*/
1159 if (p_fci_internal->fNextCab==FALSE ) {
1160 /* internal error */
1161 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1164 /* copy all CFDATA structures from data1.handle to data1new->handle */
1166 /* read CFDATA from p_fci_internal->data1.handle to cfdata*/
1167 read_result= p_fci_internal->read( p_fci_internal->data1.handle,/* handle */
1168 buffer, /* memory buffer */
1169 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1170 err, p_fci_internal->pv);
1171 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
1172 if (read_result==0) break; /* ALL DATA has been copied */
1174 set_error( p_fci_internal,FCIERR_NONE, ERROR_READ_FAULT );
1177 /* TODO error handling of err */
1179 /* REUSE buffer p_fci_internal->data_out !!! */
1180 /* read data from p_fci_internal->data1.handle to */
1181 /* p_fci_internal->data_out */
1182 if( p_fci_internal->read( p_fci_internal->data1.handle /* file handle */,
1183 p_fci_internal->data_out /* memory buffer */,
1184 pcfdata->cbData /* number of bytes to copy */,
1185 err, p_fci_internal->pv) != pcfdata->cbData ) {
1187 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1190 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1192 /* write cfdata with checksum to data1new->handle */
1193 if( p_fci_internal->write( data1new->handle, /* file handle */
1194 buffer, /* memory buffer */
1195 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
1196 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
1197 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1200 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1202 data1new->size += sizeof(CFDATA)+cbReserveCFData;
1204 /* write compressed data into data1new->handle */
1205 if( p_fci_internal->write( data1new->handle, /* file handle */
1206 p_fci_internal->data_out, /* memory buffer */
1207 pcfdata->cbData, /* number of bytes to copy */
1208 err, p_fci_internal->pv) != pcfdata->cbData) {
1209 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1212 /* TODO error handling of err */
1214 data1new->size += pcfdata->cbData;
1215 p_fci_internal->statusFolderCopied += pcfdata->cbData;
1217 /* report status with pfnfcis about copied size of folder */
1218 if( (*pfnfcis)(statusFolder,
1219 p_fci_internal->statusFolderCopied,/*cfdata.cbData(+previous ones)*/
1220 p_fci_internal->statusFolderTotal, /* total folder size */
1221 p_fci_internal->pv) == -1) {
1222 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1226 } /* end of WHILE */
1227 break; /* jump out of the next while loop */
1228 } /* end of if( split_data ) */
1229 } /* end of WHILE */
1231 } /* end of fci_flushfolder_copy_cfdata */
1237 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1239 PFNFCIGETNEXTCABINET pfnfcignc,
1240 PFNFCISTATUS pfnfcis)
1243 struct temp_file data1new;
1244 UINT cbReserveCFData, cbReserveCFFolder;
1247 cab_ULONG read_result;
1248 struct folder *folder;
1250 if ((!pfnfcignc) || (!pfnfcis)) {
1251 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1255 if( p_fci_internal->fGetNextCabInVain &&
1256 p_fci_internal->fNextCab ){
1257 /* internal error */
1258 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1262 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1263 /* this function will return TRUE */
1264 if( p_fci_internal->files_size == 0 ) {
1265 if ( p_fci_internal->data1.size != 0 ) {
1266 /* error handling */
1267 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1273 if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1274 /* error handling */
1275 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1279 /* FCIFlushFolder has already been called... */
1280 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1284 /* This can be set already, because it makes only a difference */
1285 /* when the current function exits with return FALSE */
1286 p_fci_internal->fSplitFolder=FALSE;
1288 cbReserveCFData = p_fci_internal->ccab.cbReserveCFData;
1289 cbReserveCFFolder = p_fci_internal->ccab.cbReserveCFFolder;
1292 /* if there is data in p_fci_internal->data_in */
1293 if (p_fci_internal->cdata_in!=0) {
1295 if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
1298 /* reset to get the number of data blocks of this folder which are */
1299 /* actually in this cabinet ( at least partially ) */
1300 p_fci_internal->cDataBlocks=0;
1302 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1303 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1304 p_fci_internal->placed_files_size+
1305 p_fci_internal->data2.size + p_fci_internal->files_size+
1306 p_fci_internal->data1.size + p_fci_internal->folders_size;
1307 p_fci_internal->statusFolderCopied = 0;
1309 /* report status with pfnfcis about copied size of folder */
1310 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1311 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1312 p_fci_internal->pv) == -1) {
1313 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1317 /* get a new temp file */
1318 if (!create_temp_file( p_fci_internal, &data1new )) return FALSE;
1320 /* USE the variable read_result */
1321 read_result = get_header_size( p_fci_internal ) + p_fci_internal->data2.size +
1322 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1324 if(p_fci_internal->files_size!=0) {
1325 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1328 /* Check if multiple cabinets have to be created. */
1330 /* Might be too much data for the maximum allowed cabinet size.*/
1331 /* When any further data will be added later, it might not */
1332 /* be possible to flush the cabinet, because there might */
1333 /* not be enough space to store the name of the following */
1334 /* cabinet and name of the corresponding disk. */
1335 /* So take care of this and get the name of the next cabinet */
1336 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1337 p_fci_internal->fNextCab==FALSE &&
1340 p_fci_internal->ccab.cb < read_result +
1341 p_fci_internal->data1.size +
1342 p_fci_internal->files_size +
1343 CB_MAX_CABINET_NAME + /* next cabinet name */
1344 CB_MAX_DISK_NAME /* next disk name */
1348 /* increment cabinet index */
1349 ++(p_fci_internal->pccab->iCab);
1350 /* get name of next cabinet */
1351 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1352 if (!(*pfnfcignc)(p_fci_internal->pccab,
1353 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1354 p_fci_internal->pv)) {
1355 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1356 close_temp_file( p_fci_internal, &data1new );
1360 /* Skip a few lines of code. This is caught by the next if. */
1361 p_fci_internal->fGetNextCabInVain=TRUE;
1364 /* too much data for cabinet */
1365 if( (p_fci_internal->fGetNextCabInVain ||
1366 p_fci_internal->fNextCab ) &&
1369 p_fci_internal->ccab.cb < read_result +
1370 p_fci_internal->data1.size +
1371 p_fci_internal->files_size +
1372 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1373 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1377 p_fci_internal->fGetNextCabInVain=FALSE;
1378 p_fci_internal->fNextCab=TRUE;
1380 /* return FALSE if there is not enough space left*/
1381 /* this should never happen */
1382 if (p_fci_internal->ccab.cb <=
1383 p_fci_internal->files_size +
1385 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1386 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1389 close_temp_file( p_fci_internal, &data1new );
1393 /* the folder will be split across cabinets */
1394 p_fci_internal->fSplitFolder=TRUE;
1397 /* this should never happen */
1398 if (p_fci_internal->fNextCab) {
1399 /* internal error */
1400 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1405 /* set seek of p_fci_internal->data1.handle to 0 */
1406 if( p_fci_internal->seek(p_fci_internal->data1.handle,0,SEEK_SET,&err,
1407 p_fci_internal->pv) !=0 ) {
1408 /* wrong return value */
1409 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
1410 close_temp_file( p_fci_internal, &data1new );
1413 /* TODO error handling of err */
1415 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1417 if(!(reserved = p_fci_internal->alloc( cbReserveCFData+sizeof(CFDATA)))) {
1418 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1419 close_temp_file( p_fci_internal, &data1new );
1423 if(!fci_flushfolder_copy_cfdata(p_fci_internal, reserved, cbReserveCFData, pfnfcis, &err,
1424 &data1new, &payload ))
1426 close_temp_file( p_fci_internal, &data1new );
1427 p_fci_internal->free(reserved);
1431 p_fci_internal->free(reserved);
1433 folder->data_count = p_fci_internal->cDataBlocks;
1435 if (!add_files_to_folder( p_fci_internal, folder, payload ))
1437 close_temp_file( p_fci_internal, &data1new );
1441 close_temp_file( p_fci_internal, &p_fci_internal->data1 );
1442 p_fci_internal->data1 = data1new;
1444 /* reset CFFolder specific information */
1445 p_fci_internal->cDataBlocks=0;
1446 p_fci_internal->cCompressedBytesInFolder=0;
1454 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1456 PFNFCIGETNEXTCABINET pfnfcignc,
1457 PFNFCISTATUS pfnfcis)
1459 cab_ULONG read_result=0;
1460 BOOL returntrue=FALSE;
1462 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1464 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1465 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1469 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1470 /* TODO set error */
1474 if(returntrue) return TRUE;
1476 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1477 (p_fci_internal->folders_size==0 &&
1478 (p_fci_internal->files_size!=0 ||
1479 p_fci_internal->placed_files_size!=0 )
1483 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1487 /* create the cabinet */
1488 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1490 if (!create_temp_file( p_fci_internal, &p_fci_internal->data2 )) return FALSE;
1492 p_fci_internal->fPrevCab=TRUE;
1493 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1494 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1496 if (p_fci_internal->fNextCab) {
1497 p_fci_internal->fNextCab=FALSE;
1499 if (p_fci_internal->files_size==0 && p_fci_internal->data1.size!=0) {
1500 /* THIS CAN NEVER HAPPEN */
1501 /* set error code */
1502 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1506 if( p_fci_internal->fNewPrevious ) {
1507 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1508 CB_MAX_CABINET_NAME);
1509 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1511 p_fci_internal->fNewPrevious=FALSE;
1513 p_fci_internal->ccab = *p_fci_internal->pccab;
1515 /* REUSE the variable read_result */
1516 read_result=get_header_size( p_fci_internal );
1517 if(p_fci_internal->files_size!=0) {
1518 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1520 read_result+= p_fci_internal->data1.size +
1521 p_fci_internal->files_size + p_fci_internal->data2.size +
1522 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1523 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1525 /* too much data for the maximum size of a cabinet */
1526 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1527 p_fci_internal->ccab.cb < read_result ) {
1528 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1531 /* Might be too much data for the maximum size of a cabinet.*/
1532 /* When any further data will be added later, it might not */
1533 /* be possible to flush the cabinet, because there might */
1534 /* not be enough space to store the name of the following */
1535 /* cabinet and name of the corresponding disk. */
1536 /* So take care of this and get the name of the next cabinet */
1537 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1538 p_fci_internal->ccab.cb < read_result +
1539 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1541 /* increment cabinet index */
1542 ++(p_fci_internal->pccab->iCab);
1543 /* get name of next cabinet */
1544 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1545 if (!(*pfnfcignc)(p_fci_internal->pccab,
1546 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1547 p_fci_internal->pv)) {
1548 /* error handling */
1549 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1552 /* Skip a few lines of code. This is caught by the next if. */
1553 p_fci_internal->fGetNextCabInVain=TRUE;
1556 /* too much data for cabinet */
1557 if (p_fci_internal->fGetNextCabInVain && (
1558 p_fci_internal->ccab.cb < read_result +
1559 strlen(p_fci_internal->ccab.szCab)+1+
1560 strlen(p_fci_internal->ccab.szDisk)+1
1562 p_fci_internal->fGetNextCabInVain=FALSE;
1563 p_fci_internal->fNextCab=TRUE;
1564 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1567 /* if the FolderThreshold has been reached flush the folder automatically */
1568 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1569 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1571 if( p_fci_internal->files_size>0 ) {
1572 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1573 p_fci_internal->fNewPrevious=TRUE;
1576 p_fci_internal->fNewPrevious=FALSE;
1577 if( p_fci_internal->files_size>0 || p_fci_internal->data1.size) {
1578 /* THIS MAY NEVER HAPPEN */
1579 /* set error structures */
1580 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1586 } /* end of fci_flush_cabinet */
1592 /***********************************************************************
1593 * FCIAddFile (CABINET.11)
1595 * FCIAddFile adds a file to the to be created cabinet file
1598 * hfci [I] An HFCI from FCICreate
1599 * pszSourceFile [I] A pointer to a C string which contains the name and
1600 * location of the file which will be added to the cabinet
1601 * pszFileName [I] A pointer to a C string which contains the name under
1602 * which the file will be stored in the cabinet
1603 * fExecute [I] A boolean value which indicates if the file should be
1604 * executed after extraction of self extracting
1606 * pfnfcignc [I] A pointer to a function which gets information about
1608 * pfnfcis [IO] A pointer to a function which will report status
1609 * information about the compression process
1610 * pfnfcioi [I] A pointer to a function which reports file attributes
1611 * and time and date information
1612 * typeCompress [I] Compression type
1615 * On success, returns TRUE
1616 * On failure, returns FALSE
1622 BOOL __cdecl FCIAddFile(
1624 char *pszSourceFile,
1627 PFNFCIGETNEXTCABINET pfnfcignc,
1628 PFNFCISTATUS pfnfcis,
1629 PFNFCIGETOPENINFO pfnfcigoi,
1633 cab_ULONG read_result;
1636 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1638 if (!p_fci_internal) return FALSE;
1640 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1641 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1642 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1646 /* TODO check if pszSourceFile??? */
1648 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1649 /* internal error */
1650 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1654 if(p_fci_internal->fNextCab) {
1655 /* internal error */
1656 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1660 if (!(file = add_file( p_fci_internal, pszFileName ))) return FALSE;
1662 /* allocation of memory */
1663 if (p_fci_internal->data_in==NULL) {
1664 if (p_fci_internal->cdata_in!=0) {
1665 /* error handling */
1666 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1669 if (p_fci_internal->data_out!=NULL) {
1670 /* error handling */
1671 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1674 if(!(p_fci_internal->data_in = p_fci_internal->alloc(CB_MAX_CHUNK))) {
1675 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1678 if (p_fci_internal->data_out==NULL) {
1679 if(!(p_fci_internal->data_out = p_fci_internal->alloc( 2 * CB_MAX_CHUNK))){
1680 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1686 if (p_fci_internal->data_out==NULL) {
1687 p_fci_internal->free(p_fci_internal->data_in);
1688 /* error handling */
1689 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1693 /* get information about the file */
1694 /* set defaults in case callback doesn't set one or more fields */
1695 file_handle = pfnfcigoi( pszSourceFile, &file->date, &file->time, &file->attribs,
1696 &err, p_fci_internal->pv );
1697 /* check file_handle */
1699 set_error( p_fci_internal, FCIERR_OPEN_SRC, ERROR_OPEN_FAILED );
1701 /* TODO error handling of err */
1703 if (fExecute) { file->attribs |= _A_EXEC; }
1705 /* REUSE the variable read_result */
1706 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1708 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1709 p_fci_internal->files_size + p_fci_internal->data2.size +
1710 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1711 sizeof(CFFOLDER); /* size of new CFFolder entry */
1713 /* Might be too much data for the maximum size of a cabinet.*/
1714 /* When any further data will be added later, it might not */
1715 /* be possible to flush the cabinet, because there might */
1716 /* not be enough space to store the name of the following */
1717 /* cabinet and name of the corresponding disk. */
1718 /* So take care of this and get the name of the next cabinet */
1719 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1720 p_fci_internal->fNextCab==FALSE &&
1721 ( p_fci_internal->ccab.cb < read_result +
1722 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1725 /* increment cabinet index */
1726 ++(p_fci_internal->pccab->iCab);
1727 /* get name of next cabinet */
1728 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1729 if (!(*pfnfcignc)(p_fci_internal->pccab,
1730 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1731 p_fci_internal->pv)) {
1732 /* error handling */
1733 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1736 /* Skip a few lines of code. This is caught by the next if. */
1737 p_fci_internal->fGetNextCabInVain=TRUE;
1740 if( p_fci_internal->fGetNextCabInVain &&
1741 p_fci_internal->fNextCab
1743 /* THIS CAN NEVER HAPPEN */
1744 /* set error code */
1745 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1749 /* too much data for cabinet */
1750 if( p_fci_internal->fGetNextCabInVain &&
1752 p_fci_internal->ccab.cb < read_result +
1753 strlen(p_fci_internal->pccab->szCab)+1+
1754 strlen(p_fci_internal->pccab->szDisk)+1
1756 p_fci_internal->fGetNextCabInVain=FALSE;
1757 p_fci_internal->fNextCab=TRUE;
1758 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1761 if( p_fci_internal->fNextCab ) {
1762 /* THIS MAY NEVER HAPPEN */
1763 /* set error code */
1764 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1768 /* read the contents of the file blockwise */
1770 if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
1771 /* internal error */
1772 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1776 read_result = p_fci_internal->read( file_handle /* file handle */,
1777 (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
1778 (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
1779 &err, p_fci_internal->pv);
1780 /* TODO error handling of err */
1782 if( read_result==0 ) break;
1784 /* increment the block size */
1785 p_fci_internal->cdata_in += read_result;
1787 /* increment the file size */
1788 file->size += read_result;
1790 if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
1791 /* report internal error */
1792 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1795 /* write a whole block */
1796 if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
1798 if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
1802 /* close the file from FCIAddFile */
1803 p_fci_internal->close(file_handle,&err,p_fci_internal->pv);
1804 /* TODO error handling of err */
1806 p_fci_internal->files_size += sizeof(CFFILE) + strlen(pszFileName)+1;
1808 /* REUSE the variable read_result */
1809 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1810 read_result+= p_fci_internal->data1.size +
1811 p_fci_internal->files_size + p_fci_internal->data2.size +
1812 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1813 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1815 /* too much data for the maximum size of a cabinet */
1816 /* (ignoring the unflushed data block) */
1817 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1818 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1819 p_fci_internal->ccab.cb < read_result ) {
1820 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1823 /* Might be too much data for the maximum size of a cabinet.*/
1824 /* When any further data will be added later, it might not */
1825 /* be possible to flush the cabinet, because there might */
1826 /* not be enough space to store the name of the following */
1827 /* cabinet and name of the corresponding disk. */
1828 /* So take care of this and get the name of the next cabinet */
1829 /* (ignoring the unflushed data block) */
1830 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1831 p_fci_internal->fNextCab==FALSE &&
1832 ( p_fci_internal->ccab.cb < read_result +
1833 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1836 /* increment cabinet index */
1837 ++(p_fci_internal->pccab->iCab);
1838 /* get name of next cabinet */
1839 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1840 if (!(*pfnfcignc)(p_fci_internal->pccab,
1841 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1842 p_fci_internal->pv)) {
1843 /* error handling */
1844 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1847 /* Skip a few lines of code. This is caught by the next if. */
1848 p_fci_internal->fGetNextCabInVain=TRUE;
1851 if( p_fci_internal->fGetNextCabInVain &&
1852 p_fci_internal->fNextCab
1854 /* THIS CAN NEVER HAPPEN */
1855 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1859 /* too much data for cabinet */
1860 if( (p_fci_internal->fGetNextCabInVain ||
1861 p_fci_internal->fNextCab) && (
1862 p_fci_internal->ccab.cb < read_result +
1863 strlen(p_fci_internal->pccab->szCab)+1+
1864 strlen(p_fci_internal->pccab->szDisk)+1
1867 p_fci_internal->fGetNextCabInVain=FALSE;
1868 p_fci_internal->fNextCab=TRUE;
1869 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1872 if( p_fci_internal->fNextCab ) {
1873 /* THIS MAY NEVER HAPPEN */
1874 /* set error code */
1875 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1879 /* if the FolderThreshold has been reached flush the folder automatically */
1880 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1881 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1884 } /* end of FCIAddFile */
1890 /***********************************************************************
1891 * FCIFlushFolder (CABINET.12)
1893 * FCIFlushFolder completes the CFFolder structure under construction.
1895 * All further data which is added by FCIAddFile will be associated to
1896 * the next CFFolder structure.
1898 * FCIFlushFolder will be called by FCIAddFile automatically if the
1899 * threshold (stored in the member cbFolderThresh of the CCAB structure
1900 * pccab passed to FCICreate) is exceeded.
1902 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1903 * any data will be written into the cabinet file.
1906 * hfci [I] An HFCI from FCICreate
1907 * pfnfcignc [I] A pointer to a function which gets information about
1909 * pfnfcis [IO] A pointer to a function which will report status
1910 * information about the compression process
1913 * On success, returns TRUE
1914 * On failure, returns FALSE
1920 BOOL __cdecl FCIFlushFolder(
1922 PFNFCIGETNEXTCABINET pfnfcignc,
1923 PFNFCISTATUS pfnfcis)
1925 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1927 if (!p_fci_internal) return FALSE;
1928 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1933 /***********************************************************************
1934 * FCIFlushCabinet (CABINET.13)
1936 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1937 * into the cabinet file. If the maximum cabinet size (stored in the
1938 * member cb of the CCAB structure pccab passed to FCICreate) has been
1939 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1940 * The remaining data still has to be flushed manually by calling
1943 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1944 * NOT be called again. Then hfci has to be released by FCIDestroy.
1947 * hfci [I] An HFCI from FCICreate
1948 * fGetNextCab [I] Whether you want to add additional files to a
1949 * cabinet set (TRUE) or whether you want to
1950 * finalize it (FALSE)
1951 * pfnfcignc [I] A pointer to a function which gets information about
1953 * pfnfcis [IO] A pointer to a function which will report status
1954 * information about the compression process
1957 * On success, returns TRUE
1958 * On failure, returns FALSE
1964 BOOL __cdecl FCIFlushCabinet(
1967 PFNFCIGETNEXTCABINET pfnfcignc,
1968 PFNFCISTATUS pfnfcis)
1970 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1972 if (!p_fci_internal) return FALSE;
1974 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1976 while( p_fci_internal->files_size>0 ||
1977 p_fci_internal->placed_files_size>0 ) {
1978 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1985 /***********************************************************************
1986 * FCIDestroy (CABINET.14)
1988 * Frees a handle created by FCICreate.
1989 * Only reason for failure would be an invalid handle.
1992 * hfci [I] The HFCI to free
1998 BOOL __cdecl FCIDestroy(HFCI hfci)
2000 struct folder *folder, *folder_next;
2001 struct file *file, *file_next;
2002 struct data_block *block, *block_next;
2003 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2005 if (!p_fci_internal) return FALSE;
2007 /* before hfci can be removed all temporary files must be closed */
2009 p_fci_internal->magic = 0;
2011 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
2013 free_folder( p_fci_internal, folder );
2015 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
2017 free_file( p_fci_internal, file );
2019 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
2021 free_data_block( p_fci_internal, block );
2024 close_temp_file( p_fci_internal, &p_fci_internal->data1 );
2025 close_temp_file( p_fci_internal, &p_fci_internal->data2 );
2027 /* data in and out buffers have to be removed */
2028 if (p_fci_internal->data_in!=NULL)
2029 p_fci_internal->free(p_fci_internal->data_in);
2030 if (p_fci_internal->data_out!=NULL)
2031 p_fci_internal->free(p_fci_internal->data_out);
2033 /* hfci can now be removed */
2034 p_fci_internal->free(hfci);