2 * File Compression Interface
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
6 * Copyright 2011 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 There is still some work to be done:
27 - no real compression yet
28 - unknown behaviour if files>=2GB or cabinet >=4GB
29 - check if the maximum size for a cabinet is too small to store any data
30 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
49 #include "wine/list.h"
50 #include "wine/debug.h"
53 #ifdef WORDS_BIGENDIAN
54 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
55 #define fci_endian_uword(x) RtlUshortByteSwap(x)
57 #define fci_endian_ulong(x) (x)
58 #define fci_endian_uword(x) (x)
63 cab_UBYTE signature
[4]; /* !CAB for unfinished cabinets else MSCF */
65 cab_ULONG cbCabinet
; /* size of the cabinet file in bytes*/
67 cab_ULONG coffFiles
; /* offset to first CFFILE section */
69 cab_UBYTE versionMinor
; /* 3 */
70 cab_UBYTE versionMajor
; /* 1 */
71 cab_UWORD cFolders
; /* number of CFFOLDER entries in the cabinet*/
72 cab_UWORD cFiles
; /* number of CFFILE entries in the cabinet*/
73 cab_UWORD flags
; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
74 cab_UWORD setID
; /* identification number of all cabinets in a set*/
75 cab_UWORD iCabinet
; /* number of the cabinet in a set */
76 /* additional area if "flags" were set*/
77 } CFHEADER
; /* minimum 36 bytes */
80 cab_ULONG coffCabStart
; /* offset to the folder's first CFDATA section */
81 cab_UWORD cCFData
; /* number of this folder's CFDATA sections */
82 cab_UWORD typeCompress
; /* compression type of data in CFDATA section*/
83 /* additional area if reserve flag was set */
84 } CFFOLDER
; /* minimum 8 bytes */
87 cab_ULONG cbFile
; /* size of the uncompressed file in bytes */
88 cab_ULONG uoffFolderStart
; /* offset of the uncompressed file in the folder */
89 cab_UWORD iFolder
; /* number of folder in the cabinet 0=first */
90 /* for special values see below this structure*/
91 cab_UWORD date
; /* last modification date*/
92 cab_UWORD time
; /* last modification time*/
93 cab_UWORD attribs
; /* DOS fat attributes and UTF indicator */
94 /* ... and a C string with the name of the file */
95 } CFFILE
; /* 16 bytes + name of file */
99 cab_ULONG csum
; /* checksum of this entry*/
100 cab_UWORD cbData
; /* number of compressed bytes */
101 cab_UWORD cbUncomp
; /* number of bytes when data is uncompressed */
102 /* optional reserved area */
103 /* compressed data */
109 struct list files_list
;
110 cab_ULONG data_start
;
111 cab_UWORD data_count
;
112 cab_UWORD compression
;
118 cab_ULONG size
; /* uncompressed size */
119 cab_ULONG offset
; /* offset in folder */
120 cab_UWORD folder
; /* index of folder */
131 PFNFCIFILEPLACED fileplaced
;
140 PFNFCIGETTEMPFILE gettemp
;
145 cab_ULONG statusFolderCopied
;
146 cab_ULONG statusFolderTotal
;
147 BOOL fGetNextCabInVain
;
149 char szPrevCab
[CB_MAX_CABINET_NAME
]; /* previous cabinet name */
150 char szPrevDisk
[CB_MAX_DISK_NAME
]; /* disk name of previous cabinet */
152 char* data_in
; /* uncompressed data blocks */
154 char* data_out
; /* compressed data blocks */
155 ULONG cCompressedBytesInFolder
;
158 cab_ULONG cDataBlocks
;
159 cab_ULONG cbFileRemainer
; /* uncompressed, yet to be written data */
160 /* of spanned file of a spanning folder of a spanning cabinet */
161 char szFileNameCFDATA1
[CB_MAX_FILENAME
];
163 char szFileNameCFDATA2
[CB_MAX_FILENAME
];
165 cab_ULONG sizeFileCFDATA1
;
166 cab_ULONG sizeFileCFDATA2
;
168 cab_ULONG estimatedCabinetSize
;
169 struct list folders_list
;
170 struct list files_list
;
171 cab_ULONG folders_size
;
172 cab_ULONG files_size
;
173 cab_ULONG placed_files_size
;
176 #define FCI_INT_MAGIC 0xfcfcfc05
178 static void set_error( FCI_Int
*fci
, int oper
, int err
)
180 fci
->perf
->erfOper
= oper
;
181 fci
->perf
->erfType
= err
;
182 fci
->perf
->fError
= TRUE
;
183 if (err
) SetLastError( err
);
186 static FCI_Int
*get_fci_ptr( HFCI hfci
)
188 FCI_Int
*fci
= (FCI_Int
*)hfci
;
190 if (!fci
|| !fci
->magic
== FCI_INT_MAGIC
)
192 SetLastError( ERROR_INVALID_HANDLE
);
198 static cab_ULONG
get_folder_size( FCI_Int
*fci
)
200 if (fci
->fNextCab
|| fci
->fGetNextCabInVain
)
201 return sizeof(CFFOLDER
) + fci
->oldCCAB
.cbReserveCFFolder
;
203 return sizeof(CFFOLDER
) + fci
->pccab
->cbReserveCFFolder
;
206 static struct file
*add_file( FCI_Int
*fci
, const char *filename
)
208 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(filename
) + 1] );
209 struct file
*file
= fci
->alloc( size
);
213 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
217 file
->offset
= fci
->cDataBlocks
* CAB_BLOCKMAX
+ fci
->cdata_in
;
218 file
->folder
= fci
->cFolders
;
222 strcpy( file
->name
, filename
);
223 list_add_tail( &fci
->files_list
, &file
->entry
);
227 static struct file
*copy_file( FCI_Int
*fci
, const struct file
*orig
)
229 unsigned int size
= FIELD_OFFSET( struct file
, name
[strlen(orig
->name
) + 1] );
230 struct file
*file
= fci
->alloc( size
);
234 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
237 memcpy( file
, orig
, size
);
241 static void free_file( FCI_Int
*fci
, struct file
*file
)
243 list_remove( &file
->entry
);
247 static struct folder
*add_folder( FCI_Int
*fci
)
249 struct folder
*folder
= fci
->alloc( sizeof(*folder
) );
253 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
256 folder
->data_start
= fci
->sizeFileCFDATA2
;
257 folder
->compression
= tcompTYPE_NONE
; /* FIXME */
258 list_init( &folder
->files_list
);
259 list_add_tail( &fci
->folders_list
, &folder
->entry
);
260 fci
->folders_size
+= get_folder_size( fci
);
265 static void free_folder( FCI_Int
*fci
, struct folder
*folder
)
267 struct file
*file
, *next
;
269 LIST_FOR_EACH_ENTRY_SAFE( file
, next
, &folder
->files_list
, struct file
, entry
) free_file( fci
, file
);
270 list_remove( &folder
->entry
);
274 /* write all folders to disk and remove them from the list */
275 static BOOL
write_folders( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG header_size
, PFNFCISTATUS status_callback
)
277 struct folder
*folder
, *next
;
283 cab_ULONG file_size
, folder_size
= get_folder_size( fci
);
285 if (!(cffolder
= fci
->alloc( folder_size
)))
287 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
290 memset( cffolder
, 0, folder_size
);
292 if (!(cffile
= fci
->alloc( sizeof(CFFILE
) + CB_MAX_FILENAME
)))
294 fci
->free( cffolder
);
295 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
299 /* write the folders */
300 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
302 cffolder
->coffCabStart
= fci_endian_ulong( folder
->data_start
+ header_size
);
303 cffolder
->cCFData
= fci_endian_uword( folder
->data_count
);
304 cffolder
->typeCompress
= fci_endian_uword( folder
->compression
);
305 if (fci
->write( handle
, cffolder
, folder_size
, &err
, fci
->pv
) != folder_size
)
307 set_error( fci
, FCIERR_CAB_FILE
, err
);
313 /* write all the folders files */
314 LIST_FOR_EACH_ENTRY( folder
, &fci
->folders_list
, struct folder
, entry
)
316 LIST_FOR_EACH_ENTRY( file
, &folder
->files_list
, struct file
, entry
)
318 cffile
->cbFile
= fci_endian_ulong( file
->size
);
319 cffile
->uoffFolderStart
= fci_endian_ulong( file
->offset
);
320 cffile
->iFolder
= fci_endian_uword( file
->folder
);
321 cffile
->date
= fci_endian_uword( file
->date
);
322 cffile
->time
= fci_endian_uword( file
->time
);
323 cffile
->attribs
= fci_endian_uword( file
->attribs
);
324 lstrcpynA( (char *)(cffile
+ 1), file
->name
, CB_MAX_FILENAME
);
325 file_size
= sizeof(CFFILE
) + strlen( (char *)(cffile
+ 1) ) + 1;
326 if (fci
->write( handle
, cffile
, file_size
, &err
, fci
->pv
) != file_size
)
328 set_error( fci
, FCIERR_CAB_FILE
, err
);
332 if (!fci
->fSplitFolder
)
334 fci
->statusFolderCopied
= 0;
335 /* TODO TEST THIS further */
336 fci
->statusFolderTotal
= fci
->sizeFileCFDATA2
+ fci
->placed_files_size
;
338 fci
->statusFolderCopied
+= file_size
;
339 /* report status about copied size of folder */
340 if (status_callback( statusFolder
, fci
->statusFolderCopied
,
341 fci
->statusFolderTotal
, fci
->pv
) == -1)
343 set_error( fci
, FCIERR_USER_ABORT
, 0 );
351 LIST_FOR_EACH_ENTRY_SAFE( folder
, next
, &fci
->folders_list
, struct folder
, entry
)
353 free_folder( fci
, folder
);
355 fci
->free( cffolder
);
360 /* add all pending files to folder */
361 static BOOL
add_files_to_folder( FCI_Int
*fci
, struct folder
*folder
, cab_ULONG payload
)
363 cab_ULONG sizeOfFiles
= 0, sizeOfFilesPrev
;
364 cab_ULONG cbFileRemainer
= 0;
365 struct file
*file
, *next
;
367 LIST_FOR_EACH_ENTRY_SAFE( file
, next
, &fci
->files_list
, struct file
, entry
)
369 cab_ULONG size
= sizeof(CFFILE
) + strlen(file
->name
) + 1;
371 /* fnfilfnfildest: placed file on cabinet */
372 if (fci
->fNextCab
|| fci
->fGetNextCabInVain
)
373 fci
->fileplaced( &fci
->oldCCAB
, file
->name
, file
->size
,
374 (file
->folder
== cffileCONTINUED_FROM_PREV
), fci
->pv
);
376 fci
->fileplaced( fci
->pccab
, file
->name
, file
->size
,
377 (file
->folder
== cffileCONTINUED_FROM_PREV
), fci
->pv
);
379 sizeOfFilesPrev
= sizeOfFiles
;
380 /* set complete size of all processed files */
381 if (file
->folder
== cffileCONTINUED_FROM_PREV
&& fci
->cbFileRemainer
!= 0)
383 sizeOfFiles
+= fci
->cbFileRemainer
;
384 fci
->cbFileRemainer
= 0;
386 else sizeOfFiles
+= file
->size
;
388 /* check if spanned file fits into this cabinet folder */
389 if (sizeOfFiles
> payload
)
391 if (file
->folder
== cffileCONTINUED_FROM_PREV
)
392 file
->folder
= cffileCONTINUED_PREV_AND_NEXT
;
394 file
->folder
= cffileCONTINUED_TO_NEXT
;
397 list_remove( &file
->entry
);
398 list_add_tail( &folder
->files_list
, &file
->entry
);
399 fci
->placed_files_size
+= size
;
402 /* This is only true for files which will be written into the */
403 /* next cabinet of the spanning folder */
404 if (sizeOfFiles
> payload
)
406 /* add a copy back onto the list */
407 if (!(file
= copy_file( fci
, file
))) return FALSE
;
408 list_add_before( &next
->entry
, &file
->entry
);
410 /* Files which data will be partially written into the current cabinet */
411 if (file
->folder
== cffileCONTINUED_PREV_AND_NEXT
|| file
->folder
== cffileCONTINUED_TO_NEXT
)
413 if (sizeOfFilesPrev
<= payload
)
415 /* The size of the uncompressed, data of a spanning file in a */
417 cbFileRemainer
= sizeOfFiles
- payload
;
419 file
->folder
= cffileCONTINUED_FROM_PREV
;
421 else file
->folder
= 0;
425 fci
->files_size
-= size
;
428 fci
->cbFileRemainer
= cbFileRemainer
;
432 /***********************************************************************
433 * FCICreate (CABINET.10)
435 * FCICreate is provided with several callbacks and
436 * returns a handle which can be used to create cabinet files.
439 * perf [IO] A pointer to an ERF structure. When FCICreate
440 * returns an error condition, error information may
441 * be found here as well as from GetLastError.
442 * pfnfiledest [I] A pointer to a function which is called when a file
443 * is placed. Only useful for subsequent cabinet files.
444 * pfnalloc [I] A pointer to a function which allocates ram. Uses
445 * the same interface as malloc.
446 * pfnfree [I] A pointer to a function which frees ram. Uses the
447 * same interface as free.
448 * pfnopen [I] A pointer to a function which opens a file. Uses
449 * the same interface as _open.
450 * pfnread [I] A pointer to a function which reads from a file into
451 * a caller-provided buffer. Uses the same interface
453 * pfnwrite [I] A pointer to a function which writes to a file from
454 * a caller-provided buffer. Uses the same interface
456 * pfnclose [I] A pointer to a function which closes a file handle.
457 * Uses the same interface as _close.
458 * pfnseek [I] A pointer to a function which seeks in a file.
459 * Uses the same interface as _lseek.
460 * pfndelete [I] A pointer to a function which deletes a file.
461 * pfnfcigtf [I] A pointer to a function which gets the name of a
463 * pccab [I] A pointer to an initialized CCAB structure.
464 * pv [I] A pointer to an application-defined notification
465 * function which will be passed to other FCI functions
469 * On success, returns an FCI handle of type HFCI.
470 * On failure, the NULL file handle is returned. Error
471 * info can be retrieved from perf.
477 HFCI __cdecl
FCICreate(
479 PFNFCIFILEPLACED pfnfiledest
,
480 PFNFCIALLOC pfnalloc
,
484 PFNFCIWRITE pfnwrite
,
485 PFNFCICLOSE pfnclose
,
487 PFNFCIDELETE pfndelete
,
488 PFNFCIGETTEMPFILE pfnfcigtf
,
493 FCI_Int
*p_fci_internal
;
496 SetLastError(ERROR_BAD_ARGUMENTS
);
499 if ((!pfnalloc
) || (!pfnfree
) || (!pfnopen
) || (!pfnread
) ||
500 (!pfnwrite
) || (!pfnclose
) || (!pfnseek
) || (!pfndelete
) ||
501 (!pfnfcigtf
) || (!pccab
)) {
502 perf
->erfOper
= FCIERR_NONE
;
503 perf
->erfType
= ERROR_BAD_ARGUMENTS
;
506 SetLastError(ERROR_BAD_ARGUMENTS
);
510 if (!((p_fci_internal
= pfnalloc(sizeof(FCI_Int
))))) {
511 perf
->erfOper
= FCIERR_ALLOC_FAIL
;
512 perf
->erfType
= ERROR_NOT_ENOUGH_MEMORY
;
515 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
519 p_fci_internal
->magic
= FCI_INT_MAGIC
;
520 p_fci_internal
->perf
= perf
;
521 p_fci_internal
->fileplaced
= pfnfiledest
;
522 p_fci_internal
->alloc
= pfnalloc
;
523 p_fci_internal
->free
= pfnfree
;
524 p_fci_internal
->open
= pfnopen
;
525 p_fci_internal
->read
= pfnread
;
526 p_fci_internal
->write
= pfnwrite
;
527 p_fci_internal
->close
= pfnclose
;
528 p_fci_internal
->seek
= pfnseek
;
529 p_fci_internal
->delete = pfndelete
;
530 p_fci_internal
->gettemp
= pfnfcigtf
;
531 p_fci_internal
->pccab
= pccab
;
532 p_fci_internal
->fPrevCab
= FALSE
;
533 p_fci_internal
->fNextCab
= FALSE
;
534 p_fci_internal
->fSplitFolder
= FALSE
;
535 p_fci_internal
->fGetNextCabInVain
= FALSE
;
536 p_fci_internal
->pv
= pv
;
537 p_fci_internal
->data_in
= NULL
;
538 p_fci_internal
->cdata_in
= 0;
539 p_fci_internal
->data_out
= NULL
;
540 p_fci_internal
->cCompressedBytesInFolder
= 0;
541 p_fci_internal
->cFolders
= 0;
542 p_fci_internal
->cFiles
= 0;
543 p_fci_internal
->cDataBlocks
= 0;
544 p_fci_internal
->sizeFileCFDATA1
= 0;
545 p_fci_internal
->sizeFileCFDATA2
= 0;
546 p_fci_internal
->fNewPrevious
= FALSE
;
547 p_fci_internal
->estimatedCabinetSize
= 0;
548 p_fci_internal
->statusFolderTotal
= 0;
549 p_fci_internal
->folders_size
= 0;
550 p_fci_internal
->files_size
= 0;
551 p_fci_internal
->placed_files_size
= 0;
553 list_init( &p_fci_internal
->folders_list
);
554 list_init( &p_fci_internal
->files_list
);
556 memset(&p_fci_internal
->oldCCAB
, 0, sizeof(CCAB
));
557 memcpy(p_fci_internal
->szPrevCab
, pccab
->szCab
, CB_MAX_CABINET_NAME
);
558 memcpy(p_fci_internal
->szPrevDisk
, pccab
->szDisk
, CB_MAX_DISK_NAME
);
561 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFDATA1
,
562 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
563 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
567 if ( strlen(p_fci_internal
->szFileNameCFDATA1
) >= CB_MAX_FILENAME
) {
568 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
572 p_fci_internal
->handleCFDATA1
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA1
,
573 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
574 _S_IREAD
| _S_IWRITE
, &err
, pv
);
575 if(p_fci_internal
->handleCFDATA1
==0){
576 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
579 /* TODO error checking of err */
581 /* CFDATA with checksum and ready to be copied into cabinet */
582 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFDATA2
,
583 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
584 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
588 if ( strlen(p_fci_internal
->szFileNameCFDATA2
) >= CB_MAX_FILENAME
) {
589 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
592 p_fci_internal
->handleCFDATA2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA2
,
593 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
594 _S_IREAD
| _S_IWRITE
, &err
, pv
);
595 if(p_fci_internal
->handleCFDATA2
==0){
596 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
599 /* TODO error checking of err */
601 /* TODO close and delete new files when return FALSE */
603 return (HFCI
)p_fci_internal
;
611 static BOOL
fci_flush_data_block (FCI_Int
*p_fci_internal
, int* err
,
612 PFNFCISTATUS pfnfcis
) {
614 /* attention no checks if there is data available!!! */
616 CFDATA
* cfdata
=&data
;
618 UINT cbReserveCFData
=p_fci_internal
->pccab
->cbReserveCFData
;
621 /* TODO compress the data of p_fci_internal->data_in */
622 /* and write it to p_fci_internal->data_out */
623 memcpy(p_fci_internal
->data_out
, p_fci_internal
->data_in
,
624 p_fci_internal
->cdata_in
/* number of bytes to copy */);
626 cfdata
->csum
=0; /* checksum has to be set later */
627 /* TODO set realsize of compressed data */
628 cfdata
->cbData
= p_fci_internal
->cdata_in
;
629 cfdata
->cbUncomp
= p_fci_internal
->cdata_in
;
631 /* write cfdata to p_fci_internal->handleCFDATA1 */
632 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
633 cfdata
, sizeof(*cfdata
), err
, p_fci_internal
->pv
)
634 != sizeof(*cfdata
) ) {
635 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
638 /* TODO error handling of err */
640 p_fci_internal
->sizeFileCFDATA1
+= sizeof(*cfdata
);
642 /* add optional reserved area */
644 /* This allocation and freeing at each CFData block is a bit */
645 /* inefficient, but it's harder to forget about freeing the buffer :-). */
646 /* Reserved areas are used seldom besides that... */
647 if (cbReserveCFData
!=0) {
648 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFData
))) {
649 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
652 for(i
=0;i
<cbReserveCFData
;) {
655 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
656 reserved
, /* memory buffer */
657 cbReserveCFData
, /* number of bytes to copy */
658 err
, p_fci_internal
->pv
) != cbReserveCFData
) {
659 p_fci_internal
->free(reserved
);
660 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
663 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
665 p_fci_internal
->sizeFileCFDATA1
+= cbReserveCFData
;
666 p_fci_internal
->free( reserved
);
669 /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
670 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
671 p_fci_internal
->data_out
, /* memory buffer */
672 cfdata
->cbData
, /* number of bytes to copy */
673 err
, p_fci_internal
->pv
) != cfdata
->cbData
) {
674 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
677 /* TODO error handling of err */
679 p_fci_internal
->sizeFileCFDATA1
+= cfdata
->cbData
;
681 /* reset the offset */
682 p_fci_internal
->cdata_in
= 0;
683 p_fci_internal
->cCompressedBytesInFolder
+= cfdata
->cbData
;
685 /* report status with pfnfcis about uncompressed and compressed file data */
686 if( (*pfnfcis
)(statusFile
, cfdata
->cbData
, cfdata
->cbUncomp
,
687 p_fci_internal
->pv
) == -1) {
688 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
692 ++(p_fci_internal
->cDataBlocks
);
695 } /* end of fci_flush_data_block */
701 static cab_ULONG
fci_get_checksum(const void *pv
, UINT cb
, CHECKSUM seed
)
712 while (cUlong
-- > 0) {
714 ul
|= (((cab_ULONG
)(*pb
++)) << 8);
715 ul
|= (((cab_ULONG
)(*pb
++)) << 16);
716 ul
|= (((cab_ULONG
)(*pb
++)) << 24);
724 ul
|= (((ULONG
)(*pb
++)) << 16);
726 ul
|= (((ULONG
)(*pb
++)) << 8);
735 } /* end of fci_get_checksum */
739 static BOOL
fci_flushfolder_copy_cfdata(FCI_Int
*p_fci_internal
, char* buffer
, UINT cbReserveCFData
,
740 PFNFCISTATUS pfnfcis
, int* err
, int handleCFDATA1new
,
741 cab_ULONG
* psizeFileCFDATA1new
, cab_ULONG
* payload
)
743 cab_ULONG read_result
;
744 CFDATA
* pcfdata
=(CFDATA
*)buffer
;
745 BOOL split_block
=FALSE
;
746 cab_UWORD savedUncomp
=0;
750 /* while not all CFDATAs have been copied do */
752 if( p_fci_internal
->fNextCab
) {
754 /* internal error should never happen */
755 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
759 /* REUSE the variable read_result */
760 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
761 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
762 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
767 if (p_fci_internal
->fPrevCab
) {
768 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
769 strlen(p_fci_internal
->szPrevDisk
)+1;
771 /* No more CFDATA fits into the cabinet under construction */
772 /* So don't try to store more data into it */
773 if( p_fci_internal
->fNextCab
&&
774 (p_fci_internal
->oldCCAB
.cb
<= sizeof(CFDATA
) + cbReserveCFData
+
775 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
776 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
779 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
781 p_fci_internal
->oldCCAB
.cbReserveCFFolder
+
782 strlen(p_fci_internal
->pccab
->szCab
)+1 +
783 strlen(p_fci_internal
->pccab
->szDisk
)+1
785 /* This may never be run for the first time the while loop is entered.
786 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
787 split_block
=TRUE
; /* In this case split_block is abused to store */
788 /* the complete data block into the next cabinet and not into the */
789 /* current one. Originally split_block is the indicator that a */
790 /* data block has been split across different cabinets. */
793 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
794 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA1
,/*file handle*/
795 buffer
, /* memory buffer */
796 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
797 err
, p_fci_internal
->pv
);
798 if (read_result
!=sizeof(CFDATA
)+cbReserveCFData
) {
799 if (read_result
==0) break; /* ALL DATA has been copied */
801 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
804 /* TODO error handling of err */
806 /* REUSE buffer p_fci_internal->data_out !!! */
807 /* read data from p_fci_internal->handleCFDATA1 to */
808 /* p_fci_internal->data_out */
809 if( p_fci_internal
->read( p_fci_internal
->handleCFDATA1
/* file handle */,
810 p_fci_internal
->data_out
/* memory buffer */,
811 pcfdata
->cbData
/* number of bytes to copy */,
812 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
814 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
817 /* TODO error handling of err */
819 /* if cabinet size is too large */
821 /* REUSE the variable read_result */
822 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
823 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
824 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
829 if (p_fci_internal
->fPrevCab
) {
830 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
831 strlen(p_fci_internal
->szPrevDisk
)+1;
834 /* Is cabinet with new CFDATA too large? Then data block has to be split */
835 if( p_fci_internal
->fNextCab
&&
836 (p_fci_internal
->oldCCAB
.cb
< sizeof(CFDATA
) + cbReserveCFData
+
838 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
839 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
842 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
843 sizeof(CFFOLDER
) + /* size of new CFFolder entry */
844 p_fci_internal
->oldCCAB
.cbReserveCFFolder
+
845 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* name of next cabinet */
846 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* name of next disk */
848 /* REUSE read_result to save the size of the compressed data */
849 read_result
=pcfdata
->cbData
;
850 /* Modify the size of the compressed data to store only a part of the */
851 /* data block into the current cabinet. This is done to prevent */
852 /* that the maximum cabinet size will be exceeded. The remainder */
853 /* will be stored into the next following cabinet. */
855 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
856 /* Substract everything except the size of the block of data */
857 /* to get it's actual size */
858 pcfdata
->cbData
= p_fci_internal
->oldCCAB
.cb
- (
859 sizeof(CFDATA
) + cbReserveCFData
+
860 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
861 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
863 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
864 sizeof(CFFOLDER
) + /* set size of new CFFolder entry */
865 p_fci_internal
->oldCCAB
.cbReserveCFFolder
);
866 /* substract the size of special header fields */
867 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
868 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
869 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
872 if (p_fci_internal
->fPrevCab
) {
873 pcfdata
->cbData
-=strlen(p_fci_internal
->szPrevCab
)+1 +
874 strlen(p_fci_internal
->szPrevDisk
)+1;
876 pcfdata
->cbData
-=strlen(p_fci_internal
->pccab
->szCab
)+1 +
877 strlen(p_fci_internal
->pccab
->szDisk
)+1;
879 savedUncomp
= pcfdata
->cbUncomp
;
880 pcfdata
->cbUncomp
= 0; /* on split blocks of data this is zero */
882 /* if split_block==TRUE then the above while loop won't */
883 /* be executed again */
884 split_block
=TRUE
; /* split_block is the indicator that */
885 /* a data block has been split across */
886 /* different cabinets.*/
889 /* This should never happen !!! */
890 if (pcfdata
->cbData
==0) {
892 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
896 /* set little endian */
897 pcfdata
->cbData
=fci_endian_uword(pcfdata
->cbData
);
898 pcfdata
->cbUncomp
=fci_endian_uword(pcfdata
->cbUncomp
);
900 /* get checksum and write to cfdata.csum */
901 pcfdata
->csum
= fci_get_checksum( &(pcfdata
->cbData
),
902 sizeof(CFDATA
)+cbReserveCFData
-
903 sizeof(pcfdata
->csum
), fci_get_checksum( p_fci_internal
->data_out
, /*buffer*/
904 pcfdata
->cbData
, 0 ) );
906 /* set little endian */
907 pcfdata
->csum
=fci_endian_ulong(pcfdata
->csum
);
909 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
910 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA2
, /* file handle */
911 buffer
, /* memory buffer */
912 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
913 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
914 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
917 /* TODO error handling of err */
919 p_fci_internal
->sizeFileCFDATA2
+= sizeof(CFDATA
)+cbReserveCFData
;
921 /* reset little endian */
922 pcfdata
->cbData
=fci_endian_uword(pcfdata
->cbData
);
923 pcfdata
->cbUncomp
=fci_endian_uword(pcfdata
->cbUncomp
);
924 pcfdata
->csum
=fci_endian_ulong(pcfdata
->csum
);
926 /* write compressed data into p_fci_internal->handleCFDATA2 */
927 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA2
, /* file handle */
928 p_fci_internal
->data_out
, /* memory buffer */
929 pcfdata
->cbData
, /* number of bytes to copy */
930 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
931 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
934 /* TODO error handling of err */
936 p_fci_internal
->sizeFileCFDATA2
+= pcfdata
->cbData
;
937 ++(p_fci_internal
->cDataBlocks
);
938 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
939 (*payload
)+=pcfdata
->cbUncomp
;
940 /* if cabinet size too large and data has been split */
941 /* write the remainder of the data block to the new CFDATA1 file */
942 if( split_block
) { /* This does not include the */
943 /* abused one (just search for "abused" )*/
944 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
945 if (p_fci_internal
->fNextCab
==FALSE
) {
947 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
951 /* set cbData to the size of the remainder of the data block */
952 pcfdata
->cbData
= read_result
- pcfdata
->cbData
;
953 /*recover former value of cfdata.cbData; read_result will be the offset*/
954 read_result
-= pcfdata
->cbData
;
955 pcfdata
->cbUncomp
= savedUncomp
;
957 /* reset checksum, it will be computed later */
960 /* write cfdata WITHOUT checksum to handleCFDATA1new */
961 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
962 buffer
, /* memory buffer */
963 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
964 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
965 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
968 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
970 *psizeFileCFDATA1new
+= sizeof(CFDATA
)+cbReserveCFData
;
972 /* write compressed data into handleCFDATA1new */
973 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
974 p_fci_internal
->data_out
+ read_result
, /* memory buffer + offset */
975 /* to last part of split data */
976 pcfdata
->cbData
, /* number of bytes to copy */
977 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
978 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
981 /* TODO error handling of err */
983 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
985 *psizeFileCFDATA1new
+= pcfdata
->cbData
;
986 /* the two blocks of the split data block have been written */
987 /* don't reset split_data yet, because it is still needed see below */
990 /* report status with pfnfcis about copied size of folder */
991 if( (*pfnfcis
)(statusFolder
,
992 p_fci_internal
->statusFolderCopied
, /*cfdata.cbData(+previous ones)*/
993 p_fci_internal
->statusFolderTotal
, /* total folder size */
994 p_fci_internal
->pv
) == -1) {
995 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1000 /* if cabinet size too large */
1001 /* write the remaining data blocks to the new CFDATA1 file */
1002 if ( split_block
) { /* This does include the */
1003 /* abused one (just search for "abused" )*/
1004 if (p_fci_internal
->fNextCab
==FALSE
) {
1005 /* internal error */
1006 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1009 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
1011 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
1012 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA1
,/* handle */
1013 buffer
, /* memory buffer */
1014 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
1015 err
, p_fci_internal
->pv
);
1016 if (read_result
!=sizeof(CFDATA
)+cbReserveCFData
) {
1017 if (read_result
==0) break; /* ALL DATA has been copied */
1019 set_error( p_fci_internal
,FCIERR_NONE
, ERROR_READ_FAULT
);
1022 /* TODO error handling of err */
1024 /* REUSE buffer p_fci_internal->data_out !!! */
1025 /* read data from p_fci_internal->handleCFDATA1 to */
1026 /* p_fci_internal->data_out */
1027 if( p_fci_internal
->read( p_fci_internal
->handleCFDATA1
/* file handle */,
1028 p_fci_internal
->data_out
/* memory buffer */,
1029 pcfdata
->cbData
/* number of bytes to copy */,
1030 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
1032 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
1035 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1037 /* write cfdata with checksum to handleCFDATA1new */
1038 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
1039 buffer
, /* memory buffer */
1040 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
1041 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
1042 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1045 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
1047 *psizeFileCFDATA1new
+= sizeof(CFDATA
)+cbReserveCFData
;
1049 /* write compressed data into handleCFDATA1new */
1050 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
1051 p_fci_internal
->data_out
, /* memory buffer */
1052 pcfdata
->cbData
, /* number of bytes to copy */
1053 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
1054 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1057 /* TODO error handling of err */
1059 *psizeFileCFDATA1new
+= pcfdata
->cbData
;
1060 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
1062 /* report status with pfnfcis about copied size of folder */
1063 if( (*pfnfcis
)(statusFolder
,
1064 p_fci_internal
->statusFolderCopied
,/*cfdata.cbData(+previous ones)*/
1065 p_fci_internal
->statusFolderTotal
, /* total folder size */
1066 p_fci_internal
->pv
) == -1) {
1067 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1071 } /* end of WHILE */
1072 break; /* jump out of the next while loop */
1073 } /* end of if( split_data ) */
1074 } /* end of WHILE */
1076 } /* end of fci_flushfolder_copy_cfdata */
1082 static BOOL
fci_flush_folder( FCI_Int
*p_fci_internal
,
1084 PFNFCIGETNEXTCABINET pfnfcignc
,
1085 PFNFCISTATUS pfnfcis
)
1088 int handleCFDATA1new
; /* handle for new temp file */
1089 char szFileNameCFDATA1new
[CB_MAX_FILENAME
]; /* name buffer for temp file */
1090 int handleCFFILE1new
; /* handle for new temp file */
1091 char szFileNameCFFILE1new
[CB_MAX_FILENAME
]; /* name buffer for temp file */
1092 UINT cbReserveCFData
, cbReserveCFFolder
;
1094 cab_ULONG sizeFileCFDATA1new
=0;
1096 cab_ULONG read_result
;
1097 struct folder
*folder
;
1099 if ((!pfnfcignc
) || (!pfnfcis
)) {
1100 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1104 if( p_fci_internal
->fGetNextCabInVain
&&
1105 p_fci_internal
->fNextCab
){
1106 /* internal error */
1107 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1111 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1112 /* this function will return TRUE */
1113 if( p_fci_internal
->files_size
== 0 ) {
1114 if ( p_fci_internal
->sizeFileCFDATA1
!= 0 ) {
1115 /* error handling */
1116 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1122 if (p_fci_internal
->data_in
==NULL
|| p_fci_internal
->data_out
==NULL
) {
1123 /* error handling */
1124 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1128 /* FCIFlushFolder has already been called... */
1129 if (p_fci_internal
->fSplitFolder
&& p_fci_internal
->placed_files_size
!=0) {
1133 /* This can be set already, because it makes only a difference */
1134 /* when the current function exits with return FALSE */
1135 p_fci_internal
->fSplitFolder
=FALSE
;
1138 if( p_fci_internal
->fGetNextCabInVain
||
1139 p_fci_internal
->fNextCab
){
1140 cbReserveCFData
= p_fci_internal
->oldCCAB
.cbReserveCFData
;
1141 cbReserveCFFolder
= p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1143 cbReserveCFData
= p_fci_internal
->pccab
->cbReserveCFData
;
1144 cbReserveCFFolder
= p_fci_internal
->pccab
->cbReserveCFFolder
;
1148 /* if there is data in p_fci_internal->data_in */
1149 if (p_fci_internal
->cdata_in
!=0) {
1151 if( !fci_flush_data_block(p_fci_internal
, &err
, pfnfcis
) ) return FALSE
;
1154 /* reset to get the number of data blocks of this folder which are */
1155 /* actually in this cabinet ( at least partially ) */
1156 p_fci_internal
->cDataBlocks
=0;
1158 if ( p_fci_internal
->fNextCab
||
1159 p_fci_internal
->fGetNextCabInVain
) {
1160 read_result
= p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
1161 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1162 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1163 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1164 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1168 read_result
= p_fci_internal
->pccab
->cbReserveCFHeader
+
1169 p_fci_internal
->pccab
->cbReserveCFFolder
;
1170 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1171 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1172 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1176 if (p_fci_internal
->fPrevCab
) {
1177 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1178 strlen(p_fci_internal
->szPrevDisk
)+1;
1180 if (p_fci_internal
->fNextCab
) {
1181 read_result
+=strlen(p_fci_internal
->pccab
->szCab
)+1 +
1182 strlen(p_fci_internal
->pccab
->szDisk
)+1;
1185 p_fci_internal
->statusFolderTotal
= sizeof(CFHEADER
)+read_result
+
1186 sizeof(CFFOLDER
) + p_fci_internal
->placed_files_size
+
1187 p_fci_internal
->sizeFileCFDATA2
+ p_fci_internal
->files_size
+
1188 p_fci_internal
->sizeFileCFDATA1
+ p_fci_internal
->folders_size
;
1189 p_fci_internal
->statusFolderCopied
= 0;
1191 /* report status with pfnfcis about copied size of folder */
1192 if( (*pfnfcis
)(statusFolder
, p_fci_internal
->statusFolderCopied
,
1193 p_fci_internal
->statusFolderTotal
, /* TODO total folder size */
1194 p_fci_internal
->pv
) == -1) {
1195 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1199 /* get a new temp file */
1200 if(!p_fci_internal
->gettemp(szFileNameCFDATA1new
,CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
1201 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1205 if ( strlen(szFileNameCFDATA1new
) >= CB_MAX_FILENAME
) {
1206 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1209 handleCFDATA1new
= p_fci_internal
->open(szFileNameCFDATA1new
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
1210 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1211 if(handleCFDATA1new
==0){
1212 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
1215 /* TODO error handling of err */
1219 /* get a new temp file */
1220 if(!p_fci_internal
->gettemp(szFileNameCFFILE1new
,CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
1221 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1222 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1223 /* TODO error handling of err */
1227 if ( strlen(szFileNameCFFILE1new
) >= CB_MAX_FILENAME
) {
1228 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1229 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1230 /* TODO error handling of err */
1233 handleCFFILE1new
= p_fci_internal
->open(szFileNameCFFILE1new
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
1234 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1235 if(handleCFFILE1new
==0){
1236 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
1239 /* TODO error handling of err */
1241 /* USE the variable read_result */
1242 if ( p_fci_internal
->fNextCab
||
1243 p_fci_internal
->fGetNextCabInVain
) {
1244 read_result
= p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1245 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1246 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1247 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1251 read_result
= p_fci_internal
->pccab
->cbReserveCFHeader
;
1252 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1253 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1254 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1258 if (p_fci_internal
->fPrevCab
) {
1259 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1260 strlen(p_fci_internal
->szPrevDisk
)+1;
1262 read_result
+= sizeof(CFHEADER
) + p_fci_internal
->sizeFileCFDATA2
+
1263 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
;
1265 if(p_fci_internal
->files_size
!=0) {
1266 read_result
+= sizeof(CFFOLDER
)+p_fci_internal
->pccab
->cbReserveCFFolder
;
1269 /* Check if multiple cabinets have to be created. */
1271 /* Might be too much data for the maximum allowed cabinet size.*/
1272 /* When any further data will be added later, it might not */
1273 /* be possible to flush the cabinet, because there might */
1274 /* not be enough space to store the name of the following */
1275 /* cabinet and name of the corresponding disk. */
1276 /* So take care of this and get the name of the next cabinet */
1277 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1278 p_fci_internal
->fNextCab
==FALSE
&&
1281 p_fci_internal
->pccab
->cb
< read_result
+
1282 p_fci_internal
->sizeFileCFDATA1
+
1283 p_fci_internal
->files_size
+
1284 CB_MAX_CABINET_NAME
+ /* next cabinet name */
1285 CB_MAX_DISK_NAME
/* next disk name */
1290 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
1291 /* increment cabinet index */
1292 ++(p_fci_internal
->pccab
->iCab
);
1293 /* get name of next cabinet */
1294 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1295 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1296 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1297 p_fci_internal
->pv
)) {
1298 /* error handling */
1299 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1300 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1301 /* TODO error handling of err */
1302 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1303 /* TODO error handling of err */
1307 /* Skip a few lines of code. This is caught by the next if. */
1308 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1311 /* too much data for cabinet */
1312 if( (p_fci_internal
->fGetNextCabInVain
||
1313 p_fci_internal
->fNextCab
) &&
1316 p_fci_internal
->oldCCAB
.cb
< read_result
+
1317 p_fci_internal
->sizeFileCFDATA1
+
1318 p_fci_internal
->files_size
+
1319 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1320 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1324 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1325 p_fci_internal
->fNextCab
=TRUE
;
1327 /* return FALSE if there is not enough space left*/
1328 /* this should never happen */
1329 if (p_fci_internal
->oldCCAB
.cb
<=
1330 p_fci_internal
->files_size
+
1332 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1333 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1336 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1337 /* TODO error handling of err */
1338 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1339 /* TODO error handling of err */
1341 /* close and delete p_fci_internal->handleCFFILE1 */
1342 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1343 /* TODO error handling of err */
1344 p_fci_internal
->delete(szFileNameCFFILE1new
,&err
,p_fci_internal
->pv
);
1345 /* TODO error handling of err */
1350 /* the folder will be split across cabinets */
1351 p_fci_internal
->fSplitFolder
=TRUE
;
1354 /* this should never happen */
1355 if (p_fci_internal
->fNextCab
) {
1356 /* internal error */
1357 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1362 /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1363 if( p_fci_internal
->seek(p_fci_internal
->handleCFDATA1
,0,SEEK_SET
,&err
,
1364 p_fci_internal
->pv
) !=0 ) {
1365 /* wrong return value */
1366 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1367 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1368 /* TODO error handling of err */
1369 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1370 /* TODO error handling of err */
1373 /* TODO error handling of err */
1375 if (!(folder
= add_folder( p_fci_internal
))) return FALSE
;
1377 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFData
+sizeof(CFDATA
)))) {
1378 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
1379 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1380 /* TODO error handling of err */
1381 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1382 /* TODO error handling of err */
1386 if(!fci_flushfolder_copy_cfdata(p_fci_internal
, reserved
, cbReserveCFData
, pfnfcis
, &err
,
1387 handleCFDATA1new
, &sizeFileCFDATA1new
, &payload
1389 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1390 /* TODO error handling of err */
1391 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1392 /* TODO error handling of err */
1393 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1394 /* TODO error handling of err */
1395 p_fci_internal
->free(reserved
);
1399 p_fci_internal
->free(reserved
);
1401 folder
->data_count
= p_fci_internal
->cDataBlocks
;
1403 if (!add_files_to_folder( p_fci_internal
, folder
, payload
))
1405 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1406 /* TODO error handling of err */
1407 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1408 /* TODO error handling of err */
1409 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1410 /* TODO error handling of err */
1411 p_fci_internal
->delete(szFileNameCFFILE1new
,&err
,p_fci_internal
->pv
);
1412 /* TODO error handling of err */
1416 /* close and delete p_fci_internal->handleCFDATA1 */
1417 p_fci_internal
->close(p_fci_internal
->handleCFDATA1
,&err
,p_fci_internal
->pv
);
1418 /* TODO error handling of err */
1419 p_fci_internal
->delete(p_fci_internal
->szFileNameCFDATA1
,&err
,p_fci_internal
->pv
);
1420 /* TODO error handling of err */
1422 /* put new CFDATA1 into hfci */
1423 memcpy(p_fci_internal
->szFileNameCFDATA1
,szFileNameCFDATA1new
,
1426 /* put CFDATA1 file handle */
1427 p_fci_internal
->handleCFDATA1
= handleCFDATA1new
;
1429 p_fci_internal
->sizeFileCFDATA1
= sizeFileCFDATA1new
;
1431 /* reset CFFolder specific information */
1432 p_fci_internal
->cDataBlocks
=0;
1433 p_fci_internal
->cCompressedBytesInFolder
=0;
1436 } /* end of fci_flush_folder */
1441 static BOOL
fci_flush_cabinet( FCI_Int
*p_fci_internal
,
1443 PFNFCIGETNEXTCABINET pfnfcignc
,
1444 PFNFCISTATUS pfnfcis
)
1449 cab_UWORD cbCFHeader
;
1450 cab_UBYTE cbCFFolder
;
1453 cab_ULONG header_size
;
1454 cab_ULONG read_result
=0;
1455 int handleCABINET
; /* file handle for cabinet */
1456 char szFileNameCABINET
[CB_MAX_CAB_PATH
+CB_MAX_CABINET_NAME
];/* name buffer */
1457 UINT cbReserveCFHeader
, cbReserveCFFolder
, i
;
1459 BOOL returntrue
=FALSE
;
1461 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1463 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1464 if( p_fci_internal
->files_size
==0 && fGetNextCab
) {
1468 if (!fci_flush_folder(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)){
1469 /* TODO set error */
1473 if(returntrue
) return TRUE
;
1475 if ( (p_fci_internal
->fSplitFolder
&& p_fci_internal
->fNextCab
==FALSE
)||
1476 (p_fci_internal
->folders_size
==0 &&
1477 (p_fci_internal
->files_size
!=0 ||
1478 p_fci_internal
->placed_files_size
!=0 )
1482 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1486 if( p_fci_internal
->fNextCab
||
1487 p_fci_internal
->fGetNextCabInVain
) {
1488 cbReserveCFFolder
=p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1489 cbReserveCFHeader
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1491 if (strlen(p_fci_internal
->oldCCAB
.szCabPath
)>=CB_MAX_CAB_PATH
||
1492 strlen(p_fci_internal
->oldCCAB
.szCab
)>=CB_MAX_CABINET_NAME
) {
1494 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1497 /* get the full name of the cabinet */
1498 memcpy(szFileNameCABINET
,p_fci_internal
->oldCCAB
.szCabPath
,
1500 memcpy(szFileNameCABINET
+strlen(szFileNameCABINET
),
1501 p_fci_internal
->oldCCAB
.szCab
, CB_MAX_CABINET_NAME
);
1503 cbReserveCFFolder
=p_fci_internal
->pccab
->cbReserveCFFolder
;
1504 cbReserveCFHeader
=p_fci_internal
->pccab
->cbReserveCFHeader
;
1506 if (strlen(p_fci_internal
->pccab
->szCabPath
)>=CB_MAX_CAB_PATH
||
1507 strlen(p_fci_internal
->pccab
->szCab
)>=CB_MAX_CABINET_NAME
) {
1509 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1512 /* get the full name of the cabinet */
1513 memcpy(szFileNameCABINET
,p_fci_internal
->pccab
->szCabPath
,
1515 memcpy(szFileNameCABINET
+strlen(szFileNameCABINET
),
1516 p_fci_internal
->pccab
->szCab
, CB_MAX_CABINET_NAME
);
1519 memcpy(cfheader
.signature
,"!CAB",4);
1520 cfheader
.reserved1
=0;
1521 cfheader
.cbCabinet
= /* size of the cabinet file in bytes */
1523 p_fci_internal
->folders_size
+
1524 p_fci_internal
->placed_files_size
+
1525 p_fci_internal
->sizeFileCFDATA2
;
1527 if (p_fci_internal
->fPrevCab
) {
1528 cfheader
.cbCabinet
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1529 strlen(p_fci_internal
->szPrevDisk
)+1;
1531 if (p_fci_internal
->fNextCab
) {
1532 cfheader
.cbCabinet
+=strlen(p_fci_internal
->pccab
->szCab
)+1 +
1533 strlen(p_fci_internal
->pccab
->szDisk
)+1;
1535 if( p_fci_internal
->fNextCab
||
1536 p_fci_internal
->fGetNextCabInVain
) {
1537 cfheader
.cbCabinet
+=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1538 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1539 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1540 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1541 cfheader
.cbCabinet
+=4;
1544 cfheader
.cbCabinet
+=p_fci_internal
->pccab
->cbReserveCFHeader
;
1545 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1546 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1547 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1548 cfheader
.cbCabinet
+=4;
1552 if( ( ( p_fci_internal
->fNextCab
||
1553 p_fci_internal
->fGetNextCabInVain
) &&
1554 cfheader
.cbCabinet
> p_fci_internal
->oldCCAB
.cb
1556 ( ( p_fci_internal
->fNextCab
==FALSE
&&
1557 p_fci_internal
->fGetNextCabInVain
==FALSE
) &&
1558 cfheader
.cbCabinet
> p_fci_internal
->pccab
->cb
1562 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_MORE_DATA
);
1567 cfheader
.reserved2
=0;
1568 cfheader
.coffFiles
= /* offset to first CFFILE section */
1569 cfheader
.cbCabinet
- p_fci_internal
->placed_files_size
-
1570 p_fci_internal
->sizeFileCFDATA2
;
1572 cfheader
.reserved3
=0;
1573 cfheader
.versionMinor
=3;
1574 cfheader
.versionMajor
=1;
1575 /* number of CFFOLDER entries in the cabinet */
1576 cfheader
.cFolders
=p_fci_internal
->cFolders
;
1577 /* number of CFFILE entries in the cabinet */
1578 cfheader
.cFiles
=p_fci_internal
->cFiles
;
1579 cfheader
.flags
=0; /* 1=prev cab, 2=next cabinet, 4=reserved sections */
1581 if( p_fci_internal
->fPrevCab
) {
1582 cfheader
.flags
= cfheadPREV_CABINET
;
1585 if( p_fci_internal
->fNextCab
) {
1586 cfheader
.flags
|= cfheadNEXT_CABINET
;
1589 if( p_fci_internal
->fNextCab
||
1590 p_fci_internal
->fGetNextCabInVain
) {
1591 if( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1592 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1593 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1594 cfheader
.flags
|= cfheadRESERVE_PRESENT
;
1596 cfheader
.setID
= p_fci_internal
->oldCCAB
.setID
;
1597 cfheader
.iCabinet
= p_fci_internal
->oldCCAB
.iCab
-1;
1599 if( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1600 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1601 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1602 cfheader
.flags
|= cfheadRESERVE_PRESENT
;
1604 cfheader
.setID
= p_fci_internal
->pccab
->setID
;
1605 cfheader
.iCabinet
= p_fci_internal
->pccab
->iCab
-1;
1608 /* create the cabinet */
1609 handleCABINET
= p_fci_internal
->open( szFileNameCABINET
, _O_RDWR
| _O_CREAT
| _O_TRUNC
| _O_BINARY
,
1610 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1611 if(handleCABINET
==-1)
1613 set_error( p_fci_internal
, FCIERR_CAB_FILE
, err
);
1616 /* TODO error checking of err */
1618 /* set little endian */
1619 cfheader
.reserved1
=fci_endian_ulong(cfheader
.reserved1
);
1620 cfheader
.cbCabinet
=fci_endian_ulong(cfheader
.cbCabinet
);
1621 cfheader
.reserved2
=fci_endian_ulong(cfheader
.reserved2
);
1622 cfheader
.coffFiles
=fci_endian_ulong(cfheader
.coffFiles
);
1623 cfheader
.reserved3
=fci_endian_ulong(cfheader
.reserved3
);
1624 cfheader
.cFolders
=fci_endian_uword(cfheader
.cFolders
);
1625 cfheader
.cFiles
=fci_endian_uword(cfheader
.cFiles
);
1626 cfheader
.flags
=fci_endian_uword(cfheader
.flags
);
1627 cfheader
.setID
=fci_endian_uword(cfheader
.setID
);
1628 cfheader
.iCabinet
=fci_endian_uword(cfheader
.iCabinet
);
1630 /* write CFHEADER into cabinet file */
1631 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1632 &cfheader
, /* memory buffer */
1633 sizeof(cfheader
), /* number of bytes to copy */
1634 &err
, p_fci_internal
->pv
) != sizeof(cfheader
) ) {
1636 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1639 /* TODO error handling of err */
1641 /* reset little endian */
1642 cfheader
.reserved1
=fci_endian_ulong(cfheader
.reserved1
);
1643 cfheader
.cbCabinet
=fci_endian_ulong(cfheader
.cbCabinet
);
1644 cfheader
.reserved2
=fci_endian_ulong(cfheader
.reserved2
);
1645 cfheader
.coffFiles
=fci_endian_ulong(cfheader
.coffFiles
);
1646 cfheader
.reserved3
=fci_endian_ulong(cfheader
.reserved3
);
1647 cfheader
.cFolders
=fci_endian_uword(cfheader
.cFolders
);
1648 cfheader
.cFiles
=fci_endian_uword(cfheader
.cFiles
);
1649 cfheader
.flags
=fci_endian_uword(cfheader
.flags
);
1650 cfheader
.setID
=fci_endian_uword(cfheader
.setID
);
1651 cfheader
.iCabinet
=fci_endian_uword(cfheader
.iCabinet
);
1653 if( cfheader
.flags
& cfheadRESERVE_PRESENT
) {
1654 /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1655 cfreserved
.cbCFHeader
= cbReserveCFHeader
;
1656 cfreserved
.cbCFFolder
= cbReserveCFFolder
;
1657 if( p_fci_internal
->fNextCab
||
1658 p_fci_internal
->fGetNextCabInVain
) {
1659 cfreserved
.cbCFData
= p_fci_internal
->oldCCAB
.cbReserveCFData
;
1661 cfreserved
.cbCFData
= p_fci_internal
->pccab
->cbReserveCFData
;
1664 /* set little endian */
1665 cfreserved
.cbCFHeader
=fci_endian_uword(cfreserved
.cbCFHeader
);
1667 /* write reserved info into cabinet file */
1668 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1669 &cfreserved
, /* memory buffer */
1670 sizeof(cfreserved
), /* number of bytes to copy */
1671 &err
, p_fci_internal
->pv
) != sizeof(cfreserved
) ) {
1673 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1676 /* TODO error handling of err */
1678 /* reset little endian */
1679 cfreserved
.cbCFHeader
=fci_endian_uword(cfreserved
.cbCFHeader
);
1682 /* add optional reserved area */
1683 if (cbReserveCFHeader
!=0) {
1684 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFHeader
))) {
1685 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
1688 for(i
=0;i
<cbReserveCFHeader
;) {
1691 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1692 reserved
, /* memory buffer */
1693 cbReserveCFHeader
, /* number of bytes to copy */
1694 &err
, p_fci_internal
->pv
) != cbReserveCFHeader
) {
1695 p_fci_internal
->free(reserved
);
1697 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1700 /* TODO error handling of err */
1701 p_fci_internal
->free(reserved
);
1704 if( cfheader
.flags
& cfheadPREV_CABINET
) {
1705 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1706 p_fci_internal
->szPrevCab
, /* memory buffer */
1707 strlen(p_fci_internal
->szPrevCab
)+1, /* number of bytes to copy */
1708 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->szPrevCab
)+1 ) {
1710 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1713 /* TODO error handling of err */
1715 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1716 p_fci_internal
->szPrevDisk
, /* memory buffer */
1717 strlen(p_fci_internal
->szPrevDisk
)+1, /* number of bytes to copy */
1718 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->szPrevDisk
)+1 ) {
1720 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1723 /* TODO error handling of err */
1726 if( cfheader
.flags
& cfheadNEXT_CABINET
) {
1727 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1728 p_fci_internal
->pccab
->szCab
, /* memory buffer */
1729 strlen(p_fci_internal
->pccab
->szCab
)+1, /* number of bytes to copy */
1730 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->pccab
->szCab
)+1 ) {
1732 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1735 /* TODO error handling of err */
1737 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1738 p_fci_internal
->pccab
->szDisk
, /* memory buffer */
1739 strlen(p_fci_internal
->pccab
->szDisk
)+1, /* number of bytes to copy */
1740 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->pccab
->szDisk
)+1 ) {
1742 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1745 /* TODO error handling of err */
1748 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1749 header_size
= p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+ sizeof(CFHEADER
);
1750 if( p_fci_internal
->fNextCab
|| p_fci_internal
->fGetNextCabInVain
) {
1751 header_size
+=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1753 header_size
+=p_fci_internal
->pccab
->cbReserveCFHeader
;
1756 if (p_fci_internal
->fPrevCab
) {
1757 header_size
+= strlen(p_fci_internal
->szPrevCab
)+1 +
1758 strlen(p_fci_internal
->szPrevDisk
)+1;
1761 if (p_fci_internal
->fNextCab
) {
1762 header_size
+= strlen(p_fci_internal
->oldCCAB
.szCab
)+1 +
1763 strlen(p_fci_internal
->oldCCAB
.szDisk
)+1;
1766 if( p_fci_internal
->fNextCab
|| p_fci_internal
->fGetNextCabInVain
) {
1767 header_size
+= p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1768 if( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1769 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1770 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1774 header_size
+= p_fci_internal
->pccab
->cbReserveCFHeader
;
1775 if( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1776 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1777 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1782 if (!write_folders( p_fci_internal
, handleCABINET
, header_size
, pfnfcis
)) return FALSE
;
1784 /* set seek of p_fci_internal->handleCFDATA2 to 0 */
1785 if( p_fci_internal
->seek(p_fci_internal
->handleCFDATA2
,
1786 0, SEEK_SET
, &err
, p_fci_internal
->pv
) != 0 ) {
1787 /* wrong return value */
1788 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1791 /* TODO error handling of err */
1793 /* reset the number of folders for the next cabinet */
1794 p_fci_internal
->cFolders
=0;
1795 /* reset the number of files for the next cabinet */
1796 p_fci_internal
->cFiles
=0;
1798 /* while not all CFDATA structures have been copied to the cabinet do */
1799 if (p_fci_internal
->data_out
) while(!FALSE
) {
1800 /* REUSE the variable read_result AGAIN */
1801 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1802 /* read a block from p_fci_internal->handleCFDATA2 */
1803 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA2
/* handle */,
1804 p_fci_internal
->data_out
, /* memory buffer */
1805 CB_MAX_CHUNK
, /* number of bytes to copy */
1806 &err
, p_fci_internal
->pv
);
1807 if( read_result
== 0 ) break; /* ALL CFDATA structures have been copied */
1808 /* TODO error handling of err */
1810 /* write the block to the cabinet file */
1811 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1812 p_fci_internal
->data_out
, /* memory buffer */
1813 read_result
, /* number of bytes to copy */
1814 &err
, p_fci_internal
->pv
) != read_result
) {
1816 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1819 /* TODO error handling of err */
1821 p_fci_internal
->statusFolderCopied
+= read_result
;
1822 /* report status with pfnfcis about copied size of folder */
1823 if( (*pfnfcis
)(statusFolder
,
1824 p_fci_internal
->statusFolderCopied
, /* length of copied blocks */
1825 p_fci_internal
->statusFolderTotal
, /* total size of folder */
1826 p_fci_internal
->pv
) == -1) {
1827 /* set error code and abort */
1828 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1831 } /* END OF while */
1833 /* set seek of the cabinet file to 0 */
1834 if( p_fci_internal
->seek( handleCABINET
,
1835 0, SEEK_SET
, &err
, p_fci_internal
->pv
) != 0 ) {
1836 /* wrong return value */
1837 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1840 /* TODO error handling of err */
1842 /* write the signature "MSCF" into the cabinet file */
1843 memcpy( cfheader
.signature
, "MSCF", 4 );
1844 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1845 &cfheader
, /* memory buffer */
1846 4, /* number of bytes to copy */
1847 &err
, p_fci_internal
->pv
) != 4 ) {
1849 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1852 /* TODO error handling of err */
1854 /* close the cabinet file */
1855 p_fci_internal
->close(handleCABINET
,&err
,p_fci_internal
->pv
);
1856 /* TODO error handling of err */
1858 p_fci_internal
->close( p_fci_internal
->handleCFDATA2
,&err
,p_fci_internal
->pv
);
1859 /* TODO error handling of err */
1860 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA2
, &err
,
1861 p_fci_internal
->pv
);
1862 /* TODO error handling of err */
1864 /* get 3 temporary files and open them */
1865 /* write names and handles to hfci */
1867 p_fci_internal
->sizeFileCFDATA2
= 0;
1868 p_fci_internal
->placed_files_size
= 0;
1869 p_fci_internal
->folders_size
= 0;
1871 /* CFDATA with checksum and ready to be copied into cabinet */
1872 if( !p_fci_internal
->gettemp( p_fci_internal
->szFileNameCFDATA2
,
1873 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
1874 /* error handling */
1875 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1879 if ( strlen(p_fci_internal
->szFileNameCFDATA2
) >= CB_MAX_FILENAME
) {
1880 /* set error code and abort */
1881 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1884 p_fci_internal
->handleCFDATA2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA2
,
1885 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
1886 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1888 if(p_fci_internal
->handleCFDATA2
==0){
1889 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
1892 /* TODO error checking of err */
1894 /* TODO close and delete new files when return FALSE */
1897 /* report status with pfnfcis about copied size of folder */
1898 (*pfnfcis
)(statusCabinet
,
1899 p_fci_internal
->estimatedCabinetSize
, /* estimated cabinet file size */
1900 cfheader
.cbCabinet
/* real cabinet file size */, p_fci_internal
->pv
);
1902 p_fci_internal
->fPrevCab
=TRUE
;
1903 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1904 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1906 if (p_fci_internal
->fNextCab
) {
1907 p_fci_internal
->fNextCab
=FALSE
;
1909 if (p_fci_internal
->files_size
==0 && p_fci_internal
->sizeFileCFDATA1
!=0) {
1910 /* THIS CAN NEVER HAPPEN */
1911 /* set error code */
1912 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1916 /* COPIED FROM FCIAddFile and modified */
1918 /* REUSE the variable read_result */
1919 if (p_fci_internal
->fGetNextCabInVain
) {
1920 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1921 if(p_fci_internal
->files_size
!=0) {
1922 read_result
+=p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1924 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1925 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1926 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1930 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
;
1931 if(p_fci_internal
->files_size
!=0) {
1932 read_result
+=p_fci_internal
->pccab
->cbReserveCFFolder
;
1934 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1935 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1936 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1940 if ( p_fci_internal
->fPrevCab
) {
1941 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
1942 strlen(p_fci_internal
->szPrevDisk
)+1;
1944 read_result
+= p_fci_internal
->sizeFileCFDATA1
+
1945 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
1946 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
1948 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
1950 if( p_fci_internal
->fNewPrevious
) {
1951 memcpy(p_fci_internal
->szPrevCab
, p_fci_internal
->oldCCAB
.szCab
,
1952 CB_MAX_CABINET_NAME
);
1953 memcpy(p_fci_internal
->szPrevDisk
, p_fci_internal
->oldCCAB
.szDisk
,
1955 p_fci_internal
->fNewPrevious
=FALSE
;
1958 /* too much data for the maximum size of a cabinet */
1959 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1960 p_fci_internal
->pccab
->cb
< read_result
) {
1961 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
1964 /* Might be too much data for the maximum size of a cabinet.*/
1965 /* When any further data will be added later, it might not */
1966 /* be possible to flush the cabinet, because there might */
1967 /* not be enough space to store the name of the following */
1968 /* cabinet and name of the corresponding disk. */
1969 /* So take care of this and get the name of the next cabinet */
1970 if (p_fci_internal
->fGetNextCabInVain
==FALSE
&& (
1971 p_fci_internal
->pccab
->cb
< read_result
+
1972 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
1975 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
1976 /* increment cabinet index */
1977 ++(p_fci_internal
->pccab
->iCab
);
1978 /* get name of next cabinet */
1979 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
1980 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
1981 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
1982 p_fci_internal
->pv
)) {
1983 /* error handling */
1984 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1987 /* Skip a few lines of code. This is caught by the next if. */
1988 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1991 /* too much data for cabinet */
1992 if (p_fci_internal
->fGetNextCabInVain
&& (
1993 p_fci_internal
->oldCCAB
.cb
< read_result
+
1994 strlen(p_fci_internal
->oldCCAB
.szCab
)+1+
1995 strlen(p_fci_internal
->oldCCAB
.szDisk
)+1
1997 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1998 p_fci_internal
->fNextCab
=TRUE
;
1999 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2002 /* if the FolderThreshold has been reached flush the folder automatically */
2003 if( p_fci_internal
->fGetNextCabInVain
) {
2004 if( p_fci_internal
->cCompressedBytesInFolder
>=
2005 p_fci_internal
->oldCCAB
.cbFolderThresh
) {
2006 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2009 if( p_fci_internal
->cCompressedBytesInFolder
>=
2010 p_fci_internal
->pccab
->cbFolderThresh
) {
2011 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2015 /* END OF COPIED FROM FCIAddFile and modified */
2017 if( p_fci_internal
->files_size
>0 ) {
2018 if( !fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
) ) return FALSE
;
2019 p_fci_internal
->fNewPrevious
=TRUE
;
2022 p_fci_internal
->fNewPrevious
=FALSE
;
2023 if( p_fci_internal
->files_size
>0 || p_fci_internal
->sizeFileCFDATA1
) {
2024 /* THIS MAY NEVER HAPPEN */
2025 /* set error structures */
2026 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2032 } /* end of fci_flush_cabinet */
2038 /***********************************************************************
2039 * FCIAddFile (CABINET.11)
2041 * FCIAddFile adds a file to the to be created cabinet file
2044 * hfci [I] An HFCI from FCICreate
2045 * pszSourceFile [I] A pointer to a C string which contains the name and
2046 * location of the file which will be added to the cabinet
2047 * pszFileName [I] A pointer to a C string which contains the name under
2048 * which the file will be stored in the cabinet
2049 * fExecute [I] A boolean value which indicates if the file should be
2050 * executed after extraction of self extracting
2052 * pfnfcignc [I] A pointer to a function which gets information about
2054 * pfnfcis [IO] A pointer to a function which will report status
2055 * information about the compression process
2056 * pfnfcioi [I] A pointer to a function which reports file attributes
2057 * and time and date information
2058 * typeCompress [I] Compression type
2061 * On success, returns TRUE
2062 * On failure, returns FALSE
2068 BOOL __cdecl
FCIAddFile(
2070 char *pszSourceFile
,
2073 PFNFCIGETNEXTCABINET pfnfcignc
,
2074 PFNFCISTATUS pfnfcis
,
2075 PFNFCIGETOPENINFO pfnfcigoi
,
2079 cab_ULONG read_result
;
2082 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2084 if (!p_fci_internal
) return FALSE
;
2086 if ((!pszSourceFile
) || (!pszFileName
) || (!pfnfcignc
) || (!pfnfcis
) ||
2087 (!pfnfcigoi
) || strlen(pszFileName
)>=CB_MAX_FILENAME
) {
2088 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
2092 /* TODO check if pszSourceFile??? */
2094 if(p_fci_internal
->fGetNextCabInVain
&& p_fci_internal
->fNextCab
) {
2095 /* internal error */
2096 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2100 if(p_fci_internal
->fNextCab
) {
2101 /* internal error */
2102 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2106 if (!(file
= add_file( p_fci_internal
, pszFileName
))) return FALSE
;
2108 /* allocation of memory */
2109 if (p_fci_internal
->data_in
==NULL
) {
2110 if (p_fci_internal
->cdata_in
!=0) {
2111 /* error handling */
2112 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2115 if (p_fci_internal
->data_out
!=NULL
) {
2116 /* error handling */
2117 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2120 if(!(p_fci_internal
->data_in
= p_fci_internal
->alloc(CB_MAX_CHUNK
))) {
2121 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
2124 if (p_fci_internal
->data_out
==NULL
) {
2125 if(!(p_fci_internal
->data_out
= p_fci_internal
->alloc( 2 * CB_MAX_CHUNK
))){
2126 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
2132 if (p_fci_internal
->data_out
==NULL
) {
2133 p_fci_internal
->free(p_fci_internal
->data_in
);
2134 /* error handling */
2135 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2139 /* get information about the file */
2140 /* set defaults in case callback doesn't set one or more fields */
2141 file_handle
= pfnfcigoi( pszSourceFile
, &file
->date
, &file
->time
, &file
->attribs
,
2142 &err
, p_fci_internal
->pv
);
2143 /* check file_handle */
2145 set_error( p_fci_internal
, FCIERR_OPEN_SRC
, ERROR_OPEN_FAILED
);
2147 /* TODO error handling of err */
2149 if (fExecute
) { file
->attribs
|= _A_EXEC
; }
2151 /* REUSE the variable read_result */
2152 if (p_fci_internal
->fGetNextCabInVain
) {
2153 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
2154 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
2155 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
2156 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
2157 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
2161 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
+
2162 p_fci_internal
->pccab
->cbReserveCFFolder
;
2163 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
2164 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
2165 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
2169 if ( p_fci_internal
->fPrevCab
) {
2170 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
2171 strlen(p_fci_internal
->szPrevDisk
)+1;
2173 if ( p_fci_internal
->fNextCab
) { /* this is never the case */
2174 read_result
+= strlen(p_fci_internal
->pccab
->szCab
)+1+
2175 strlen(p_fci_internal
->pccab
->szDisk
)+1;
2178 read_result
+= sizeof(CFFILE
) + strlen(pszFileName
)+1 +
2179 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
2180 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
2182 sizeof(CFFOLDER
); /* size of new CFFolder entry */
2184 /* Might be too much data for the maximum size of a cabinet.*/
2185 /* When any further data will be added later, it might not */
2186 /* be possible to flush the cabinet, because there might */
2187 /* not be enough space to store the name of the following */
2188 /* cabinet and name of the corresponding disk. */
2189 /* So take care of this and get the name of the next cabinet */
2190 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2191 p_fci_internal
->fNextCab
==FALSE
&&
2192 ( p_fci_internal
->pccab
->cb
< read_result
+
2193 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
2197 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
2198 /* increment cabinet index */
2199 ++(p_fci_internal
->pccab
->iCab
);
2200 /* get name of next cabinet */
2201 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
2202 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
2203 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
2204 p_fci_internal
->pv
)) {
2205 /* error handling */
2206 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2209 /* Skip a few lines of code. This is caught by the next if. */
2210 p_fci_internal
->fGetNextCabInVain
=TRUE
;
2213 if( p_fci_internal
->fGetNextCabInVain
&&
2214 p_fci_internal
->fNextCab
2216 /* THIS CAN NEVER HAPPEN */
2217 /* set error code */
2218 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2222 /* too much data for cabinet */
2223 if( p_fci_internal
->fGetNextCabInVain
&&
2225 p_fci_internal
->oldCCAB
.cb
< read_result
+
2226 strlen(p_fci_internal
->pccab
->szCab
)+1+
2227 strlen(p_fci_internal
->pccab
->szDisk
)+1
2229 p_fci_internal
->fGetNextCabInVain
=FALSE
;
2230 p_fci_internal
->fNextCab
=TRUE
;
2231 if(!fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
)) return FALSE
;
2234 if( p_fci_internal
->fNextCab
) {
2235 /* THIS MAY NEVER HAPPEN */
2236 /* set error code */
2237 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2241 /* read the contents of the file blockwise */
2243 if (p_fci_internal
->cdata_in
> CAB_BLOCKMAX
) {
2244 /* internal error */
2245 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2249 read_result
= p_fci_internal
->read( file_handle
/* file handle */,
2250 (p_fci_internal
->data_in
+ p_fci_internal
->cdata_in
) /* memory buffer */,
2251 (CAB_BLOCKMAX
- p_fci_internal
->cdata_in
) /* number of bytes to copy */,
2252 &err
, p_fci_internal
->pv
);
2253 /* TODO error handling of err */
2255 if( read_result
==0 ) break;
2257 /* increment the block size */
2258 p_fci_internal
->cdata_in
+= read_result
;
2260 /* increment the file size */
2261 file
->size
+= read_result
;
2263 if ( p_fci_internal
->cdata_in
> CAB_BLOCKMAX
) {
2264 /* report internal error */
2265 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2268 /* write a whole block */
2269 if ( p_fci_internal
->cdata_in
== CAB_BLOCKMAX
) {
2271 if( !fci_flush_data_block(p_fci_internal
, &err
, pfnfcis
) ) return FALSE
;
2275 /* close the file from FCIAddFile */
2276 p_fci_internal
->close(file_handle
,&err
,p_fci_internal
->pv
);
2277 /* TODO error handling of err */
2279 p_fci_internal
->files_size
+= sizeof(CFFILE
) + strlen(pszFileName
)+1;
2281 /* REUSE the variable read_result */
2282 if (p_fci_internal
->fGetNextCabInVain
||
2283 p_fci_internal
->fNextCab
2285 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
2286 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
2287 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
2288 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
2289 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
2293 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
+
2294 p_fci_internal
->pccab
->cbReserveCFFolder
;
2295 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
2296 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
2297 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
2301 if ( p_fci_internal
->fPrevCab
) {
2302 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
2303 strlen(p_fci_internal
->szPrevDisk
)+1;
2305 if ( p_fci_internal
->fNextCab
) { /* this is never the case */
2306 read_result
+= strlen(p_fci_internal
->pccab
->szCab
)+1+
2307 strlen(p_fci_internal
->pccab
->szDisk
)+1;
2309 read_result
+= p_fci_internal
->sizeFileCFDATA1
+
2310 p_fci_internal
->files_size
+ p_fci_internal
->sizeFileCFDATA2
+
2311 p_fci_internal
->placed_files_size
+ p_fci_internal
->folders_size
+
2313 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
2315 /* too much data for the maximum size of a cabinet */
2316 /* (ignoring the unflushed data block) */
2317 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2318 p_fci_internal
->fNextCab
==FALSE
&& /* this is always the case */
2319 p_fci_internal
->pccab
->cb
< read_result
) {
2320 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2323 /* Might be too much data for the maximum size of a cabinet.*/
2324 /* When any further data will be added later, it might not */
2325 /* be possible to flush the cabinet, because there might */
2326 /* not be enough space to store the name of the following */
2327 /* cabinet and name of the corresponding disk. */
2328 /* So take care of this and get the name of the next cabinet */
2329 /* (ignoring the unflushed data block) */
2330 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2331 p_fci_internal
->fNextCab
==FALSE
&&
2332 ( p_fci_internal
->pccab
->cb
< read_result
+
2333 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
2337 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
2338 /* increment cabinet index */
2339 ++(p_fci_internal
->pccab
->iCab
);
2340 /* get name of next cabinet */
2341 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
2342 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
2343 p_fci_internal
->estimatedCabinetSize
,/* estimated size of cab */
2344 p_fci_internal
->pv
)) {
2345 /* error handling */
2346 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2349 /* Skip a few lines of code. This is caught by the next if. */
2350 p_fci_internal
->fGetNextCabInVain
=TRUE
;
2353 if( p_fci_internal
->fGetNextCabInVain
&&
2354 p_fci_internal
->fNextCab
2356 /* THIS CAN NEVER HAPPEN */
2357 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2361 /* too much data for cabinet */
2362 if( (p_fci_internal
->fGetNextCabInVain
||
2363 p_fci_internal
->fNextCab
) && (
2364 p_fci_internal
->oldCCAB
.cb
< read_result
+
2365 strlen(p_fci_internal
->pccab
->szCab
)+1+
2366 strlen(p_fci_internal
->pccab
->szDisk
)+1
2369 p_fci_internal
->fGetNextCabInVain
=FALSE
;
2370 p_fci_internal
->fNextCab
=TRUE
;
2371 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2374 if( p_fci_internal
->fNextCab
) {
2375 /* THIS MAY NEVER HAPPEN */
2376 /* set error code */
2377 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2381 /* if the FolderThreshold has been reached flush the folder automatically */
2382 if( p_fci_internal
->fGetNextCabInVain
) {
2383 if( p_fci_internal
->cCompressedBytesInFolder
>=
2384 p_fci_internal
->oldCCAB
.cbFolderThresh
) {
2385 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
2388 if( p_fci_internal
->cCompressedBytesInFolder
>=
2389 p_fci_internal
->pccab
->cbFolderThresh
) {
2390 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
2395 } /* end of FCIAddFile */
2401 /***********************************************************************
2402 * FCIFlushFolder (CABINET.12)
2404 * FCIFlushFolder completes the CFFolder structure under construction.
2406 * All further data which is added by FCIAddFile will be associated to
2407 * the next CFFolder structure.
2409 * FCIFlushFolder will be called by FCIAddFile automatically if the
2410 * threshold (stored in the member cbFolderThresh of the CCAB structure
2411 * pccab passed to FCICreate) is exceeded.
2413 * FCIFlushFolder will be called by FCIFlushFolder automatically before
2414 * any data will be written into the cabinet file.
2417 * hfci [I] An HFCI from FCICreate
2418 * pfnfcignc [I] A pointer to a function which gets information about
2420 * pfnfcis [IO] A pointer to a function which will report status
2421 * information about the compression process
2424 * On success, returns TRUE
2425 * On failure, returns FALSE
2431 BOOL __cdecl
FCIFlushFolder(
2433 PFNFCIGETNEXTCABINET pfnfcignc
,
2434 PFNFCISTATUS pfnfcis
)
2436 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2438 if (!p_fci_internal
) return FALSE
;
2439 return fci_flush_folder(p_fci_internal
,FALSE
,pfnfcignc
,pfnfcis
);
2444 /***********************************************************************
2445 * FCIFlushCabinet (CABINET.13)
2447 * FCIFlushCabinet stores the data which has been added by FCIAddFile
2448 * into the cabinet file. If the maximum cabinet size (stored in the
2449 * member cb of the CCAB structure pccab passed to FCICreate) has been
2450 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2451 * The remaining data still has to be flushed manually by calling
2454 * After FCIFlushCabinet has been called (manually) FCIAddFile must
2455 * NOT be called again. Then hfci has to be released by FCIDestroy.
2458 * hfci [I] An HFCI from FCICreate
2459 * fGetNextCab [I] Whether you want to add additional files to a
2460 * cabinet set (TRUE) or whether you want to
2461 * finalize it (FALSE)
2462 * pfnfcignc [I] A pointer to a function which gets information about
2464 * pfnfcis [IO] A pointer to a function which will report status
2465 * information about the compression process
2468 * On success, returns TRUE
2469 * On failure, returns FALSE
2475 BOOL __cdecl
FCIFlushCabinet(
2478 PFNFCIGETNEXTCABINET pfnfcignc
,
2479 PFNFCISTATUS pfnfcis
)
2481 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2483 if (!p_fci_internal
) return FALSE
;
2485 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
2487 while( p_fci_internal
->files_size
>0 ||
2488 p_fci_internal
->placed_files_size
>0 ) {
2489 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
2496 /***********************************************************************
2497 * FCIDestroy (CABINET.14)
2499 * Frees a handle created by FCICreate.
2500 * Only reason for failure would be an invalid handle.
2503 * hfci [I] The HFCI to free
2509 BOOL __cdecl
FCIDestroy(HFCI hfci
)
2512 struct folder
*folder
, *folder_next
;
2513 struct file
*file
, *file_next
;
2514 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2516 if (!p_fci_internal
) return FALSE
;
2518 /* before hfci can be removed all temporary files must be closed */
2520 p_fci_internal
->magic
= 0;
2522 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &p_fci_internal
->folders_list
, struct folder
, entry
)
2524 free_folder( p_fci_internal
, folder
);
2526 LIST_FOR_EACH_ENTRY_SAFE( file
, file_next
, &p_fci_internal
->files_list
, struct file
, entry
)
2528 free_file( p_fci_internal
, file
);
2531 p_fci_internal
->close( p_fci_internal
->handleCFDATA1
,&err
,p_fci_internal
->pv
);
2532 /* TODO error handling of err */
2533 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA1
, &err
,
2534 p_fci_internal
->pv
);
2535 /* TODO error handling of err */
2536 p_fci_internal
->close( p_fci_internal
->handleCFDATA2
,&err
,p_fci_internal
->pv
);
2537 /* TODO error handling of err */
2538 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA2
, &err
,
2539 p_fci_internal
->pv
);
2540 /* TODO error handling of err */
2542 /* data in and out buffers have to be removed */
2543 if (p_fci_internal
->data_in
!=NULL
)
2544 p_fci_internal
->free(p_fci_internal
->data_in
);
2545 if (p_fci_internal
->data_out
!=NULL
)
2546 p_fci_internal
->free(p_fci_internal
->data_out
);
2548 /* hfci can now be removed */
2549 p_fci_internal
->free(hfci
);