2 * File Compression Interface
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 There is still some work to be done:
26 - no real compression yet
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
48 #include "wine/list.h"
49 #include "wine/debug.h"
52 #ifdef WORDS_BIGENDIAN
53 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
54 #define fci_endian_uword(x) RtlUshortByteSwap(x)
56 #define fci_endian_ulong(x) (x)
57 #define fci_endian_uword(x) (x)
62 cab_UBYTE signature
[4]; /* !CAB for unfinished cabinets else MSCF */
64 cab_ULONG cbCabinet
; /* size of the cabinet file in bytes*/
66 cab_ULONG coffFiles
; /* offset to first CFFILE section */
68 cab_UBYTE versionMinor
; /* 3 */
69 cab_UBYTE versionMajor
; /* 1 */
70 cab_UWORD cFolders
; /* number of CFFOLDER entries in the cabinet*/
71 cab_UWORD cFiles
; /* number of CFFILE entries in the cabinet*/
72 cab_UWORD flags
; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
73 cab_UWORD setID
; /* identification number of all cabinets in a set*/
74 cab_UWORD iCabinet
; /* number of the cabinet in a set */
75 /* additional area if "flags" were set*/
76 } CFHEADER
; /* minimum 36 bytes */
79 cab_ULONG coffCabStart
; /* offset to the folder's first CFDATA section */
80 cab_UWORD cCFData
; /* number of this folder's CFDATA sections */
81 cab_UWORD typeCompress
; /* compression type of data in CFDATA section*/
82 /* additional area if reserve flag was set */
83 } CFFOLDER
; /* minimum 8 bytes */
86 cab_ULONG cbFile
; /* size of the uncompressed file in bytes */
87 cab_ULONG uoffFolderStart
; /* offset of the uncompressed file in the folder */
88 cab_UWORD iFolder
; /* number of folder in the cabinet 0=first */
89 /* for special values see below this structure*/
90 cab_UWORD date
; /* last modification date*/
91 cab_UWORD time
; /* last modification time*/
92 cab_UWORD attribs
; /* DOS fat attributes and UTF indicator */
93 /* ... and a C string with the name of the file */
94 } CFFILE
; /* 16 bytes + name of file */
98 cab_ULONG csum
; /* checksum of this entry*/
99 cab_UWORD cbData
; /* number of compressed bytes */
100 cab_UWORD cbUncomp
; /* number of bytes when data is uncompressed */
101 /* optional reserved area */
102 /* compressed data */
108 cab_ULONG data_start
;
109 cab_UWORD data_count
;
110 cab_UWORD compression
;
117 PFNFCIFILEPLACED fileplaced
;
126 PFNFCIGETTEMPFILE gettemp
;
131 cab_ULONG statusFolderCopied
;
132 cab_ULONG statusFolderTotal
;
133 BOOL fGetNextCabInVain
;
135 char szPrevCab
[CB_MAX_CABINET_NAME
]; /* previous cabinet name */
136 char szPrevDisk
[CB_MAX_DISK_NAME
]; /* disk name of previous cabinet */
138 char* data_in
; /* uncompressed data blocks */
140 char* data_out
; /* compressed data blocks */
141 ULONG cCompressedBytesInFolder
;
144 cab_ULONG cDataBlocks
;
145 cab_ULONG cbFileRemainer
; /* uncompressed, yet to be written data */
146 /* of spanned file of a spanning folder of a spanning cabinet */
147 char szFileNameCFDATA1
[CB_MAX_FILENAME
];
149 char szFileNameCFFILE1
[CB_MAX_FILENAME
];
151 char szFileNameCFDATA2
[CB_MAX_FILENAME
];
153 char szFileNameCFFILE2
[CB_MAX_FILENAME
];
155 cab_ULONG sizeFileCFDATA1
;
156 cab_ULONG sizeFileCFFILE1
;
157 cab_ULONG sizeFileCFDATA2
;
158 cab_ULONG sizeFileCFFILE2
;
160 cab_ULONG estimatedCabinetSize
;
161 struct list folders_list
;
162 cab_ULONG folders_size
;
165 #define FCI_INT_MAGIC 0xfcfcfc05
167 static void set_error( FCI_Int
*fci
, int oper
, int err
)
169 fci
->perf
->erfOper
= oper
;
170 fci
->perf
->erfType
= err
;
171 fci
->perf
->fError
= TRUE
;
172 if (err
) SetLastError( err
);
175 static FCI_Int
*get_fci_ptr( HFCI hfci
)
177 FCI_Int
*fci
= (FCI_Int
*)hfci
;
179 if (!fci
|| !fci
->magic
== FCI_INT_MAGIC
)
181 SetLastError( ERROR_INVALID_HANDLE
);
187 static cab_ULONG
get_folder_size( FCI_Int
*fci
)
189 if (fci
->fNextCab
|| fci
->fGetNextCabInVain
)
190 return sizeof(CFFOLDER
) + fci
->oldCCAB
.cbReserveCFFolder
;
192 return sizeof(CFFOLDER
) + fci
->pccab
->cbReserveCFFolder
;
195 static struct folder
*add_folder( FCI_Int
*fci
)
197 struct folder
*folder
= fci
->alloc( sizeof(*folder
) );
201 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
204 folder
->data_start
= fci
->sizeFileCFDATA2
;
205 folder
->compression
= tcompTYPE_NONE
; /* FIXME */
206 list_add_tail( &fci
->folders_list
, &folder
->entry
);
207 fci
->folders_size
+= get_folder_size( fci
);
212 /* write all folders to disk and remove them from the list */
213 static BOOL
write_folders( FCI_Int
*fci
, INT_PTR handle
, cab_ULONG header_size
)
215 struct folder
*folder
, *next
;
219 cab_ULONG folder_size
= get_folder_size( fci
);
221 if (!(cffolder
= fci
->alloc( folder_size
)))
223 set_error( fci
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
226 memset( cffolder
, 0, folder_size
);
228 LIST_FOR_EACH_ENTRY_SAFE( folder
, next
, &fci
->folders_list
, struct folder
, entry
)
230 cffolder
->coffCabStart
= fci_endian_ulong( folder
->data_start
+ header_size
);
231 cffolder
->cCFData
= fci_endian_uword( folder
->data_count
);
232 cffolder
->typeCompress
= fci_endian_uword( folder
->compression
);
233 if (fci
->write( handle
, cffolder
, folder_size
, &err
, fci
->pv
) != folder_size
)
235 set_error( fci
, FCIERR_CAB_FILE
, err
);
239 list_remove( &folder
->entry
);
241 fci
->free( cffolder
);
245 /***********************************************************************
246 * FCICreate (CABINET.10)
248 * FCICreate is provided with several callbacks and
249 * returns a handle which can be used to create cabinet files.
252 * perf [IO] A pointer to an ERF structure. When FCICreate
253 * returns an error condition, error information may
254 * be found here as well as from GetLastError.
255 * pfnfiledest [I] A pointer to a function which is called when a file
256 * is placed. Only useful for subsequent cabinet files.
257 * pfnalloc [I] A pointer to a function which allocates ram. Uses
258 * the same interface as malloc.
259 * pfnfree [I] A pointer to a function which frees ram. Uses the
260 * same interface as free.
261 * pfnopen [I] A pointer to a function which opens a file. Uses
262 * the same interface as _open.
263 * pfnread [I] A pointer to a function which reads from a file into
264 * a caller-provided buffer. Uses the same interface
266 * pfnwrite [I] A pointer to a function which writes to a file from
267 * a caller-provided buffer. Uses the same interface
269 * pfnclose [I] A pointer to a function which closes a file handle.
270 * Uses the same interface as _close.
271 * pfnseek [I] A pointer to a function which seeks in a file.
272 * Uses the same interface as _lseek.
273 * pfndelete [I] A pointer to a function which deletes a file.
274 * pfnfcigtf [I] A pointer to a function which gets the name of a
276 * pccab [I] A pointer to an initialized CCAB structure.
277 * pv [I] A pointer to an application-defined notification
278 * function which will be passed to other FCI functions
282 * On success, returns an FCI handle of type HFCI.
283 * On failure, the NULL file handle is returned. Error
284 * info can be retrieved from perf.
290 HFCI __cdecl
FCICreate(
292 PFNFCIFILEPLACED pfnfiledest
,
293 PFNFCIALLOC pfnalloc
,
297 PFNFCIWRITE pfnwrite
,
298 PFNFCICLOSE pfnclose
,
300 PFNFCIDELETE pfndelete
,
301 PFNFCIGETTEMPFILE pfnfcigtf
,
306 FCI_Int
*p_fci_internal
;
309 SetLastError(ERROR_BAD_ARGUMENTS
);
312 if ((!pfnalloc
) || (!pfnfree
) || (!pfnopen
) || (!pfnread
) ||
313 (!pfnwrite
) || (!pfnclose
) || (!pfnseek
) || (!pfndelete
) ||
314 (!pfnfcigtf
) || (!pccab
)) {
315 perf
->erfOper
= FCIERR_NONE
;
316 perf
->erfType
= ERROR_BAD_ARGUMENTS
;
319 SetLastError(ERROR_BAD_ARGUMENTS
);
323 if (!((p_fci_internal
= pfnalloc(sizeof(FCI_Int
))))) {
324 perf
->erfOper
= FCIERR_ALLOC_FAIL
;
325 perf
->erfType
= ERROR_NOT_ENOUGH_MEMORY
;
328 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
332 p_fci_internal
->magic
= FCI_INT_MAGIC
;
333 p_fci_internal
->perf
= perf
;
334 p_fci_internal
->fileplaced
= pfnfiledest
;
335 p_fci_internal
->alloc
= pfnalloc
;
336 p_fci_internal
->free
= pfnfree
;
337 p_fci_internal
->open
= pfnopen
;
338 p_fci_internal
->read
= pfnread
;
339 p_fci_internal
->write
= pfnwrite
;
340 p_fci_internal
->close
= pfnclose
;
341 p_fci_internal
->seek
= pfnseek
;
342 p_fci_internal
->delete = pfndelete
;
343 p_fci_internal
->gettemp
= pfnfcigtf
;
344 p_fci_internal
->pccab
= pccab
;
345 p_fci_internal
->fPrevCab
= FALSE
;
346 p_fci_internal
->fNextCab
= FALSE
;
347 p_fci_internal
->fSplitFolder
= FALSE
;
348 p_fci_internal
->fGetNextCabInVain
= FALSE
;
349 p_fci_internal
->pv
= pv
;
350 p_fci_internal
->data_in
= NULL
;
351 p_fci_internal
->cdata_in
= 0;
352 p_fci_internal
->data_out
= NULL
;
353 p_fci_internal
->cCompressedBytesInFolder
= 0;
354 p_fci_internal
->cFolders
= 0;
355 p_fci_internal
->cFiles
= 0;
356 p_fci_internal
->cDataBlocks
= 0;
357 p_fci_internal
->sizeFileCFDATA1
= 0;
358 p_fci_internal
->sizeFileCFFILE1
= 0;
359 p_fci_internal
->sizeFileCFDATA2
= 0;
360 p_fci_internal
->sizeFileCFFILE2
= 0;
361 p_fci_internal
->fNewPrevious
= FALSE
;
362 p_fci_internal
->estimatedCabinetSize
= 0;
363 p_fci_internal
->statusFolderTotal
= 0;
364 p_fci_internal
->folders_size
= 0;
366 list_init( &p_fci_internal
->folders_list
);
368 memset(&p_fci_internal
->oldCCAB
, 0, sizeof(CCAB
));
369 memcpy(p_fci_internal
->szPrevCab
, pccab
->szCab
, CB_MAX_CABINET_NAME
);
370 memcpy(p_fci_internal
->szPrevDisk
, pccab
->szDisk
, CB_MAX_DISK_NAME
);
373 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFDATA1
,
374 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
375 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
379 if ( strlen(p_fci_internal
->szFileNameCFDATA1
) >= CB_MAX_FILENAME
) {
380 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
384 p_fci_internal
->handleCFDATA1
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA1
,
385 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
386 _S_IREAD
| _S_IWRITE
, &err
, pv
);
387 if(p_fci_internal
->handleCFDATA1
==0){
388 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
391 /* TODO error checking of err */
393 /* array of all CFFILE in a folder */
394 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFFILE1
,
395 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
396 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
400 if ( strlen(p_fci_internal
->szFileNameCFFILE1
) >= CB_MAX_FILENAME
) {
401 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
404 p_fci_internal
->handleCFFILE1
= p_fci_internal
->open( p_fci_internal
->szFileNameCFFILE1
,
405 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
406 _S_IREAD
| _S_IWRITE
, &err
, pv
);
407 if(p_fci_internal
->handleCFFILE1
==0){
408 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
411 /* TODO error checking of err */
413 /* CFDATA with checksum and ready to be copied into cabinet */
414 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFDATA2
,
415 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
416 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
420 if ( strlen(p_fci_internal
->szFileNameCFDATA2
) >= CB_MAX_FILENAME
) {
421 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
424 p_fci_internal
->handleCFDATA2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA2
,
425 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
426 _S_IREAD
| _S_IWRITE
, &err
, pv
);
427 if(p_fci_internal
->handleCFDATA2
==0){
428 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
431 /* TODO error checking of err */
433 /* array of all CFFILE in a folder, ready to be copied into cabinet */
434 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFFILE2
,
435 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
436 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
440 if ( strlen(p_fci_internal
->szFileNameCFFILE2
) >= CB_MAX_FILENAME
) {
441 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
444 p_fci_internal
->handleCFFILE2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFFILE2
,
445 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
446 _S_IREAD
| _S_IWRITE
, &err
, pv
);
447 if(p_fci_internal
->handleCFFILE2
==0){
448 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
451 /* TODO error checking of err */
453 /* TODO close and delete new files when return FALSE */
455 return (HFCI
)p_fci_internal
;
463 static BOOL
fci_flush_data_block (FCI_Int
*p_fci_internal
, int* err
,
464 PFNFCISTATUS pfnfcis
) {
466 /* attention no checks if there is data available!!! */
468 CFDATA
* cfdata
=&data
;
470 UINT cbReserveCFData
=p_fci_internal
->pccab
->cbReserveCFData
;
473 /* TODO compress the data of p_fci_internal->data_in */
474 /* and write it to p_fci_internal->data_out */
475 memcpy(p_fci_internal
->data_out
, p_fci_internal
->data_in
,
476 p_fci_internal
->cdata_in
/* number of bytes to copy */);
478 cfdata
->csum
=0; /* checksum has to be set later */
479 /* TODO set realsize of compressed data */
480 cfdata
->cbData
= p_fci_internal
->cdata_in
;
481 cfdata
->cbUncomp
= p_fci_internal
->cdata_in
;
483 /* write cfdata to p_fci_internal->handleCFDATA1 */
484 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
485 cfdata
, sizeof(*cfdata
), err
, p_fci_internal
->pv
)
486 != sizeof(*cfdata
) ) {
487 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
490 /* TODO error handling of err */
492 p_fci_internal
->sizeFileCFDATA1
+= sizeof(*cfdata
);
494 /* add optional reserved area */
496 /* This allocation and freeing at each CFData block is a bit */
497 /* inefficient, but it's harder to forget about freeing the buffer :-). */
498 /* Reserved areas are used seldom besides that... */
499 if (cbReserveCFData
!=0) {
500 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFData
))) {
501 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
504 for(i
=0;i
<cbReserveCFData
;) {
507 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
508 reserved
, /* memory buffer */
509 cbReserveCFData
, /* number of bytes to copy */
510 err
, p_fci_internal
->pv
) != cbReserveCFData
) {
511 p_fci_internal
->free(reserved
);
512 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
515 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
517 p_fci_internal
->sizeFileCFDATA1
+= cbReserveCFData
;
518 p_fci_internal
->free( reserved
);
521 /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
522 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA1
, /* file handle */
523 p_fci_internal
->data_out
, /* memory buffer */
524 cfdata
->cbData
, /* number of bytes to copy */
525 err
, p_fci_internal
->pv
) != cfdata
->cbData
) {
526 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
529 /* TODO error handling of err */
531 p_fci_internal
->sizeFileCFDATA1
+= cfdata
->cbData
;
533 /* reset the offset */
534 p_fci_internal
->cdata_in
= 0;
535 p_fci_internal
->cCompressedBytesInFolder
+= cfdata
->cbData
;
537 /* report status with pfnfcis about uncompressed and compressed file data */
538 if( (*pfnfcis
)(statusFile
, cfdata
->cbData
, cfdata
->cbUncomp
,
539 p_fci_internal
->pv
) == -1) {
540 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
544 ++(p_fci_internal
->cDataBlocks
);
547 } /* end of fci_flush_data_block */
553 static cab_ULONG
fci_get_checksum(const void *pv
, UINT cb
, CHECKSUM seed
)
564 while (cUlong
-- > 0) {
566 ul
|= (((cab_ULONG
)(*pb
++)) << 8);
567 ul
|= (((cab_ULONG
)(*pb
++)) << 16);
568 ul
|= (((cab_ULONG
)(*pb
++)) << 24);
576 ul
|= (((ULONG
)(*pb
++)) << 16);
578 ul
|= (((ULONG
)(*pb
++)) << 8);
587 } /* end of fci_get_checksum */
591 static BOOL
fci_flushfolder_copy_cfdata(FCI_Int
*p_fci_internal
, char* buffer
, UINT cbReserveCFData
,
592 PFNFCISTATUS pfnfcis
, int* err
, int handleCFDATA1new
,
593 cab_ULONG
* psizeFileCFDATA1new
, cab_ULONG
* payload
)
595 cab_ULONG read_result
;
596 CFDATA
* pcfdata
=(CFDATA
*)buffer
;
597 BOOL split_block
=FALSE
;
598 cab_UWORD savedUncomp
=0;
602 /* while not all CFDATAs have been copied do */
604 if( p_fci_internal
->fNextCab
) {
606 /* internal error should never happen */
607 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
611 /* REUSE the variable read_result */
612 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
613 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
614 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
619 if (p_fci_internal
->fPrevCab
) {
620 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
621 strlen(p_fci_internal
->szPrevDisk
)+1;
623 /* No more CFDATA fits into the cabinet under construction */
624 /* So don't try to store more data into it */
625 if( p_fci_internal
->fNextCab
&&
626 (p_fci_internal
->oldCCAB
.cb
<= sizeof(CFDATA
) + cbReserveCFData
+
627 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
628 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
631 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
633 p_fci_internal
->oldCCAB
.cbReserveCFFolder
+
634 strlen(p_fci_internal
->pccab
->szCab
)+1 +
635 strlen(p_fci_internal
->pccab
->szDisk
)+1
637 /* This may never be run for the first time the while loop is entered.
638 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
639 split_block
=TRUE
; /* In this case split_block is abused to store */
640 /* the complete data block into the next cabinet and not into the */
641 /* current one. Originally split_block is the indicator that a */
642 /* data block has been split across different cabinets. */
645 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
646 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA1
,/*file handle*/
647 buffer
, /* memory buffer */
648 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
649 err
, p_fci_internal
->pv
);
650 if (read_result
!=sizeof(CFDATA
)+cbReserveCFData
) {
651 if (read_result
==0) break; /* ALL DATA has been copied */
653 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
656 /* TODO error handling of err */
658 /* REUSE buffer p_fci_internal->data_out !!! */
659 /* read data from p_fci_internal->handleCFDATA1 to */
660 /* p_fci_internal->data_out */
661 if( p_fci_internal
->read( p_fci_internal
->handleCFDATA1
/* file handle */,
662 p_fci_internal
->data_out
/* memory buffer */,
663 pcfdata
->cbData
/* number of bytes to copy */,
664 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
666 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
669 /* TODO error handling of err */
671 /* if cabinet size is too large */
673 /* REUSE the variable read_result */
674 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
675 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
676 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
681 if (p_fci_internal
->fPrevCab
) {
682 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
683 strlen(p_fci_internal
->szPrevDisk
)+1;
686 /* Is cabinet with new CFDATA too large? Then data block has to be split */
687 if( p_fci_internal
->fNextCab
&&
688 (p_fci_internal
->oldCCAB
.cb
< sizeof(CFDATA
) + cbReserveCFData
+
690 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
691 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
694 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
695 sizeof(CFFOLDER
) + /* size of new CFFolder entry */
696 p_fci_internal
->oldCCAB
.cbReserveCFFolder
+
697 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* name of next cabinet */
698 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* name of next disk */
700 /* REUSE read_result to save the size of the compressed data */
701 read_result
=pcfdata
->cbData
;
702 /* Modify the size of the compressed data to store only a part of the */
703 /* data block into the current cabinet. This is done to prevent */
704 /* that the maximum cabinet size will be exceeded. The remainder */
705 /* will be stored into the next following cabinet. */
707 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
708 /* Substract everything except the size of the block of data */
709 /* to get it's actual size */
710 pcfdata
->cbData
= p_fci_internal
->oldCCAB
.cb
- (
711 sizeof(CFDATA
) + cbReserveCFData
+
712 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
713 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
715 p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
716 sizeof(CFFOLDER
) + /* set size of new CFFolder entry */
717 p_fci_internal
->oldCCAB
.cbReserveCFFolder
);
718 /* substract the size of special header fields */
719 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
720 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
721 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
724 if (p_fci_internal
->fPrevCab
) {
725 pcfdata
->cbData
-=strlen(p_fci_internal
->szPrevCab
)+1 +
726 strlen(p_fci_internal
->szPrevDisk
)+1;
728 pcfdata
->cbData
-=strlen(p_fci_internal
->pccab
->szCab
)+1 +
729 strlen(p_fci_internal
->pccab
->szDisk
)+1;
731 savedUncomp
= pcfdata
->cbUncomp
;
732 pcfdata
->cbUncomp
= 0; /* on split blocks of data this is zero */
734 /* if split_block==TRUE then the above while loop won't */
735 /* be executed again */
736 split_block
=TRUE
; /* split_block is the indicator that */
737 /* a data block has been split across */
738 /* different cabinets.*/
741 /* This should never happen !!! */
742 if (pcfdata
->cbData
==0) {
744 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
748 /* set little endian */
749 pcfdata
->cbData
=fci_endian_uword(pcfdata
->cbData
);
750 pcfdata
->cbUncomp
=fci_endian_uword(pcfdata
->cbUncomp
);
752 /* get checksum and write to cfdata.csum */
753 pcfdata
->csum
= fci_get_checksum( &(pcfdata
->cbData
),
754 sizeof(CFDATA
)+cbReserveCFData
-
755 sizeof(pcfdata
->csum
), fci_get_checksum( p_fci_internal
->data_out
, /*buffer*/
756 pcfdata
->cbData
, 0 ) );
758 /* set little endian */
759 pcfdata
->csum
=fci_endian_ulong(pcfdata
->csum
);
761 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
762 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA2
, /* file handle */
763 buffer
, /* memory buffer */
764 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
765 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
766 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
769 /* TODO error handling of err */
771 p_fci_internal
->sizeFileCFDATA2
+= sizeof(CFDATA
)+cbReserveCFData
;
773 /* reset little endian */
774 pcfdata
->cbData
=fci_endian_uword(pcfdata
->cbData
);
775 pcfdata
->cbUncomp
=fci_endian_uword(pcfdata
->cbUncomp
);
776 pcfdata
->csum
=fci_endian_ulong(pcfdata
->csum
);
778 /* write compressed data into p_fci_internal->handleCFDATA2 */
779 if( p_fci_internal
->write( p_fci_internal
->handleCFDATA2
, /* file handle */
780 p_fci_internal
->data_out
, /* memory buffer */
781 pcfdata
->cbData
, /* number of bytes to copy */
782 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
783 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
786 /* TODO error handling of err */
788 p_fci_internal
->sizeFileCFDATA2
+= pcfdata
->cbData
;
789 ++(p_fci_internal
->cDataBlocks
);
790 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
791 (*payload
)+=pcfdata
->cbUncomp
;
792 /* if cabinet size too large and data has been split */
793 /* write the remainder of the data block to the new CFDATA1 file */
794 if( split_block
) { /* This does not include the */
795 /* abused one (just search for "abused" )*/
796 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
797 if (p_fci_internal
->fNextCab
==FALSE
) {
799 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
803 /* set cbData to the size of the remainder of the data block */
804 pcfdata
->cbData
= read_result
- pcfdata
->cbData
;
805 /*recover former value of cfdata.cbData; read_result will be the offset*/
806 read_result
-= pcfdata
->cbData
;
807 pcfdata
->cbUncomp
= savedUncomp
;
809 /* reset checksum, it will be computed later */
812 /* write cfdata WITHOUT checksum to handleCFDATA1new */
813 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
814 buffer
, /* memory buffer */
815 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
816 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
817 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
820 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
822 *psizeFileCFDATA1new
+= sizeof(CFDATA
)+cbReserveCFData
;
824 /* write compressed data into handleCFDATA1new */
825 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
826 p_fci_internal
->data_out
+ read_result
, /* memory buffer + offset */
827 /* to last part of split data */
828 pcfdata
->cbData
, /* number of bytes to copy */
829 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
830 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
833 /* TODO error handling of err */
835 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
837 *psizeFileCFDATA1new
+= pcfdata
->cbData
;
838 /* the two blocks of the split data block have been written */
839 /* don't reset split_data yet, because it is still needed see below */
842 /* report status with pfnfcis about copied size of folder */
843 if( (*pfnfcis
)(statusFolder
,
844 p_fci_internal
->statusFolderCopied
, /*cfdata.cbData(+previous ones)*/
845 p_fci_internal
->statusFolderTotal
, /* total folder size */
846 p_fci_internal
->pv
) == -1) {
847 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
852 /* if cabinet size too large */
853 /* write the remaining data blocks to the new CFDATA1 file */
854 if ( split_block
) { /* This does include the */
855 /* abused one (just search for "abused" )*/
856 if (p_fci_internal
->fNextCab
==FALSE
) {
858 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
861 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
863 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
864 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA1
,/* handle */
865 buffer
, /* memory buffer */
866 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
867 err
, p_fci_internal
->pv
);
868 if (read_result
!=sizeof(CFDATA
)+cbReserveCFData
) {
869 if (read_result
==0) break; /* ALL DATA has been copied */
871 set_error( p_fci_internal
,FCIERR_NONE
, ERROR_READ_FAULT
);
874 /* TODO error handling of err */
876 /* REUSE buffer p_fci_internal->data_out !!! */
877 /* read data from p_fci_internal->handleCFDATA1 to */
878 /* p_fci_internal->data_out */
879 if( p_fci_internal
->read( p_fci_internal
->handleCFDATA1
/* file handle */,
880 p_fci_internal
->data_out
/* memory buffer */,
881 pcfdata
->cbData
/* number of bytes to copy */,
882 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
884 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
887 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
889 /* write cfdata with checksum to handleCFDATA1new */
890 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
891 buffer
, /* memory buffer */
892 sizeof(CFDATA
)+cbReserveCFData
, /* number of bytes to copy */
893 err
, p_fci_internal
->pv
) != sizeof(CFDATA
)+cbReserveCFData
) {
894 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
897 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
899 *psizeFileCFDATA1new
+= sizeof(CFDATA
)+cbReserveCFData
;
901 /* write compressed data into handleCFDATA1new */
902 if( p_fci_internal
->write( handleCFDATA1new
, /* file handle */
903 p_fci_internal
->data_out
, /* memory buffer */
904 pcfdata
->cbData
, /* number of bytes to copy */
905 err
, p_fci_internal
->pv
) != pcfdata
->cbData
) {
906 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
909 /* TODO error handling of err */
911 *psizeFileCFDATA1new
+= pcfdata
->cbData
;
912 p_fci_internal
->statusFolderCopied
+= pcfdata
->cbData
;
914 /* report status with pfnfcis about copied size of folder */
915 if( (*pfnfcis
)(statusFolder
,
916 p_fci_internal
->statusFolderCopied
,/*cfdata.cbData(+previous ones)*/
917 p_fci_internal
->statusFolderTotal
, /* total folder size */
918 p_fci_internal
->pv
) == -1) {
919 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
924 break; /* jump out of the next while loop */
925 } /* end of if( split_data ) */
928 } /* end of fci_flushfolder_copy_cfdata */
934 static BOOL
fci_flushfolder_copy_cffile(FCI_Int
*p_fci_internal
, int* err
, int handleCFFILE1new
,
935 cab_ULONG
*psizeFileCFFILE1new
, cab_ULONG payload
)
938 cab_ULONG read_result
;
940 cab_ULONG sizeOfFiles
=0, sizeOfFilesPrev
;
941 BOOL may_be_prev
=TRUE
;
942 cab_ULONG cbFileRemainer
=0;
944 /* set seek of p_fci_internal->handleCFFILE1 to 0 */
945 if( p_fci_internal
->seek(p_fci_internal
->handleCFFILE1
,0,SEEK_SET
,err
,
946 p_fci_internal
->pv
) !=0 ) {
947 /* wrong return value */
948 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
951 /* TODO error handling of err */
953 /* while not all CFFILE structures have been copied do */
955 /* REUSE the variable read_result */
956 /* read data from p_fci_internal->handleCFFILE1 to cffile */
957 read_result
= p_fci_internal
->read(p_fci_internal
->handleCFFILE1
/* file handle */,
958 &cffile
, /* memory buffer */
959 sizeof(cffile
), /* number of bytes to copy */
960 err
, p_fci_internal
->pv
);
961 if( read_result
!= sizeof(cffile
) ) {
962 if( read_result
== 0 ) break; /* ALL CFFILE structures have been copied */
964 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
967 /* TODO error handling of err */
969 /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
970 /* position. I don't know why so I'll just omit it */
972 /* read the filename from p_fci_internal->handleCFFILE1 */
973 /* REUSE the variable read_result AGAIN */
974 /* REUSE the memory buffer PFCI(hfci)->data_out */
975 if( p_fci_internal
->read( p_fci_internal
->handleCFFILE1
/*file handle*/,
976 p_fci_internal
->data_out
, /* memory buffer */
977 CB_MAX_FILENAME
, /* number of bytes to copy */
978 err
, p_fci_internal
->pv
) <2) {
980 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_READ_FAULT
);
983 /* TODO maybe other checks of read_result */
984 /* TODO error handling of err */
987 if( strlen(p_fci_internal
->data_out
)>=CB_MAX_FILENAME
) {
988 /* set error code internal error */
989 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
993 seek
+=sizeof(cffile
) + strlen(p_fci_internal
->data_out
)+1;
995 /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
996 /* i.e. seek to the next CFFILE area */
997 if( p_fci_internal
->seek(p_fci_internal
->handleCFFILE1
,
998 seek
, /* seek position*/
1002 /* wrong return value */
1003 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1006 /* TODO error handling of err */
1008 /* fnfilfnfildest: placed file on cabinet */
1009 if (p_fci_internal
->fNextCab
||
1010 p_fci_internal
->fGetNextCabInVain
) {
1011 p_fci_internal
->fileplaced( &p_fci_internal
->oldCCAB
,
1012 p_fci_internal
->data_out
, /* the file name*/
1013 cffile
.cbFile
, /* file size */
1014 (cffile
.iFolder
==cffileCONTINUED_FROM_PREV
),
1018 p_fci_internal
->fileplaced( p_fci_internal
->pccab
,
1019 p_fci_internal
->data_out
, /* the file name*/
1020 cffile
.cbFile
, /* file size */
1021 (cffile
.iFolder
==cffileCONTINUED_FROM_PREV
),
1026 /* Check special iFolder values */
1027 if( cffile
.iFolder
==cffileCONTINUED_FROM_PREV
&&
1028 p_fci_internal
->fPrevCab
==FALSE
) {
1029 /* THIS MAY NEVER HAPPEN */
1030 /* set error code */
1031 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1034 if( cffile
.iFolder
==cffileCONTINUED_PREV_AND_NEXT
||
1035 cffile
.iFolder
==cffileCONTINUED_TO_NEXT
) {
1036 /* THIS MAY NEVER HAPPEN */
1037 /* set error code */
1038 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1041 if( may_be_prev
&& cffile
.iFolder
!=cffileCONTINUED_FROM_PREV
) {
1044 if( cffile
.iFolder
==cffileCONTINUED_FROM_PREV
&& may_be_prev
==FALSE
) {
1045 /* THIS MAY NEVER HAPPEN */
1046 /* set error code */
1047 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1050 if( cffile
.iFolder
!=cffileCONTINUED_FROM_PREV
) {
1054 sizeOfFilesPrev
=sizeOfFiles
;
1055 /* Set complete size of all processed files */
1056 if( cffile
.iFolder
==cffileCONTINUED_FROM_PREV
&&
1057 p_fci_internal
->cbFileRemainer
!=0
1059 sizeOfFiles
+=p_fci_internal
->cbFileRemainer
;
1060 p_fci_internal
->cbFileRemainer
=0;
1062 sizeOfFiles
+=cffile
.cbFile
;
1065 /* Check if spanned file fits into this cabinet folder */
1066 if( cffile
.iFolder
==cffileCONTINUED_FROM_PREV
&& sizeOfFiles
>payload
) {
1067 cffile
.iFolder
=cffileCONTINUED_PREV_AND_NEXT
;
1070 /* Check if file doesn't fit into this cabinet folder */
1071 if( sizeOfFiles
>payload
) {
1072 cffile
.iFolder
=cffileCONTINUED_TO_NEXT
;
1075 /* set little endian */
1076 cffile
.cbFile
=fci_endian_ulong(cffile
.cbFile
);
1077 cffile
.uoffFolderStart
=fci_endian_ulong(cffile
.uoffFolderStart
);
1078 cffile
.iFolder
=fci_endian_uword(cffile
.iFolder
);
1079 cffile
.date
=fci_endian_uword(cffile
.date
);
1080 cffile
.time
=fci_endian_uword(cffile
.time
);
1081 cffile
.attribs
=fci_endian_uword(cffile
.attribs
);
1083 /* write cffile to p_fci_internal->handleCFFILE2 */
1084 if( p_fci_internal
->write( p_fci_internal
->handleCFFILE2
, /* file handle */
1085 &cffile
, /* memory buffer */
1086 sizeof(cffile
), /* number of bytes to copy */
1087 err
, p_fci_internal
->pv
) != sizeof(cffile
) ) {
1088 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1091 /* TODO error handling of err */
1093 p_fci_internal
->sizeFileCFFILE2
+= sizeof(cffile
);
1095 /* reset little endian */
1096 cffile
.cbFile
=fci_endian_ulong(cffile
.cbFile
);
1097 cffile
.uoffFolderStart
=fci_endian_ulong(cffile
.uoffFolderStart
);
1098 cffile
.iFolder
=fci_endian_uword(cffile
.iFolder
);
1099 cffile
.date
=fci_endian_uword(cffile
.date
);
1100 cffile
.time
=fci_endian_uword(cffile
.time
);
1101 cffile
.attribs
=fci_endian_uword(cffile
.attribs
);
1103 /* write file name to p_fci_internal->handleCFFILE2 */
1104 if( p_fci_internal
->write( p_fci_internal
->handleCFFILE2
, /* file handle */
1105 p_fci_internal
->data_out
, /* memory buffer */
1106 strlen(p_fci_internal
->data_out
)+1, /* number of bytes to copy */
1107 err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->data_out
)+1 ) {
1108 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1111 /* TODO error handling of err */
1113 p_fci_internal
->sizeFileCFFILE2
+= strlen(p_fci_internal
->data_out
)+1;
1115 /* cFiles is used to count all files of a cabinet */
1116 ++(p_fci_internal
->cFiles
);
1118 /* This is only true for files which will be written into the */
1119 /* next cabinet of the spanning folder */
1120 if( sizeOfFiles
>payload
) {
1122 /* Files which data will be partially written into the current cabinet */
1123 if( cffile
.iFolder
==cffileCONTINUED_PREV_AND_NEXT
||
1124 cffile
.iFolder
==cffileCONTINUED_TO_NEXT
1126 if( sizeOfFilesPrev
<=payload
) {
1127 /* The size of the uncompressed, data of a spanning file in a */
1129 cbFileRemainer
=sizeOfFiles
-payload
;
1131 cffile
.iFolder
=cffileCONTINUED_FROM_PREV
;
1136 /* write cffile into handleCFFILE1new */
1137 if( p_fci_internal
->write( handleCFFILE1new
, /* file handle */
1138 &cffile
, /* memory buffer */
1139 sizeof(cffile
), /* number of bytes to copy */
1140 err
, p_fci_internal
->pv
) != sizeof(cffile
) ) {
1141 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1144 /* TODO error handling of err */
1146 *psizeFileCFFILE1new
+= sizeof(cffile
);
1147 /* write name of file into handleCFFILE1new */
1148 if( p_fci_internal
->write( handleCFFILE1new
, /* file handle */
1149 p_fci_internal
->data_out
, /* memory buffer */
1150 strlen(p_fci_internal
->data_out
)+1, /* number of bytes to copy */
1151 err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->data_out
)+1 ) {
1152 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
1155 /* TODO error handling of err */
1157 *psizeFileCFFILE1new
+= strlen(p_fci_internal
->data_out
)+1;
1160 } /* END OF while */
1161 p_fci_internal
->cbFileRemainer
=cbFileRemainer
;
1163 } /* end of fci_flushfolder_copy_cffile */
1168 static BOOL
fci_flush_folder( FCI_Int
*p_fci_internal
,
1170 PFNFCIGETNEXTCABINET pfnfcignc
,
1171 PFNFCISTATUS pfnfcis
)
1174 int handleCFDATA1new
; /* handle for new temp file */
1175 char szFileNameCFDATA1new
[CB_MAX_FILENAME
]; /* name buffer for temp file */
1176 int handleCFFILE1new
; /* handle for new temp file */
1177 char szFileNameCFFILE1new
[CB_MAX_FILENAME
]; /* name buffer for temp file */
1178 UINT cbReserveCFData
, cbReserveCFFolder
;
1180 cab_ULONG sizeFileCFDATA1new
=0;
1181 cab_ULONG sizeFileCFFILE1new
=0;
1183 cab_ULONG read_result
;
1184 struct folder
*folder
;
1186 if ((!pfnfcignc
) || (!pfnfcis
)) {
1187 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
1191 if( p_fci_internal
->fGetNextCabInVain
&&
1192 p_fci_internal
->fNextCab
){
1193 /* internal error */
1194 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1198 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1199 /* this function will return TRUE */
1200 if( p_fci_internal
->sizeFileCFFILE1
== 0 ) {
1201 if ( p_fci_internal
->sizeFileCFDATA1
!= 0 ) {
1202 /* error handling */
1203 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1209 if (p_fci_internal
->data_in
==NULL
|| p_fci_internal
->data_out
==NULL
) {
1210 /* error handling */
1211 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1215 /* FCIFlushFolder has already been called... */
1216 if (p_fci_internal
->fSplitFolder
&& p_fci_internal
->sizeFileCFFILE2
!=0) {
1220 /* This can be set already, because it makes only a difference */
1221 /* when the current function exits with return FALSE */
1222 p_fci_internal
->fSplitFolder
=FALSE
;
1225 if( p_fci_internal
->fGetNextCabInVain
||
1226 p_fci_internal
->fNextCab
){
1227 cbReserveCFData
= p_fci_internal
->oldCCAB
.cbReserveCFData
;
1228 cbReserveCFFolder
= p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1230 cbReserveCFData
= p_fci_internal
->pccab
->cbReserveCFData
;
1231 cbReserveCFFolder
= p_fci_internal
->pccab
->cbReserveCFFolder
;
1235 /* if there is data in p_fci_internal->data_in */
1236 if (p_fci_internal
->cdata_in
!=0) {
1238 if( !fci_flush_data_block(p_fci_internal
, &err
, pfnfcis
) ) return FALSE
;
1241 /* reset to get the number of data blocks of this folder which are */
1242 /* actually in this cabinet ( at least partially ) */
1243 p_fci_internal
->cDataBlocks
=0;
1245 if ( p_fci_internal
->fNextCab
||
1246 p_fci_internal
->fGetNextCabInVain
) {
1247 read_result
= p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
1248 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1249 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1250 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1251 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1255 read_result
= p_fci_internal
->pccab
->cbReserveCFHeader
+
1256 p_fci_internal
->pccab
->cbReserveCFFolder
;
1257 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1258 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1259 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1263 if (p_fci_internal
->fPrevCab
) {
1264 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1265 strlen(p_fci_internal
->szPrevDisk
)+1;
1267 if (p_fci_internal
->fNextCab
) {
1268 read_result
+=strlen(p_fci_internal
->pccab
->szCab
)+1 +
1269 strlen(p_fci_internal
->pccab
->szDisk
)+1;
1272 p_fci_internal
->statusFolderTotal
= sizeof(CFHEADER
)+read_result
+
1273 sizeof(CFFOLDER
) + p_fci_internal
->sizeFileCFFILE2
+
1274 p_fci_internal
->sizeFileCFDATA2
+ p_fci_internal
->sizeFileCFFILE1
+
1275 p_fci_internal
->sizeFileCFDATA1
+ p_fci_internal
->folders_size
;
1276 p_fci_internal
->statusFolderCopied
= 0;
1278 /* report status with pfnfcis about copied size of folder */
1279 if( (*pfnfcis
)(statusFolder
, p_fci_internal
->statusFolderCopied
,
1280 p_fci_internal
->statusFolderTotal
, /* TODO total folder size */
1281 p_fci_internal
->pv
) == -1) {
1282 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1286 /* get a new temp file */
1287 if(!p_fci_internal
->gettemp(szFileNameCFDATA1new
,CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
1288 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1292 if ( strlen(szFileNameCFDATA1new
) >= CB_MAX_FILENAME
) {
1293 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1296 handleCFDATA1new
= p_fci_internal
->open(szFileNameCFDATA1new
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
1297 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1298 if(handleCFDATA1new
==0){
1299 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
1302 /* TODO error handling of err */
1306 /* get a new temp file */
1307 if(!p_fci_internal
->gettemp(szFileNameCFFILE1new
,CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
1308 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
1309 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1310 /* TODO error handling of err */
1314 if ( strlen(szFileNameCFFILE1new
) >= CB_MAX_FILENAME
) {
1315 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1316 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1317 /* TODO error handling of err */
1320 handleCFFILE1new
= p_fci_internal
->open(szFileNameCFFILE1new
, _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
1321 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1322 if(handleCFFILE1new
==0){
1323 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
1326 /* TODO error handling of err */
1328 /* USE the variable read_result */
1329 if ( p_fci_internal
->fNextCab
||
1330 p_fci_internal
->fGetNextCabInVain
) {
1331 read_result
= p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1332 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1333 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1334 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1338 read_result
= p_fci_internal
->pccab
->cbReserveCFHeader
;
1339 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1340 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1341 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1345 if (p_fci_internal
->fPrevCab
) {
1346 read_result
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1347 strlen(p_fci_internal
->szPrevDisk
)+1;
1349 read_result
+= sizeof(CFHEADER
) + p_fci_internal
->sizeFileCFDATA2
+
1350 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
;
1352 if(p_fci_internal
->sizeFileCFFILE1
!=0) {
1353 read_result
+= sizeof(CFFOLDER
)+p_fci_internal
->pccab
->cbReserveCFFolder
;
1356 /* Check if multiple cabinets have to be created. */
1358 /* Might be too much data for the maximum allowed cabinet size.*/
1359 /* When any further data will be added later, it might not */
1360 /* be possible to flush the cabinet, because there might */
1361 /* not be enough space to store the name of the following */
1362 /* cabinet and name of the corresponding disk. */
1363 /* So take care of this and get the name of the next cabinet */
1364 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
1365 p_fci_internal
->fNextCab
==FALSE
&&
1368 p_fci_internal
->pccab
->cb
< read_result
+
1369 p_fci_internal
->sizeFileCFDATA1
+
1370 p_fci_internal
->sizeFileCFFILE1
+
1371 CB_MAX_CABINET_NAME
+ /* next cabinet name */
1372 CB_MAX_DISK_NAME
/* next disk name */
1377 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
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
);
1387 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1388 /* TODO error handling of err */
1389 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1390 /* TODO error handling of err */
1394 /* Skip a few lines of code. This is caught by the next if. */
1395 p_fci_internal
->fGetNextCabInVain
=TRUE
;
1398 /* too much data for cabinet */
1399 if( (p_fci_internal
->fGetNextCabInVain
||
1400 p_fci_internal
->fNextCab
) &&
1403 p_fci_internal
->oldCCAB
.cb
< read_result
+
1404 p_fci_internal
->sizeFileCFDATA1
+
1405 p_fci_internal
->sizeFileCFFILE1
+
1406 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1407 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1411 p_fci_internal
->fGetNextCabInVain
=FALSE
;
1412 p_fci_internal
->fNextCab
=TRUE
;
1414 /* return FALSE if there is not enough space left*/
1415 /* this should never happen */
1416 if (p_fci_internal
->oldCCAB
.cb
<=
1417 p_fci_internal
->sizeFileCFFILE1
+
1419 strlen(p_fci_internal
->pccab
->szCab
)+1 + /* next cabinet name */
1420 strlen(p_fci_internal
->pccab
->szDisk
)+1 /* next disk name */
1423 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1424 /* TODO error handling of err */
1425 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1426 /* TODO error handling of err */
1428 /* close and delete p_fci_internal->handleCFFILE1 */
1429 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1430 /* TODO error handling of err */
1431 p_fci_internal
->delete(szFileNameCFFILE1new
,&err
,p_fci_internal
->pv
);
1432 /* TODO error handling of err */
1437 /* the folder will be split across cabinets */
1438 p_fci_internal
->fSplitFolder
=TRUE
;
1441 /* this should never happen */
1442 if (p_fci_internal
->fNextCab
) {
1443 /* internal error */
1444 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1449 /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1450 if( p_fci_internal
->seek(p_fci_internal
->handleCFDATA1
,0,SEEK_SET
,&err
,
1451 p_fci_internal
->pv
) !=0 ) {
1452 /* wrong return value */
1453 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1454 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1455 /* TODO error handling of err */
1456 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1457 /* TODO error handling of err */
1460 /* TODO error handling of err */
1462 if (!(folder
= add_folder( p_fci_internal
))) return FALSE
;
1464 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFData
+sizeof(CFDATA
)))) {
1465 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
1466 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1467 /* TODO error handling of err */
1468 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1469 /* TODO error handling of err */
1473 if(!fci_flushfolder_copy_cfdata(p_fci_internal
, reserved
, cbReserveCFData
, pfnfcis
, &err
,
1474 handleCFDATA1new
, &sizeFileCFDATA1new
, &payload
1476 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1477 /* TODO error handling of err */
1478 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1479 /* TODO error handling of err */
1480 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1481 /* TODO error handling of err */
1482 p_fci_internal
->free(reserved
);
1486 p_fci_internal
->free(reserved
);
1488 folder
->data_count
= p_fci_internal
->cDataBlocks
;
1490 if(!fci_flushfolder_copy_cffile(p_fci_internal
, &err
, handleCFFILE1new
,
1491 &sizeFileCFFILE1new
, payload
)) {
1492 p_fci_internal
->close(handleCFDATA1new
,&err
,p_fci_internal
->pv
);
1493 /* TODO error handling of err */
1494 p_fci_internal
->delete(szFileNameCFDATA1new
,&err
,p_fci_internal
->pv
);
1495 /* TODO error handling of err */
1496 p_fci_internal
->close(handleCFFILE1new
,&err
,p_fci_internal
->pv
);
1497 /* TODO error handling of err */
1498 p_fci_internal
->delete(szFileNameCFFILE1new
,&err
,p_fci_internal
->pv
);
1499 /* TODO error handling of err */
1503 /* close and delete p_fci_internal->handleCFDATA1 */
1504 p_fci_internal
->close(p_fci_internal
->handleCFDATA1
,&err
,p_fci_internal
->pv
);
1505 /* TODO error handling of err */
1506 p_fci_internal
->delete(p_fci_internal
->szFileNameCFDATA1
,&err
,p_fci_internal
->pv
);
1507 /* TODO error handling of err */
1509 /* put new CFDATA1 into hfci */
1510 memcpy(p_fci_internal
->szFileNameCFDATA1
,szFileNameCFDATA1new
,
1513 /* put CFDATA1 file handle */
1514 p_fci_internal
->handleCFDATA1
= handleCFDATA1new
;
1516 p_fci_internal
->sizeFileCFDATA1
= sizeFileCFDATA1new
;
1518 /* close and delete PFCI_INT(hfci)->handleCFFILE1 */
1519 p_fci_internal
->close(p_fci_internal
->handleCFFILE1
,&err
,p_fci_internal
->pv
);
1520 /* TODO error handling of err */
1521 p_fci_internal
->delete(p_fci_internal
->szFileNameCFFILE1
,&err
,p_fci_internal
->pv
);
1522 /* TODO error handling of err */
1524 /* put new CFFILE1 into hfci */
1525 memcpy(p_fci_internal
->szFileNameCFFILE1
,szFileNameCFFILE1new
,
1528 /* put CFFILE1 file handle */
1529 p_fci_internal
->handleCFFILE1
= handleCFFILE1new
;
1531 p_fci_internal
->sizeFileCFFILE1
= sizeFileCFFILE1new
;
1533 /* reset CFFolder specific information */
1534 p_fci_internal
->cDataBlocks
=0;
1535 p_fci_internal
->cCompressedBytesInFolder
=0;
1538 } /* end of fci_flush_folder */
1543 static BOOL
fci_flush_cabinet( FCI_Int
*p_fci_internal
,
1545 PFNFCIGETNEXTCABINET pfnfcignc
,
1546 PFNFCISTATUS pfnfcis
)
1551 cab_UWORD cbCFHeader
;
1552 cab_UBYTE cbCFFolder
;
1555 cab_ULONG header_size
;
1556 cab_ULONG read_result
=0;
1557 int handleCABINET
; /* file handle for cabinet */
1558 char szFileNameCABINET
[CB_MAX_CAB_PATH
+CB_MAX_CABINET_NAME
];/* name buffer */
1559 UINT cbReserveCFHeader
, cbReserveCFFolder
, i
;
1561 BOOL returntrue
=FALSE
;
1563 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1565 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1566 if( p_fci_internal
->sizeFileCFFILE1
==0 && fGetNextCab
) {
1570 if (!fci_flush_folder(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)){
1571 /* TODO set error */
1575 if(returntrue
) return TRUE
;
1577 if ( (p_fci_internal
->fSplitFolder
&& p_fci_internal
->fNextCab
==FALSE
)||
1578 (p_fci_internal
->folders_size
==0 &&
1579 (p_fci_internal
->sizeFileCFFILE1
!=0 ||
1580 p_fci_internal
->sizeFileCFFILE2
!=0 )
1584 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
1588 if( p_fci_internal
->fNextCab
||
1589 p_fci_internal
->fGetNextCabInVain
) {
1590 cbReserveCFFolder
=p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
1591 cbReserveCFHeader
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1593 if (strlen(p_fci_internal
->oldCCAB
.szCabPath
)>=CB_MAX_CAB_PATH
||
1594 strlen(p_fci_internal
->oldCCAB
.szCab
)>=CB_MAX_CABINET_NAME
) {
1596 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1599 /* get the full name of the cabinet */
1600 memcpy(szFileNameCABINET
,p_fci_internal
->oldCCAB
.szCabPath
,
1602 memcpy(szFileNameCABINET
+strlen(szFileNameCABINET
),
1603 p_fci_internal
->oldCCAB
.szCab
, CB_MAX_CABINET_NAME
);
1605 cbReserveCFFolder
=p_fci_internal
->pccab
->cbReserveCFFolder
;
1606 cbReserveCFHeader
=p_fci_internal
->pccab
->cbReserveCFHeader
;
1608 if (strlen(p_fci_internal
->pccab
->szCabPath
)>=CB_MAX_CAB_PATH
||
1609 strlen(p_fci_internal
->pccab
->szCab
)>=CB_MAX_CABINET_NAME
) {
1611 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
1614 /* get the full name of the cabinet */
1615 memcpy(szFileNameCABINET
,p_fci_internal
->pccab
->szCabPath
,
1617 memcpy(szFileNameCABINET
+strlen(szFileNameCABINET
),
1618 p_fci_internal
->pccab
->szCab
, CB_MAX_CABINET_NAME
);
1621 memcpy(cfheader
.signature
,"!CAB",4);
1622 cfheader
.reserved1
=0;
1623 cfheader
.cbCabinet
= /* size of the cabinet file in bytes */
1625 p_fci_internal
->folders_size
+
1626 p_fci_internal
->sizeFileCFFILE2
+
1627 p_fci_internal
->sizeFileCFDATA2
;
1629 if (p_fci_internal
->fPrevCab
) {
1630 cfheader
.cbCabinet
+=strlen(p_fci_internal
->szPrevCab
)+1 +
1631 strlen(p_fci_internal
->szPrevDisk
)+1;
1633 if (p_fci_internal
->fNextCab
) {
1634 cfheader
.cbCabinet
+=strlen(p_fci_internal
->pccab
->szCab
)+1 +
1635 strlen(p_fci_internal
->pccab
->szDisk
)+1;
1637 if( p_fci_internal
->fNextCab
||
1638 p_fci_internal
->fGetNextCabInVain
) {
1639 cfheader
.cbCabinet
+=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1640 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1641 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1642 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1643 cfheader
.cbCabinet
+=4;
1646 cfheader
.cbCabinet
+=p_fci_internal
->pccab
->cbReserveCFHeader
;
1647 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1648 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1649 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1650 cfheader
.cbCabinet
+=4;
1654 if( ( ( p_fci_internal
->fNextCab
||
1655 p_fci_internal
->fGetNextCabInVain
) &&
1656 cfheader
.cbCabinet
> p_fci_internal
->oldCCAB
.cb
1658 ( ( p_fci_internal
->fNextCab
==FALSE
&&
1659 p_fci_internal
->fGetNextCabInVain
==FALSE
) &&
1660 cfheader
.cbCabinet
> p_fci_internal
->pccab
->cb
1664 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_MORE_DATA
);
1669 cfheader
.reserved2
=0;
1670 cfheader
.coffFiles
= /* offset to first CFFILE section */
1671 cfheader
.cbCabinet
- p_fci_internal
->sizeFileCFFILE2
-
1672 p_fci_internal
->sizeFileCFDATA2
;
1674 cfheader
.reserved3
=0;
1675 cfheader
.versionMinor
=3;
1676 cfheader
.versionMajor
=1;
1677 /* number of CFFOLDER entries in the cabinet */
1678 cfheader
.cFolders
=p_fci_internal
->cFolders
;
1679 /* number of CFFILE entries in the cabinet */
1680 cfheader
.cFiles
=p_fci_internal
->cFiles
;
1681 cfheader
.flags
=0; /* 1=prev cab, 2=next cabinet, 4=reserved sections */
1683 if( p_fci_internal
->fPrevCab
) {
1684 cfheader
.flags
= cfheadPREV_CABINET
;
1687 if( p_fci_internal
->fNextCab
) {
1688 cfheader
.flags
|= cfheadNEXT_CABINET
;
1691 if( p_fci_internal
->fNextCab
||
1692 p_fci_internal
->fGetNextCabInVain
) {
1693 if( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1694 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1695 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1696 cfheader
.flags
|= cfheadRESERVE_PRESENT
;
1698 cfheader
.setID
= p_fci_internal
->oldCCAB
.setID
;
1699 cfheader
.iCabinet
= p_fci_internal
->oldCCAB
.iCab
-1;
1701 if( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1702 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1703 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1704 cfheader
.flags
|= cfheadRESERVE_PRESENT
;
1706 cfheader
.setID
= p_fci_internal
->pccab
->setID
;
1707 cfheader
.iCabinet
= p_fci_internal
->pccab
->iCab
-1;
1710 /* create the cabinet */
1711 handleCABINET
= p_fci_internal
->open( szFileNameCABINET
, _O_RDWR
| _O_CREAT
| _O_TRUNC
| _O_BINARY
,
1712 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
1713 if(handleCABINET
==-1)
1715 set_error( p_fci_internal
, FCIERR_CAB_FILE
, err
);
1718 /* TODO error checking of err */
1720 /* set little endian */
1721 cfheader
.reserved1
=fci_endian_ulong(cfheader
.reserved1
);
1722 cfheader
.cbCabinet
=fci_endian_ulong(cfheader
.cbCabinet
);
1723 cfheader
.reserved2
=fci_endian_ulong(cfheader
.reserved2
);
1724 cfheader
.coffFiles
=fci_endian_ulong(cfheader
.coffFiles
);
1725 cfheader
.reserved3
=fci_endian_ulong(cfheader
.reserved3
);
1726 cfheader
.cFolders
=fci_endian_uword(cfheader
.cFolders
);
1727 cfheader
.cFiles
=fci_endian_uword(cfheader
.cFiles
);
1728 cfheader
.flags
=fci_endian_uword(cfheader
.flags
);
1729 cfheader
.setID
=fci_endian_uword(cfheader
.setID
);
1730 cfheader
.iCabinet
=fci_endian_uword(cfheader
.iCabinet
);
1732 /* write CFHEADER into cabinet file */
1733 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1734 &cfheader
, /* memory buffer */
1735 sizeof(cfheader
), /* number of bytes to copy */
1736 &err
, p_fci_internal
->pv
) != sizeof(cfheader
) ) {
1738 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1741 /* TODO error handling of err */
1743 /* reset little endian */
1744 cfheader
.reserved1
=fci_endian_ulong(cfheader
.reserved1
);
1745 cfheader
.cbCabinet
=fci_endian_ulong(cfheader
.cbCabinet
);
1746 cfheader
.reserved2
=fci_endian_ulong(cfheader
.reserved2
);
1747 cfheader
.coffFiles
=fci_endian_ulong(cfheader
.coffFiles
);
1748 cfheader
.reserved3
=fci_endian_ulong(cfheader
.reserved3
);
1749 cfheader
.cFolders
=fci_endian_uword(cfheader
.cFolders
);
1750 cfheader
.cFiles
=fci_endian_uword(cfheader
.cFiles
);
1751 cfheader
.flags
=fci_endian_uword(cfheader
.flags
);
1752 cfheader
.setID
=fci_endian_uword(cfheader
.setID
);
1753 cfheader
.iCabinet
=fci_endian_uword(cfheader
.iCabinet
);
1755 if( cfheader
.flags
& cfheadRESERVE_PRESENT
) {
1756 /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1757 cfreserved
.cbCFHeader
= cbReserveCFHeader
;
1758 cfreserved
.cbCFFolder
= cbReserveCFFolder
;
1759 if( p_fci_internal
->fNextCab
||
1760 p_fci_internal
->fGetNextCabInVain
) {
1761 cfreserved
.cbCFData
= p_fci_internal
->oldCCAB
.cbReserveCFData
;
1763 cfreserved
.cbCFData
= p_fci_internal
->pccab
->cbReserveCFData
;
1766 /* set little endian */
1767 cfreserved
.cbCFHeader
=fci_endian_uword(cfreserved
.cbCFHeader
);
1769 /* write reserved info into cabinet file */
1770 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1771 &cfreserved
, /* memory buffer */
1772 sizeof(cfreserved
), /* number of bytes to copy */
1773 &err
, p_fci_internal
->pv
) != sizeof(cfreserved
) ) {
1775 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1778 /* TODO error handling of err */
1780 /* reset little endian */
1781 cfreserved
.cbCFHeader
=fci_endian_uword(cfreserved
.cbCFHeader
);
1784 /* add optional reserved area */
1785 if (cbReserveCFHeader
!=0) {
1786 if(!(reserved
= p_fci_internal
->alloc( cbReserveCFHeader
))) {
1787 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
1790 for(i
=0;i
<cbReserveCFHeader
;) {
1793 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1794 reserved
, /* memory buffer */
1795 cbReserveCFHeader
, /* number of bytes to copy */
1796 &err
, p_fci_internal
->pv
) != cbReserveCFHeader
) {
1797 p_fci_internal
->free(reserved
);
1799 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1802 /* TODO error handling of err */
1803 p_fci_internal
->free(reserved
);
1806 if( cfheader
.flags
& cfheadPREV_CABINET
) {
1807 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1808 p_fci_internal
->szPrevCab
, /* memory buffer */
1809 strlen(p_fci_internal
->szPrevCab
)+1, /* number of bytes to copy */
1810 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->szPrevCab
)+1 ) {
1812 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1815 /* TODO error handling of err */
1817 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1818 p_fci_internal
->szPrevDisk
, /* memory buffer */
1819 strlen(p_fci_internal
->szPrevDisk
)+1, /* number of bytes to copy */
1820 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->szPrevDisk
)+1 ) {
1822 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1825 /* TODO error handling of err */
1828 if( cfheader
.flags
& cfheadNEXT_CABINET
) {
1829 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1830 p_fci_internal
->pccab
->szCab
, /* memory buffer */
1831 strlen(p_fci_internal
->pccab
->szCab
)+1, /* number of bytes to copy */
1832 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->pccab
->szCab
)+1 ) {
1834 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1837 /* TODO error handling of err */
1839 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1840 p_fci_internal
->pccab
->szDisk
, /* memory buffer */
1841 strlen(p_fci_internal
->pccab
->szDisk
)+1, /* number of bytes to copy */
1842 &err
, p_fci_internal
->pv
) != strlen(p_fci_internal
->pccab
->szDisk
)+1 ) {
1844 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1847 /* TODO error handling of err */
1850 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1851 header_size
= p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+ sizeof(CFHEADER
);
1852 if( p_fci_internal
->fNextCab
|| p_fci_internal
->fGetNextCabInVain
) {
1853 header_size
+=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1855 header_size
+=p_fci_internal
->pccab
->cbReserveCFHeader
;
1858 if (p_fci_internal
->fPrevCab
) {
1859 header_size
+= strlen(p_fci_internal
->szPrevCab
)+1 +
1860 strlen(p_fci_internal
->szPrevDisk
)+1;
1863 if (p_fci_internal
->fNextCab
) {
1864 header_size
+= strlen(p_fci_internal
->oldCCAB
.szCab
)+1 +
1865 strlen(p_fci_internal
->oldCCAB
.szDisk
)+1;
1868 if( p_fci_internal
->fNextCab
|| p_fci_internal
->fGetNextCabInVain
) {
1869 header_size
+= p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
1870 if( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
1871 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
1872 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
1876 header_size
+= p_fci_internal
->pccab
->cbReserveCFHeader
;
1877 if( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
1878 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
1879 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
1884 if (!write_folders( p_fci_internal
, handleCABINET
, header_size
)) return FALSE
;
1886 /* set seek of p_fci_internal->handleCFFILE2 to 0 */
1887 if( p_fci_internal
->seek(p_fci_internal
->handleCFFILE2
,
1888 0, SEEK_SET
, &err
, p_fci_internal
->pv
) != 0 ) {
1889 /* wrong return value */
1890 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1893 /* TODO error handling of err */
1895 /* while not all CFFILE structures have been copied to the cabinet do */
1896 if (p_fci_internal
->data_out
) while(!FALSE
) {
1897 /* REUSE the variable read_result */
1898 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1899 /* read a block from p_fci_internal->handleCFFILE2 */
1900 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFFILE2
/* handle */,
1901 p_fci_internal
->data_out
, /* memory buffer */
1902 CB_MAX_CHUNK
, /* number of bytes to copy */
1903 &err
, p_fci_internal
->pv
);
1904 if( read_result
== 0 ) break; /* ALL CFFILE structures have been copied */
1905 /* TODO error handling of err */
1907 /* write the block to the cabinet file */
1908 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1909 p_fci_internal
->data_out
, /* memory buffer */
1910 read_result
, /* number of bytes to copy */
1911 &err
, p_fci_internal
->pv
) != read_result
) {
1913 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1916 /* TODO error handling of err */
1918 if (p_fci_internal
->fSplitFolder
==FALSE
) {
1919 p_fci_internal
->statusFolderCopied
= 0;
1920 /* TODO TEST THIS further */
1921 p_fci_internal
->statusFolderTotal
= p_fci_internal
->sizeFileCFDATA2
+
1922 p_fci_internal
->sizeFileCFFILE2
;
1924 p_fci_internal
->statusFolderCopied
+= read_result
;
1926 /* report status with pfnfcis about copied size of folder */
1927 if( (*pfnfcis
)(statusFolder
,
1928 p_fci_internal
->statusFolderCopied
, /* length of copied blocks */
1929 p_fci_internal
->statusFolderTotal
, /* total size of folder */
1930 p_fci_internal
->pv
) == -1) {
1931 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1935 } /* END OF while */
1937 /* set seek of p_fci_internal->handleCFDATA2 to 0 */
1938 if( p_fci_internal
->seek(p_fci_internal
->handleCFDATA2
,
1939 0, SEEK_SET
, &err
, p_fci_internal
->pv
) != 0 ) {
1940 /* wrong return value */
1941 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1944 /* TODO error handling of err */
1946 /* reset the number of folders for the next cabinet */
1947 p_fci_internal
->cFolders
=0;
1948 /* reset the number of files for the next cabinet */
1949 p_fci_internal
->cFiles
=0;
1951 /* while not all CFDATA structures have been copied to the cabinet do */
1952 if (p_fci_internal
->data_out
) while(!FALSE
) {
1953 /* REUSE the variable read_result AGAIN */
1954 /* REUSE the buffer p_fci_internal->data_out AGAIN */
1955 /* read a block from p_fci_internal->handleCFDATA2 */
1956 read_result
= p_fci_internal
->read( p_fci_internal
->handleCFDATA2
/* handle */,
1957 p_fci_internal
->data_out
, /* memory buffer */
1958 CB_MAX_CHUNK
, /* number of bytes to copy */
1959 &err
, p_fci_internal
->pv
);
1960 if( read_result
== 0 ) break; /* ALL CFDATA structures have been copied */
1961 /* TODO error handling of err */
1963 /* write the block to the cabinet file */
1964 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1965 p_fci_internal
->data_out
, /* memory buffer */
1966 read_result
, /* number of bytes to copy */
1967 &err
, p_fci_internal
->pv
) != read_result
) {
1969 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
1972 /* TODO error handling of err */
1974 p_fci_internal
->statusFolderCopied
+= read_result
;
1975 /* report status with pfnfcis about copied size of folder */
1976 if( (*pfnfcis
)(statusFolder
,
1977 p_fci_internal
->statusFolderCopied
, /* length of copied blocks */
1978 p_fci_internal
->statusFolderTotal
, /* total size of folder */
1979 p_fci_internal
->pv
) == -1) {
1980 /* set error code and abort */
1981 set_error( p_fci_internal
, FCIERR_USER_ABORT
, 0 );
1984 } /* END OF while */
1986 /* set seek of the cabinet file to 0 */
1987 if( p_fci_internal
->seek( handleCABINET
,
1988 0, SEEK_SET
, &err
, p_fci_internal
->pv
) != 0 ) {
1989 /* wrong return value */
1990 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_SEEK
);
1993 /* TODO error handling of err */
1995 /* write the signature "MSCF" into the cabinet file */
1996 memcpy( cfheader
.signature
, "MSCF", 4 );
1997 if( p_fci_internal
->write( handleCABINET
, /* file handle */
1998 &cfheader
, /* memory buffer */
1999 4, /* number of bytes to copy */
2000 &err
, p_fci_internal
->pv
) != 4 ) {
2002 set_error( p_fci_internal
, FCIERR_CAB_FILE
, ERROR_WRITE_FAULT
);
2005 /* TODO error handling of err */
2007 /* close the cabinet file */
2008 p_fci_internal
->close(handleCABINET
,&err
,p_fci_internal
->pv
);
2009 /* TODO error handling of err */
2012 /* COPIED FROM FCIDestroy */
2014 p_fci_internal
->close( p_fci_internal
->handleCFDATA2
,&err
,p_fci_internal
->pv
);
2015 /* TODO error handling of err */
2016 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA2
, &err
,
2017 p_fci_internal
->pv
);
2018 /* TODO error handling of err */
2019 p_fci_internal
->close( p_fci_internal
->handleCFFILE2
,&err
,p_fci_internal
->pv
);
2020 /* TODO error handling of err */
2021 p_fci_internal
->delete( p_fci_internal
->szFileNameCFFILE2
, &err
,
2022 p_fci_internal
->pv
);
2023 /* TODO error handling of err */
2025 /* END OF copied from FCIDestroy */
2027 /* get 3 temporary files and open them */
2028 /* write names and handles to hfci */
2030 p_fci_internal
->folders_size
= 0;
2031 p_fci_internal
->sizeFileCFDATA2
= 0;
2032 p_fci_internal
->sizeFileCFFILE2
= 0;
2033 p_fci_internal
->folders_size
= 0;
2035 /* COPIED FROM FCICreate */
2037 /* CFDATA with checksum and ready to be copied into cabinet */
2038 if( !p_fci_internal
->gettemp( p_fci_internal
->szFileNameCFDATA2
,
2039 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
2040 /* error handling */
2041 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2045 if ( strlen(p_fci_internal
->szFileNameCFDATA2
) >= CB_MAX_FILENAME
) {
2046 /* set error code and abort */
2047 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
2050 p_fci_internal
->handleCFDATA2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFDATA2
,
2051 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
2052 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
2054 if(p_fci_internal
->handleCFDATA2
==0){
2055 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
2058 /* TODO error checking of err */
2060 /* array of all CFFILE in a folder, ready to be copied into cabinet */
2061 if( !p_fci_internal
->gettemp(p_fci_internal
->szFileNameCFFILE2
,
2062 CB_MAX_FILENAME
, p_fci_internal
->pv
)) {
2063 /* error handling */
2064 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2068 if ( strlen(p_fci_internal
->szFileNameCFFILE2
) >= CB_MAX_FILENAME
) {
2069 /* set error code and abort */
2070 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
2073 p_fci_internal
->handleCFFILE2
= p_fci_internal
->open( p_fci_internal
->szFileNameCFFILE2
,
2074 _O_RDWR
| _O_CREAT
| _O_EXCL
| _O_BINARY
,
2075 _S_IREAD
| _S_IWRITE
, &err
, p_fci_internal
->pv
);
2077 if(p_fci_internal
->handleCFFILE2
==0){
2078 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_OPEN_FAILED
);
2081 /* TODO error checking of err */
2083 /* END OF copied from FCICreate */
2086 /* TODO close and delete new files when return FALSE */
2089 /* report status with pfnfcis about copied size of folder */
2090 (*pfnfcis
)(statusCabinet
,
2091 p_fci_internal
->estimatedCabinetSize
, /* estimated cabinet file size */
2092 cfheader
.cbCabinet
/* real cabinet file size */, p_fci_internal
->pv
);
2094 p_fci_internal
->fPrevCab
=TRUE
;
2095 /* The sections szPrevCab and szPrevDisk are not being updated, because */
2096 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
2098 if (p_fci_internal
->fNextCab
) {
2099 p_fci_internal
->fNextCab
=FALSE
;
2101 if (p_fci_internal
->sizeFileCFFILE1
==0 && p_fci_internal
->sizeFileCFDATA1
!=0) {
2102 /* THIS CAN NEVER HAPPEN */
2103 /* set error code */
2104 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2108 /* COPIED FROM FCIAddFile and modified */
2110 /* REUSE the variable read_result */
2111 if (p_fci_internal
->fGetNextCabInVain
) {
2112 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
;
2113 if(p_fci_internal
->sizeFileCFFILE1
!=0) {
2114 read_result
+=p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
2116 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
2117 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
2118 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
2122 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
;
2123 if(p_fci_internal
->sizeFileCFFILE1
!=0) {
2124 read_result
+=p_fci_internal
->pccab
->cbReserveCFFolder
;
2126 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
2127 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
2128 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
2132 if ( p_fci_internal
->fPrevCab
) {
2133 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
2134 strlen(p_fci_internal
->szPrevDisk
)+1;
2136 read_result
+= p_fci_internal
->sizeFileCFDATA1
+
2137 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
2138 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
2140 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
2142 if( p_fci_internal
->fNewPrevious
) {
2143 memcpy(p_fci_internal
->szPrevCab
, p_fci_internal
->oldCCAB
.szCab
,
2144 CB_MAX_CABINET_NAME
);
2145 memcpy(p_fci_internal
->szPrevDisk
, p_fci_internal
->oldCCAB
.szDisk
,
2147 p_fci_internal
->fNewPrevious
=FALSE
;
2150 /* too much data for the maximum size of a cabinet */
2151 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2152 p_fci_internal
->pccab
->cb
< read_result
) {
2153 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2156 /* Might be too much data for the maximum size of a cabinet.*/
2157 /* When any further data will be added later, it might not */
2158 /* be possible to flush the cabinet, because there might */
2159 /* not be enough space to store the name of the following */
2160 /* cabinet and name of the corresponding disk. */
2161 /* So take care of this and get the name of the next cabinet */
2162 if (p_fci_internal
->fGetNextCabInVain
==FALSE
&& (
2163 p_fci_internal
->pccab
->cb
< read_result
+
2164 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
2167 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
2168 /* increment cabinet index */
2169 ++(p_fci_internal
->pccab
->iCab
);
2170 /* get name of next cabinet */
2171 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
2172 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
2173 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
2174 p_fci_internal
->pv
)) {
2175 /* error handling */
2176 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2179 /* Skip a few lines of code. This is caught by the next if. */
2180 p_fci_internal
->fGetNextCabInVain
=TRUE
;
2183 /* too much data for cabinet */
2184 if (p_fci_internal
->fGetNextCabInVain
&& (
2185 p_fci_internal
->oldCCAB
.cb
< read_result
+
2186 strlen(p_fci_internal
->oldCCAB
.szCab
)+1+
2187 strlen(p_fci_internal
->oldCCAB
.szDisk
)+1
2189 p_fci_internal
->fGetNextCabInVain
=FALSE
;
2190 p_fci_internal
->fNextCab
=TRUE
;
2191 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2194 /* if the FolderThreshold has been reached flush the folder automatically */
2195 if( p_fci_internal
->fGetNextCabInVain
) {
2196 if( p_fci_internal
->cCompressedBytesInFolder
>=
2197 p_fci_internal
->oldCCAB
.cbFolderThresh
) {
2198 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2201 if( p_fci_internal
->cCompressedBytesInFolder
>=
2202 p_fci_internal
->pccab
->cbFolderThresh
) {
2203 return fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2207 /* END OF COPIED FROM FCIAddFile and modified */
2209 if( p_fci_internal
->sizeFileCFFILE1
>0 ) {
2210 if( !fci_flush_folder(p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
) ) return FALSE
;
2211 p_fci_internal
->fNewPrevious
=TRUE
;
2214 p_fci_internal
->fNewPrevious
=FALSE
;
2215 if( p_fci_internal
->sizeFileCFFILE1
>0 || p_fci_internal
->sizeFileCFDATA1
) {
2216 /* THIS MAY NEVER HAPPEN */
2217 /* set error structures */
2218 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2224 } /* end of fci_flush_cabinet */
2230 /***********************************************************************
2231 * FCIAddFile (CABINET.11)
2233 * FCIAddFile adds a file to the to be created cabinet file
2236 * hfci [I] An HFCI from FCICreate
2237 * pszSourceFile [I] A pointer to a C string which contains the name and
2238 * location of the file which will be added to the cabinet
2239 * pszFileName [I] A pointer to a C string which contains the name under
2240 * which the file will be stored in the cabinet
2241 * fExecute [I] A boolean value which indicates if the file should be
2242 * executed after extraction of self extracting
2244 * pfnfcignc [I] A pointer to a function which gets information about
2246 * pfnfcis [IO] A pointer to a function which will report status
2247 * information about the compression process
2248 * pfnfcioi [I] A pointer to a function which reports file attributes
2249 * and time and date information
2250 * typeCompress [I] Compression type
2253 * On success, returns TRUE
2254 * On failure, returns FALSE
2260 BOOL __cdecl
FCIAddFile(
2262 char *pszSourceFile
,
2265 PFNFCIGETNEXTCABINET pfnfcignc
,
2266 PFNFCISTATUS pfnfcis
,
2267 PFNFCIGETOPENINFO pfnfcigoi
,
2272 cab_ULONG read_result
;
2274 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2276 if (!p_fci_internal
) return FALSE
;
2278 if ((!pszSourceFile
) || (!pszFileName
) || (!pfnfcignc
) || (!pfnfcis
) ||
2279 (!pfnfcigoi
) || strlen(pszFileName
)>=CB_MAX_FILENAME
) {
2280 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_BAD_ARGUMENTS
);
2284 /* TODO check if pszSourceFile??? */
2286 if(p_fci_internal
->fGetNextCabInVain
&& p_fci_internal
->fNextCab
) {
2287 /* internal error */
2288 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2292 if(p_fci_internal
->fNextCab
) {
2293 /* internal error */
2294 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2298 cffile
.cbFile
=0; /* size of the to be added file*/
2299 /* offset of the uncompressed file in the folder */
2300 cffile
.uoffFolderStart
=p_fci_internal
->cDataBlocks
*CAB_BLOCKMAX
+ p_fci_internal
->cdata_in
;
2301 /* number of folder in the cabinet or special 0=first */
2302 cffile
.iFolder
= p_fci_internal
->cFolders
;
2304 /* allocation of memory */
2305 if (p_fci_internal
->data_in
==NULL
) {
2306 if (p_fci_internal
->cdata_in
!=0) {
2307 /* error handling */
2308 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2311 if (p_fci_internal
->data_out
!=NULL
) {
2312 /* error handling */
2313 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2316 if(!(p_fci_internal
->data_in
= p_fci_internal
->alloc(CB_MAX_CHUNK
))) {
2317 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
2320 if (p_fci_internal
->data_out
==NULL
) {
2321 if(!(p_fci_internal
->data_out
= p_fci_internal
->alloc( 2 * CB_MAX_CHUNK
))){
2322 set_error( p_fci_internal
, FCIERR_ALLOC_FAIL
, ERROR_NOT_ENOUGH_MEMORY
);
2328 if (p_fci_internal
->data_out
==NULL
) {
2329 p_fci_internal
->free(p_fci_internal
->data_in
);
2330 /* error handling */
2331 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2335 /* get information about the file */
2336 /* set defaults in case callback doesn't set one or more fields */
2340 file_handle
=(*pfnfcigoi
)(pszSourceFile
, &(cffile
.date
), &(cffile
.time
),
2341 &(cffile
.attribs
), &err
, p_fci_internal
->pv
);
2342 /* check file_handle */
2344 set_error( p_fci_internal
, FCIERR_OPEN_SRC
, ERROR_OPEN_FAILED
);
2346 /* TODO error handling of err */
2348 if (fExecute
) { cffile
.attribs
|= _A_EXEC
; }
2350 /* REUSE the variable read_result */
2351 if (p_fci_internal
->fGetNextCabInVain
) {
2352 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
2353 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
2354 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
2355 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
2356 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
2360 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
+
2361 p_fci_internal
->pccab
->cbReserveCFFolder
;
2362 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
2363 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
2364 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
2368 if ( p_fci_internal
->fPrevCab
) {
2369 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
2370 strlen(p_fci_internal
->szPrevDisk
)+1;
2372 if ( p_fci_internal
->fNextCab
) { /* this is never the case */
2373 read_result
+= strlen(p_fci_internal
->pccab
->szCab
)+1+
2374 strlen(p_fci_internal
->pccab
->szDisk
)+1;
2377 read_result
+= sizeof(CFFILE
) + strlen(pszFileName
)+1 +
2378 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
2379 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
2381 sizeof(CFFOLDER
); /* size of new CFFolder entry */
2383 /* Might be too much data for the maximum size of a cabinet.*/
2384 /* When any further data will be added later, it might not */
2385 /* be possible to flush the cabinet, because there might */
2386 /* not be enough space to store the name of the following */
2387 /* cabinet and name of the corresponding disk. */
2388 /* So take care of this and get the name of the next cabinet */
2389 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2390 p_fci_internal
->fNextCab
==FALSE
&&
2391 ( p_fci_internal
->pccab
->cb
< read_result
+
2392 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
2396 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
2397 /* increment cabinet index */
2398 ++(p_fci_internal
->pccab
->iCab
);
2399 /* get name of next cabinet */
2400 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
2401 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
2402 p_fci_internal
->estimatedCabinetSize
, /* estimated size of cab */
2403 p_fci_internal
->pv
)) {
2404 /* error handling */
2405 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2408 /* Skip a few lines of code. This is caught by the next if. */
2409 p_fci_internal
->fGetNextCabInVain
=TRUE
;
2412 if( p_fci_internal
->fGetNextCabInVain
&&
2413 p_fci_internal
->fNextCab
2415 /* THIS CAN NEVER HAPPEN */
2416 /* set error code */
2417 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2421 /* too much data for cabinet */
2422 if( p_fci_internal
->fGetNextCabInVain
&&
2424 p_fci_internal
->oldCCAB
.cb
< read_result
+
2425 strlen(p_fci_internal
->pccab
->szCab
)+1+
2426 strlen(p_fci_internal
->pccab
->szDisk
)+1
2428 p_fci_internal
->fGetNextCabInVain
=FALSE
;
2429 p_fci_internal
->fNextCab
=TRUE
;
2430 if(!fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
)) return FALSE
;
2433 if( p_fci_internal
->fNextCab
) {
2434 /* THIS MAY NEVER HAPPEN */
2435 /* set error code */
2436 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2440 /* read the contents of the file blockwise */
2442 if (p_fci_internal
->cdata_in
> CAB_BLOCKMAX
) {
2443 /* internal error */
2444 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2448 read_result
= p_fci_internal
->read( file_handle
/* file handle */,
2449 (p_fci_internal
->data_in
+ p_fci_internal
->cdata_in
) /* memory buffer */,
2450 (CAB_BLOCKMAX
- p_fci_internal
->cdata_in
) /* number of bytes to copy */,
2451 &err
, p_fci_internal
->pv
);
2452 /* TODO error handling of err */
2454 if( read_result
==0 ) break;
2456 /* increment the block size */
2457 p_fci_internal
->cdata_in
+= read_result
;
2459 /* increment the file size */
2460 cffile
.cbFile
+= read_result
;
2462 if ( p_fci_internal
->cdata_in
> CAB_BLOCKMAX
) {
2463 /* report internal error */
2464 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2467 /* write a whole block */
2468 if ( p_fci_internal
->cdata_in
== CAB_BLOCKMAX
) {
2470 if( !fci_flush_data_block(p_fci_internal
, &err
, pfnfcis
) ) return FALSE
;
2474 /* close the file from FCIAddFile */
2475 p_fci_internal
->close(file_handle
,&err
,p_fci_internal
->pv
);
2476 /* TODO error handling of err */
2478 /* write cffile to p_fci_internal->handleCFFILE1 */
2479 if( p_fci_internal
->write( p_fci_internal
->handleCFFILE1
, /* file handle */
2480 &cffile
, sizeof(cffile
),&err
, p_fci_internal
->pv
) != sizeof(cffile
) ) {
2482 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
2485 /* TODO error handling of err */
2487 p_fci_internal
->sizeFileCFFILE1
+= sizeof(cffile
);
2489 /* append the name of file */
2490 if (strlen(pszFileName
)>=CB_MAX_FILENAME
) {
2492 /* set error code */
2493 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_INVALID_DATA
);
2496 if( p_fci_internal
->write( p_fci_internal
->handleCFFILE1
, /* file handle */
2497 pszFileName
, strlen(pszFileName
)+1, &err
, p_fci_internal
->pv
)
2498 != strlen(pszFileName
)+1 ) {
2500 set_error( p_fci_internal
, FCIERR_TEMP_FILE
, ERROR_WRITE_FAULT
);
2503 /* TODO error handling of err */
2505 p_fci_internal
->sizeFileCFFILE1
+= strlen(pszFileName
)+1;
2507 /* REUSE the variable read_result */
2508 if (p_fci_internal
->fGetNextCabInVain
||
2509 p_fci_internal
->fNextCab
2511 read_result
=p_fci_internal
->oldCCAB
.cbReserveCFHeader
+
2512 p_fci_internal
->oldCCAB
.cbReserveCFFolder
;
2513 if ( p_fci_internal
->oldCCAB
.cbReserveCFHeader
!= 0 ||
2514 p_fci_internal
->oldCCAB
.cbReserveCFFolder
!= 0 ||
2515 p_fci_internal
->oldCCAB
.cbReserveCFData
!= 0 ) {
2519 read_result
=p_fci_internal
->pccab
->cbReserveCFHeader
+
2520 p_fci_internal
->pccab
->cbReserveCFFolder
;
2521 if ( p_fci_internal
->pccab
->cbReserveCFHeader
!= 0 ||
2522 p_fci_internal
->pccab
->cbReserveCFFolder
!= 0 ||
2523 p_fci_internal
->pccab
->cbReserveCFData
!= 0 ) {
2527 if ( p_fci_internal
->fPrevCab
) {
2528 read_result
+= strlen(p_fci_internal
->szPrevCab
)+1+
2529 strlen(p_fci_internal
->szPrevDisk
)+1;
2531 if ( p_fci_internal
->fNextCab
) { /* this is never the case */
2532 read_result
+= strlen(p_fci_internal
->pccab
->szCab
)+1+
2533 strlen(p_fci_internal
->pccab
->szDisk
)+1;
2535 read_result
+= p_fci_internal
->sizeFileCFDATA1
+
2536 p_fci_internal
->sizeFileCFFILE1
+ p_fci_internal
->sizeFileCFDATA2
+
2537 p_fci_internal
->sizeFileCFFILE2
+ p_fci_internal
->folders_size
+
2539 sizeof(CFFOLDER
); /* set size of new CFFolder entry */
2541 /* too much data for the maximum size of a cabinet */
2542 /* (ignoring the unflushed data block) */
2543 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2544 p_fci_internal
->fNextCab
==FALSE
&& /* this is always the case */
2545 p_fci_internal
->pccab
->cb
< read_result
) {
2546 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2549 /* Might be too much data for the maximum size of a cabinet.*/
2550 /* When any further data will be added later, it might not */
2551 /* be possible to flush the cabinet, because there might */
2552 /* not be enough space to store the name of the following */
2553 /* cabinet and name of the corresponding disk. */
2554 /* So take care of this and get the name of the next cabinet */
2555 /* (ignoring the unflushed data block) */
2556 if( p_fci_internal
->fGetNextCabInVain
==FALSE
&&
2557 p_fci_internal
->fNextCab
==FALSE
&&
2558 ( p_fci_internal
->pccab
->cb
< read_result
+
2559 CB_MAX_CABINET_NAME
+ CB_MAX_DISK_NAME
2563 p_fci_internal
->oldCCAB
= *p_fci_internal
->pccab
;
2564 /* increment cabinet index */
2565 ++(p_fci_internal
->pccab
->iCab
);
2566 /* get name of next cabinet */
2567 p_fci_internal
->estimatedCabinetSize
=p_fci_internal
->statusFolderTotal
;
2568 if (!(*pfnfcignc
)(p_fci_internal
->pccab
,
2569 p_fci_internal
->estimatedCabinetSize
,/* estimated size of cab */
2570 p_fci_internal
->pv
)) {
2571 /* error handling */
2572 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_FUNCTION_FAILED
);
2575 /* Skip a few lines of code. This is caught by the next if. */
2576 p_fci_internal
->fGetNextCabInVain
=TRUE
;
2579 if( p_fci_internal
->fGetNextCabInVain
&&
2580 p_fci_internal
->fNextCab
2582 /* THIS CAN NEVER HAPPEN */
2583 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2587 /* too much data for cabinet */
2588 if( (p_fci_internal
->fGetNextCabInVain
||
2589 p_fci_internal
->fNextCab
) && (
2590 p_fci_internal
->oldCCAB
.cb
< read_result
+
2591 strlen(p_fci_internal
->pccab
->szCab
)+1+
2592 strlen(p_fci_internal
->pccab
->szDisk
)+1
2595 p_fci_internal
->fGetNextCabInVain
=FALSE
;
2596 p_fci_internal
->fNextCab
=TRUE
;
2597 return fci_flush_cabinet( p_fci_internal
, FALSE
, pfnfcignc
, pfnfcis
);
2600 if( p_fci_internal
->fNextCab
) {
2601 /* THIS MAY NEVER HAPPEN */
2602 /* set error code */
2603 set_error( p_fci_internal
, FCIERR_NONE
, ERROR_GEN_FAILURE
);
2607 /* if the FolderThreshold has been reached flush the folder automatically */
2608 if( p_fci_internal
->fGetNextCabInVain
) {
2609 if( p_fci_internal
->cCompressedBytesInFolder
>=
2610 p_fci_internal
->oldCCAB
.cbFolderThresh
) {
2611 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
2614 if( p_fci_internal
->cCompressedBytesInFolder
>=
2615 p_fci_internal
->pccab
->cbFolderThresh
) {
2616 return FCIFlushFolder(hfci
, pfnfcignc
, pfnfcis
);
2621 } /* end of FCIAddFile */
2627 /***********************************************************************
2628 * FCIFlushFolder (CABINET.12)
2630 * FCIFlushFolder completes the CFFolder structure under construction.
2632 * All further data which is added by FCIAddFile will be associated to
2633 * the next CFFolder structure.
2635 * FCIFlushFolder will be called by FCIAddFile automatically if the
2636 * threshold (stored in the member cbFolderThresh of the CCAB structure
2637 * pccab passed to FCICreate) is exceeded.
2639 * FCIFlushFolder will be called by FCIFlushFolder automatically before
2640 * any data will be written into the cabinet file.
2643 * hfci [I] An HFCI from FCICreate
2644 * pfnfcignc [I] A pointer to a function which gets information about
2646 * pfnfcis [IO] A pointer to a function which will report status
2647 * information about the compression process
2650 * On success, returns TRUE
2651 * On failure, returns FALSE
2657 BOOL __cdecl
FCIFlushFolder(
2659 PFNFCIGETNEXTCABINET pfnfcignc
,
2660 PFNFCISTATUS pfnfcis
)
2662 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2664 if (!p_fci_internal
) return FALSE
;
2665 return fci_flush_folder(p_fci_internal
,FALSE
,pfnfcignc
,pfnfcis
);
2670 /***********************************************************************
2671 * FCIFlushCabinet (CABINET.13)
2673 * FCIFlushCabinet stores the data which has been added by FCIAddFile
2674 * into the cabinet file. If the maximum cabinet size (stored in the
2675 * member cb of the CCAB structure pccab passed to FCICreate) has been
2676 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2677 * The remaining data still has to be flushed manually by calling
2680 * After FCIFlushCabinet has been called (manually) FCIAddFile must
2681 * NOT be called again. Then hfci has to be released by FCIDestroy.
2684 * hfci [I] An HFCI from FCICreate
2685 * fGetNextCab [I] Whether you want to add additional files to a
2686 * cabinet set (TRUE) or whether you want to
2687 * finalize it (FALSE)
2688 * pfnfcignc [I] A pointer to a function which gets information about
2690 * pfnfcis [IO] A pointer to a function which will report status
2691 * information about the compression process
2694 * On success, returns TRUE
2695 * On failure, returns FALSE
2701 BOOL __cdecl
FCIFlushCabinet(
2704 PFNFCIGETNEXTCABINET pfnfcignc
,
2705 PFNFCISTATUS pfnfcis
)
2707 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2709 if (!p_fci_internal
) return FALSE
;
2711 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
2713 while( p_fci_internal
->sizeFileCFFILE1
>0 ||
2714 p_fci_internal
->sizeFileCFFILE2
>0 ) {
2715 if(!fci_flush_cabinet(p_fci_internal
,fGetNextCab
,pfnfcignc
,pfnfcis
)) return FALSE
;
2722 /***********************************************************************
2723 * FCIDestroy (CABINET.14)
2725 * Frees a handle created by FCICreate.
2726 * Only reason for failure would be an invalid handle.
2729 * hfci [I] The HFCI to free
2735 BOOL __cdecl
FCIDestroy(HFCI hfci
)
2738 struct folder
*folder
, *folder_next
;
2739 FCI_Int
*p_fci_internal
= get_fci_ptr( hfci
);
2741 if (!p_fci_internal
) return FALSE
;
2743 /* before hfci can be removed all temporary files must be closed */
2745 p_fci_internal
->magic
= 0;
2747 LIST_FOR_EACH_ENTRY_SAFE( folder
, folder_next
, &p_fci_internal
->folders_list
, struct folder
, entry
)
2749 list_remove( &folder
->entry
);
2750 p_fci_internal
->free( folder
);
2753 p_fci_internal
->close( p_fci_internal
->handleCFDATA1
,&err
,p_fci_internal
->pv
);
2754 /* TODO error handling of err */
2755 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA1
, &err
,
2756 p_fci_internal
->pv
);
2757 /* TODO error handling of err */
2758 p_fci_internal
->close( p_fci_internal
->handleCFFILE1
,&err
,p_fci_internal
->pv
);
2759 /* TODO error handling of err */
2760 p_fci_internal
->delete( p_fci_internal
->szFileNameCFFILE1
, &err
,
2761 p_fci_internal
->pv
);
2762 /* TODO error handling of err */
2763 p_fci_internal
->close( p_fci_internal
->handleCFDATA2
,&err
,p_fci_internal
->pv
);
2764 /* TODO error handling of err */
2765 p_fci_internal
->delete( p_fci_internal
->szFileNameCFDATA2
, &err
,
2766 p_fci_internal
->pv
);
2767 /* TODO error handling of err */
2768 p_fci_internal
->close( p_fci_internal
->handleCFFILE2
,&err
,p_fci_internal
->pv
);
2769 /* TODO error handling of err */
2770 p_fci_internal
->delete( p_fci_internal
->szFileNameCFFILE2
, &err
,
2771 p_fci_internal
->pv
);
2772 /* TODO error handling of err */
2774 /* data in and out buffers have to be removed */
2775 if (p_fci_internal
->data_in
!=NULL
)
2776 p_fci_internal
->free(p_fci_internal
->data_in
);
2777 if (p_fci_internal
->data_out
!=NULL
)
2778 p_fci_internal
->free(p_fci_internal
->data_out
);
2780 /* hfci can now be removed */
2781 p_fci_internal
->free(hfci
);