2 * File Compression Interface
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
6 * Copyright 2011 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 There is still some work to be done:
27 - unknown behaviour if files>=2GB or cabinet >=4GB
28 - check if the maximum size for a cabinet is too small to store any data
29 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
51 #include "wine/list.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(cabinet
);
56 #ifdef WORDS_BIGENDIAN
57 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
58 #define fci_endian_uword(x) RtlUshortByteSwap(x)
60 #define fci_endian_ulong(x) (x)
61 #define fci_endian_uword(x) (x)
66 cab_UBYTE signature
[4]; /* !CAB for unfinished cabinets else MSCF */
68 cab_ULONG cbCabinet
; /* size of the cabinet file in bytes*/
70 cab_ULONG coffFiles
; /* offset to first CFFILE section */
72 cab_UBYTE versionMinor
; /* 3 */
73 cab_UBYTE versionMajor
; /* 1 */
74 cab_UWORD cFolders
; /* number of CFFOLDER entries in the cabinet*/
75 cab_UWORD cFiles
; /* number of CFFILE entries in the cabinet*/
76 cab_UWORD flags
; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
77 cab_UWORD setID
; /* identification number of all cabinets in a set*/
78 cab_UWORD iCabinet
; /* number of the cabinet in a set */
79 /* additional area if "flags" were set*/
80 } CFHEADER
; /* minimum 36 bytes */
83 cab_ULONG coffCabStart
; /* offset to the folder's first CFDATA section */
84 cab_UWORD cCFData
; /* number of this folder's CFDATA sections */
85 cab_UWORD typeCompress
; /* compression type of data in CFDATA section*/
86 /* additional area if reserve flag was set */
87 } CFFOLDER
; /* minimum 8 bytes */
90 cab_ULONG cbFile
; /* size of the uncompressed file in bytes */
91 cab_ULONG uoffFolderStart
; /* offset of the uncompressed file in the folder */
92 cab_UWORD iFolder
; /* number of folder in the cabinet 0=first */
93 /* for special values see below this structure*/
94 cab_UWORD date
; /* last modification date*/
95 cab_UWORD time
; /* last modification time*/
96 cab_UWORD attribs
; /* DOS fat attributes and UTF indicator */
97 /* ... and a C string with the name of the file */
98 } CFFILE
; /* 16 bytes + name of file */
102 cab_ULONG csum
; /* checksum of this entry*/
103 cab_UWORD cbData
; /* number of compressed bytes */
104 cab_UWORD cbUncomp
; /* number of bytes when data is uncompressed */
105 /* optional reserved area */
106 /* compressed data */
112 char name
[CB_MAX_FILENAME
];
118 struct list files_list
;
119 struct list blocks_list
;
120 struct temp_file data
;
121 cab_ULONG data_start
;
122 cab_UWORD data_count
;
129 cab_ULONG size
; /* uncompressed size */
130 cab_ULONG offset
; /* offset in folder */
131 cab_UWORD folder
; /* index of folder */
141 cab_UWORD compressed
;
142 cab_UWORD uncompressed
;
145 typedef struct FCI_Int
149 PFNFCIFILEPLACED fileplaced
;
158 PFNFCIGETTEMPFILE gettemp
;
164 cab_ULONG statusFolderCopied
;
165 cab_ULONG statusFolderTotal
;
166 BOOL fGetNextCabInVain
;
168 char szPrevCab
[CB_MAX_CABINET_NAME
]; /* previous cabinet name */
169 char szPrevDisk
[CB_MAX_DISK_NAME
]; /* disk name of previous cabinet */
170 unsigned char *data_in
; /* uncompressed data blocks */
172 unsigned char *data_out
; /* compressed data blocks */
173 ULONG cCompressedBytesInFolder
;
176 cab_ULONG cDataBlocks
;
177 cab_ULONG cbFileRemainer
; /* uncompressed, yet to be written data */
178 /* of spanned file of a spanning folder of a spanning cabinet */
179 struct temp_file data
;
181 cab_ULONG estimatedCabinetSize
;
182 struct list folders_list
;
183 struct list files_list
;
184 struct list blocks_list
;
185 cab_ULONG folders_size
;
186 cab_ULONG files_size
; /* size of files not yet assigned to a folder */
187 cab_ULONG placed_files_size
; /* size of files already placed into a folder */
188 cab_ULONG pending_data_size
; /* size of data not yet assigned to a folder */
189 cab_ULONG folders_data_size
; /* total size of data contained in the current folders */
191 cab_UWORD (*compress
)(struct FCI_Int
*);
194 #define FCI_INT_MAGIC 0xfcfcfc05
196 static void set_error( FCI_Int
*fci
, int oper
, int err
)
198 fci
->perf
->erfOper
= oper
;
199 fci
->perf
->erfType
= err
;
200 fci
->perf
->fError
= TRUE
;
201 if (err
) SetLastError( err
);
204 static FCI_Int
*get_fci_ptr( HFCI hfci
)
206 FCI_Int
*fci
= (FCI_Int
*)hfci
;
208 if (!fci
|| !fci
->magic
== FCI_INT_MAGIC
)
210 SetLastError( ERROR_INVALID_HANDLE
);
216 /* compute the cabinet header size */
217 static cab_ULONG
get_header_size( FCI_Int
*fci
)
219 cab_ULONG ret
= sizeof(CFHEADER
) + fci
->ccab
.cbReserveCFHeader
;
221 if (fci
->ccab
.cbReserveCFHeader
|| fci
->ccab
.cbReserveCFFolder
|| fci
->ccab
.cbReserveCFData
)
225 ret
+= strlen( fci
->szPrevCab
) + 1 + strlen( fci
->szPrevDisk
) + 1;
228 ret
+= strlen( fci
->pccab
->szCab
) + 1 + strlen( fci
->pccab
->szDisk
) + 1;
233 static BOOL
create_temp_file( FCI_Int
*fci
, struct temp_file
*file
)
237 if (!fci
->gettemp( file
->name
, CB_MAX_FILENAME
, fci
->pv
))
239 set_error( fci
, FCIERR_TEMP_FILE
, ERROR_FUNCTION_FAILED
);
242 if ((file
->handle
= fci
->open( file
->name
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
243 _S_IREAD
| _S_IWRITE
, &err
, fci
->pv
)) == -1)
245 set_error( fci
, FCIERR_TEMP_FILE
, err
);
251 static BOOL
close_temp_file( FCI_Int
*fci
, struct temp_file
*file
)
255 if (file
->handle
== -1) return TRUE
;
256 if (fci
->close( file
->handle
, &err
, fci
->pv
) == -1)
258 set_error( fci
, FCIERR_TEMP_FILE
, err
);
262 if (fci
->delete( file
->name
, &err
, fci
->pv
) == -1)
264 set_error( fci
, FCIERR_TEMP_FILE
, err
);
270 static struct file
*add_file( FCI_Int
*fci
, const char *filename
)
272 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(filename
) + 1] );
273 struct file
*file
= fci
->alloc( size
);
277 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
281 file
->offset
= fci
->cDataBlocks
* CAB_BLOCKMAX
+ fci
->cdata_in
;
282 file
->folder
= fci
->cFolders
;
286 strcpy( file
->name
, filename
);
287 list_add_tail( &fci
->files_list
, &file
->entry
);
288 fci
->files_size
+= sizeof(CFFILE
) + strlen(filename
) + 1;
292 static struct file
*copy_file( FCI_Int
*fci
, const struct file
*orig
)
294 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(orig
->name
) + 1] );
295 struct file
*file
= fci
->alloc( size
);
299 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
302 memcpy( file
, orig
, size
);
306 static void free_file( FCI_Int
*fci
, struct file
*file
)
308 list_remove( &file
->entry
);
312 /* create a new data block for the data in fci->data_in */
313 static BOOL
add_data_block( FCI_Int
*fci
, PFNFCISTATUS status_callback
)
316 struct data_block
*block
;
318 if (!fci
->cdata_in
) return TRUE
;
320 if (fci
->data
.handle
== -1 && !create_temp_file( fci
, &fci
->data
)) return FALSE
;
322 if (!(block
= fci
->alloc( sizeof(*block
) )))
324 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
327 block
->uncompressed
= fci
->cdata_in
;
328 block
->compressed
= fci
->compress( fci
);
330 if (fci
->write( fci
->data
.handle
, fci
->data_out
,
331 block
->compressed
, &err
, fci
->pv
) != block
->compressed
)
333 set_error( fci
, FCIERR_TEMP_FILE
, err
);
339 fci
->pending_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ block
->compressed
;
340 fci
->cCompressedBytesInFolder
+= block
->compressed
;
342 list_add_tail( &fci
->blocks_list
, &block
->entry
);
344 if (status_callback( statusFile
, block
->compressed
, block
->uncompressed
, fci
->pv
) == -1)
346 set_error( fci
, FCIERR_USER_ABORT
, 0 );
352 /* add compressed blocks for all the data that can be read from the file */
353 static BOOL
add_file_data( FCI_Int
*fci
, char *sourcefile
, char *filename
, BOOL execute
,
354 PFNFCIGETOPENINFO get_open_info
, PFNFCISTATUS status_callback
)
360 /* make sure we have buffers */
361 if (!fci
->data_in
&& !(fci
->data_in
= fci
->alloc( CB_MAX_CHUNK
)))
363 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
366 if (!fci
->data_out
&& !(fci
->data_out
= fci
->alloc( 2 * CB_MAX_CHUNK
)))
368 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
372 if (!(file
= add_file( fci
, filename
))) return FALSE
;
374 handle
= get_open_info( sourcefile
, &file
->date
, &file
->time
, &file
->attribs
, &err
, fci
->pv
);
377 free_file( fci
, file
);
378 set_error( fci
, FCIERR_OPEN_SRC
, err
);
381 if (execute
) file
->attribs
|= _A_EXEC
;
385 len
= fci
->read( handle
, fci
->data_in
+ fci
->cdata_in
,
386 CAB_BLOCKMAX
- fci
->cdata_in
, &err
, fci
->pv
);
391 set_error( fci
, FCIERR_READ_SRC
, err
);
395 fci
->cdata_in
+= len
;
396 if (fci
->cdata_in
== CAB_BLOCKMAX
&& !add_data_block( fci
, status_callback
)) return FALSE
;
398 fci
->close( handle
, &err
, fci
->pv
);
402 static void free_data_block( FCI_Int
*fci
, struct data_block
*block
)
404 list_remove( &block
->entry
);
408 static struct folder
*add_folder( FCI_Int
*fci
)
410 struct folder
*folder
= fci
->alloc( sizeof(*folder
) );
414 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
417 folder
->data
.handle
= -1;
418 folder
->data_start
= fci
->folders_data_size
;
419 folder
->data_count
= 0;
420 folder
->compression
= fci
->compression
;
421 list_init( &folder
->files_list
);
422 list_init( &folder
->blocks_list
);
423 list_add_tail( &fci
->folders_list
, &folder
->entry
);
424 fci
->folders_size
+= sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
;
429 static void free_folder( FCI_Int
*fci
, struct folder
*folder
)
431 struct file
*file
, *file_next
;
432 struct data_block
*block
, *block_next
;
434 LIST_FOR_EACH_ENTRY_SAFE( file
, file_next
, &folder
->files_list
, struct file
, entry
)
435 free_file( fci
, file
);
436 LIST_FOR_EACH_ENTRY_SAFE( block
, block_next
, &folder
->blocks_list
, struct data_block
, entry
)
437 free_data_block( fci
, block
);
438 close_temp_file( fci
, &folder
->data
);
439 list_remove( &folder
->entry
);
443 /* reset state for the next cabinet file once the current one has been flushed */
444 static void reset_cabinet( FCI_Int
*fci
)
446 struct folder
*folder
, *folder_next
;
448 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &fci
->folders_list
, struct folder
, entry
)
449 free_folder( fci
, folder
);
453 fci
->folders_size
= 0;
454 fci
->placed_files_size
= 0;
455 fci
->folders_data_size
= 0;
458 static cab_ULONG
fci_get_checksum( const void *pv
, UINT cb
, cab_ULONG seed
)
469 while (cUlong
-- > 0) {
471 ul
|= (((cab_ULONG
)(*pb
++)) << 8);
472 ul
|= (((cab_ULONG
)(*pb
++)) << 16);
473 ul
|= (((cab_ULONG
)(*pb
++)) << 24);
480 ul
|= (((ULONG
)(*pb
++)) << 16);
482 ul
|= (((ULONG
)(*pb
++)) << 8);
493 /* copy all remaining data block to a new temp file */
494 static BOOL
copy_data_blocks( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG start_pos
,
495 struct temp_file
*temp
, PFNFCISTATUS status_callback
)
497 struct data_block
*block
;
500 if (fci
->seek( handle
, start_pos
, SEEK_SET
, &err
, fci
->pv
) != start_pos
)
502 set_error( fci
, FCIERR_TEMP_FILE
, err
);
505 if (!create_temp_file( fci
, temp
)) return FALSE
;
507 LIST_FOR_EACH_ENTRY( block
, &fci
->blocks_list
, struct data_block
, entry
)
509 if (fci
->read( handle
, fci
->data_out
, block
->compressed
,
510 &err
, fci
->pv
) != block
->compressed
)
512 close_temp_file( fci
, temp
);
513 set_error( fci
, FCIERR_TEMP_FILE
, err
);
516 if (fci
->write( temp
->handle
, fci
->data_out
, block
->compressed
,
517 &err
, fci
->pv
) != block
->compressed
)
519 close_temp_file( fci
, temp
);
520 set_error( fci
, FCIERR_TEMP_FILE
, err
);
523 fci
->pending_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ block
->compressed
;
524 fci
->statusFolderCopied
+= block
->compressed
;
526 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
527 fci
->statusFolderTotal
, fci
->pv
) == -1)
529 close_temp_file( fci
, temp
);
530 set_error( fci
, FCIERR_USER_ABORT
, 0 );
537 /* write all folders to disk and remove them from the list */
538 static BOOL
write_folders( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG header_size
, PFNFCISTATUS status_callback
)
540 struct folder
*folder
;
544 cab_ULONG folder_size
= sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
;
546 if (!(cffolder
= fci
->alloc( folder_size
)))
548 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
551 memset( cffolder
, 0, folder_size
);
553 /* write the folders */
554 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
556 cffolder
->coffCabStart
= fci_endian_ulong( folder
->data_start
+ header_size
);
557 cffolder
->cCFData
= fci_endian_uword( folder
->data_count
);
558 cffolder
->typeCompress
= fci_endian_uword( folder
->compression
);
559 if (fci
->write( handle
, cffolder
, folder_size
, &err
, fci
->pv
) != folder_size
)
561 set_error( fci
, FCIERR_CAB_FILE
, err
);
567 fci
->free( cffolder
);
571 /* write all the files to the cabinet file */
572 static BOOL
write_files( FCI_Int
*fci
, INT_PTR handle
, PFNFCISTATUS status_callback
)
575 struct folder
*folder
;
581 if (!(cffile
= fci
->alloc( sizeof(CFFILE
) + CB_MAX_FILENAME
)))
583 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
587 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
589 LIST_FOR_EACH_ENTRY( file
, &folder
->files_list
, struct file
, entry
)
591 cffile
->cbFile
= fci_endian_ulong( file
->size
);
592 cffile
->uoffFolderStart
= fci_endian_ulong( file
->offset
);
593 cffile
->iFolder
= fci_endian_uword( file
->folder
);
594 cffile
->date
= fci_endian_uword( file
->date
);
595 cffile
->time
= fci_endian_uword( file
->time
);
596 cffile
->attribs
= fci_endian_uword( file
->attribs
);
597 lstrcpynA( (char *)(cffile
+ 1), file
->name
, CB_MAX_FILENAME
);
598 file_size
= sizeof(CFFILE
) + strlen( (char *)(cffile
+ 1) ) + 1;
599 if (fci
->write( handle
, cffile
, file_size
, &err
, fci
->pv
) != file_size
)
601 set_error( fci
, FCIERR_CAB_FILE
, err
);
605 if (!fci
->fSplitFolder
)
607 fci
->statusFolderCopied
= 0;
608 /* TODO TEST THIS further */
609 fci
->statusFolderTotal
= fci
->folders_data_size
+ fci
->placed_files_size
;
611 fci
->statusFolderCopied
+= file_size
;
612 /* report status about copied size of folder */
613 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
614 fci
->statusFolderTotal
, fci
->pv
) == -1)
616 set_error( fci
, FCIERR_USER_ABORT
, 0 );
627 /* write all data blocks to the cabinet file */
628 static BOOL
write_data_blocks( FCI_Int
*fci
, INT_PTR handle
, PFNFCISTATUS status_callback
)
630 struct folder
*folder
;
631 struct data_block
*block
;
635 cab_UWORD header_size
;
637 if (!fci
->data_out
) return TRUE
;
639 header_size
= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
;
640 cfdata
= (CFDATA
*)fci
->data_out
;
641 memset( cfdata
, 0, header_size
);
642 data
= (char *)cfdata
+ header_size
;
644 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
646 if (fci
->seek( folder
->data
.handle
, 0, SEEK_SET
, &err
, fci
->pv
) != 0)
648 set_error( fci
, FCIERR_CAB_FILE
, err
);
651 LIST_FOR_EACH_ENTRY( block
, &folder
->blocks_list
, struct data_block
, entry
)
653 len
= fci
->read( folder
->data
.handle
, data
, block
->compressed
, &err
, fci
->pv
);
654 if (len
!= block
->compressed
) return FALSE
;
656 cfdata
->cbData
= fci_endian_uword( block
->compressed
);
657 cfdata
->cbUncomp
= fci_endian_uword( block
->uncompressed
);
658 cfdata
->csum
= fci_endian_ulong( fci_get_checksum( &cfdata
->cbData
,
659 header_size
- FIELD_OFFSET(CFDATA
, cbData
),
660 fci_get_checksum( data
, len
, 0 )));
662 fci
->statusFolderCopied
+= len
;
664 if (fci
->write( handle
, fci
->data_out
, len
, &err
, fci
->pv
) != len
)
666 set_error( fci
, FCIERR_CAB_FILE
, err
);
669 if (status_callback( statusFolder
, fci
->statusFolderCopied
, fci
->statusFolderTotal
, fci
->pv
) == -1)
671 set_error( fci
, FCIERR_USER_ABORT
, 0 );
679 /* write the cabinet file to disk */
680 static BOOL
write_cabinet( FCI_Int
*fci
, PFNFCISTATUS status_callback
)
682 char filename
[CB_MAX_CAB_PATH
+ CB_MAX_CABINET_NAME
];
688 cab_ULONG header_size
= get_header_size( fci
);
689 cab_ULONG total_size
= header_size
+ fci
->folders_size
+ fci
->placed_files_size
+ fci
->folders_data_size
;
691 if (!(cfheader
= fci
->alloc( header_size
)))
693 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
696 memset( cfheader
, 0, header_size
);
698 if (fci
->fPrevCab
) flags
|= cfheadPREV_CABINET
;
699 if (fci
->fNextCab
) flags
|= cfheadNEXT_CABINET
;
700 if (fci
->ccab
.cbReserveCFHeader
|| fci
->ccab
.cbReserveCFFolder
|| fci
->ccab
.cbReserveCFData
)
701 flags
|= cfheadRESERVE_PRESENT
;
703 memcpy( cfheader
->signature
, "!CAB", 4 );
704 cfheader
->cbCabinet
= fci_endian_ulong( total_size
);
705 cfheader
->coffFiles
= fci_endian_ulong( header_size
+ fci
->folders_size
);
706 cfheader
->versionMinor
= 3;
707 cfheader
->versionMajor
= 1;
708 cfheader
->cFolders
= fci_endian_uword( fci
->cFolders
);
709 cfheader
->cFiles
= fci_endian_uword( fci
->cFiles
);
710 cfheader
->flags
= fci_endian_uword( flags
);
711 cfheader
->setID
= fci_endian_uword( fci
->ccab
.setID
);
712 cfheader
->iCabinet
= fci_endian_uword( fci
->ccab
.iCab
- 1 );
713 ptr
= (char *)(cfheader
+ 1);
715 if (flags
& cfheadRESERVE_PRESENT
)
719 cab_UWORD cbCFHeader
;
720 cab_UBYTE cbCFFolder
;
722 } *reserve
= (void *)ptr
;
724 reserve
->cbCFHeader
= fci_endian_uword( fci
->ccab
.cbReserveCFHeader
);
725 reserve
->cbCFFolder
= fci
->ccab
.cbReserveCFFolder
;
726 reserve
->cbCFData
= fci
->ccab
.cbReserveCFData
;
727 ptr
= (char *)(reserve
+ 1);
729 ptr
+= fci
->ccab
.cbReserveCFHeader
;
731 if (flags
& cfheadPREV_CABINET
)
733 strcpy( ptr
, fci
->szPrevCab
);
734 ptr
+= strlen( ptr
) + 1;
735 strcpy( ptr
, fci
->szPrevDisk
);
736 ptr
+= strlen( ptr
) + 1;
739 if (flags
& cfheadNEXT_CABINET
)
741 strcpy( ptr
, fci
->pccab
->szCab
);
742 ptr
+= strlen( ptr
) + 1;
743 strcpy( ptr
, fci
->pccab
->szDisk
);
744 ptr
+= strlen( ptr
) + 1;
747 assert( ptr
- (char *)cfheader
== header_size
);
749 strcpy( filename
, fci
->ccab
.szCabPath
);
750 strcat( filename
, fci
->ccab
.szCab
);
752 if ((handle
= fci
->open( filename
, _O_RDWR
| _O_CREAT
| _O_TRUNC
| _O_BINARY
,
753 _S_IREAD
| _S_IWRITE
, &err
, fci
->pv
)) == -1)
755 set_error( fci
, FCIERR_CAB_FILE
, err
);
756 fci
->free( cfheader
);
760 if (fci
->write( handle
, cfheader
, header_size
, &err
, fci
->pv
) != header_size
)
762 set_error( fci
, FCIERR_CAB_FILE
, err
);
766 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
767 header_size
+= fci
->placed_files_size
+ fci
->folders_size
;
768 if (!write_folders( fci
, handle
, header_size
, status_callback
)) goto failed
;
769 if (!write_files( fci
, handle
, status_callback
)) goto failed
;
770 if (!write_data_blocks( fci
, handle
, status_callback
)) goto failed
;
772 /* update the signature */
773 if (fci
->seek( handle
, 0, SEEK_SET
, &err
, fci
->pv
) != 0 )
775 set_error( fci
, FCIERR_CAB_FILE
, err
);
778 memcpy( cfheader
->signature
, "MSCF", 4 );
779 if (fci
->write( handle
, cfheader
->signature
, 4, &err
, fci
->pv
) != 4)
781 set_error( fci
, FCIERR_CAB_FILE
, err
);
784 fci
->close( handle
, &err
, fci
->pv
);
785 fci
->free( cfheader
);
787 reset_cabinet( fci
);
788 status_callback( statusCabinet
, fci
->estimatedCabinetSize
, total_size
, fci
->pv
);
792 fci
->close( handle
, &err
, fci
->pv
);
793 fci
->delete( filename
, &err
, fci
->pv
);
794 fci
->free( cfheader
);
798 /* add all pending data blocks folder */
799 static BOOL
add_data_to_folder( FCI_Int
*fci
, struct folder
*folder
, cab_ULONG
*payload
,
800 PFNFCISTATUS status_callback
)
802 struct data_block
*block
, *new, *next
;
803 BOOL split_block
= FALSE
;
804 cab_ULONG current_size
, start_pos
= 0;
807 current_size
= get_header_size( fci
) + fci
->folders_size
+
808 fci
->files_size
+ fci
->placed_files_size
+ fci
->folders_data_size
;
810 /* move the temp file into the folder structure */
811 folder
->data
= fci
->data
;
812 fci
->data
.handle
= -1;
813 fci
->pending_data_size
= 0;
815 LIST_FOR_EACH_ENTRY_SAFE( block
, next
, &fci
->blocks_list
, struct data_block
, entry
)
817 /* No more CFDATA fits into the cabinet under construction */
818 /* So don't try to store more data into it */
819 if (fci
->fNextCab
&& (fci
->ccab
.cb
<= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+
820 current_size
+ sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
))
823 if (!(new = fci
->alloc( sizeof(*new) )))
825 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
828 /* Is cabinet with new CFDATA too large? Then data block has to be split */
830 (fci
->ccab
.cb
< sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+
831 block
->compressed
+ current_size
+ sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
))
833 /* Modify the size of the compressed data to store only a part of the */
834 /* data block into the current cabinet. This is done to prevent */
835 /* that the maximum cabinet size will be exceeded. The remainder */
836 /* will be stored into the next following cabinet. */
838 new->compressed
= fci
->ccab
.cb
- (sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ current_size
+
839 sizeof(CFFOLDER
) + fci
->ccab
.cbReserveCFFolder
);
840 new->uncompressed
= 0; /* on split blocks of data this is zero */
841 block
->compressed
-= new->compressed
;
846 new->compressed
= block
->compressed
;
847 new->uncompressed
= block
->uncompressed
;
850 start_pos
+= new->compressed
;
851 current_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ new->compressed
;
852 fci
->folders_data_size
+= sizeof(CFDATA
) + fci
->ccab
.cbReserveCFData
+ new->compressed
;
853 fci
->statusFolderCopied
+= new->compressed
;
854 (*payload
) += new->uncompressed
;
856 list_add_tail( &folder
->blocks_list
, &new->entry
);
857 folder
->data_count
++;
859 /* report status with pfnfcis about copied size of folder */
860 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
861 fci
->statusFolderTotal
, fci
->pv
) == -1)
863 set_error( fci
, FCIERR_USER_ABORT
, 0 );
866 if (split_block
) break;
867 free_data_block( fci
, block
);
871 if (list_empty( &fci
->blocks_list
)) return TRUE
;
872 return copy_data_blocks( fci
, folder
->data
.handle
, start_pos
, &fci
->data
, status_callback
);
875 /* add all pending files to folder */
876 static BOOL
add_files_to_folder( FCI_Int
*fci
, struct folder
*folder
, cab_ULONG payload
)
878 cab_ULONG sizeOfFiles
= 0, sizeOfFilesPrev
;
879 cab_ULONG cbFileRemainer
= 0;
880 struct file
*file
, *next
;
882 LIST_FOR_EACH_ENTRY_SAFE( file
, next
, &fci
->files_list
, struct file
, entry
)
884 cab_ULONG size
= sizeof(CFFILE
) + strlen(file
->name
) + 1;
886 /* fnfilfnfildest: placed file on cabinet */
887 fci
->fileplaced( &fci
->ccab
, file
->name
, file
->size
,
888 (file
->folder
== cffileCONTINUED_FROM_PREV
), fci
->pv
);
890 sizeOfFilesPrev
= sizeOfFiles
;
891 /* set complete size of all processed files */
892 if (file
->folder
== cffileCONTINUED_FROM_PREV
&& fci
->cbFileRemainer
!= 0)
894 sizeOfFiles
+= fci
->cbFileRemainer
;
895 fci
->cbFileRemainer
= 0;
897 else sizeOfFiles
+= file
->size
;
899 /* check if spanned file fits into this cabinet folder */
900 if (sizeOfFiles
> payload
)
902 if (file
->folder
== cffileCONTINUED_FROM_PREV
)
903 file
->folder
= cffileCONTINUED_PREV_AND_NEXT
;
905 file
->folder
= cffileCONTINUED_TO_NEXT
;
908 list_remove( &file
->entry
);
909 list_add_tail( &folder
->files_list
, &file
->entry
);
910 fci
->placed_files_size
+= size
;
913 /* This is only true for files which will be written into the */
914 /* next cabinet of the spanning folder */
915 if (sizeOfFiles
> payload
)
917 /* add a copy back onto the list */
918 if (!(file
= copy_file( fci
, file
))) return FALSE
;
919 list_add_before( &next
->entry
, &file
->entry
);
921 /* Files which data will be partially written into the current cabinet */
922 if (file
->folder
== cffileCONTINUED_PREV_AND_NEXT
|| file
->folder
== cffileCONTINUED_TO_NEXT
)
924 if (sizeOfFilesPrev
<= payload
)
926 /* The size of the uncompressed, data of a spanning file in a */
928 cbFileRemainer
= sizeOfFiles
- payload
;
930 file
->folder
= cffileCONTINUED_FROM_PREV
;
932 else file
->folder
= 0;
936 fci
->files_size
-= size
;
939 fci
->cbFileRemainer
= cbFileRemainer
;
943 static cab_UWORD
compress_NONE( FCI_Int
*fci
)
945 memcpy( fci
->data_out
, fci
->data_in
, fci
->cdata_in
);
946 return fci
->cdata_in
;
951 static void *zalloc( void *opaque
, unsigned int items
, unsigned int size
)
953 FCI_Int
*fci
= opaque
;
954 return fci
->alloc( items
* size
);
957 static void zfree( void *opaque
, void *ptr
)
959 FCI_Int
*fci
= opaque
;
960 return fci
->free( ptr
);
963 static cab_UWORD
compress_MSZIP( FCI_Int
*fci
)
967 stream
.zalloc
= zalloc
;
968 stream
.zfree
= zfree
;
970 if (deflateInit2( &stream
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
, -15, 8, Z_DEFAULT_STRATEGY
) != Z_OK
)
972 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
975 stream
.next_in
= fci
->data_in
;
976 stream
.avail_in
= fci
->cdata_in
;
977 stream
.next_out
= fci
->data_out
+ 2;
978 stream
.avail_out
= 2 * CB_MAX_CHUNK
- 2;
979 /* insert the signature */
980 fci
->data_out
[0] = 'C';
981 fci
->data_out
[1] = 'K';
982 deflate( &stream
, Z_FINISH
);
983 deflateEnd( &stream
);
984 return stream
.total_out
+ 2;
987 #endif /* HAVE_ZLIB */
990 /***********************************************************************
991 * FCICreate (CABINET.10)
993 * FCICreate is provided with several callbacks and
994 * returns a handle which can be used to create cabinet files.
997 * perf [IO] A pointer to an ERF structure. When FCICreate
998 * returns an error condition, error information may
999 * be found here as well as from GetLastError.
1000 * pfnfiledest [I] A pointer to a function which is called when a file
1001 * is placed. Only useful for subsequent cabinet files.
1002 * pfnalloc [I] A pointer to a function which allocates ram. Uses
1003 * the same interface as malloc.
1004 * pfnfree [I] A pointer to a function which frees ram. Uses the
1005 * same interface as free.
1006 * pfnopen [I] A pointer to a function which opens a file. Uses
1007 * the same interface as _open.
1008 * pfnread [I] A pointer to a function which reads from a file into
1009 * a caller-provided buffer. Uses the same interface
1011 * pfnwrite [I] A pointer to a function which writes to a file from
1012 * a caller-provided buffer. Uses the same interface
1014 * pfnclose [I] A pointer to a function which closes a file handle.
1015 * Uses the same interface as _close.
1016 * pfnseek [I] A pointer to a function which seeks in a file.
1017 * Uses the same interface as _lseek.
1018 * pfndelete [I] A pointer to a function which deletes a file.
1019 * pfnfcigtf [I] A pointer to a function which gets the name of a
1021 * pccab [I] A pointer to an initialized CCAB structure.
1022 * pv [I] A pointer to an application-defined notification
1023 * function which will be passed to other FCI functions
1027 * On success, returns an FCI handle of type HFCI.
1028 * On failure, the NULL file handle is returned. Error
1029 * info can be retrieved from perf.
1035 HFCI __cdecl
FCICreate(
1037 PFNFCIFILEPLACED pfnfiledest
,
1038 PFNFCIALLOC pfnalloc
,
1042 PFNFCIWRITE pfnwrite
,
1043 PFNFCICLOSE pfnclose
,
1045 PFNFCIDELETE pfndelete
,
1046 PFNFCIGETTEMPFILE pfnfcigtf
,
1050 FCI_Int
*p_fci_internal
;
1053 SetLastError(ERROR_BAD_ARGUMENTS
);
1056 if ((!pfnalloc
) || (!pfnfree
) || (!pfnopen
) || (!pfnread
) ||
1057 (!pfnwrite
) || (!pfnclose
) || (!pfnseek
) || (!pfndelete
) ||
1058 (!pfnfcigtf
) || (!pccab
)) {
1059 perf
->erfOper
= FCIERR_NONE
;
1060 perf
->erfType
= ERROR_BAD_ARGUMENTS
;
1061 perf
->fError
= TRUE
;
1063 SetLastError(ERROR_BAD_ARGUMENTS
);
1067 if (!((p_fci_internal
= pfnalloc(sizeof(FCI_Int
))))) {
1068 perf
->erfOper
= FCIERR_ALLOC_FAIL
;
1069 perf
->erfType
= ERROR_NOT_ENOUGH_MEMORY
;
1070 perf
->fError
= TRUE
;
1072 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1076 p_fci_internal
->magic
= FCI_INT_MAGIC
;
1077 p_fci_internal
->perf
= perf
;
1078 p_fci_internal
->fileplaced
= pfnfiledest
;
1079 p_fci_internal
->alloc
= pfnalloc
;
1080 p_fci_internal
->free
= pfnfree
;
1081 p_fci_internal
->open
= pfnopen
;
1082 p_fci_internal
->read
= pfnread
;
1083 p_fci_internal
->write
= pfnwrite
;
1084 p_fci_internal
->close
= pfnclose
;
1085 p_fci_internal
->seek
= pfnseek
;
1086 p_fci_internal
->delete = pfndelete
;
1087 p_fci_internal
->gettemp
= pfnfcigtf
;
1088 p_fci_internal
->ccab
= *pccab
;
1089 p_fci_internal
->pccab
= pccab
;
1090 p_fci_internal
->fPrevCab
= FALSE
;
1091 p_fci_internal
->fNextCab
= FALSE
;
1092 p_fci_internal
->fSplitFolder
= FALSE
;
1093 p_fci_internal
->fGetNextCabInVain
= FALSE
;
1094 p_fci_internal
->pv
= pv
;
1095 p_fci_internal
->data_in
= NULL
;
1096 p_fci_internal
->cdata_in
= 0;
1097 p_fci_internal
->data_out
= NULL
;
1098 p_fci_internal
->cCompressedBytesInFolder
= 0;
1099 p_fci_internal
->cFolders
= 0;
1100 p_fci_internal
->cFiles
= 0;
1101 p_fci_internal
->cDataBlocks
= 0;
1102 p_fci_internal
->data
.handle
= -1;
1103 p_fci_internal
->fNewPrevious
= FALSE
;
1104 p_fci_internal
->estimatedCabinetSize
= 0;
1105 p_fci_internal
->statusFolderTotal
= 0;
1106 p_fci_internal
->folders_size
= 0;
1107 p_fci_internal
->files_size
= 0;
1108 p_fci_internal
->placed_files_size
= 0;
1109 p_fci_internal
->pending_data_size
= 0;
1110 p_fci_internal
->folders_data_size
= 0;
1111 p_fci_internal
->compression
= tcompTYPE_NONE
;
1112 p_fci_internal
->compress
= compress_NONE
;
1114 list_init( &p_fci_internal
->folders_list
);
1115 list_init( &p_fci_internal
->files_list
);
1116 list_init( &p_fci_internal
->blocks_list
);
1118 memcpy(p_fci_internal
->szPrevCab
, pccab
->szCab
, CB_MAX_CABINET_NAME
);
1119 memcpy(p_fci_internal
->szPrevDisk
, pccab
->szDisk
, CB_MAX_DISK_NAME
);
1121 return (HFCI
)p_fci_internal
;
1127 static BOOL
fci_flush_folder( FCI_Int
*p_fci_internal
,
1129 PFNFCIGETNEXTCABINET pfnfcignc
,
1130 PFNFCISTATUS pfnfcis
)
1133 cab_ULONG read_result
;
1134 struct folder
*folder
;
1136 if ((!pfnfcignc
) || (!pfnfcis
)) {
1137 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1141 if( p_fci_internal
->fGetNextCabInVain
&&
1142 p_fci_internal
->fNextCab
){
1143 /* internal error */
1144 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1148 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1149 /* this function will return TRUE */
1150 if( p_fci_internal
->files_size
== 0 ) {
1151 if ( p_fci_internal
->pending_data_size
!= 0 ) {
1152 /* error handling */
1153 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1159 if (p_fci_internal
->data_in
==NULL
|| p_fci_internal
->data_out
==NULL
) {
1160 /* error handling */
1161 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1165 /* FCIFlushFolder has already been called... */
1166 if (p_fci_internal
->fSplitFolder
&& p_fci_internal
->placed_files_size
!=0) {
1170 /* This can be set already, because it makes only a difference */
1171 /* when the current function exits with return FALSE */
1172 p_fci_internal
->fSplitFolder
=FALSE
;
1175 if (!add_data_block( p_fci_internal
, pfnfcis
)) return FALSE
;
1177 /* reset to get the number of data blocks of this folder which are */
1178 /* actually in this cabinet ( at least partially ) */
1179 p_fci_internal
->cDataBlocks
=0;
1181 p_fci_internal
->statusFolderTotal
= get_header_size( p_fci_internal
) +
1182 sizeof(CFFOLDER
) + p_fci_internal
->ccab
.cbReserveCFFolder
+
1183 p_fci_internal
->placed_files_size
+
1184 p_fci_internal
->folders_data_size
+ p_fci_internal
->files_size
+
1185 p_fci_internal
->pending_data_size
+ p_fci_internal
->folders_size
;
1186 p_fci_internal
->statusFolderCopied
= 0;
1188 /* report status with pfnfcis about copied size of folder */
1189 if( (*pfnfcis
)(statusFolder
, p_fci_internal
->statusFolderCopied
,
1190 p_fci_internal
->statusFolderTotal
, /* TODO total folder size */
1191 p_fci_internal
->pv
) == -1) {
1192 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1196 /* USE the variable read_result */
1197 read_result
= get_header_size( p_fci_internal
) + p_fci_internal
->folders_data_size
+
1198 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
;
1200 if(p_fci_internal
->files_size
!=0) {
1201 read_result
+= sizeof(CFFOLDER
)+p_fci_internal
->ccab
.cbReserveCFFolder
;
1204 /* Check if multiple cabinets have to be created. */
1206 /* Might be too much data for the maximum allowed cabinet size.*/
1207 /* When any further data will be added later, it might not */
1208 /* be possible to flush the cabinet, because there might */
1209 /* not be enough space to store the name of the following */
1210 /* cabinet and name of the corresponding disk. */
1211 /* So take care of this and get the name of the next cabinet */
1212 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1213 p_fci_internal
->fNextCab
==FALSE
&&
1216 p_fci_internal
->ccab
.cb
< read_result
+
1217 p_fci_internal
->pending_data_size
+
1218 p_fci_internal
->files_size
+
1219 CB_MAX_CABINET_NAME
+ /* next cabinet name */
1220 CB_MAX_DISK_NAME
/* next disk name */
1224 /* increment cabinet index */
1225 ++(p_fci_internal
->pccab
->iCab
);
1226 /* get name of next cabinet */
1227 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1228 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1229 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1230 p_fci_internal
->pv
)) {
1231 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1235 /* Skip a few lines of code. This is caught by the next if. */
1236 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1239 /* too much data for cabinet */
1240 if( (p_fci_internal
->fGetNextCabInVain
||
1241 p_fci_internal
->fNextCab
) &&
1244 p_fci_internal
->ccab
.cb
< read_result
+
1245 p_fci_internal
->pending_data_size
+
1246 p_fci_internal
->files_size
+
1247 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1248 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1252 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1253 p_fci_internal
->fNextCab
=TRUE
;
1255 /* return FALSE if there is not enough space left*/
1256 /* this should never happen */
1257 if (p_fci_internal
->ccab
.cb
<=
1258 p_fci_internal
->files_size
+
1260 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1261 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1267 /* the folder will be split across cabinets */
1268 p_fci_internal
->fSplitFolder
=TRUE
;
1271 /* this should never happen */
1272 if (p_fci_internal
->fNextCab
) {
1273 /* internal error */
1274 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1279 if (!(folder
= add_folder( p_fci_internal
))) return FALSE
;
1280 if (!add_data_to_folder( p_fci_internal
, folder
, &payload
, pfnfcis
)) return FALSE
;
1281 if (!add_files_to_folder( p_fci_internal
, folder
, payload
)) return FALSE
;
1283 /* reset CFFolder specific information */
1284 p_fci_internal
->cDataBlocks
=0;
1285 p_fci_internal
->cCompressedBytesInFolder
=0;
1293 static BOOL
fci_flush_cabinet( FCI_Int
*p_fci_internal
,
1295 PFNFCIGETNEXTCABINET pfnfcignc
,
1296 PFNFCISTATUS pfnfcis
)
1298 cab_ULONG read_result
=0;
1299 BOOL returntrue
=FALSE
;
1301 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1303 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1304 if( p_fci_internal
->files_size
==0 && fGetNextCab
) {
1308 if (!fci_flush_folder(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)){
1309 /* TODO set error */
1313 if(returntrue
) return TRUE
;
1315 if ( (p_fci_internal
->fSplitFolder
&& p_fci_internal
->fNextCab
==FALSE
)||
1316 (p_fci_internal
->folders_size
==0 &&
1317 (p_fci_internal
->files_size
!=0 ||
1318 p_fci_internal
->placed_files_size
!=0 )
1322 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1326 /* create the cabinet */
1327 if (!write_cabinet( p_fci_internal
, pfnfcis
)) return FALSE
;
1329 p_fci_internal
->fPrevCab
=TRUE
;
1330 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1331 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1333 if (p_fci_internal
->fNextCab
) {
1334 p_fci_internal
->fNextCab
=FALSE
;
1336 if (p_fci_internal
->files_size
==0 && p_fci_internal
->pending_data_size
!=0) {
1337 /* THIS CAN NEVER HAPPEN */
1338 /* set error code */
1339 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1343 if( p_fci_internal
->fNewPrevious
) {
1344 memcpy(p_fci_internal
->szPrevCab
, p_fci_internal
->ccab
.szCab
,
1345 CB_MAX_CABINET_NAME
);
1346 memcpy(p_fci_internal
->szPrevDisk
, p_fci_internal
->ccab
.szDisk
,
1348 p_fci_internal
->fNewPrevious
=FALSE
;
1350 p_fci_internal
->ccab
= *p_fci_internal
->pccab
;
1352 /* REUSE the variable read_result */
1353 read_result
=get_header_size( p_fci_internal
);
1354 if(p_fci_internal
->files_size
!=0) {
1355 read_result
+=p_fci_internal
->ccab
.cbReserveCFFolder
;
1357 read_result
+= p_fci_internal
->pending_data_size
+
1358 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1359 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1360 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
1362 /* too much data for the maximum size of a cabinet */
1363 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1364 p_fci_internal
->ccab
.cb
< read_result
) {
1365 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1368 /* Might be too much data for the maximum size of a cabinet.*/
1369 /* When any further data will be added later, it might not */
1370 /* be possible to flush the cabinet, because there might */
1371 /* not be enough space to store the name of the following */
1372 /* cabinet and name of the corresponding disk. */
1373 /* So take care of this and get the name of the next cabinet */
1374 if (p_fci_internal
->fGetNextCabInVain
==FALSE
&& (
1375 p_fci_internal
->ccab
.cb
< read_result
+
1376 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1378 /* increment cabinet index */
1379 ++(p_fci_internal
->pccab
->iCab
);
1380 /* get name of next cabinet */
1381 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1382 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1383 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1384 p_fci_internal
->pv
)) {
1385 /* error handling */
1386 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1389 /* Skip a few lines of code. This is caught by the next if. */
1390 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1393 /* too much data for cabinet */
1394 if (p_fci_internal
->fGetNextCabInVain
&& (
1395 p_fci_internal
->ccab
.cb
< read_result
+
1396 strlen(p_fci_internal
->ccab
.szCab
)+1+
1397 strlen(p_fci_internal
->ccab
.szDisk
)+1
1399 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1400 p_fci_internal
->fNextCab
=TRUE
;
1401 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1404 /* if the FolderThreshold has been reached flush the folder automatically */
1405 if (p_fci_internal
->cCompressedBytesInFolder
>= p_fci_internal
->ccab
.cbFolderThresh
)
1406 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1408 if( p_fci_internal
->files_size
>0 ) {
1409 if( !fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
) ) return FALSE
;
1410 p_fci_internal
->fNewPrevious
=TRUE
;
1413 p_fci_internal
->fNewPrevious
=FALSE
;
1414 if( p_fci_internal
->files_size
>0 || p_fci_internal
->pending_data_size
) {
1415 /* THIS MAY NEVER HAPPEN */
1416 /* set error structures */
1417 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1423 } /* end of fci_flush_cabinet */
1429 /***********************************************************************
1430 * FCIAddFile (CABINET.11)
1432 * FCIAddFile adds a file to the to be created cabinet file
1435 * hfci [I] An HFCI from FCICreate
1436 * pszSourceFile [I] A pointer to a C string which contains the name and
1437 * location of the file which will be added to the cabinet
1438 * pszFileName [I] A pointer to a C string which contains the name under
1439 * which the file will be stored in the cabinet
1440 * fExecute [I] A boolean value which indicates if the file should be
1441 * executed after extraction of self extracting
1443 * pfnfcignc [I] A pointer to a function which gets information about
1445 * pfnfcis [IO] A pointer to a function which will report status
1446 * information about the compression process
1447 * pfnfcioi [I] A pointer to a function which reports file attributes
1448 * and time and date information
1449 * typeCompress [I] Compression type
1452 * On success, returns TRUE
1453 * On failure, returns FALSE
1459 BOOL __cdecl
FCIAddFile(
1461 char *pszSourceFile
,
1464 PFNFCIGETNEXTCABINET pfnfcignc
,
1465 PFNFCISTATUS pfnfcis
,
1466 PFNFCIGETOPENINFO pfnfcigoi
,
1469 cab_ULONG read_result
;
1470 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1472 if (!p_fci_internal
) return FALSE
;
1474 if ((!pszSourceFile
) || (!pszFileName
) || (!pfnfcignc
) || (!pfnfcis
) ||
1475 (!pfnfcigoi
) || strlen(pszFileName
)>=CB_MAX_FILENAME
) {
1476 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1480 if (typeCompress
!= p_fci_internal
->compression
)
1482 if (!FCIFlushFolder( hfci
, pfnfcignc
, pfnfcis
)) return FALSE
;
1483 switch (typeCompress
)
1485 case tcompTYPE_MSZIP
:
1487 p_fci_internal
->compression
= tcompTYPE_MSZIP
;
1488 p_fci_internal
->compress
= compress_MSZIP
;
1492 FIXME( "compression %x not supported, defaulting to none\n", typeCompress
);
1494 case tcompTYPE_NONE
:
1495 p_fci_internal
->compression
= tcompTYPE_NONE
;
1496 p_fci_internal
->compress
= compress_NONE
;
1501 /* TODO check if pszSourceFile??? */
1503 if(p_fci_internal
->fGetNextCabInVain
&& p_fci_internal
->fNextCab
) {
1504 /* internal error */
1505 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1509 if(p_fci_internal
->fNextCab
) {
1510 /* internal error */
1511 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1515 /* REUSE the variable read_result */
1516 read_result
=get_header_size( p_fci_internal
) + p_fci_internal
->ccab
.cbReserveCFFolder
;
1518 read_result
+= sizeof(CFFILE
) + strlen(pszFileName
)+1 +
1519 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1520 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1521 sizeof(CFFOLDER
); /* size of new CFFolder entry */
1523 /* Might be too much data for the maximum size of a cabinet.*/
1524 /* When any further data will be added later, it might not */
1525 /* be possible to flush the cabinet, because there might */
1526 /* not be enough space to store the name of the following */
1527 /* cabinet and name of the corresponding disk. */
1528 /* So take care of this and get the name of the next cabinet */
1529 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1530 p_fci_internal
->fNextCab
==FALSE
&&
1531 ( p_fci_internal
->ccab
.cb
< read_result
+
1532 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1535 /* increment cabinet index */
1536 ++(p_fci_internal
->pccab
->iCab
);
1537 /* get name of next cabinet */
1538 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1539 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1540 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1541 p_fci_internal
->pv
)) {
1542 /* error handling */
1543 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1546 /* Skip a few lines of code. This is caught by the next if. */
1547 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1550 if( p_fci_internal
->fGetNextCabInVain
&&
1551 p_fci_internal
->fNextCab
1553 /* THIS CAN NEVER HAPPEN */
1554 /* set error code */
1555 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1559 /* too much data for cabinet */
1560 if( p_fci_internal
->fGetNextCabInVain
&&
1562 p_fci_internal
->ccab
.cb
< read_result
+
1563 strlen(p_fci_internal
->pccab
->szCab
)+1+
1564 strlen(p_fci_internal
->pccab
->szDisk
)+1
1566 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1567 p_fci_internal
->fNextCab
=TRUE
;
1568 if(!fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
)) return FALSE
;
1571 if( p_fci_internal
->fNextCab
) {
1572 /* THIS MAY NEVER HAPPEN */
1573 /* set error code */
1574 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1578 if (!add_file_data( p_fci_internal
, pszSourceFile
, pszFileName
, fExecute
, pfnfcigoi
, pfnfcis
))
1581 /* REUSE the variable read_result */
1582 read_result
= get_header_size( p_fci_internal
) + p_fci_internal
->ccab
.cbReserveCFFolder
;
1583 read_result
+= p_fci_internal
->pending_data_size
+
1584 p_fci_internal
->files_size
+ p_fci_internal
->folders_data_size
+
1585 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1586 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
1588 /* too much data for the maximum size of a cabinet */
1589 /* (ignoring the unflushed data block) */
1590 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1591 p_fci_internal
->fNextCab
==FALSE
&& /* this is always the case */
1592 p_fci_internal
->ccab
.cb
< read_result
) {
1593 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1596 /* Might be too much data for the maximum size of a cabinet.*/
1597 /* When any further data will be added later, it might not */
1598 /* be possible to flush the cabinet, because there might */
1599 /* not be enough space to store the name of the following */
1600 /* cabinet and name of the corresponding disk. */
1601 /* So take care of this and get the name of the next cabinet */
1602 /* (ignoring the unflushed data block) */
1603 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1604 p_fci_internal
->fNextCab
==FALSE
&&
1605 ( p_fci_internal
->ccab
.cb
< read_result
+
1606 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1609 /* increment cabinet index */
1610 ++(p_fci_internal
->pccab
->iCab
);
1611 /* get name of next cabinet */
1612 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1613 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1614 p_fci_internal
->estimatedCabinetSize
,/* estimated size of cab */
1615 p_fci_internal
->pv
)) {
1616 /* error handling */
1617 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1620 /* Skip a few lines of code. This is caught by the next if. */
1621 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1624 if( p_fci_internal
->fGetNextCabInVain
&&
1625 p_fci_internal
->fNextCab
1627 /* THIS CAN NEVER HAPPEN */
1628 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1632 /* too much data for cabinet */
1633 if( (p_fci_internal
->fGetNextCabInVain
||
1634 p_fci_internal
->fNextCab
) && (
1635 p_fci_internal
->ccab
.cb
< read_result
+
1636 strlen(p_fci_internal
->pccab
->szCab
)+1+
1637 strlen(p_fci_internal
->pccab
->szDisk
)+1
1640 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1641 p_fci_internal
->fNextCab
=TRUE
;
1642 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1645 if( p_fci_internal
->fNextCab
) {
1646 /* THIS MAY NEVER HAPPEN */
1647 /* set error code */
1648 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1652 /* if the FolderThreshold has been reached flush the folder automatically */
1653 if (p_fci_internal
->cCompressedBytesInFolder
>= p_fci_internal
->ccab
.cbFolderThresh
)
1654 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
1657 } /* end of FCIAddFile */
1663 /***********************************************************************
1664 * FCIFlushFolder (CABINET.12)
1666 * FCIFlushFolder completes the CFFolder structure under construction.
1668 * All further data which is added by FCIAddFile will be associated to
1669 * the next CFFolder structure.
1671 * FCIFlushFolder will be called by FCIAddFile automatically if the
1672 * threshold (stored in the member cbFolderThresh of the CCAB structure
1673 * pccab passed to FCICreate) is exceeded.
1675 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1676 * any data will be written into the cabinet file.
1679 * hfci [I] An HFCI from FCICreate
1680 * pfnfcignc [I] A pointer to a function which gets information about
1682 * pfnfcis [IO] A pointer to a function which will report status
1683 * information about the compression process
1686 * On success, returns TRUE
1687 * On failure, returns FALSE
1693 BOOL __cdecl
FCIFlushFolder(
1695 PFNFCIGETNEXTCABINET pfnfcignc
,
1696 PFNFCISTATUS pfnfcis
)
1698 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1700 if (!p_fci_internal
) return FALSE
;
1701 return fci_flush_folder(p_fci_internal
,FALSE
,pfnfcignc
,pfnfcis
);
1706 /***********************************************************************
1707 * FCIFlushCabinet (CABINET.13)
1709 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1710 * into the cabinet file. If the maximum cabinet size (stored in the
1711 * member cb of the CCAB structure pccab passed to FCICreate) has been
1712 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1713 * The remaining data still has to be flushed manually by calling
1716 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1717 * NOT be called again. Then hfci has to be released by FCIDestroy.
1720 * hfci [I] An HFCI from FCICreate
1721 * fGetNextCab [I] Whether you want to add additional files to a
1722 * cabinet set (TRUE) or whether you want to
1723 * finalize it (FALSE)
1724 * pfnfcignc [I] A pointer to a function which gets information about
1726 * pfnfcis [IO] A pointer to a function which will report status
1727 * information about the compression process
1730 * On success, returns TRUE
1731 * On failure, returns FALSE
1737 BOOL __cdecl
FCIFlushCabinet(
1740 PFNFCIGETNEXTCABINET pfnfcignc
,
1741 PFNFCISTATUS pfnfcis
)
1743 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1745 if (!p_fci_internal
) return FALSE
;
1747 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
1749 while( p_fci_internal
->files_size
>0 ||
1750 p_fci_internal
->placed_files_size
>0 ) {
1751 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
1758 /***********************************************************************
1759 * FCIDestroy (CABINET.14)
1761 * Frees a handle created by FCICreate.
1762 * Only reason for failure would be an invalid handle.
1765 * hfci [I] The HFCI to free
1771 BOOL __cdecl
FCIDestroy(HFCI hfci
)
1773 struct folder
*folder
, *folder_next
;
1774 struct file
*file
, *file_next
;
1775 struct data_block
*block
, *block_next
;
1776 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
1778 if (!p_fci_internal
) return FALSE
;
1780 /* before hfci can be removed all temporary files must be closed */
1782 p_fci_internal
->magic
= 0;
1784 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &p_fci_internal
->folders_list
, struct folder
, entry
)
1786 free_folder( p_fci_internal
, folder
);
1788 LIST_FOR_EACH_ENTRY_SAFE( file
, file_next
, &p_fci_internal
->files_list
, struct file
, entry
)
1790 free_file( p_fci_internal
, file
);
1792 LIST_FOR_EACH_ENTRY_SAFE( block
, block_next
, &p_fci_internal
->blocks_list
, struct data_block
, entry
)
1794 free_data_block( p_fci_internal
, block
);
1797 close_temp_file( p_fci_internal
, &p_fci_internal
->data
);
1799 /* data in and out buffers have to be removed */
1800 if (p_fci_internal
->data_in
!=NULL
)
1801 p_fci_internal
->free(p_fci_internal
->data_in
);
1802 if (p_fci_internal
->data_out
!=NULL
)
1803 p_fci_internal
->free(p_fci_internal
->data_out
);
1805 /* hfci can now be removed */
1806 p_fci_internal
->free(hfci
);