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
44 //#include <winbase.h>
45 //#include "winerror.h"
46 //#include "winternl.h"
49 #include <wine/list.h>
50 #include <wine/debug.h>
52 WINE_DEFAULT_DEBUG_CHANNEL(cabinet
);
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 */
110 char name
[CB_MAX_FILENAME
];
116 struct list files_list
;
117 struct list blocks_list
;
118 struct temp_file data
;
119 cab_ULONG data_start
;
120 cab_UWORD data_count
;
127 cab_ULONG size
; /* uncompressed size */
128 cab_ULONG offset
; /* offset in folder */
129 cab_UWORD folder
; /* index of folder */
139 cab_UWORD compressed
;
140 cab_UWORD uncompressed
;
143 typedef struct FCI_Int
147 PFNFCIFILEPLACED fileplaced
;
156 PFNFCIGETTEMPFILE gettemp
;
162 cab_ULONG statusFolderCopied
;
163 cab_ULONG statusFolderTotal
;
164 BOOL fGetNextCabInVain
;
166 char szPrevCab
[CB_MAX_CABINET_NAME
]; /* previous cabinet name */
167 char szPrevDisk
[CB_MAX_DISK_NAME
]; /* disk name of previous cabinet */
168 unsigned char data_in
[CAB_BLOCKMAX
]; /* uncompressed data blocks */
169 unsigned char data_out
[2 * CAB_BLOCKMAX
]; /* compressed data blocks */
171 ULONG cCompressedBytesInFolder
;
174 cab_ULONG cDataBlocks
;
175 cab_ULONG cbFileRemainer
; /* uncompressed, yet to be written data */
176 /* of spanned file of a spanning folder of a spanning cabinet */
177 struct temp_file data
;
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
; /* size of files not yet assigned to a folder */
185 cab_ULONG placed_files_size
; /* size of files already placed into a folder */
186 cab_ULONG pending_data_size
; /* size of data not yet assigned to a folder */
187 cab_ULONG folders_data_size
; /* total size of data contained in the current folders */
189 cab_UWORD (*compress
)(struct FCI_Int
*);
192 #define FCI_INT_MAGIC 0xfcfcfc05
194 static void set_error( FCI_Int
*fci
, int oper
, int err
)
196 fci
->perf
->erfOper
= oper
;
197 fci
->perf
->erfType
= err
;
198 fci
->perf
->fError
= TRUE
;
199 if (err
) SetLastError( err
);
202 static FCI_Int
*get_fci_ptr( HFCI hfci
)
204 FCI_Int
*fci
= (FCI_Int
*)hfci
;
206 if (!fci
|| fci
->magic
!= FCI_INT_MAGIC
)
208 SetLastError( ERROR_INVALID_HANDLE
);
214 /* compute the cabinet header size */
215 static cab_ULONG
get_header_size( FCI_Int
*fci
)
217 cab_ULONG ret
= sizeof(CFHEADER
) + fci
->ccab
.cbReserveCFHeader
;
219 if (fci
->ccab
.cbReserveCFHeader
|| fci
->ccab
.cbReserveCFFolder
|| fci
->ccab
.cbReserveCFData
)
223 ret
+= strlen( fci
->szPrevCab
) + 1 + strlen( fci
->szPrevDisk
) + 1;
226 ret
+= strlen( fci
->pccab
->szCab
) + 1 + strlen( fci
->pccab
->szDisk
) + 1;
231 static BOOL
create_temp_file( FCI_Int
*fci
, struct temp_file
*file
)
235 if (!fci
->gettemp( file
->name
, CB_MAX_FILENAME
, fci
->pv
))
237 set_error( fci
, FCIERR_TEMP_FILE
, ERROR_FUNCTION_FAILED
);
240 if ((file
->handle
= fci
->open( file
->name
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
241 _S_IREAD
| _S_IWRITE
, &err
, fci
->pv
)) == -1)
243 set_error( fci
, FCIERR_TEMP_FILE
, err
);
249 static BOOL
close_temp_file( FCI_Int
*fci
, struct temp_file
*file
)
253 if (file
->handle
== -1) return TRUE
;
254 if (fci
->close( file
->handle
, &err
, fci
->pv
) == -1)
256 set_error( fci
, FCIERR_TEMP_FILE
, err
);
260 if (fci
->delete( file
->name
, &err
, fci
->pv
) == -1)
262 set_error( fci
, FCIERR_TEMP_FILE
, err
);
268 static struct file
*add_file( FCI_Int
*fci
, const char *filename
)
270 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(filename
) + 1] );
271 struct file
*file
= fci
->alloc( size
);
275 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
279 file
->offset
= fci
->cDataBlocks
* CAB_BLOCKMAX
+ fci
->cdata_in
;
280 file
->folder
= fci
->cFolders
;
284 strcpy( file
->name
, filename
);
285 list_add_tail( &fci
->files_list
, &file
->entry
);
286 fci
->files_size
+= sizeof(CFFILE
) + strlen(filename
) + 1;
290 static struct file
*copy_file( FCI_Int
*fci
, const struct file
*orig
)
292 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(orig
->name
) + 1] );
293 struct file
*file
= fci
->alloc( size
);
297 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
300 memcpy( file
, orig
, size
);
304 static void free_file( FCI_Int
*fci
, struct file
*file
)
306 list_remove( &file
->entry
);
310 /* create a new data block for the data in fci->data_in */
311 static BOOL
add_data_block( FCI_Int
*fci
, PFNFCISTATUS status_callback
)
314 struct data_block
*block
;
316 if (!fci
->cdata_in
) return TRUE
;
318 if (fci
->data
.handle
== -1 && !create_temp_file( fci
, &fci
->data
)) return FALSE
;
320 if (!(block
= fci
->alloc( sizeof(*block
) )))
322 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
325 block
->uncompressed
= fci
->cdata_in
;
326 block
->compressed
= fci
->compress( fci
);
328 if (fci
->write( fci
->data
.handle
, fci
->data_out
,
329 block
->compressed
, &err
, fci
->pv
) != block
->compressed
)
331 set_error( fci
, FCIERR_TEMP_FILE
, err
);
337 fci
->pending_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ block
->compressed
;
338 fci
->cCompressedBytesInFolder
+= block
->compressed
;
340 list_add_tail( &fci
->blocks_list
, &block
->entry
);
342 if (status_callback( statusFile
, block
->compressed
, block
->uncompressed
, fci
->pv
) == -1)
344 set_error( fci
, FCIERR_USER_ABORT
, 0 );
350 /* add compressed blocks for all the data that can be read from the file */
351 static BOOL
add_file_data( FCI_Int
*fci
, char *sourcefile
, char *filename
, BOOL execute
,
352 PFNFCIGETOPENINFO get_open_info
, PFNFCISTATUS status_callback
)
358 if (!(file
= add_file( fci
, filename
))) return FALSE
;
360 handle
= get_open_info( sourcefile
, &file
->date
, &file
->time
, &file
->attribs
, &err
, fci
->pv
);
363 free_file( fci
, file
);
364 set_error( fci
, FCIERR_OPEN_SRC
, err
);
367 if (execute
) file
->attribs
|= _A_EXEC
;
371 len
= fci
->read( handle
, fci
->data_in
+ fci
->cdata_in
,
372 CAB_BLOCKMAX
- fci
->cdata_in
, &err
, fci
->pv
);
377 set_error( fci
, FCIERR_READ_SRC
, err
);
381 fci
->cdata_in
+= len
;
382 if (fci
->cdata_in
== CAB_BLOCKMAX
&& !add_data_block( fci
, status_callback
)) return FALSE
;
384 fci
->close( handle
, &err
, fci
->pv
);
388 static void free_data_block( FCI_Int
*fci
, struct data_block
*block
)
390 list_remove( &block
->entry
);
394 static struct folder
*add_folder( FCI_Int
*fci
)
396 struct folder
*folder
= fci
->alloc( sizeof(*folder
) );
400 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
403 folder
->data
.handle
= -1;
404 folder
->data_start
= fci
->folders_data_size
;
405 folder
->data_count
= 0;
406 folder
->compression
= fci
->compression
;
407 list_init( &folder
->files_list
);
408 list_init( &folder
->blocks_list
);
409 list_add_tail( &fci
->folders_list
, &folder
->entry
);
410 fci
->folders_size
+= sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
;
415 static void free_folder( FCI_Int
*fci
, struct folder
*folder
)
417 struct file
*file
, *file_next
;
418 struct data_block
*block
, *block_next
;
420 LIST_FOR_EACH_ENTRY_SAFE( file
, file_next
, &folder
->files_list
, struct file
, entry
)
421 free_file( fci
, file
);
422 LIST_FOR_EACH_ENTRY_SAFE( block
, block_next
, &folder
->blocks_list
, struct data_block
, entry
)
423 free_data_block( fci
, block
);
424 close_temp_file( fci
, &folder
->data
);
425 list_remove( &folder
->entry
);
429 /* reset state for the next cabinet file once the current one has been flushed */
430 static void reset_cabinet( FCI_Int
*fci
)
432 struct folder
*folder
, *folder_next
;
434 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &fci
->folders_list
, struct folder
, entry
)
435 free_folder( fci
, folder
);
439 fci
->folders_size
= 0;
440 fci
->placed_files_size
= 0;
441 fci
->folders_data_size
= 0;
444 static cab_ULONG
fci_get_checksum( const void *pv
, UINT cb
, cab_ULONG seed
)
455 while (cUlong
-- > 0) {
457 ul
|= (((cab_ULONG
)(*pb
++)) << 8);
458 ul
|= (((cab_ULONG
)(*pb
++)) << 16);
459 ul
|= (((cab_ULONG
)(*pb
++)) << 24);
466 ul
|= (((ULONG
)(*pb
++)) << 16);
469 ul
|= (((ULONG
)(*pb
++)) << 8);
482 /* copy all remaining data block to a new temp file */
483 static BOOL
copy_data_blocks( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG start_pos
,
484 struct temp_file
*temp
, PFNFCISTATUS status_callback
)
486 struct data_block
*block
;
489 if (fci
->seek( handle
, start_pos
, SEEK_SET
, &err
, fci
->pv
) != start_pos
)
491 set_error( fci
, FCIERR_TEMP_FILE
, err
);
494 if (!create_temp_file( fci
, temp
)) return FALSE
;
496 LIST_FOR_EACH_ENTRY( block
, &fci
->blocks_list
, struct data_block
, entry
)
498 if (fci
->read( handle
, fci
->data_out
, block
->compressed
,
499 &err
, fci
->pv
) != block
->compressed
)
501 close_temp_file( fci
, temp
);
502 set_error( fci
, FCIERR_TEMP_FILE
, err
);
505 if (fci
->write( temp
->handle
, fci
->data_out
, block
->compressed
,
506 &err
, fci
->pv
) != block
->compressed
)
508 close_temp_file( fci
, temp
);
509 set_error( fci
, FCIERR_TEMP_FILE
, err
);
512 fci
->pending_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ block
->compressed
;
513 fci
->statusFolderCopied
+= block
->compressed
;
515 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
516 fci
->statusFolderTotal
, fci
->pv
) == -1)
518 close_temp_file( fci
, temp
);
519 set_error( fci
, FCIERR_USER_ABORT
, 0 );
526 /* write all folders to disk and remove them from the list */
527 static BOOL
write_folders( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG header_size
, PFNFCISTATUS status_callback
)
529 struct folder
*folder
;
531 CFFOLDER
*cffolder
= (CFFOLDER
*)fci
->data_out
;
532 cab_ULONG folder_size
= sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
;
534 memset( cffolder
, 0, folder_size
);
536 /* write the folders */
537 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
539 cffolder
->coffCabStart
= fci_endian_ulong( folder
->data_start
+ header_size
);
540 cffolder
->cCFData
= fci_endian_uword( folder
->data_count
);
541 cffolder
->typeCompress
= fci_endian_uword( folder
->compression
);
542 if (fci
->write( handle
, cffolder
, folder_size
, &err
, fci
->pv
) != folder_size
)
544 set_error( fci
, FCIERR_CAB_FILE
, err
);
551 /* write all the files to the cabinet file */
552 static BOOL
write_files( FCI_Int
*fci
, INT_PTR handle
, PFNFCISTATUS status_callback
)
555 struct folder
*folder
;
558 CFFILE
*cffile
= (CFFILE
*)fci
->data_out
;
560 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
562 LIST_FOR_EACH_ENTRY( file
, &folder
->files_list
, struct file
, entry
)
564 cffile
->cbFile
= fci_endian_ulong( file
->size
);
565 cffile
->uoffFolderStart
= fci_endian_ulong( file
->offset
);
566 cffile
->iFolder
= fci_endian_uword( file
->folder
);
567 cffile
->date
= fci_endian_uword( file
->date
);
568 cffile
->time
= fci_endian_uword( file
->time
);
569 cffile
->attribs
= fci_endian_uword( file
->attribs
);
570 lstrcpynA( (char *)(cffile
+ 1), file
->name
, CB_MAX_FILENAME
);
571 file_size
= sizeof(CFFILE
) + strlen( (char *)(cffile
+ 1) ) + 1;
572 if (fci
->write( handle
, cffile
, file_size
, &err
, fci
->pv
) != file_size
)
574 set_error( fci
, FCIERR_CAB_FILE
, err
);
577 if (!fci
->fSplitFolder
)
579 fci
->statusFolderCopied
= 0;
580 /* TODO TEST THIS further */
581 fci
->statusFolderTotal
= fci
->folders_data_size
+ fci
->placed_files_size
;
583 fci
->statusFolderCopied
+= file_size
;
584 /* report status about copied size of folder */
585 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
586 fci
->statusFolderTotal
, fci
->pv
) == -1)
588 set_error( fci
, FCIERR_USER_ABORT
, 0 );
596 /* write all data blocks to the cabinet file */
597 static BOOL
write_data_blocks( FCI_Int
*fci
, INT_PTR handle
, PFNFCISTATUS status_callback
)
599 struct folder
*folder
;
600 struct data_block
*block
;
604 cab_UWORD header_size
;
606 header_size
= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
;
607 cfdata
= (CFDATA
*)fci
->data_out
;
608 memset( cfdata
, 0, header_size
);
609 data
= (char *)cfdata
+ header_size
;
611 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
613 if (fci
->seek( folder
->data
.handle
, 0, SEEK_SET
, &err
, fci
->pv
) != 0)
615 set_error( fci
, FCIERR_CAB_FILE
, err
);
618 LIST_FOR_EACH_ENTRY( block
, &folder
->blocks_list
, struct data_block
, entry
)
620 len
= fci
->read( folder
->data
.handle
, data
, block
->compressed
, &err
, fci
->pv
);
621 if (len
!= block
->compressed
) return FALSE
;
623 cfdata
->cbData
= fci_endian_uword( block
->compressed
);
624 cfdata
->cbUncomp
= fci_endian_uword( block
->uncompressed
);
625 cfdata
->csum
= fci_endian_ulong( fci_get_checksum( &cfdata
->cbData
,
626 header_size
- FIELD_OFFSET(CFDATA
, cbData
),
627 fci_get_checksum( data
, len
, 0 )));
629 fci
->statusFolderCopied
+= len
;
631 if (fci
->write( handle
, fci
->data_out
, len
, &err
, fci
->pv
) != len
)
633 set_error( fci
, FCIERR_CAB_FILE
, err
);
636 if (status_callback( statusFolder
, fci
->statusFolderCopied
, fci
->statusFolderTotal
, fci
->pv
) == -1)
638 set_error( fci
, FCIERR_USER_ABORT
, 0 );
646 /* write the cabinet file to disk */
647 static BOOL
write_cabinet( FCI_Int
*fci
, PFNFCISTATUS status_callback
)
649 char filename
[CB_MAX_CAB_PATH
+ CB_MAX_CABINET_NAME
];
653 CFHEADER
*cfheader
= (CFHEADER
*)fci
->data_out
;
655 cab_ULONG header_size
= get_header_size( fci
);
656 cab_ULONG total_size
= header_size
+ fci
->folders_size
+
657 fci
->placed_files_size
+ fci
->folders_data_size
;
659 assert( header_size
<= sizeof(fci
->data_out
) );
660 memset( cfheader
, 0, header_size
);
662 if (fci
->fPrevCab
) flags
|= cfheadPREV_CABINET
;
663 if (fci
->fNextCab
) flags
|= cfheadNEXT_CABINET
;
664 if (fci
->ccab
.cbReserveCFHeader
|| fci
->ccab
.cbReserveCFFolder
|| fci
->ccab
.cbReserveCFData
)
665 flags
|= cfheadRESERVE_PRESENT
;
667 memcpy( cfheader
->signature
, "!CAB", 4 );
668 cfheader
->cbCabinet
= fci_endian_ulong( total_size
);
669 cfheader
->coffFiles
= fci_endian_ulong( header_size
+ fci
->folders_size
);
670 cfheader
->versionMinor
= 3;
671 cfheader
->versionMajor
= 1;
672 cfheader
->cFolders
= fci_endian_uword( fci
->cFolders
);
673 cfheader
->cFiles
= fci_endian_uword( fci
->cFiles
);
674 cfheader
->flags
= fci_endian_uword( flags
);
675 cfheader
->setID
= fci_endian_uword( fci
->ccab
.setID
);
676 cfheader
->iCabinet
= fci_endian_uword( fci
->ccab
.iCab
);
677 ptr
= (char *)(cfheader
+ 1);
679 if (flags
& cfheadRESERVE_PRESENT
)
683 cab_UWORD cbCFHeader
;
684 cab_UBYTE cbCFFolder
;
686 } *reserve
= (void *)ptr
;
688 reserve
->cbCFHeader
= fci_endian_uword( fci
->ccab
.cbReserveCFHeader
);
689 reserve
->cbCFFolder
= fci
->ccab
.cbReserveCFFolder
;
690 reserve
->cbCFData
= fci
->ccab
.cbReserveCFData
;
691 ptr
= (char *)(reserve
+ 1);
693 ptr
+= fci
->ccab
.cbReserveCFHeader
;
695 if (flags
& cfheadPREV_CABINET
)
697 strcpy( ptr
, fci
->szPrevCab
);
698 ptr
+= strlen( ptr
) + 1;
699 strcpy( ptr
, fci
->szPrevDisk
);
700 ptr
+= strlen( ptr
) + 1;
703 if (flags
& cfheadNEXT_CABINET
)
705 strcpy( ptr
, fci
->pccab
->szCab
);
706 ptr
+= strlen( ptr
) + 1;
707 strcpy( ptr
, fci
->pccab
->szDisk
);
708 ptr
+= strlen( ptr
) + 1;
711 assert( ptr
- (char *)cfheader
== header_size
);
713 strcpy( filename
, fci
->ccab
.szCabPath
);
714 strcat( filename
, fci
->ccab
.szCab
);
716 if ((handle
= fci
->open( filename
, _O_RDWR
| _O_CREAT
| _O_TRUNC
| _O_BINARY
,
717 _S_IREAD
| _S_IWRITE
, &err
, fci
->pv
)) == -1)
719 set_error( fci
, FCIERR_CAB_FILE
, err
);
723 if (fci
->write( handle
, cfheader
, header_size
, &err
, fci
->pv
) != header_size
)
725 set_error( fci
, FCIERR_CAB_FILE
, err
);
729 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
730 header_size
+= fci
->placed_files_size
+ fci
->folders_size
;
731 if (!write_folders( fci
, handle
, header_size
, status_callback
)) goto failed
;
732 if (!write_files( fci
, handle
, status_callback
)) goto failed
;
733 if (!write_data_blocks( fci
, handle
, status_callback
)) goto failed
;
735 /* update the signature */
736 if (fci
->seek( handle
, 0, SEEK_SET
, &err
, fci
->pv
) != 0 )
738 set_error( fci
, FCIERR_CAB_FILE
, err
);
741 memcpy( cfheader
->signature
, "MSCF", 4 );
742 if (fci
->write( handle
, cfheader
->signature
, 4, &err
, fci
->pv
) != 4)
744 set_error( fci
, FCIERR_CAB_FILE
, err
);
747 fci
->close( handle
, &err
, fci
->pv
);
749 reset_cabinet( fci
);
750 status_callback( statusCabinet
, fci
->estimatedCabinetSize
, total_size
, fci
->pv
);
754 fci
->close( handle
, &err
, fci
->pv
);
755 fci
->delete( filename
, &err
, fci
->pv
);
759 /* add all pending data blocks folder */
760 static BOOL
add_data_to_folder( FCI_Int
*fci
, struct folder
*folder
, cab_ULONG
*payload
,
761 PFNFCISTATUS status_callback
)
763 struct data_block
*block
, *new, *next
;
764 BOOL split_block
= FALSE
;
765 cab_ULONG current_size
, start_pos
= 0;
768 current_size
= get_header_size( fci
) + fci
->folders_size
+
769 fci
->files_size
+ fci
->placed_files_size
+ fci
->folders_data_size
;
771 /* move the temp file into the folder structure */
772 folder
->data
= fci
->data
;
773 fci
->data
.handle
= -1;
774 fci
->pending_data_size
= 0;
776 LIST_FOR_EACH_ENTRY_SAFE( block
, next
, &fci
->blocks_list
, struct data_block
, entry
)
778 /* No more CFDATA fits into the cabinet under construction */
779 /* So don't try to store more data into it */
780 if (fci
->fNextCab
&& (fci
->ccab
.cb
<= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+
781 current_size
+ sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
))
784 if (!(new = fci
->alloc( sizeof(*new) )))
786 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
789 /* Is cabinet with new CFDATA too large? Then data block has to be split */
791 (fci
->ccab
.cb
< sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+
792 block
->compressed
+ current_size
+ sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
))
794 /* Modify the size of the compressed data to store only a part of the */
795 /* data block into the current cabinet. This is done to prevent */
796 /* that the maximum cabinet size will be exceeded. The remainder */
797 /* will be stored into the next following cabinet. */
799 new->compressed
= fci
->ccab
.cb
- (sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ current_size
+
800 sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
);
801 new->uncompressed
= 0; /* on split blocks of data this is zero */
802 block
->compressed
-= new->compressed
;
807 new->compressed
= block
->compressed
;
808 new->uncompressed
= block
->uncompressed
;
811 start_pos
+= new->compressed
;
812 current_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ new->compressed
;
813 fci
->folders_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ new->compressed
;
814 fci
->statusFolderCopied
+= new->compressed
;
815 (*payload
) += new->uncompressed
;
817 list_add_tail( &folder
->blocks_list
, &new->entry
);
818 folder
->data_count
++;
820 /* report status with pfnfcis about copied size of folder */
821 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
822 fci
->statusFolderTotal
, fci
->pv
) == -1)
824 set_error( fci
, FCIERR_USER_ABORT
, 0 );
827 if (split_block
) break;
828 free_data_block( fci
, block
);
832 if (list_empty( &fci
->blocks_list
)) return TRUE
;
833 return copy_data_blocks( fci
, folder
->data
.handle
, start_pos
, &fci
->data
, status_callback
);
836 /* add all pending files to folder */
837 static BOOL
add_files_to_folder( FCI_Int
*fci
, struct folder
*folder
, cab_ULONG payload
)
839 cab_ULONG sizeOfFiles
= 0, sizeOfFilesPrev
;
840 cab_ULONG cbFileRemainer
= 0;
841 struct file
*file
, *next
;
843 LIST_FOR_EACH_ENTRY_SAFE( file
, next
, &fci
->files_list
, struct file
, entry
)
845 cab_ULONG size
= sizeof(CFFILE
) + strlen(file
->name
) + 1;
847 /* fnfilfnfildest: placed file on cabinet */
848 fci
->fileplaced( &fci
->ccab
, file
->name
, file
->size
,
849 (file
->folder
== cffileCONTINUED_FROM_PREV
), fci
->pv
);
851 sizeOfFilesPrev
= sizeOfFiles
;
852 /* set complete size of all processed files */
853 if (file
->folder
== cffileCONTINUED_FROM_PREV
&& fci
->cbFileRemainer
!= 0)
855 sizeOfFiles
+= fci
->cbFileRemainer
;
856 fci
->cbFileRemainer
= 0;
858 else sizeOfFiles
+= file
->size
;
860 /* check if spanned file fits into this cabinet folder */
861 if (sizeOfFiles
> payload
)
863 if (file
->folder
== cffileCONTINUED_FROM_PREV
)
864 file
->folder
= cffileCONTINUED_PREV_AND_NEXT
;
866 file
->folder
= cffileCONTINUED_TO_NEXT
;
869 list_remove( &file
->entry
);
870 list_add_tail( &folder
->files_list
, &file
->entry
);
871 fci
->placed_files_size
+= size
;
874 /* This is only true for files which will be written into the */
875 /* next cabinet of the spanning folder */
876 if (sizeOfFiles
> payload
)
878 /* add a copy back onto the list */
879 if (!(file
= copy_file( fci
, file
))) return FALSE
;
880 list_add_before( &next
->entry
, &file
->entry
);
882 /* Files which data will be partially written into the current cabinet */
883 if (file
->folder
== cffileCONTINUED_PREV_AND_NEXT
|| file
->folder
== cffileCONTINUED_TO_NEXT
)
885 if (sizeOfFilesPrev
<= payload
)
887 /* The size of the uncompressed, data of a spanning file in a */
889 cbFileRemainer
= sizeOfFiles
- payload
;
891 file
->folder
= cffileCONTINUED_FROM_PREV
;
893 else file
->folder
= 0;
897 fci
->files_size
-= size
;
900 fci
->cbFileRemainer
= cbFileRemainer
;
904 static cab_UWORD
compress_NONE( FCI_Int
*fci
)
906 memcpy( fci
->data_out
, fci
->data_in
, fci
->cdata_in
);
907 return fci
->cdata_in
;
912 static void *zalloc( void *opaque
, unsigned int items
, unsigned int size
)
914 FCI_Int
*fci
= opaque
;
915 return fci
->alloc( items
* size
);
918 static void zfree( void *opaque
, void *ptr
)
920 FCI_Int
*fci
= opaque
;
924 static cab_UWORD
compress_MSZIP( FCI_Int
*fci
)
928 stream
.zalloc
= zalloc
;
929 stream
.zfree
= zfree
;
931 if (deflateInit2( &stream
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
, -15, 8, Z_DEFAULT_STRATEGY
) != Z_OK
)
933 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
936 stream
.next_in
= fci
->data_in
;
937 stream
.avail_in
= fci
->cdata_in
;
938 stream
.next_out
= fci
->data_out
+ 2;
939 stream
.avail_out
= sizeof(fci
->data_out
) - 2;
940 /* insert the signature */
941 fci
->data_out
[0] = 'C';
942 fci
->data_out
[1] = 'K';
943 deflate( &stream
, Z_FINISH
);
944 deflateEnd( &stream
);
945 return stream
.total_out
+ 2;
948 #endif /* HAVE_ZLIB */
951 /***********************************************************************
952 * FCICreate (CABINET.10)
954 * FCICreate is provided with several callbacks and
955 * returns a handle which can be used to create cabinet files.
958 * perf [IO] A pointer to an ERF structure. When FCICreate
959 * returns an error condition, error information may
960 * be found here as well as from GetLastError.
961 * pfnfiledest [I] A pointer to a function which is called when a file
962 * is placed. Only useful for subsequent cabinet files.
963 * pfnalloc [I] A pointer to a function which allocates ram. Uses
964 * the same interface as malloc.
965 * pfnfree [I] A pointer to a function which frees ram. Uses the
966 * same interface as free.
967 * pfnopen [I] A pointer to a function which opens a file. Uses
968 * the same interface as _open.
969 * pfnread [I] A pointer to a function which reads from a file into
970 * a caller-provided buffer. Uses the same interface
972 * pfnwrite [I] A pointer to a function which writes to a file from
973 * a caller-provided buffer. Uses the same interface
975 * pfnclose [I] A pointer to a function which closes a file handle.
976 * Uses the same interface as _close.
977 * pfnseek [I] A pointer to a function which seeks in a file.
978 * Uses the same interface as _lseek.
979 * pfndelete [I] A pointer to a function which deletes a file.
980 * pfnfcigtf [I] A pointer to a function which gets the name of a
982 * pccab [I] A pointer to an initialized CCAB structure.
983 * pv [I] A pointer to an application-defined notification
984 * function which will be passed to other FCI functions
988 * On success, returns an FCI handle of type HFCI.
989 * On failure, the NULL file handle is returned. Error
990 * info can be retrieved from perf.
996 HFCI __cdecl
FCICreate(
998 PFNFCIFILEPLACED pfnfiledest
,
999 PFNFCIALLOC pfnalloc
,
1003 PFNFCIWRITE pfnwrite
,
1004 PFNFCICLOSE pfnclose
,
1006 PFNFCIDELETE pfndelete
,
1007 PFNFCIGETTEMPFILE pfnfcigtf
,
1011 FCI_Int
*p_fci_internal
;
1014 SetLastError(ERROR_BAD_ARGUMENTS
);
1017 if ((!pfnalloc
) || (!pfnfree
) || (!pfnopen
) || (!pfnread
) ||
1018 (!pfnwrite
) || (!pfnclose
) || (!pfnseek
) || (!pfndelete
) ||
1019 (!pfnfcigtf
) || (!pccab
)) {
1020 perf
->erfOper
= FCIERR_NONE
;
1021 perf
->erfType
= ERROR_BAD_ARGUMENTS
;
1022 perf
->fError
= TRUE
;
1024 SetLastError(ERROR_BAD_ARGUMENTS
);
1028 if (!((p_fci_internal
= pfnalloc(sizeof(FCI_Int
))))) {
1029 perf
->erfOper
= FCIERR_ALLOC_FAIL
;
1030 perf
->erfType
= ERROR_NOT_ENOUGH_MEMORY
;
1031 perf
->fError
= TRUE
;
1033 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1037 p_fci_internal
->magic
= FCI_INT_MAGIC
;
1038 p_fci_internal
->perf
= perf
;
1039 p_fci_internal
->fileplaced
= pfnfiledest
;
1040 p_fci_internal
->alloc
= pfnalloc
;
1041 p_fci_internal
->free
= pfnfree
;
1042 p_fci_internal
->open
= pfnopen
;
1043 p_fci_internal
->read
= pfnread
;
1044 p_fci_internal
->write
= pfnwrite
;
1045 p_fci_internal
->close
= pfnclose
;
1046 p_fci_internal
->seek
= pfnseek
;
1047 p_fci_internal
->delete = pfndelete
;
1048 p_fci_internal
->gettemp
= pfnfcigtf
;
1049 p_fci_internal
->ccab
= *pccab
;
1050 p_fci_internal
->pccab
= pccab
;
1051 p_fci_internal
->fPrevCab
= FALSE
;
1052 p_fci_internal
->fNextCab
= FALSE
;
1053 p_fci_internal
->fSplitFolder
= FALSE
;
1054 p_fci_internal
->fGetNextCabInVain
= FALSE
;
1055 p_fci_internal
->pv
= pv
;
1056 p_fci_internal
->cdata_in
= 0;
1057 p_fci_internal
->cCompressedBytesInFolder
= 0;
1058 p_fci_internal
->cFolders
= 0;
1059 p_fci_internal
->cFiles
= 0;
1060 p_fci_internal
->cDataBlocks
= 0;
1061 p_fci_internal
->data
.handle
= -1;
1062 p_fci_internal
->fNewPrevious
= FALSE
;
1063 p_fci_internal
->estimatedCabinetSize
= 0;
1064 p_fci_internal
->statusFolderTotal
= 0;
1065 p_fci_internal
->folders_size
= 0;
1066 p_fci_internal
->files_size
= 0;
1067 p_fci_internal
->placed_files_size
= 0;
1068 p_fci_internal
->pending_data_size
= 0;
1069 p_fci_internal
->folders_data_size
= 0;
1070 p_fci_internal
->compression
= tcompTYPE_NONE
;
1071 p_fci_internal
->compress
= compress_NONE
;
1073 list_init( &p_fci_internal
->folders_list
);
1074 list_init( &p_fci_internal
->files_list
);
1075 list_init( &p_fci_internal
->blocks_list
);
1077 memcpy(p_fci_internal
->szPrevCab
, pccab
->szCab
, CB_MAX_CABINET_NAME
);
1078 memcpy(p_fci_internal
->szPrevDisk
, pccab
->szDisk
, CB_MAX_DISK_NAME
);
1080 return (HFCI
)p_fci_internal
;
1086 static BOOL
fci_flush_folder( FCI_Int
*p_fci_internal
,
1088 PFNFCIGETNEXTCABINET pfnfcignc
,
1089 PFNFCISTATUS pfnfcis
)
1092 cab_ULONG read_result
;
1093 struct folder
*folder
;
1095 if ((!pfnfcignc
) || (!pfnfcis
)) {
1096 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1100 if( p_fci_internal
->fGetNextCabInVain
&&
1101 p_fci_internal
->fNextCab
){
1102 /* internal error */
1103 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1107 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1108 /* this function will return TRUE */
1109 if( p_fci_internal
->files_size
== 0 ) {
1110 if ( p_fci_internal
->pending_data_size
!= 0 ) {
1111 /* error handling */
1112 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1118 /* FCIFlushFolder has already been called... */
1119 if (p_fci_internal
->fSplitFolder
&& p_fci_internal
->placed_files_size
!=0) {
1123 /* This can be set already, because it makes only a difference */
1124 /* when the current function exits with return FALSE */
1125 p_fci_internal
->fSplitFolder
=FALSE
;
1128 if (!add_data_block( p_fci_internal
, pfnfcis
)) return FALSE
;
1130 /* reset to get the number of data blocks of this folder which are */
1131 /* actually in this cabinet ( at least partially ) */
1132 p_fci_internal
->cDataBlocks
=0;
1134 p_fci_internal
->statusFolderTotal
= get_header_size( p_fci_internal
) +
1135 sizeof(CFFOLDER
) + p_fci_internal
->ccab
.cbReserveCFFolder
+
1136 p_fci_internal
->placed_files_size
+
1137 p_fci_internal
->folders_data_size
+ p_fci_internal
->files_size
+
1138 p_fci_internal
->pending_data_size
+ p_fci_internal
->folders_size
;
1139 p_fci_internal
->statusFolderCopied
= 0;
1141 /* report status with pfnfcis about copied size of folder */
1142 if( (*pfnfcis
)(statusFolder
, p_fci_internal
->statusFolderCopied
,
1143 p_fci_internal
->statusFolderTotal
, /* TODO total folder size */
1144 p_fci_internal
->pv
) == -1) {
1145 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1149 /* USE the variable read_result */
1150 read_result
= get_header_size( p_fci_internal
) + p_fci_internal
->folders_data_size
+
1151 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
;
1153 if(p_fci_internal
->files_size
!=0) {
1154 read_result
+= sizeof(CFFOLDER
)+p_fci_internal
->ccab
.cbReserveCFFolder
;
1157 /* Check if multiple cabinets have to be created. */
1159 /* Might be too much data for the maximum allowed cabinet size.*/
1160 /* When any further data will be added later, it might not */
1161 /* be possible to flush the cabinet, because there might */
1162 /* not be enough space to store the name of the following */
1163 /* cabinet and name of the corresponding disk. */
1164 /* So take care of this and get the name of the next cabinet */
1165 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1166 p_fci_internal
->fNextCab
==FALSE
&&
1169 p_fci_internal
->ccab
.cb
< read_result
+
1170 p_fci_internal
->pending_data_size
+
1171 p_fci_internal
->files_size
+
1172 CB_MAX_CABINET_NAME
+ /* next cabinet name */
1173 CB_MAX_DISK_NAME
/* next disk name */
1177 /* increment cabinet index */
1178 ++(p_fci_internal
->pccab
->iCab
);
1179 /* get name of next cabinet */
1180 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1181 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1182 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1183 p_fci_internal
->pv
)) {
1184 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1188 /* Skip a few lines of code. This is caught by the next if. */
1189 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1192 /* too much data for cabinet */
1193 if( (p_fci_internal
->fGetNextCabInVain
||
1194 p_fci_internal
->fNextCab
) &&
1197 p_fci_internal
->ccab
.cb
< read_result
+
1198 p_fci_internal
->pending_data_size
+
1199 p_fci_internal
->files_size
+
1200 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1201 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1205 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1206 p_fci_internal
->fNextCab
=TRUE
;
1208 /* return FALSE if there is not enough space left*/
1209 /* this should never happen */
1210 if (p_fci_internal
->ccab
.cb
<=
1211 p_fci_internal
->files_size
+
1213 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1214 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1220 /* the folder will be split across cabinets */
1221 p_fci_internal
->fSplitFolder
=TRUE
;
1224 /* this should never happen */
1225 if (p_fci_internal
->fNextCab
) {
1226 /* internal error */
1227 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1232 if (!(folder
= add_folder( p_fci_internal
))) return FALSE
;
1233 if (!add_data_to_folder( p_fci_internal
, folder
, &payload
, pfnfcis
)) return FALSE
;
1234 if (!add_files_to_folder( p_fci_internal
, folder
, payload
)) return FALSE
;
1236 /* reset CFFolder specific information */
1237 p_fci_internal
->cDataBlocks
=0;
1238 p_fci_internal
->cCompressedBytesInFolder
=0;
1246 static BOOL
fci_flush_cabinet( FCI_Int
*p_fci_internal
,
1248 PFNFCIGETNEXTCABINET pfnfcignc
,
1249 PFNFCISTATUS pfnfcis
)
1251 cab_ULONG read_result
=0;
1252 BOOL returntrue
=FALSE
;
1254 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1256 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1257 if( p_fci_internal
->files_size
==0 && fGetNextCab
) {
1261 if (!fci_flush_folder(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)){
1262 /* TODO set error */
1266 if(returntrue
) return TRUE
;
1268 if ( (p_fci_internal
->fSplitFolder
&& p_fci_internal
->fNextCab
==FALSE
)||
1269 (p_fci_internal
->folders_size
==0 &&
1270 (p_fci_internal
->files_size
!=0 ||
1271 p_fci_internal
->placed_files_size
!=0 )
1275 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1279 /* create the cabinet */
1280 if (!write_cabinet( p_fci_internal
, pfnfcis
)) return FALSE
;
1282 p_fci_internal
->fPrevCab
=TRUE
;
1283 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1284 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1286 if (p_fci_internal
->fNextCab
) {
1287 p_fci_internal
->fNextCab
=FALSE
;
1289 if (p_fci_internal
->files_size
==0 && p_fci_internal
->pending_data_size
!=0) {
1290 /* THIS CAN NEVER HAPPEN */
1291 /* set error code */
1292 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1296 if( p_fci_internal
->fNewPrevious
) {
1297 memcpy(p_fci_internal
->szPrevCab
, p_fci_internal
->ccab
.szCab
,
1298 CB_MAX_CABINET_NAME
);
1299 memcpy(p_fci_internal
->szPrevDisk
, p_fci_internal
->ccab
.szDisk
,
1301 p_fci_internal
->fNewPrevious
=FALSE
;
1303 p_fci_internal
->ccab
= *p_fci_internal
->pccab
;
1305 /* REUSE the variable read_result */
1306 read_result
=get_header_size( p_fci_internal
);
1307 if(p_fci_internal
->files_size
!=0) {
1308 read_result
+=p_fci_internal
->ccab
.cbReserveCFFolder
;
1310 read_result
+= p_fci_internal
->pending_data_size
+
1311 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1312 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1313 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
1315 /* too much data for the maximum size of a cabinet */
1316 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1317 p_fci_internal
->ccab
.cb
< read_result
) {
1318 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1321 /* Might be too much data for the maximum size of a cabinet.*/
1322 /* When any further data will be added later, it might not */
1323 /* be possible to flush the cabinet, because there might */
1324 /* not be enough space to store the name of the following */
1325 /* cabinet and name of the corresponding disk. */
1326 /* So take care of this and get the name of the next cabinet */
1327 if (p_fci_internal
->fGetNextCabInVain
==FALSE
&& (
1328 p_fci_internal
->ccab
.cb
< read_result
+
1329 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1331 /* increment cabinet index */
1332 ++(p_fci_internal
->pccab
->iCab
);
1333 /* get name of next cabinet */
1334 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1335 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1336 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1337 p_fci_internal
->pv
)) {
1338 /* error handling */
1339 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1342 /* Skip a few lines of code. This is caught by the next if. */
1343 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1346 /* too much data for cabinet */
1347 if (p_fci_internal
->fGetNextCabInVain
&& (
1348 p_fci_internal
->ccab
.cb
< read_result
+
1349 strlen(p_fci_internal
->ccab
.szCab
)+1+
1350 strlen(p_fci_internal
->ccab
.szDisk
)+1
1352 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1353 p_fci_internal
->fNextCab
=TRUE
;
1354 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1357 /* if the FolderThreshold has been reached flush the folder automatically */
1358 if (p_fci_internal
->cCompressedBytesInFolder
>= p_fci_internal
->ccab
.cbFolderThresh
)
1359 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1361 if( p_fci_internal
->files_size
>0 ) {
1362 if( !fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
) ) return FALSE
;
1363 p_fci_internal
->fNewPrevious
=TRUE
;
1366 p_fci_internal
->fNewPrevious
=FALSE
;
1367 if( p_fci_internal
->files_size
>0 || p_fci_internal
->pending_data_size
) {
1368 /* THIS MAY NEVER HAPPEN */
1369 /* set error structures */
1370 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1376 } /* end of fci_flush_cabinet */
1382 /***********************************************************************
1383 * FCIAddFile (CABINET.11)
1385 * FCIAddFile adds a file to the to be created cabinet file
1388 * hfci [I] An HFCI from FCICreate
1389 * pszSourceFile [I] A pointer to a C string which contains the name and
1390 * location of the file which will be added to the cabinet
1391 * pszFileName [I] A pointer to a C string which contains the name under
1392 * which the file will be stored in the cabinet
1393 * fExecute [I] A boolean value which indicates if the file should be
1394 * executed after extraction of self extracting
1396 * pfnfcignc [I] A pointer to a function which gets information about
1398 * pfnfcis [IO] A pointer to a function which will report status
1399 * information about the compression process
1400 * pfnfcioi [I] A pointer to a function which reports file attributes
1401 * and time and date information
1402 * typeCompress [I] Compression type
1405 * On success, returns TRUE
1406 * On failure, returns FALSE
1412 BOOL __cdecl
FCIAddFile(
1414 char *pszSourceFile
,
1417 PFNFCIGETNEXTCABINET pfnfcignc
,
1418 PFNFCISTATUS pfnfcis
,
1419 PFNFCIGETOPENINFO pfnfcigoi
,
1422 cab_ULONG read_result
;
1423 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1425 if (!p_fci_internal
) return FALSE
;
1427 if ((!pszSourceFile
) || (!pszFileName
) || (!pfnfcignc
) || (!pfnfcis
) ||
1428 (!pfnfcigoi
) || strlen(pszFileName
)>=CB_MAX_FILENAME
) {
1429 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1433 if (typeCompress
!= p_fci_internal
->compression
)
1435 if (!FCIFlushFolder( hfci
, pfnfcignc
, pfnfcis
)) return FALSE
;
1436 switch (typeCompress
)
1438 case tcompTYPE_MSZIP
:
1440 p_fci_internal
->compression
= tcompTYPE_MSZIP
;
1441 p_fci_internal
->compress
= compress_MSZIP
;
1445 FIXME( "compression %x not supported, defaulting to none\n", typeCompress
);
1447 case tcompTYPE_NONE
:
1448 p_fci_internal
->compression
= tcompTYPE_NONE
;
1449 p_fci_internal
->compress
= compress_NONE
;
1454 /* TODO check if pszSourceFile??? */
1456 if(p_fci_internal
->fGetNextCabInVain
&& p_fci_internal
->fNextCab
) {
1457 /* internal error */
1458 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1462 if(p_fci_internal
->fNextCab
) {
1463 /* internal error */
1464 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1468 /* REUSE the variable read_result */
1469 read_result
=get_header_size( p_fci_internal
) + p_fci_internal
->ccab
.cbReserveCFFolder
;
1471 read_result
+= sizeof(CFFILE
) + strlen(pszFileName
)+1 +
1472 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1473 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1474 sizeof(CFFOLDER
); /* size of new CFFolder entry */
1476 /* Might be too much data for the maximum size of a cabinet.*/
1477 /* When any further data will be added later, it might not */
1478 /* be possible to flush the cabinet, because there might */
1479 /* not be enough space to store the name of the following */
1480 /* cabinet and name of the corresponding disk. */
1481 /* So take care of this and get the name of the next cabinet */
1482 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1483 p_fci_internal
->fNextCab
==FALSE
&&
1484 ( p_fci_internal
->ccab
.cb
< read_result
+
1485 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1488 /* increment cabinet index */
1489 ++(p_fci_internal
->pccab
->iCab
);
1490 /* get name of next cabinet */
1491 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1492 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1493 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1494 p_fci_internal
->pv
)) {
1495 /* error handling */
1496 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1499 /* Skip a few lines of code. This is caught by the next if. */
1500 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1503 if( p_fci_internal
->fGetNextCabInVain
&&
1504 p_fci_internal
->fNextCab
1506 /* THIS CAN NEVER HAPPEN */
1507 /* set error code */
1508 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1512 /* too much data for cabinet */
1513 if( p_fci_internal
->fGetNextCabInVain
&&
1515 p_fci_internal
->ccab
.cb
< read_result
+
1516 strlen(p_fci_internal
->pccab
->szCab
)+1+
1517 strlen(p_fci_internal
->pccab
->szDisk
)+1
1519 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1520 p_fci_internal
->fNextCab
=TRUE
;
1521 if(!fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
)) return FALSE
;
1524 if( p_fci_internal
->fNextCab
) {
1525 /* THIS MAY NEVER HAPPEN */
1526 /* set error code */
1527 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1531 if (!add_file_data( p_fci_internal
, pszSourceFile
, pszFileName
, fExecute
, pfnfcigoi
, pfnfcis
))
1534 /* REUSE the variable read_result */
1535 read_result
= get_header_size( p_fci_internal
) + p_fci_internal
->ccab
.cbReserveCFFolder
;
1536 read_result
+= p_fci_internal
->pending_data_size
+
1537 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1538 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1539 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
1541 /* too much data for the maximum size of a cabinet */
1542 /* (ignoring the unflushed data block) */
1543 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1544 p_fci_internal
->fNextCab
==FALSE
&& /* this is always the case */
1545 p_fci_internal
->ccab
.cb
< read_result
) {
1546 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1549 /* Might be too much data for the maximum size of a cabinet.*/
1550 /* When any further data will be added later, it might not */
1551 /* be possible to flush the cabinet, because there might */
1552 /* not be enough space to store the name of the following */
1553 /* cabinet and name of the corresponding disk. */
1554 /* So take care of this and get the name of the next cabinet */
1555 /* (ignoring the unflushed data block) */
1556 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1557 p_fci_internal
->fNextCab
==FALSE
&&
1558 ( p_fci_internal
->ccab
.cb
< read_result
+
1559 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1562 /* increment cabinet index */
1563 ++(p_fci_internal
->pccab
->iCab
);
1564 /* get name of next cabinet */
1565 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1566 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1567 p_fci_internal
->estimatedCabinetSize
,/* estimated size of cab */
1568 p_fci_internal
->pv
)) {
1569 /* error handling */
1570 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1573 /* Skip a few lines of code. This is caught by the next if. */
1574 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1577 if( p_fci_internal
->fGetNextCabInVain
&&
1578 p_fci_internal
->fNextCab
1580 /* THIS CAN NEVER HAPPEN */
1581 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1585 /* too much data for cabinet */
1586 if( (p_fci_internal
->fGetNextCabInVain
||
1587 p_fci_internal
->fNextCab
) && (
1588 p_fci_internal
->ccab
.cb
< read_result
+
1589 strlen(p_fci_internal
->pccab
->szCab
)+1+
1590 strlen(p_fci_internal
->pccab
->szDisk
)+1
1593 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1594 p_fci_internal
->fNextCab
=TRUE
;
1595 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1598 if( p_fci_internal
->fNextCab
) {
1599 /* THIS MAY NEVER HAPPEN */
1600 /* set error code */
1601 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1605 /* if the FolderThreshold has been reached flush the folder automatically */
1606 if (p_fci_internal
->cCompressedBytesInFolder
>= p_fci_internal
->ccab
.cbFolderThresh
)
1607 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
1610 } /* end of FCIAddFile */
1616 /***********************************************************************
1617 * FCIFlushFolder (CABINET.12)
1619 * FCIFlushFolder completes the CFFolder structure under construction.
1621 * All further data which is added by FCIAddFile will be associated to
1622 * the next CFFolder structure.
1624 * FCIFlushFolder will be called by FCIAddFile automatically if the
1625 * threshold (stored in the member cbFolderThresh of the CCAB structure
1626 * pccab passed to FCICreate) is exceeded.
1628 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1629 * any data will be written into the cabinet file.
1632 * hfci [I] An HFCI from FCICreate
1633 * pfnfcignc [I] A pointer to a function which gets information about
1635 * pfnfcis [IO] A pointer to a function which will report status
1636 * information about the compression process
1639 * On success, returns TRUE
1640 * On failure, returns FALSE
1646 BOOL __cdecl
FCIFlushFolder(
1648 PFNFCIGETNEXTCABINET pfnfcignc
,
1649 PFNFCISTATUS pfnfcis
)
1651 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1653 if (!p_fci_internal
) return FALSE
;
1654 return fci_flush_folder(p_fci_internal
,FALSE
,pfnfcignc
,pfnfcis
);
1659 /***********************************************************************
1660 * FCIFlushCabinet (CABINET.13)
1662 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1663 * into the cabinet file. If the maximum cabinet size (stored in the
1664 * member cb of the CCAB structure pccab passed to FCICreate) has been
1665 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1666 * The remaining data still has to be flushed manually by calling
1669 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1670 * NOT be called again. Then hfci has to be released by FCIDestroy.
1673 * hfci [I] An HFCI from FCICreate
1674 * fGetNextCab [I] Whether you want to add additional files to a
1675 * cabinet set (TRUE) or whether you want to
1676 * finalize it (FALSE)
1677 * pfnfcignc [I] A pointer to a function which gets information about
1679 * pfnfcis [IO] A pointer to a function which will report status
1680 * information about the compression process
1683 * On success, returns TRUE
1684 * On failure, returns FALSE
1690 BOOL __cdecl
FCIFlushCabinet(
1693 PFNFCIGETNEXTCABINET pfnfcignc
,
1694 PFNFCISTATUS pfnfcis
)
1696 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1698 if (!p_fci_internal
) return FALSE
;
1700 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
1702 while( p_fci_internal
->files_size
>0 ||
1703 p_fci_internal
->placed_files_size
>0 ) {
1704 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
1711 /***********************************************************************
1712 * FCIDestroy (CABINET.14)
1714 * Frees a handle created by FCICreate.
1715 * Only reason for failure would be an invalid handle.
1718 * hfci [I] The HFCI to free
1724 BOOL __cdecl
FCIDestroy(HFCI hfci
)
1726 struct folder
*folder
, *folder_next
;
1727 struct file
*file
, *file_next
;
1728 struct data_block
*block
, *block_next
;
1729 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1731 if (!p_fci_internal
) return FALSE
;
1733 /* before hfci can be removed all temporary files must be closed */
1735 p_fci_internal
->magic
= 0;
1737 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &p_fci_internal
->folders_list
, struct folder
, entry
)
1739 free_folder( p_fci_internal
, folder
);
1741 LIST_FOR_EACH_ENTRY_SAFE( file
, file_next
, &p_fci_internal
->files_list
, struct file
, entry
)
1743 free_file( p_fci_internal
, file
);
1745 LIST_FOR_EACH_ENTRY_SAFE( block
, block_next
, &p_fci_internal
->blocks_list
, struct data_block
, entry
)
1747 free_data_block( p_fci_internal
, block
);
1750 close_temp_file( p_fci_internal
, &p_fci_internal
->data
);
1752 /* hfci can now be removed */
1753 p_fci_internal
->free(hfci
);