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/debug.h"
51 #ifdef WORDS_BIGENDIAN
52 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
53 #define fci_endian_uword(x) RtlUshortByteSwap(x)
55 #define fci_endian_ulong(x) (x)
56 #define fci_endian_uword(x) (x)
61 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
63 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
65 cab_ULONG coffFiles; /* offset to first CFFILE section */
67 cab_UBYTE versionMinor; /* 3 */
68 cab_UBYTE versionMajor; /* 1 */
69 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
70 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
71 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
72 cab_UWORD setID; /* identification number of all cabinets in a set*/
73 cab_UWORD iCabinet; /* number of the cabinet in a set */
74 /* additional area if "flags" were set*/
75 } CFHEADER; /* minimum 36 bytes */
78 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
79 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
80 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
81 /* additional area if reserve flag was set */
82 } CFFOLDER; /* minimum 8 bytes */
85 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
86 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
87 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
88 /* for special values see below this structure*/
89 cab_UWORD date; /* last modification date*/
90 cab_UWORD time; /* last modification time*/
91 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
92 /* ... and a C string with the name of the file */
93 } CFFILE; /* 16 bytes + name of file */
97 cab_ULONG csum; /* checksum of this entry*/
98 cab_UWORD cbData; /* number of compressed bytes */
99 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
100 /* optional reserved area */
101 /* compressed data */
109 PFNFCIFILEPLACED fileplaced;
118 PFNFCIGETTEMPFILE gettemp;
123 cab_ULONG statusFolderCopied;
124 cab_ULONG statusFolderTotal;
125 BOOL fGetNextCabInVain;
127 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
128 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
130 char* data_in; /* uncompressed data blocks */
132 char* data_out; /* compressed data blocks */
133 ULONG cCompressedBytesInFolder;
136 cab_ULONG cDataBlocks;
137 cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */
138 /* of spanned file of a spanning folder of a spanning cabinet */
139 char szFileNameCFDATA1[CB_MAX_FILENAME];
141 char szFileNameCFFILE1[CB_MAX_FILENAME];
143 char szFileNameCFDATA2[CB_MAX_FILENAME];
145 char szFileNameCFFILE2[CB_MAX_FILENAME];
147 char szFileNameCFFOLDER[CB_MAX_FILENAME];
149 cab_ULONG sizeFileCFDATA1;
150 cab_ULONG sizeFileCFFILE1;
151 cab_ULONG sizeFileCFDATA2;
152 cab_ULONG sizeFileCFFILE2;
153 cab_ULONG sizeFileCFFOLDER;
155 cab_ULONG estimatedCabinetSize;
158 #define FCI_INT_MAGIC 0xfcfcfc05
160 static void set_error( FCI_Int *fci, int oper, int err )
162 fci->perf->erfOper = oper;
163 fci->perf->erfType = err;
164 fci->perf->fError = TRUE;
165 if (err) SetLastError( err );
168 static FCI_Int *get_fci_ptr( HFCI hfci )
170 FCI_Int *fci= (FCI_Int *)hfci;
172 if (!fci || !fci->magic == FCI_INT_MAGIC)
174 SetLastError( ERROR_INVALID_HANDLE );
180 /***********************************************************************
181 * FCICreate (CABINET.10)
183 * FCICreate is provided with several callbacks and
184 * returns a handle which can be used to create cabinet files.
187 * perf [IO] A pointer to an ERF structure. When FCICreate
188 * returns an error condition, error information may
189 * be found here as well as from GetLastError.
190 * pfnfiledest [I] A pointer to a function which is called when a file
191 * is placed. Only useful for subsequent cabinet files.
192 * pfnalloc [I] A pointer to a function which allocates ram. Uses
193 * the same interface as malloc.
194 * pfnfree [I] A pointer to a function which frees ram. Uses the
195 * same interface as free.
196 * pfnopen [I] A pointer to a function which opens a file. Uses
197 * the same interface as _open.
198 * pfnread [I] A pointer to a function which reads from a file into
199 * a caller-provided buffer. Uses the same interface
201 * pfnwrite [I] A pointer to a function which writes to a file from
202 * a caller-provided buffer. Uses the same interface
204 * pfnclose [I] A pointer to a function which closes a file handle.
205 * Uses the same interface as _close.
206 * pfnseek [I] A pointer to a function which seeks in a file.
207 * Uses the same interface as _lseek.
208 * pfndelete [I] A pointer to a function which deletes a file.
209 * pfnfcigtf [I] A pointer to a function which gets the name of a
211 * pccab [I] A pointer to an initialized CCAB structure.
212 * pv [I] A pointer to an application-defined notification
213 * function which will be passed to other FCI functions
217 * On success, returns an FCI handle of type HFCI.
218 * On failure, the NULL file handle is returned. Error
219 * info can be retrieved from perf.
225 HFCI __cdecl FCICreate(
227 PFNFCIFILEPLACED pfnfiledest,
228 PFNFCIALLOC pfnalloc,
232 PFNFCIWRITE pfnwrite,
233 PFNFCICLOSE pfnclose,
235 PFNFCIDELETE pfndelete,
236 PFNFCIGETTEMPFILE pfnfcigtf,
241 FCI_Int *p_fci_internal;
244 SetLastError(ERROR_BAD_ARGUMENTS);
247 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
248 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
249 (!pfnfcigtf) || (!pccab)) {
250 perf->erfOper = FCIERR_NONE;
251 perf->erfType = ERROR_BAD_ARGUMENTS;
254 SetLastError(ERROR_BAD_ARGUMENTS);
258 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
259 perf->erfOper = FCIERR_ALLOC_FAIL;
260 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
263 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
267 p_fci_internal->magic = FCI_INT_MAGIC;
268 p_fci_internal->perf = perf;
269 p_fci_internal->fileplaced = pfnfiledest;
270 p_fci_internal->alloc = pfnalloc;
271 p_fci_internal->free = pfnfree;
272 p_fci_internal->open = pfnopen;
273 p_fci_internal->read = pfnread;
274 p_fci_internal->write = pfnwrite;
275 p_fci_internal->close = pfnclose;
276 p_fci_internal->seek = pfnseek;
277 p_fci_internal->delete = pfndelete;
278 p_fci_internal->gettemp = pfnfcigtf;
279 p_fci_internal->pccab = pccab;
280 p_fci_internal->fPrevCab = FALSE;
281 p_fci_internal->fNextCab = FALSE;
282 p_fci_internal->fSplitFolder = FALSE;
283 p_fci_internal->fGetNextCabInVain = FALSE;
284 p_fci_internal->pv = pv;
285 p_fci_internal->data_in = NULL;
286 p_fci_internal->cdata_in = 0;
287 p_fci_internal->data_out = NULL;
288 p_fci_internal->cCompressedBytesInFolder = 0;
289 p_fci_internal->cFolders = 0;
290 p_fci_internal->cFiles = 0;
291 p_fci_internal->cDataBlocks = 0;
292 p_fci_internal->sizeFileCFDATA1 = 0;
293 p_fci_internal->sizeFileCFFILE1 = 0;
294 p_fci_internal->sizeFileCFDATA2 = 0;
295 p_fci_internal->sizeFileCFFILE2 = 0;
296 p_fci_internal->sizeFileCFFOLDER = 0;
297 p_fci_internal->sizeFileCFFOLDER = 0;
298 p_fci_internal->fNewPrevious = FALSE;
299 p_fci_internal->estimatedCabinetSize = 0;
300 p_fci_internal->statusFolderTotal = 0;
302 memset(&p_fci_internal->oldCCAB, 0, sizeof(CCAB));
303 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
304 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
307 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFDATA1,
308 CB_MAX_FILENAME, p_fci_internal->pv)) {
309 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
313 if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) {
314 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
318 p_fci_internal->handleCFDATA1 = p_fci_internal->open( p_fci_internal->szFileNameCFDATA1,
319 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
320 _S_IREAD | _S_IWRITE, &err, pv);
321 if(p_fci_internal->handleCFDATA1==0){
322 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
325 /* TODO error checking of err */
327 /* array of all CFFILE in a folder */
328 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFFILE1,
329 CB_MAX_FILENAME, p_fci_internal->pv)) {
330 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
334 if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) {
335 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
338 p_fci_internal->handleCFFILE1 = p_fci_internal->open( p_fci_internal->szFileNameCFFILE1,
339 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
340 _S_IREAD | _S_IWRITE, &err, pv);
341 if(p_fci_internal->handleCFFILE1==0){
342 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
345 /* TODO error checking of err */
347 /* CFDATA with checksum and ready to be copied into cabinet */
348 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFDATA2,
349 CB_MAX_FILENAME, p_fci_internal->pv)) {
350 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
354 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
355 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
358 p_fci_internal->handleCFDATA2 = p_fci_internal->open( p_fci_internal->szFileNameCFDATA2,
359 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
360 _S_IREAD | _S_IWRITE, &err, pv);
361 if(p_fci_internal->handleCFDATA2==0){
362 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
365 /* TODO error checking of err */
367 /* array of all CFFILE in a folder, ready to be copied into cabinet */
368 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFFILE2,
369 CB_MAX_FILENAME, p_fci_internal->pv)) {
370 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
374 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
375 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
378 p_fci_internal->handleCFFILE2 = p_fci_internal->open( p_fci_internal->szFileNameCFFILE2,
379 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
380 _S_IREAD | _S_IWRITE, &err, pv);
381 if(p_fci_internal->handleCFFILE2==0){
382 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
385 /* TODO error checking of err */
387 /* array of all CFFILE in a folder, ready to be copied into cabinet */
388 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFFOLDER,
389 CB_MAX_FILENAME, p_fci_internal->pv)) {
390 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
394 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
395 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
398 p_fci_internal->handleCFFOLDER = p_fci_internal->open( p_fci_internal->szFileNameCFFOLDER,
399 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
400 _S_IREAD | _S_IWRITE, &err, pv);
401 if(p_fci_internal->handleCFFOLDER==0) {
402 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
406 /* TODO close and delete new files when return FALSE */
407 /* TODO error checking of err */
409 return (HFCI)p_fci_internal;
417 static BOOL fci_flush_data_block (FCI_Int *p_fci_internal, int* err,
418 PFNFCISTATUS pfnfcis) {
420 /* attention no checks if there is data available!!! */
422 CFDATA* cfdata=&data;
424 UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData;
427 /* TODO compress the data of p_fci_internal->data_in */
428 /* and write it to p_fci_internal->data_out */
429 memcpy(p_fci_internal->data_out, p_fci_internal->data_in,
430 p_fci_internal->cdata_in /* number of bytes to copy */);
432 cfdata->csum=0; /* checksum has to be set later */
433 /* TODO set realsize of compressed data */
434 cfdata->cbData = p_fci_internal->cdata_in;
435 cfdata->cbUncomp = p_fci_internal->cdata_in;
437 /* write cfdata to p_fci_internal->handleCFDATA1 */
438 if( p_fci_internal->write( p_fci_internal->handleCFDATA1, /* file handle */
439 cfdata, sizeof(*cfdata), err, p_fci_internal->pv)
440 != sizeof(*cfdata) ) {
441 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
444 /* TODO error handling of err */
446 p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata);
448 /* add optional reserved area */
450 /* This allocation and freeing at each CFData block is a bit */
451 /* inefficient, but it's harder to forget about freeing the buffer :-). */
452 /* Reserved areas are used seldom besides that... */
453 if (cbReserveCFData!=0) {
454 if(!(reserved = p_fci_internal->alloc( cbReserveCFData))) {
455 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
458 for(i=0;i<cbReserveCFData;) {
461 if( p_fci_internal->write( p_fci_internal->handleCFDATA1, /* file handle */
462 reserved, /* memory buffer */
463 cbReserveCFData, /* number of bytes to copy */
464 err, p_fci_internal->pv) != cbReserveCFData ) {
465 p_fci_internal->free(reserved);
466 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
469 /* TODO error handling of err PFCI_FREE(hfci, reserved)*/
471 p_fci_internal->sizeFileCFDATA1 += cbReserveCFData;
472 p_fci_internal->free( reserved);
475 /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */
476 if( p_fci_internal->write( p_fci_internal->handleCFDATA1, /* file handle */
477 p_fci_internal->data_out, /* memory buffer */
478 cfdata->cbData, /* number of bytes to copy */
479 err, p_fci_internal->pv) != cfdata->cbData) {
480 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
483 /* TODO error handling of err */
485 p_fci_internal->sizeFileCFDATA1 += cfdata->cbData;
487 /* reset the offset */
488 p_fci_internal->cdata_in = 0;
489 p_fci_internal->cCompressedBytesInFolder += cfdata->cbData;
491 /* report status with pfnfcis about uncompressed and compressed file data */
492 if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp,
493 p_fci_internal->pv) == -1) {
494 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
498 ++(p_fci_internal->cDataBlocks);
501 } /* end of fci_flush_data_block */
507 static cab_ULONG fci_get_checksum(const void *pv, UINT cb, CHECKSUM seed)
518 while (cUlong-- > 0) {
520 ul |= (((cab_ULONG)(*pb++)) << 8);
521 ul |= (((cab_ULONG)(*pb++)) << 16);
522 ul |= (((cab_ULONG)(*pb++)) << 24);
530 ul |= (((ULONG)(*pb++)) << 16);
532 ul |= (((ULONG)(*pb++)) << 8);
541 } /* end of fci_get_checksum */
545 static BOOL fci_flushfolder_copy_cfdata(FCI_Int *p_fci_internal, char* buffer, UINT cbReserveCFData,
546 PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new,
547 cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload)
549 cab_ULONG read_result;
550 CFDATA* pcfdata=(CFDATA*)buffer;
551 BOOL split_block=FALSE;
552 cab_UWORD savedUncomp=0;
556 /* while not all CFDATAs have been copied do */
558 if( p_fci_internal->fNextCab ) {
560 /* internal error should never happen */
561 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
565 /* REUSE the variable read_result */
566 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
567 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
568 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
573 if (p_fci_internal->fPrevCab) {
574 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
575 strlen(p_fci_internal->szPrevDisk)+1;
577 /* No more CFDATA fits into the cabinet under construction */
578 /* So don't try to store more data into it */
579 if( p_fci_internal->fNextCab &&
580 (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData +
581 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
582 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
585 p_fci_internal->oldCCAB.cbReserveCFHeader +
587 p_fci_internal->oldCCAB.cbReserveCFFolder +
588 strlen(p_fci_internal->pccab->szCab)+1 +
589 strlen(p_fci_internal->pccab->szDisk)+1
591 /* This may never be run for the first time the while loop is entered.
592 Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/
593 split_block=TRUE; /* In this case split_block is abused to store */
594 /* the complete data block into the next cabinet and not into the */
595 /* current one. Originally split_block is the indicator that a */
596 /* data block has been split across different cabinets. */
599 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
600 read_result= p_fci_internal->read( p_fci_internal->handleCFDATA1,/*file handle*/
601 buffer, /* memory buffer */
602 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
603 err, p_fci_internal->pv);
604 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
605 if (read_result==0) break; /* ALL DATA has been copied */
607 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
610 /* TODO error handling of err */
612 /* REUSE buffer p_fci_internal->data_out !!! */
613 /* read data from p_fci_internal->handleCFDATA1 to */
614 /* p_fci_internal->data_out */
615 if( p_fci_internal->read( p_fci_internal->handleCFDATA1 /* file handle */,
616 p_fci_internal->data_out /* memory buffer */,
617 pcfdata->cbData /* number of bytes to copy */,
618 err, p_fci_internal->pv) != pcfdata->cbData ) {
620 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
623 /* TODO error handling of err */
625 /* if cabinet size is too large */
627 /* REUSE the variable read_result */
628 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
629 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
630 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
635 if (p_fci_internal->fPrevCab) {
636 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
637 strlen(p_fci_internal->szPrevDisk)+1;
640 /* Is cabinet with new CFDATA too large? Then data block has to be split */
641 if( p_fci_internal->fNextCab &&
642 (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData +
644 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
645 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
648 p_fci_internal->oldCCAB.cbReserveCFHeader +
649 sizeof(CFFOLDER) + /* size of new CFFolder entry */
650 p_fci_internal->oldCCAB.cbReserveCFFolder +
651 strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */
652 strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */
654 /* REUSE read_result to save the size of the compressed data */
655 read_result=pcfdata->cbData;
656 /* Modify the size of the compressed data to store only a part of the */
657 /* data block into the current cabinet. This is done to prevent */
658 /* that the maximum cabinet size will be exceeded. The remainder */
659 /* will be stored into the next following cabinet. */
661 /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */
662 /* Substract everything except the size of the block of data */
663 /* to get it's actual size */
664 pcfdata->cbData = p_fci_internal->oldCCAB.cb - (
665 sizeof(CFDATA) + cbReserveCFData +
666 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
667 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
669 p_fci_internal->oldCCAB.cbReserveCFHeader +
670 sizeof(CFFOLDER) + /* set size of new CFFolder entry */
671 p_fci_internal->oldCCAB.cbReserveCFFolder );
672 /* substract the size of special header fields */
673 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
674 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
675 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
678 if (p_fci_internal->fPrevCab) {
679 pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 +
680 strlen(p_fci_internal->szPrevDisk)+1;
682 pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 +
683 strlen(p_fci_internal->pccab->szDisk)+1;
685 savedUncomp = pcfdata->cbUncomp;
686 pcfdata->cbUncomp = 0; /* on split blocks of data this is zero */
688 /* if split_block==TRUE then the above while loop won't */
689 /* be executed again */
690 split_block=TRUE; /* split_block is the indicator that */
691 /* a data block has been split across */
692 /* different cabinets.*/
695 /* This should never happen !!! */
696 if (pcfdata->cbData==0) {
698 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
702 /* set little endian */
703 pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
704 pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
706 /* get checksum and write to cfdata.csum */
707 pcfdata->csum = fci_get_checksum( &(pcfdata->cbData),
708 sizeof(CFDATA)+cbReserveCFData -
709 sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/
710 pcfdata->cbData, 0 ) );
712 /* set little endian */
713 pcfdata->csum=fci_endian_ulong(pcfdata->csum);
715 /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */
716 if( p_fci_internal->write( p_fci_internal->handleCFDATA2, /* file handle */
717 buffer, /* memory buffer */
718 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
719 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
720 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
723 /* TODO error handling of err */
725 p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData;
727 /* reset little endian */
728 pcfdata->cbData=fci_endian_uword(pcfdata->cbData);
729 pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp);
730 pcfdata->csum=fci_endian_ulong(pcfdata->csum);
732 /* write compressed data into p_fci_internal->handleCFDATA2 */
733 if( p_fci_internal->write( p_fci_internal->handleCFDATA2, /* file handle */
734 p_fci_internal->data_out, /* memory buffer */
735 pcfdata->cbData, /* number of bytes to copy */
736 err, p_fci_internal->pv) != pcfdata->cbData) {
737 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
740 /* TODO error handling of err */
742 p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData;
743 ++(p_fci_internal->cDataBlocks);
744 p_fci_internal->statusFolderCopied += pcfdata->cbData;
745 (*payload)+=pcfdata->cbUncomp;
746 /* if cabinet size too large and data has been split */
747 /* write the remainder of the data block to the new CFDATA1 file */
748 if( split_block ) { /* This does not include the */
749 /* abused one (just search for "abused" )*/
750 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
751 if (p_fci_internal->fNextCab==FALSE ) {
753 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
757 /* set cbData to the size of the remainder of the data block */
758 pcfdata->cbData = read_result - pcfdata->cbData;
759 /*recover former value of cfdata.cbData; read_result will be the offset*/
760 read_result -= pcfdata->cbData;
761 pcfdata->cbUncomp = savedUncomp;
763 /* reset checksum, it will be computed later */
766 /* write cfdata WITHOUT checksum to handleCFDATA1new */
767 if( p_fci_internal->write( handleCFDATA1new, /* file handle */
768 buffer, /* memory buffer */
769 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
770 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
771 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
774 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
776 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
778 /* write compressed data into handleCFDATA1new */
779 if( p_fci_internal->write( handleCFDATA1new, /* file handle */
780 p_fci_internal->data_out + read_result, /* memory buffer + offset */
781 /* to last part of split data */
782 pcfdata->cbData, /* number of bytes to copy */
783 err, p_fci_internal->pv) != pcfdata->cbData) {
784 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
787 /* TODO error handling of err */
789 p_fci_internal->statusFolderCopied += pcfdata->cbData;
791 *psizeFileCFDATA1new += pcfdata->cbData;
792 /* the two blocks of the split data block have been written */
793 /* don't reset split_data yet, because it is still needed see below */
796 /* report status with pfnfcis about copied size of folder */
797 if( (*pfnfcis)(statusFolder,
798 p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/
799 p_fci_internal->statusFolderTotal, /* total folder size */
800 p_fci_internal->pv) == -1) {
801 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
806 /* if cabinet size too large */
807 /* write the remaining data blocks to the new CFDATA1 file */
808 if ( split_block ) { /* This does include the */
809 /* abused one (just search for "abused" )*/
810 if (p_fci_internal->fNextCab==FALSE ) {
812 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
815 /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */
817 /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/
818 read_result= p_fci_internal->read( p_fci_internal->handleCFDATA1,/* handle */
819 buffer, /* memory buffer */
820 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
821 err, p_fci_internal->pv);
822 if (read_result!=sizeof(CFDATA)+cbReserveCFData) {
823 if (read_result==0) break; /* ALL DATA has been copied */
825 set_error( p_fci_internal,FCIERR_NONE, ERROR_READ_FAULT );
828 /* TODO error handling of err */
830 /* REUSE buffer p_fci_internal->data_out !!! */
831 /* read data from p_fci_internal->handleCFDATA1 to */
832 /* p_fci_internal->data_out */
833 if( p_fci_internal->read( p_fci_internal->handleCFDATA1 /* file handle */,
834 p_fci_internal->data_out /* memory buffer */,
835 pcfdata->cbData /* number of bytes to copy */,
836 err, p_fci_internal->pv) != pcfdata->cbData ) {
838 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
841 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
843 /* write cfdata with checksum to handleCFDATA1new */
844 if( p_fci_internal->write( handleCFDATA1new, /* file handle */
845 buffer, /* memory buffer */
846 sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */
847 err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) {
848 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
851 /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */
853 *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData;
855 /* write compressed data into handleCFDATA1new */
856 if( p_fci_internal->write( handleCFDATA1new, /* file handle */
857 p_fci_internal->data_out, /* memory buffer */
858 pcfdata->cbData, /* number of bytes to copy */
859 err, p_fci_internal->pv) != pcfdata->cbData) {
860 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
863 /* TODO error handling of err */
865 *psizeFileCFDATA1new += pcfdata->cbData;
866 p_fci_internal->statusFolderCopied += pcfdata->cbData;
868 /* report status with pfnfcis about copied size of folder */
869 if( (*pfnfcis)(statusFolder,
870 p_fci_internal->statusFolderCopied,/*cfdata.cbData(+previous ones)*/
871 p_fci_internal->statusFolderTotal, /* total folder size */
872 p_fci_internal->pv) == -1) {
873 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
878 break; /* jump out of the next while loop */
879 } /* end of if( split_data ) */
882 } /* end of fci_flushfolder_copy_cfdata */
888 static BOOL fci_flushfolder_copy_cffolder(FCI_Int *p_fci_internal, int* err, UINT cbReserveCFFolder,
889 cab_ULONG sizeFileCFDATA2old)
895 /* absolute offset cannot be set yet, because the size of cabinet header, */
896 /* the number of CFFOLDERs and the number of CFFILEs may change. */
897 /* Instead the size of all previous data blocks will be stored and */
898 /* the remainder of the offset will be added when the cabinet will be */
899 /* flushed to disk. */
900 /* This is exactly the way the original CABINET.DLL works!!! */
901 cffolder.coffCabStart=sizeFileCFDATA2old;
903 /* set the number of this folder's CFDATA sections */
904 cffolder.cCFData=p_fci_internal->cDataBlocks;
905 /* TODO set compression type */
906 cffolder.typeCompress = tcompTYPE_NONE;
908 /* write cffolder to p_fci_internal->handleCFFOLDER */
909 if( p_fci_internal->write( p_fci_internal->handleCFFOLDER, /* file handle */
910 &cffolder, /* memory buffer */
911 sizeof(cffolder), /* number of bytes to copy */
912 err, p_fci_internal->pv) != sizeof(cffolder) ) {
913 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
916 /* TODO error handling of err */
918 p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder);
920 /* add optional reserved area */
921 if (cbReserveCFFolder!=0) {
922 if(!(reserved = p_fci_internal->alloc( cbReserveCFFolder))) {
923 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
926 for(i=0;i<cbReserveCFFolder;) {
929 if( p_fci_internal->write( p_fci_internal->handleCFFOLDER, /* file handle */
930 reserved, /* memory buffer */
931 cbReserveCFFolder, /* number of bytes to copy */
932 err, p_fci_internal->pv) != cbReserveCFFolder ) {
933 p_fci_internal->free(reserved);
934 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
937 /* TODO error handling of err */
939 p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder;
941 p_fci_internal->free(reserved);
944 } /* end of fci_flushfolder_copy_cffolder */
950 static BOOL fci_flushfolder_copy_cffile(FCI_Int *p_fci_internal, int* err, int handleCFFILE1new,
951 cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload)
954 cab_ULONG read_result;
956 cab_ULONG sizeOfFiles=0, sizeOfFilesPrev;
957 BOOL may_be_prev=TRUE;
958 cab_ULONG cbFileRemainer=0;
960 /* set seek of p_fci_internal->handleCFFILE1 to 0 */
961 if( p_fci_internal->seek(p_fci_internal->handleCFFILE1,0,SEEK_SET,err,
962 p_fci_internal->pv) !=0 ) {
963 /* wrong return value */
964 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
967 /* TODO error handling of err */
969 /* while not all CFFILE structures have been copied do */
971 /* REUSE the variable read_result */
972 /* read data from p_fci_internal->handleCFFILE1 to cffile */
973 read_result = p_fci_internal->read(p_fci_internal->handleCFFILE1/* file handle */,
974 &cffile, /* memory buffer */
975 sizeof(cffile), /* number of bytes to copy */
976 err, p_fci_internal->pv);
977 if( read_result != sizeof(cffile) ) {
978 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
980 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
983 /* TODO error handling of err */
985 /* Microsoft's(R) CABINET.DLL would do a seek to the current! */
986 /* position. I don't know why so I'll just omit it */
988 /* read the filename from p_fci_internal->handleCFFILE1 */
989 /* REUSE the variable read_result AGAIN */
990 /* REUSE the memory buffer PFCI(hfci)->data_out */
991 if( p_fci_internal->read( p_fci_internal->handleCFFILE1 /*file handle*/,
992 p_fci_internal->data_out, /* memory buffer */
993 CB_MAX_FILENAME, /* number of bytes to copy */
994 err, p_fci_internal->pv) <2) {
996 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
999 /* TODO maybe other checks of read_result */
1000 /* TODO error handling of err */
1003 if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) {
1004 /* set error code internal error */
1005 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
1009 seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1;
1011 /* set seek of p_fci_internal->handleCFFILE1 to end of file name */
1012 /* i.e. seek to the next CFFILE area */
1013 if( p_fci_internal->seek(p_fci_internal->handleCFFILE1,
1014 seek, /* seek position*/
1018 /* wrong return value */
1019 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
1022 /* TODO error handling of err */
1024 /* fnfilfnfildest: placed file on cabinet */
1025 if (p_fci_internal->fNextCab ||
1026 p_fci_internal->fGetNextCabInVain) {
1027 p_fci_internal->fileplaced( &p_fci_internal->oldCCAB,
1028 p_fci_internal->data_out, /* the file name*/
1029 cffile.cbFile, /* file size */
1030 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
1034 p_fci_internal->fileplaced( p_fci_internal->pccab,
1035 p_fci_internal->data_out, /* the file name*/
1036 cffile.cbFile, /* file size */
1037 (cffile.iFolder==cffileCONTINUED_FROM_PREV),
1042 /* Check special iFolder values */
1043 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
1044 p_fci_internal->fPrevCab==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_PREV_AND_NEXT ||
1051 cffile.iFolder==cffileCONTINUED_TO_NEXT ) {
1052 /* THIS MAY NEVER HAPPEN */
1053 /* set error code */
1054 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1057 if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
1060 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) {
1061 /* THIS MAY NEVER HAPPEN */
1062 /* set error code */
1063 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1066 if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) {
1070 sizeOfFilesPrev=sizeOfFiles;
1071 /* Set complete size of all processed files */
1072 if( cffile.iFolder==cffileCONTINUED_FROM_PREV &&
1073 p_fci_internal->cbFileRemainer!=0
1075 sizeOfFiles+=p_fci_internal->cbFileRemainer;
1076 p_fci_internal->cbFileRemainer=0;
1078 sizeOfFiles+=cffile.cbFile;
1081 /* Check if spanned file fits into this cabinet folder */
1082 if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) {
1083 cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT;
1086 /* Check if file doesn't fit into this cabinet folder */
1087 if( sizeOfFiles>payload ) {
1088 cffile.iFolder=cffileCONTINUED_TO_NEXT;
1091 /* set little endian */
1092 cffile.cbFile=fci_endian_ulong(cffile.cbFile);
1093 cffile.uoffFolderStart=fci_endian_ulong(cffile.uoffFolderStart);
1094 cffile.iFolder=fci_endian_uword(cffile.iFolder);
1095 cffile.date=fci_endian_uword(cffile.date);
1096 cffile.time=fci_endian_uword(cffile.time);
1097 cffile.attribs=fci_endian_uword(cffile.attribs);
1099 /* write cffile to p_fci_internal->handleCFFILE2 */
1100 if( p_fci_internal->write( p_fci_internal->handleCFFILE2, /* file handle */
1101 &cffile, /* memory buffer */
1102 sizeof(cffile), /* number of bytes to copy */
1103 err, p_fci_internal->pv) != sizeof(cffile) ) {
1104 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1107 /* TODO error handling of err */
1109 p_fci_internal->sizeFileCFFILE2 += sizeof(cffile);
1111 /* reset little endian */
1112 cffile.cbFile=fci_endian_ulong(cffile.cbFile);
1113 cffile.uoffFolderStart=fci_endian_ulong(cffile.uoffFolderStart);
1114 cffile.iFolder=fci_endian_uword(cffile.iFolder);
1115 cffile.date=fci_endian_uword(cffile.date);
1116 cffile.time=fci_endian_uword(cffile.time);
1117 cffile.attribs=fci_endian_uword(cffile.attribs);
1119 /* write file name to p_fci_internal->handleCFFILE2 */
1120 if( p_fci_internal->write( p_fci_internal->handleCFFILE2, /* file handle */
1121 p_fci_internal->data_out, /* memory buffer */
1122 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1123 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1124 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1127 /* TODO error handling of err */
1129 p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1;
1131 /* cFiles is used to count all files of a cabinet */
1132 ++(p_fci_internal->cFiles);
1134 /* This is only true for files which will be written into the */
1135 /* next cabinet of the spanning folder */
1136 if( sizeOfFiles>payload ) {
1138 /* Files which data will be partially written into the current cabinet */
1139 if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT ||
1140 cffile.iFolder==cffileCONTINUED_TO_NEXT
1142 if( sizeOfFilesPrev<=payload ) {
1143 /* The size of the uncompressed, data of a spanning file in a */
1145 cbFileRemainer=sizeOfFiles-payload;
1147 cffile.iFolder=cffileCONTINUED_FROM_PREV;
1152 /* write cffile into handleCFFILE1new */
1153 if( p_fci_internal->write( handleCFFILE1new, /* file handle */
1154 &cffile, /* memory buffer */
1155 sizeof(cffile), /* number of bytes to copy */
1156 err, p_fci_internal->pv) != sizeof(cffile) ) {
1157 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1160 /* TODO error handling of err */
1162 *psizeFileCFFILE1new += sizeof(cffile);
1163 /* write name of file into handleCFFILE1new */
1164 if( p_fci_internal->write( handleCFFILE1new, /* file handle */
1165 p_fci_internal->data_out, /* memory buffer */
1166 strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */
1167 err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) {
1168 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
1171 /* TODO error handling of err */
1173 *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1;
1176 } /* END OF while */
1177 p_fci_internal->cbFileRemainer=cbFileRemainer;
1179 } /* end of fci_flushfolder_copy_cffile */
1184 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1186 PFNFCIGETNEXTCABINET pfnfcignc,
1187 PFNFCISTATUS pfnfcis)
1190 int handleCFDATA1new; /* handle for new temp file */
1191 char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1192 int handleCFFILE1new; /* handle for new temp file */
1193 char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */
1194 UINT cbReserveCFData, cbReserveCFFolder;
1196 cab_ULONG sizeFileCFDATA1new=0;
1197 cab_ULONG sizeFileCFFILE1new=0;
1198 cab_ULONG sizeFileCFDATA2old;
1200 cab_ULONG read_result;
1202 if ((!pfnfcignc) || (!pfnfcis)) {
1203 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1207 if( p_fci_internal->fGetNextCabInVain &&
1208 p_fci_internal->fNextCab ){
1209 /* internal error */
1210 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1214 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1215 /* this function will return TRUE */
1216 if( p_fci_internal->sizeFileCFFILE1 == 0 ) {
1217 if ( p_fci_internal->sizeFileCFDATA1 != 0 ) {
1218 /* error handling */
1219 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1225 if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1226 /* error handling */
1227 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1231 /* FCIFlushFolder has already been called... */
1232 if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) {
1236 /* This can be set already, because it makes only a difference */
1237 /* when the current function exits with return FALSE */
1238 p_fci_internal->fSplitFolder=FALSE;
1241 if( p_fci_internal->fGetNextCabInVain ||
1242 p_fci_internal->fNextCab ){
1243 cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1244 cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder;
1246 cbReserveCFData = p_fci_internal->pccab->cbReserveCFData;
1247 cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder;
1251 /* if there is data in p_fci_internal->data_in */
1252 if (p_fci_internal->cdata_in!=0) {
1254 if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
1257 /* reset to get the number of data blocks of this folder which are */
1258 /* actually in this cabinet ( at least partially ) */
1259 p_fci_internal->cDataBlocks=0;
1261 if ( p_fci_internal->fNextCab ||
1262 p_fci_internal->fGetNextCabInVain ) {
1263 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+
1264 p_fci_internal->oldCCAB.cbReserveCFFolder;
1265 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1266 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1267 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1271 read_result= p_fci_internal->pccab->cbReserveCFHeader+
1272 p_fci_internal->pccab->cbReserveCFFolder;
1273 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1274 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1275 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1279 if (p_fci_internal->fPrevCab) {
1280 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1281 strlen(p_fci_internal->szPrevDisk)+1;
1283 if (p_fci_internal->fNextCab) {
1284 read_result+=strlen(p_fci_internal->pccab->szCab)+1 +
1285 strlen(p_fci_internal->pccab->szDisk)+1;
1288 p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+
1289 sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+
1290 p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+
1291 p_fci_internal->sizeFileCFDATA1 + p_fci_internal->sizeFileCFFOLDER;
1292 p_fci_internal->statusFolderCopied = 0;
1294 /* report status with pfnfcis about copied size of folder */
1295 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1296 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1297 p_fci_internal->pv) == -1) {
1298 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1302 /* get a new temp file */
1303 if(!p_fci_internal->gettemp(szFileNameCFDATA1new,CB_MAX_FILENAME, p_fci_internal->pv)) {
1304 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1308 if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) {
1309 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
1312 handleCFDATA1new = p_fci_internal->open(szFileNameCFDATA1new, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
1313 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv);
1314 if(handleCFDATA1new==0){
1315 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
1318 /* TODO error handling of err */
1322 /* get a new temp file */
1323 if(!p_fci_internal->gettemp(szFileNameCFFILE1new,CB_MAX_FILENAME, p_fci_internal->pv)) {
1324 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1325 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1326 /* TODO error handling of err */
1330 if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) {
1331 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
1332 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1333 /* TODO error handling of err */
1336 handleCFFILE1new = p_fci_internal->open(szFileNameCFFILE1new, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
1337 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv);
1338 if(handleCFFILE1new==0){
1339 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
1342 /* TODO error handling of err */
1344 /* USE the variable read_result */
1345 if ( p_fci_internal->fNextCab ||
1346 p_fci_internal->fGetNextCabInVain ) {
1347 read_result= p_fci_internal->oldCCAB.cbReserveCFHeader;
1348 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1349 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1350 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1354 read_result= p_fci_internal->pccab->cbReserveCFHeader;
1355 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1356 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1357 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1361 if (p_fci_internal->fPrevCab) {
1362 read_result+=strlen(p_fci_internal->szPrevCab)+1 +
1363 strlen(p_fci_internal->szPrevDisk)+1;
1365 read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 +
1366 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER;
1368 if(p_fci_internal->sizeFileCFFILE1!=0) {
1369 read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder;
1372 /* Check if multiple cabinets have to be created. */
1374 /* Might be too much data for the maximum allowed cabinet size.*/
1375 /* When any further data will be added later, it might not */
1376 /* be possible to flush the cabinet, because there might */
1377 /* not be enough space to store the name of the following */
1378 /* cabinet and name of the corresponding disk. */
1379 /* So take care of this and get the name of the next cabinet */
1380 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1381 p_fci_internal->fNextCab==FALSE &&
1384 p_fci_internal->pccab->cb < read_result +
1385 p_fci_internal->sizeFileCFDATA1 +
1386 p_fci_internal->sizeFileCFFILE1 +
1387 CB_MAX_CABINET_NAME + /* next cabinet name */
1388 CB_MAX_DISK_NAME /* next disk name */
1393 p_fci_internal->oldCCAB = *p_fci_internal->pccab;
1394 /* increment cabinet index */
1395 ++(p_fci_internal->pccab->iCab);
1396 /* get name of next cabinet */
1397 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1398 if (!(*pfnfcignc)(p_fci_internal->pccab,
1399 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1400 p_fci_internal->pv)) {
1401 /* error handling */
1402 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1403 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1404 /* TODO error handling of err */
1405 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1406 /* TODO error handling of err */
1410 /* Skip a few lines of code. This is caught by the next if. */
1411 p_fci_internal->fGetNextCabInVain=TRUE;
1414 /* too much data for cabinet */
1415 if( (p_fci_internal->fGetNextCabInVain ||
1416 p_fci_internal->fNextCab ) &&
1419 p_fci_internal->oldCCAB.cb < read_result +
1420 p_fci_internal->sizeFileCFDATA1 +
1421 p_fci_internal->sizeFileCFFILE1 +
1422 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1423 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1427 p_fci_internal->fGetNextCabInVain=FALSE;
1428 p_fci_internal->fNextCab=TRUE;
1430 /* return FALSE if there is not enough space left*/
1431 /* this should never happen */
1432 if (p_fci_internal->oldCCAB.cb <=
1433 p_fci_internal->sizeFileCFFILE1 +
1435 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1436 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1439 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1440 /* TODO error handling of err */
1441 p_fci_internal->delete(szFileNameCFDATA1new,&err,p_fci_internal->pv);
1442 /* TODO error handling of err */
1444 /* close and delete p_fci_internal->handleCFFILE1 */
1445 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1446 /* TODO error handling of err */
1447 p_fci_internal->delete(szFileNameCFFILE1new,&err,p_fci_internal->pv);
1448 /* TODO error handling of err */
1453 /* the folder will be split across cabinets */
1454 p_fci_internal->fSplitFolder=TRUE;
1457 /* this should never happen */
1458 if (p_fci_internal->fNextCab) {
1459 /* internal error */
1460 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1465 /* set seek of p_fci_internal->handleCFDATA1 to 0 */
1466 if( p_fci_internal->seek(p_fci_internal->handleCFDATA1,0,SEEK_SET,&err,
1467 p_fci_internal->pv) !=0 ) {
1468 /* wrong return value */
1469 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
1470 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1471 /* TODO error handling of err */
1472 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1473 /* TODO error handling of err */
1476 /* TODO error handling of err */
1478 /* save size of file CFDATA2 - required for the folder's offset to data */
1479 sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2;
1481 if(!(reserved = p_fci_internal->alloc( cbReserveCFData+sizeof(CFDATA)))) {
1482 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1483 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1484 /* TODO error handling of err */
1485 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1486 /* TODO error handling of err */
1490 if(!fci_flushfolder_copy_cfdata(p_fci_internal, reserved, cbReserveCFData, pfnfcis, &err,
1491 handleCFDATA1new, &sizeFileCFDATA1new, &payload
1493 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1494 /* TODO error handling of err */
1495 p_fci_internal->delete(szFileNameCFDATA1new,&err,p_fci_internal->pv);
1496 /* TODO error handling of err */
1497 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1498 /* TODO error handling of err */
1499 p_fci_internal->free(reserved);
1503 p_fci_internal->free(reserved);
1505 if(!fci_flushfolder_copy_cffolder(p_fci_internal, &err, cbReserveCFFolder,
1506 sizeFileCFDATA2old )) {
1507 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1508 /* TODO error handling of err */
1509 p_fci_internal->delete(szFileNameCFDATA1new,&err,p_fci_internal->pv);
1510 /* TODO error handling of err */
1511 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1512 /* TODO error handling of err */
1516 if(!fci_flushfolder_copy_cffile(p_fci_internal, &err, handleCFFILE1new,
1517 &sizeFileCFFILE1new, payload)) {
1518 p_fci_internal->close(handleCFDATA1new,&err,p_fci_internal->pv);
1519 /* TODO error handling of err */
1520 p_fci_internal->delete(szFileNameCFDATA1new,&err,p_fci_internal->pv);
1521 /* TODO error handling of err */
1522 p_fci_internal->close(handleCFFILE1new,&err,p_fci_internal->pv);
1523 /* TODO error handling of err */
1524 p_fci_internal->delete(szFileNameCFFILE1new,&err,p_fci_internal->pv);
1525 /* TODO error handling of err */
1529 /* close and delete p_fci_internal->handleCFDATA1 */
1530 p_fci_internal->close(p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
1531 /* TODO error handling of err */
1532 p_fci_internal->delete(p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv);
1533 /* TODO error handling of err */
1535 /* put new CFDATA1 into hfci */
1536 memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new,
1539 /* put CFDATA1 file handle */
1540 p_fci_internal->handleCFDATA1 = handleCFDATA1new;
1542 p_fci_internal->sizeFileCFDATA1 = sizeFileCFDATA1new;
1544 /* close and delete PFCI_INT(hfci)->handleCFFILE1 */
1545 p_fci_internal->close(p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);
1546 /* TODO error handling of err */
1547 p_fci_internal->delete(p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv);
1548 /* TODO error handling of err */
1550 /* put new CFFILE1 into hfci */
1551 memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new,
1554 /* put CFFILE1 file handle */
1555 p_fci_internal->handleCFFILE1 = handleCFFILE1new;
1557 p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new;
1559 ++(p_fci_internal->cFolders);
1561 /* reset CFFolder specific information */
1562 p_fci_internal->cDataBlocks=0;
1563 p_fci_internal->cCompressedBytesInFolder=0;
1566 } /* end of fci_flush_folder */
1571 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1573 PFNFCIGETNEXTCABINET pfnfcignc,
1574 PFNFCISTATUS pfnfcis)
1579 cab_UWORD cbCFHeader;
1580 cab_UBYTE cbCFFolder;
1584 cab_ULONG read_result=0;
1585 int handleCABINET; /* file handle for cabinet */
1586 char szFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */
1587 UINT cbReserveCFHeader, cbReserveCFFolder, i;
1589 BOOL returntrue=FALSE;
1591 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1593 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1594 if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) {
1598 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1599 /* TODO set error */
1603 if(returntrue) return TRUE;
1605 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1606 (p_fci_internal->sizeFileCFFOLDER==0 &&
1607 (p_fci_internal->sizeFileCFFILE1!=0 ||
1608 p_fci_internal->sizeFileCFFILE2!=0 )
1612 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1616 if( p_fci_internal->fNextCab ||
1617 p_fci_internal->fGetNextCabInVain ) {
1618 cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder;
1619 cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader;
1621 if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH ||
1622 strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) {
1624 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
1627 /* get the full name of the cabinet */
1628 memcpy(szFileNameCABINET,p_fci_internal->oldCCAB.szCabPath,
1630 memcpy(szFileNameCABINET+strlen(szFileNameCABINET),
1631 p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME);
1633 cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder;
1634 cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader;
1636 if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH ||
1637 strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) {
1639 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
1642 /* get the full name of the cabinet */
1643 memcpy(szFileNameCABINET,p_fci_internal->pccab->szCabPath,
1645 memcpy(szFileNameCABINET+strlen(szFileNameCABINET),
1646 p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME);
1649 memcpy(cfheader.signature,"!CAB",4);
1650 cfheader.reserved1=0;
1651 cfheader.cbCabinet= /* size of the cabinet file in bytes */
1653 p_fci_internal->sizeFileCFFOLDER +
1654 p_fci_internal->sizeFileCFFILE2 +
1655 p_fci_internal->sizeFileCFDATA2;
1657 if (p_fci_internal->fPrevCab) {
1658 cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 +
1659 strlen(p_fci_internal->szPrevDisk)+1;
1661 if (p_fci_internal->fNextCab) {
1662 cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 +
1663 strlen(p_fci_internal->pccab->szDisk)+1;
1665 if( p_fci_internal->fNextCab ||
1666 p_fci_internal->fGetNextCabInVain ) {
1667 cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1668 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1669 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1670 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1671 cfheader.cbCabinet+=4;
1674 cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader;
1675 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1676 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1677 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1678 cfheader.cbCabinet+=4;
1682 if( ( ( p_fci_internal->fNextCab ||
1683 p_fci_internal->fGetNextCabInVain ) &&
1684 cfheader.cbCabinet > p_fci_internal->oldCCAB.cb
1686 ( ( p_fci_internal->fNextCab==FALSE &&
1687 p_fci_internal->fGetNextCabInVain==FALSE ) &&
1688 cfheader.cbCabinet > p_fci_internal->pccab->cb
1692 set_error( p_fci_internal, FCIERR_NONE, ERROR_MORE_DATA );
1697 cfheader.reserved2=0;
1698 cfheader.coffFiles= /* offset to first CFFILE section */
1699 cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 -
1700 p_fci_internal->sizeFileCFDATA2;
1702 cfheader.reserved3=0;
1703 cfheader.versionMinor=3;
1704 cfheader.versionMajor=1;
1705 /* number of CFFOLDER entries in the cabinet */
1706 cfheader.cFolders=p_fci_internal->cFolders;
1707 /* number of CFFILE entries in the cabinet */
1708 cfheader.cFiles=p_fci_internal->cFiles;
1709 cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved sections */
1711 if( p_fci_internal->fPrevCab ) {
1712 cfheader.flags = cfheadPREV_CABINET;
1715 if( p_fci_internal->fNextCab ) {
1716 cfheader.flags |= cfheadNEXT_CABINET;
1719 if( p_fci_internal->fNextCab ||
1720 p_fci_internal->fGetNextCabInVain ) {
1721 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1722 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1723 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1724 cfheader.flags |= cfheadRESERVE_PRESENT;
1726 cfheader.setID = p_fci_internal->oldCCAB.setID;
1727 cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1;
1729 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1730 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1731 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1732 cfheader.flags |= cfheadRESERVE_PRESENT;
1734 cfheader.setID = p_fci_internal->pccab->setID;
1735 cfheader.iCabinet = p_fci_internal->pccab->iCab-1;
1738 /* create the cabinet */
1739 handleCABINET = p_fci_internal->open( szFileNameCABINET, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
1740 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv );
1741 if(handleCABINET==-1)
1743 set_error( p_fci_internal, FCIERR_CAB_FILE, err );
1746 /* TODO error checking of err */
1748 /* set little endian */
1749 cfheader.reserved1=fci_endian_ulong(cfheader.reserved1);
1750 cfheader.cbCabinet=fci_endian_ulong(cfheader.cbCabinet);
1751 cfheader.reserved2=fci_endian_ulong(cfheader.reserved2);
1752 cfheader.coffFiles=fci_endian_ulong(cfheader.coffFiles);
1753 cfheader.reserved3=fci_endian_ulong(cfheader.reserved3);
1754 cfheader.cFolders=fci_endian_uword(cfheader.cFolders);
1755 cfheader.cFiles=fci_endian_uword(cfheader.cFiles);
1756 cfheader.flags=fci_endian_uword(cfheader.flags);
1757 cfheader.setID=fci_endian_uword(cfheader.setID);
1758 cfheader.iCabinet=fci_endian_uword(cfheader.iCabinet);
1760 /* write CFHEADER into cabinet file */
1761 if( p_fci_internal->write( handleCABINET, /* file handle */
1762 &cfheader, /* memory buffer */
1763 sizeof(cfheader), /* number of bytes to copy */
1764 &err, p_fci_internal->pv) != sizeof(cfheader) ) {
1766 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1769 /* TODO error handling of err */
1771 /* reset little endian */
1772 cfheader.reserved1=fci_endian_ulong(cfheader.reserved1);
1773 cfheader.cbCabinet=fci_endian_ulong(cfheader.cbCabinet);
1774 cfheader.reserved2=fci_endian_ulong(cfheader.reserved2);
1775 cfheader.coffFiles=fci_endian_ulong(cfheader.coffFiles);
1776 cfheader.reserved3=fci_endian_ulong(cfheader.reserved3);
1777 cfheader.cFolders=fci_endian_uword(cfheader.cFolders);
1778 cfheader.cFiles=fci_endian_uword(cfheader.cFiles);
1779 cfheader.flags=fci_endian_uword(cfheader.flags);
1780 cfheader.setID=fci_endian_uword(cfheader.setID);
1781 cfheader.iCabinet=fci_endian_uword(cfheader.iCabinet);
1783 if( cfheader.flags & cfheadRESERVE_PRESENT ) {
1784 /* NOTE: No checks for maximum value overflows as designed by MS!!! */
1785 cfreserved.cbCFHeader = cbReserveCFHeader;
1786 cfreserved.cbCFFolder = cbReserveCFFolder;
1787 if( p_fci_internal->fNextCab ||
1788 p_fci_internal->fGetNextCabInVain ) {
1789 cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData;
1791 cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData;
1794 /* set little endian */
1795 cfreserved.cbCFHeader=fci_endian_uword(cfreserved.cbCFHeader);
1797 /* write reserved info into cabinet file */
1798 if( p_fci_internal->write( handleCABINET, /* file handle */
1799 &cfreserved, /* memory buffer */
1800 sizeof(cfreserved), /* number of bytes to copy */
1801 &err, p_fci_internal->pv) != sizeof(cfreserved) ) {
1803 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1806 /* TODO error handling of err */
1808 /* reset little endian */
1809 cfreserved.cbCFHeader=fci_endian_uword(cfreserved.cbCFHeader);
1812 /* add optional reserved area */
1813 if (cbReserveCFHeader!=0) {
1814 if(!(reserved = p_fci_internal->alloc( cbReserveCFHeader))) {
1815 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1818 for(i=0;i<cbReserveCFHeader;) {
1821 if( p_fci_internal->write( handleCABINET, /* file handle */
1822 reserved, /* memory buffer */
1823 cbReserveCFHeader, /* number of bytes to copy */
1824 &err, p_fci_internal->pv) != cbReserveCFHeader ) {
1825 p_fci_internal->free(reserved);
1827 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1830 /* TODO error handling of err */
1831 p_fci_internal->free(reserved);
1834 if( cfheader.flags & cfheadPREV_CABINET ) {
1835 if( p_fci_internal->write( handleCABINET, /* file handle */
1836 p_fci_internal->szPrevCab, /* memory buffer */
1837 strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */
1838 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) {
1840 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1843 /* TODO error handling of err */
1845 if( p_fci_internal->write( handleCABINET, /* file handle */
1846 p_fci_internal->szPrevDisk, /* memory buffer */
1847 strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */
1848 &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) {
1850 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1853 /* TODO error handling of err */
1856 if( cfheader.flags & cfheadNEXT_CABINET ) {
1857 if( p_fci_internal->write( handleCABINET, /* file handle */
1858 p_fci_internal->pccab->szCab, /* memory buffer */
1859 strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */
1860 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) {
1862 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1865 /* TODO error handling of err */
1867 if( p_fci_internal->write( handleCABINET, /* file handle */
1868 p_fci_internal->pccab->szDisk, /* memory buffer */
1869 strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */
1870 &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) {
1872 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1875 /* TODO error handling of err */
1878 /* set seek of p_fci_internal->handleCFFOLDER to 0 */
1879 if( p_fci_internal->seek(p_fci_internal->handleCFFOLDER,
1880 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
1881 /* wrong return value */
1882 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
1885 /* TODO error handling of err */
1887 /* while not all CFFOLDER structures have been copied into the cabinet do */
1889 /* use the variable read_result */
1890 /* read cffolder of p_fci_internal->handleCFFOLDER */
1891 read_result = p_fci_internal->read( p_fci_internal->handleCFFOLDER, /* handle */
1892 &cffolder, /* memory buffer */
1893 sizeof(cffolder), /* number of bytes to copy */
1894 &err, p_fci_internal->pv);
1895 if( read_result != sizeof(cffolder) ) {
1896 if( read_result == 0 ) break;/*ALL CFFOLDER structures have been copied*/
1898 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1901 /* TODO error handling of err */
1903 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
1904 cffolder.coffCabStart +=
1905 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
1907 if( p_fci_internal->fNextCab ||
1908 p_fci_internal->fGetNextCabInVain ) {
1909 cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader;
1911 cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader;
1914 if (p_fci_internal->fPrevCab) {
1915 cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 +
1916 strlen(p_fci_internal->szPrevDisk)+1;
1919 if (p_fci_internal->fNextCab) {
1920 cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 +
1921 strlen(p_fci_internal->oldCCAB.szDisk)+1;
1924 if( p_fci_internal->fNextCab ||
1925 p_fci_internal->fGetNextCabInVain ) {
1926 cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader;
1927 if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
1928 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
1929 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
1930 cffolder.coffCabStart += 4;
1933 cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader;
1934 if( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
1935 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
1936 p_fci_internal->pccab->cbReserveCFData != 0 ) {
1937 cffolder.coffCabStart += 4;
1941 /* set little endian */
1942 cffolder.coffCabStart=fci_endian_ulong(cffolder.coffCabStart);
1943 cffolder.cCFData=fci_endian_uword(cffolder.cCFData);
1944 cffolder.typeCompress=fci_endian_uword(cffolder.typeCompress);
1946 /* write cffolder to cabinet file */
1947 if( p_fci_internal->write( handleCABINET, /* file handle */
1948 &cffolder, /* memory buffer */
1949 sizeof(cffolder), /* number of bytes to copy */
1950 &err, p_fci_internal->pv) != sizeof(cffolder) ) {
1952 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1955 /* TODO error handling of err */
1957 /* reset little endian */
1958 cffolder.coffCabStart=fci_endian_ulong(cffolder.coffCabStart);
1959 cffolder.cCFData=fci_endian_uword(cffolder.cCFData);
1960 cffolder.typeCompress=fci_endian_uword(cffolder.typeCompress);
1962 /* add optional reserved area */
1964 /* This allocation and freeing at each CFFolder block is a bit */
1965 /* inefficient, but it's harder to forget about freeing the buffer :-). */
1966 /* Reserved areas are used seldom besides that... */
1967 if (cbReserveCFFolder!=0) {
1968 if(!(reserved = p_fci_internal->alloc( cbReserveCFFolder))) {
1969 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
1973 if( p_fci_internal->read( p_fci_internal->handleCFFOLDER, /* file handle */
1974 reserved, /* memory buffer */
1975 cbReserveCFFolder, /* number of bytes to copy */
1976 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1977 p_fci_internal->free(reserved);
1979 set_error( p_fci_internal, FCIERR_NONE, ERROR_READ_FAULT );
1982 /* TODO error handling of err */
1984 if( p_fci_internal->write( handleCABINET, /* file handle */
1985 reserved, /* memory buffer */
1986 cbReserveCFFolder, /* number of bytes to copy */
1987 &err, p_fci_internal->pv) != cbReserveCFFolder ) {
1988 p_fci_internal->free(reserved);
1990 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
1993 /* TODO error handling of err */
1995 p_fci_internal->free(reserved);
1998 } /* END OF while */
2000 /* set seek of p_fci_internal->handleCFFILE2 to 0 */
2001 if( p_fci_internal->seek(p_fci_internal->handleCFFILE2,
2002 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
2003 /* wrong return value */
2004 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
2007 /* TODO error handling of err */
2009 /* while not all CFFILE structures have been copied to the cabinet do */
2010 if (p_fci_internal->data_out) while(!FALSE) {
2011 /* REUSE the variable read_result */
2012 /* REUSE the buffer p_fci_internal->data_out AGAIN */
2013 /* read a block from p_fci_internal->handleCFFILE2 */
2014 read_result = p_fci_internal->read( p_fci_internal->handleCFFILE2 /* handle */,
2015 p_fci_internal->data_out, /* memory buffer */
2016 CB_MAX_CHUNK, /* number of bytes to copy */
2017 &err, p_fci_internal->pv);
2018 if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */
2019 /* TODO error handling of err */
2021 /* write the block to the cabinet file */
2022 if( p_fci_internal->write( handleCABINET, /* file handle */
2023 p_fci_internal->data_out, /* memory buffer */
2024 read_result, /* number of bytes to copy */
2025 &err, p_fci_internal->pv) != read_result ) {
2027 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
2030 /* TODO error handling of err */
2032 if (p_fci_internal->fSplitFolder==FALSE) {
2033 p_fci_internal->statusFolderCopied = 0;
2034 /* TODO TEST THIS further */
2035 p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+
2036 p_fci_internal->sizeFileCFFILE2;
2038 p_fci_internal->statusFolderCopied += read_result;
2040 /* report status with pfnfcis about copied size of folder */
2041 if( (*pfnfcis)(statusFolder,
2042 p_fci_internal->statusFolderCopied, /* length of copied blocks */
2043 p_fci_internal->statusFolderTotal, /* total size of folder */
2044 p_fci_internal->pv) == -1) {
2045 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
2049 } /* END OF while */
2051 /* set seek of p_fci_internal->handleCFDATA2 to 0 */
2052 if( p_fci_internal->seek(p_fci_internal->handleCFDATA2,
2053 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
2054 /* wrong return value */
2055 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
2058 /* TODO error handling of err */
2060 /* reset the number of folders for the next cabinet */
2061 p_fci_internal->cFolders=0;
2062 /* reset the number of files for the next cabinet */
2063 p_fci_internal->cFiles=0;
2065 /* while not all CFDATA structures have been copied to the cabinet do */
2066 if (p_fci_internal->data_out) while(!FALSE) {
2067 /* REUSE the variable read_result AGAIN */
2068 /* REUSE the buffer p_fci_internal->data_out AGAIN */
2069 /* read a block from p_fci_internal->handleCFDATA2 */
2070 read_result = p_fci_internal->read( p_fci_internal->handleCFDATA2 /* handle */,
2071 p_fci_internal->data_out, /* memory buffer */
2072 CB_MAX_CHUNK, /* number of bytes to copy */
2073 &err, p_fci_internal->pv);
2074 if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */
2075 /* TODO error handling of err */
2077 /* write the block to the cabinet file */
2078 if( p_fci_internal->write( handleCABINET, /* file handle */
2079 p_fci_internal->data_out, /* memory buffer */
2080 read_result, /* number of bytes to copy */
2081 &err, p_fci_internal->pv) != read_result ) {
2083 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
2086 /* TODO error handling of err */
2088 p_fci_internal->statusFolderCopied += read_result;
2089 /* report status with pfnfcis about copied size of folder */
2090 if( (*pfnfcis)(statusFolder,
2091 p_fci_internal->statusFolderCopied, /* length of copied blocks */
2092 p_fci_internal->statusFolderTotal, /* total size of folder */
2093 p_fci_internal->pv) == -1) {
2094 /* set error code and abort */
2095 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
2098 } /* END OF while */
2100 /* set seek of the cabinet file to 0 */
2101 if( p_fci_internal->seek( handleCABINET,
2102 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) {
2103 /* wrong return value */
2104 set_error( p_fci_internal, FCIERR_NONE, ERROR_SEEK );
2107 /* TODO error handling of err */
2109 /* write the signature "MSCF" into the cabinet file */
2110 memcpy( cfheader.signature, "MSCF", 4 );
2111 if( p_fci_internal->write( handleCABINET, /* file handle */
2112 &cfheader, /* memory buffer */
2113 4, /* number of bytes to copy */
2114 &err, p_fci_internal->pv) != 4 ) {
2116 set_error( p_fci_internal, FCIERR_CAB_FILE, ERROR_WRITE_FAULT );
2119 /* TODO error handling of err */
2121 /* close the cabinet file */
2122 p_fci_internal->close(handleCABINET,&err,p_fci_internal->pv);
2123 /* TODO error handling of err */
2126 /* COPIED FROM FCIDestroy */
2128 p_fci_internal->close( p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2129 /* TODO error handling of err */
2130 p_fci_internal->delete( p_fci_internal->szFileNameCFDATA2, &err,
2131 p_fci_internal->pv);
2132 /* TODO error handling of err */
2133 p_fci_internal->close( p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2134 /* TODO error handling of err */
2135 p_fci_internal->delete( p_fci_internal->szFileNameCFFILE2, &err,
2136 p_fci_internal->pv);
2137 /* TODO error handling of err */
2138 p_fci_internal->close( p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2139 /* TODO error handling of err */
2140 p_fci_internal->delete( p_fci_internal->szFileNameCFFOLDER, &err,
2141 p_fci_internal->pv);
2142 /* TODO error handling of err */
2144 /* END OF copied from FCIDestroy */
2146 /* get 3 temporary files and open them */
2147 /* write names and handles to hfci */
2150 p_fci_internal->sizeFileCFDATA2 = 0;
2151 p_fci_internal->sizeFileCFFILE2 = 0;
2152 p_fci_internal->sizeFileCFFOLDER = 0;
2154 /* COPIED FROM FCICreate */
2156 /* CFDATA with checksum and ready to be copied into cabinet */
2157 if( !p_fci_internal->gettemp( p_fci_internal->szFileNameCFDATA2,
2158 CB_MAX_FILENAME, p_fci_internal->pv)) {
2159 /* error handling */
2160 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2164 if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) {
2165 /* set error code and abort */
2166 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
2169 p_fci_internal->handleCFDATA2 = p_fci_internal->open( p_fci_internal->szFileNameCFDATA2,
2170 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
2171 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv);
2173 if(p_fci_internal->handleCFDATA2==0){
2174 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
2177 /* TODO error checking of err */
2179 /* array of all CFFILE in a folder, ready to be copied into cabinet */
2180 if( !p_fci_internal->gettemp(p_fci_internal->szFileNameCFFILE2,
2181 CB_MAX_FILENAME, p_fci_internal->pv)) {
2182 /* error handling */
2183 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2187 if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) {
2188 /* set error code and abort */
2189 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
2192 p_fci_internal->handleCFFILE2 = p_fci_internal->open( p_fci_internal->szFileNameCFFILE2,
2193 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
2194 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv);
2196 if(p_fci_internal->handleCFFILE2==0){
2197 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
2200 /* TODO error checking of err */
2202 /* array of all CFFILE in a folder, ready to be copied into cabinet */
2203 if (!p_fci_internal->gettemp(p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME, p_fci_internal->pv)) {
2204 /* error handling */
2205 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2209 if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) {
2210 /* set error code and abort */
2211 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
2214 p_fci_internal->handleCFFOLDER = p_fci_internal->open( p_fci_internal->szFileNameCFFOLDER,
2215 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
2216 _S_IREAD | _S_IWRITE, &err, p_fci_internal->pv);
2218 if(p_fci_internal->handleCFFOLDER==0){
2219 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_OPEN_FAILED );
2222 /* TODO error checking of err */
2224 /* END OF copied from FCICreate */
2227 /* TODO close and delete new files when return FALSE */
2230 /* report status with pfnfcis about copied size of folder */
2231 (*pfnfcis)(statusCabinet,
2232 p_fci_internal->estimatedCabinetSize, /* estimated cabinet file size */
2233 cfheader.cbCabinet /* real cabinet file size */, p_fci_internal->pv);
2235 p_fci_internal->fPrevCab=TRUE;
2236 /* The sections szPrevCab and szPrevDisk are not being updated, because */
2237 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
2239 if (p_fci_internal->fNextCab) {
2240 p_fci_internal->fNextCab=FALSE;
2242 if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) {
2243 /* THIS CAN NEVER HAPPEN */
2244 /* set error code */
2245 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2249 /* COPIED FROM FCIAddFile and modified */
2251 /* REUSE the variable read_result */
2252 if (p_fci_internal->fGetNextCabInVain) {
2253 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader;
2254 if(p_fci_internal->sizeFileCFFILE1!=0) {
2255 read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder;
2257 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2258 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2259 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2263 read_result=p_fci_internal->pccab->cbReserveCFHeader;
2264 if(p_fci_internal->sizeFileCFFILE1!=0) {
2265 read_result+=p_fci_internal->pccab->cbReserveCFFolder;
2267 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2268 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2269 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2273 if ( p_fci_internal->fPrevCab ) {
2274 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2275 strlen(p_fci_internal->szPrevDisk)+1;
2277 read_result+= p_fci_internal->sizeFileCFDATA1 +
2278 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2279 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2281 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2283 if( p_fci_internal->fNewPrevious ) {
2284 memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab,
2285 CB_MAX_CABINET_NAME);
2286 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk,
2288 p_fci_internal->fNewPrevious=FALSE;
2291 /* too much data for the maximum size of a cabinet */
2292 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2293 p_fci_internal->pccab->cb < read_result ) {
2294 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2297 /* Might be too much data for the maximum size of a cabinet.*/
2298 /* When any further data will be added later, it might not */
2299 /* be possible to flush the cabinet, because there might */
2300 /* not be enough space to store the name of the following */
2301 /* cabinet and name of the corresponding disk. */
2302 /* So take care of this and get the name of the next cabinet */
2303 if (p_fci_internal->fGetNextCabInVain==FALSE && (
2304 p_fci_internal->pccab->cb < read_result +
2305 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2308 p_fci_internal->oldCCAB = *p_fci_internal->pccab;
2309 /* increment cabinet index */
2310 ++(p_fci_internal->pccab->iCab);
2311 /* get name of next cabinet */
2312 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
2313 if (!(*pfnfcignc)(p_fci_internal->pccab,
2314 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
2315 p_fci_internal->pv)) {
2316 /* error handling */
2317 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2320 /* Skip a few lines of code. This is caught by the next if. */
2321 p_fci_internal->fGetNextCabInVain=TRUE;
2324 /* too much data for cabinet */
2325 if (p_fci_internal->fGetNextCabInVain && (
2326 p_fci_internal->oldCCAB.cb < read_result +
2327 strlen(p_fci_internal->oldCCAB.szCab)+1+
2328 strlen(p_fci_internal->oldCCAB.szDisk)+1
2330 p_fci_internal->fGetNextCabInVain=FALSE;
2331 p_fci_internal->fNextCab=TRUE;
2332 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2335 /* if the FolderThreshold has been reached flush the folder automatically */
2336 if( p_fci_internal->fGetNextCabInVain ) {
2337 if( p_fci_internal->cCompressedBytesInFolder >=
2338 p_fci_internal->oldCCAB.cbFolderThresh) {
2339 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2342 if( p_fci_internal->cCompressedBytesInFolder >=
2343 p_fci_internal->pccab->cbFolderThresh) {
2344 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2348 /* END OF COPIED FROM FCIAddFile and modified */
2350 if( p_fci_internal->sizeFileCFFILE1>0 ) {
2351 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
2352 p_fci_internal->fNewPrevious=TRUE;
2355 p_fci_internal->fNewPrevious=FALSE;
2356 if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) {
2357 /* THIS MAY NEVER HAPPEN */
2358 /* set error structures */
2359 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2365 } /* end of fci_flush_cabinet */
2371 /***********************************************************************
2372 * FCIAddFile (CABINET.11)
2374 * FCIAddFile adds a file to the to be created cabinet file
2377 * hfci [I] An HFCI from FCICreate
2378 * pszSourceFile [I] A pointer to a C string which contains the name and
2379 * location of the file which will be added to the cabinet
2380 * pszFileName [I] A pointer to a C string which contains the name under
2381 * which the file will be stored in the cabinet
2382 * fExecute [I] A boolean value which indicates if the file should be
2383 * executed after extraction of self extracting
2385 * pfnfcignc [I] A pointer to a function which gets information about
2387 * pfnfcis [IO] A pointer to a function which will report status
2388 * information about the compression process
2389 * pfnfcioi [I] A pointer to a function which reports file attributes
2390 * and time and date information
2391 * typeCompress [I] Compression type
2394 * On success, returns TRUE
2395 * On failure, returns FALSE
2401 BOOL __cdecl FCIAddFile(
2403 char *pszSourceFile,
2406 PFNFCIGETNEXTCABINET pfnfcignc,
2407 PFNFCISTATUS pfnfcis,
2408 PFNFCIGETOPENINFO pfnfcigoi,
2413 cab_ULONG read_result;
2415 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2417 if (!p_fci_internal) return FALSE;
2419 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
2420 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
2421 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
2425 /* TODO check if pszSourceFile??? */
2427 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
2428 /* internal error */
2429 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2433 if(p_fci_internal->fNextCab) {
2434 /* internal error */
2435 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2439 cffile.cbFile=0; /* size of the to be added file*/
2440 /* offset of the uncompressed file in the folder */
2441 cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in;
2442 /* number of folder in the cabinet or special 0=first */
2443 cffile.iFolder = p_fci_internal->cFolders;
2445 /* allocation of memory */
2446 if (p_fci_internal->data_in==NULL) {
2447 if (p_fci_internal->cdata_in!=0) {
2448 /* error handling */
2449 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2452 if (p_fci_internal->data_out!=NULL) {
2453 /* error handling */
2454 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2457 if(!(p_fci_internal->data_in = p_fci_internal->alloc(CB_MAX_CHUNK))) {
2458 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
2461 if (p_fci_internal->data_out==NULL) {
2462 if(!(p_fci_internal->data_out = p_fci_internal->alloc( 2 * CB_MAX_CHUNK))){
2463 set_error( p_fci_internal, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
2469 if (p_fci_internal->data_out==NULL) {
2470 p_fci_internal->free(p_fci_internal->data_in);
2471 /* error handling */
2472 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2476 /* get information about the file */
2477 /* set defaults in case callback doesn't set one or more fields */
2481 file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time),
2482 &(cffile.attribs), &err, p_fci_internal->pv);
2483 /* check file_handle */
2485 set_error( p_fci_internal, FCIERR_OPEN_SRC, ERROR_OPEN_FAILED );
2487 /* TODO error handling of err */
2489 if (fExecute) { cffile.attribs |= _A_EXEC; }
2491 /* REUSE the variable read_result */
2492 if (p_fci_internal->fGetNextCabInVain) {
2493 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2494 p_fci_internal->oldCCAB.cbReserveCFFolder;
2495 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2496 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2497 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2501 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2502 p_fci_internal->pccab->cbReserveCFFolder;
2503 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2504 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2505 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2509 if ( p_fci_internal->fPrevCab ) {
2510 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2511 strlen(p_fci_internal->szPrevDisk)+1;
2513 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2514 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2515 strlen(p_fci_internal->pccab->szDisk)+1;
2518 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
2519 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2520 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2522 sizeof(CFFOLDER); /* size of new CFFolder entry */
2524 /* Might be too much data for the maximum size of a cabinet.*/
2525 /* When any further data will be added later, it might not */
2526 /* be possible to flush the cabinet, because there might */
2527 /* not be enough space to store the name of the following */
2528 /* cabinet and name of the corresponding disk. */
2529 /* So take care of this and get the name of the next cabinet */
2530 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2531 p_fci_internal->fNextCab==FALSE &&
2532 ( p_fci_internal->pccab->cb < read_result +
2533 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2537 p_fci_internal->oldCCAB = *p_fci_internal->pccab;
2538 /* increment cabinet index */
2539 ++(p_fci_internal->pccab->iCab);
2540 /* get name of next cabinet */
2541 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
2542 if (!(*pfnfcignc)(p_fci_internal->pccab,
2543 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
2544 p_fci_internal->pv)) {
2545 /* error handling */
2546 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2549 /* Skip a few lines of code. This is caught by the next if. */
2550 p_fci_internal->fGetNextCabInVain=TRUE;
2553 if( p_fci_internal->fGetNextCabInVain &&
2554 p_fci_internal->fNextCab
2556 /* THIS CAN NEVER HAPPEN */
2557 /* set error code */
2558 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2562 /* too much data for cabinet */
2563 if( p_fci_internal->fGetNextCabInVain &&
2565 p_fci_internal->oldCCAB.cb < read_result +
2566 strlen(p_fci_internal->pccab->szCab)+1+
2567 strlen(p_fci_internal->pccab->szDisk)+1
2569 p_fci_internal->fGetNextCabInVain=FALSE;
2570 p_fci_internal->fNextCab=TRUE;
2571 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
2574 if( p_fci_internal->fNextCab ) {
2575 /* THIS MAY NEVER HAPPEN */
2576 /* set error code */
2577 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2581 /* read the contents of the file blockwise */
2583 if (p_fci_internal->cdata_in > CAB_BLOCKMAX) {
2584 /* internal error */
2585 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2589 read_result = p_fci_internal->read( file_handle /* file handle */,
2590 (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */,
2591 (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */,
2592 &err, p_fci_internal->pv);
2593 /* TODO error handling of err */
2595 if( read_result==0 ) break;
2597 /* increment the block size */
2598 p_fci_internal->cdata_in += read_result;
2600 /* increment the file size */
2601 cffile.cbFile += read_result;
2603 if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) {
2604 /* report internal error */
2605 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2608 /* write a whole block */
2609 if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) {
2611 if( !fci_flush_data_block(p_fci_internal, &err, pfnfcis) ) return FALSE;
2615 /* close the file from FCIAddFile */
2616 p_fci_internal->close(file_handle,&err,p_fci_internal->pv);
2617 /* TODO error handling of err */
2619 /* write cffile to p_fci_internal->handleCFFILE1 */
2620 if( p_fci_internal->write( p_fci_internal->handleCFFILE1, /* file handle */
2621 &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) {
2623 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
2626 /* TODO error handling of err */
2628 p_fci_internal->sizeFileCFFILE1 += sizeof(cffile);
2630 /* append the name of file */
2631 if (strlen(pszFileName)>=CB_MAX_FILENAME) {
2633 /* set error code */
2634 set_error( p_fci_internal, FCIERR_NONE, ERROR_INVALID_DATA );
2637 if( p_fci_internal->write( p_fci_internal->handleCFFILE1, /* file handle */
2638 pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv)
2639 != strlen(pszFileName)+1 ) {
2641 set_error( p_fci_internal, FCIERR_TEMP_FILE, ERROR_WRITE_FAULT );
2644 /* TODO error handling of err */
2646 p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1;
2648 /* REUSE the variable read_result */
2649 if (p_fci_internal->fGetNextCabInVain ||
2650 p_fci_internal->fNextCab
2652 read_result=p_fci_internal->oldCCAB.cbReserveCFHeader +
2653 p_fci_internal->oldCCAB.cbReserveCFFolder;
2654 if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 ||
2655 p_fci_internal->oldCCAB.cbReserveCFFolder != 0 ||
2656 p_fci_internal->oldCCAB.cbReserveCFData != 0 ) {
2660 read_result=p_fci_internal->pccab->cbReserveCFHeader +
2661 p_fci_internal->pccab->cbReserveCFFolder;
2662 if ( p_fci_internal->pccab->cbReserveCFHeader != 0 ||
2663 p_fci_internal->pccab->cbReserveCFFolder != 0 ||
2664 p_fci_internal->pccab->cbReserveCFData != 0 ) {
2668 if ( p_fci_internal->fPrevCab ) {
2669 read_result+= strlen(p_fci_internal->szPrevCab)+1+
2670 strlen(p_fci_internal->szPrevDisk)+1;
2672 if ( p_fci_internal->fNextCab ) { /* this is never the case */
2673 read_result+= strlen(p_fci_internal->pccab->szCab)+1+
2674 strlen(p_fci_internal->pccab->szDisk)+1;
2676 read_result+= p_fci_internal->sizeFileCFDATA1 +
2677 p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 +
2678 p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER +
2680 sizeof(CFFOLDER); /* set size of new CFFolder entry */
2682 /* too much data for the maximum size of a cabinet */
2683 /* (ignoring the unflushed data block) */
2684 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2685 p_fci_internal->fNextCab==FALSE && /* this is always the case */
2686 p_fci_internal->pccab->cb < read_result ) {
2687 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2690 /* Might be too much data for the maximum size of a cabinet.*/
2691 /* When any further data will be added later, it might not */
2692 /* be possible to flush the cabinet, because there might */
2693 /* not be enough space to store the name of the following */
2694 /* cabinet and name of the corresponding disk. */
2695 /* So take care of this and get the name of the next cabinet */
2696 /* (ignoring the unflushed data block) */
2697 if( p_fci_internal->fGetNextCabInVain==FALSE &&
2698 p_fci_internal->fNextCab==FALSE &&
2699 ( p_fci_internal->pccab->cb < read_result +
2700 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
2704 p_fci_internal->oldCCAB = *p_fci_internal->pccab;
2705 /* increment cabinet index */
2706 ++(p_fci_internal->pccab->iCab);
2707 /* get name of next cabinet */
2708 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
2709 if (!(*pfnfcignc)(p_fci_internal->pccab,
2710 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
2711 p_fci_internal->pv)) {
2712 /* error handling */
2713 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
2716 /* Skip a few lines of code. This is caught by the next if. */
2717 p_fci_internal->fGetNextCabInVain=TRUE;
2720 if( p_fci_internal->fGetNextCabInVain &&
2721 p_fci_internal->fNextCab
2723 /* THIS CAN NEVER HAPPEN */
2724 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2728 /* too much data for cabinet */
2729 if( (p_fci_internal->fGetNextCabInVain ||
2730 p_fci_internal->fNextCab) && (
2731 p_fci_internal->oldCCAB.cb < read_result +
2732 strlen(p_fci_internal->pccab->szCab)+1+
2733 strlen(p_fci_internal->pccab->szDisk)+1
2736 p_fci_internal->fGetNextCabInVain=FALSE;
2737 p_fci_internal->fNextCab=TRUE;
2738 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
2741 if( p_fci_internal->fNextCab ) {
2742 /* THIS MAY NEVER HAPPEN */
2743 /* set error code */
2744 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
2748 /* if the FolderThreshold has been reached flush the folder automatically */
2749 if( p_fci_internal->fGetNextCabInVain ) {
2750 if( p_fci_internal->cCompressedBytesInFolder >=
2751 p_fci_internal->oldCCAB.cbFolderThresh) {
2752 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2755 if( p_fci_internal->cCompressedBytesInFolder >=
2756 p_fci_internal->pccab->cbFolderThresh) {
2757 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
2762 } /* end of FCIAddFile */
2768 /***********************************************************************
2769 * FCIFlushFolder (CABINET.12)
2771 * FCIFlushFolder completes the CFFolder structure under construction.
2773 * All further data which is added by FCIAddFile will be associated to
2774 * the next CFFolder structure.
2776 * FCIFlushFolder will be called by FCIAddFile automatically if the
2777 * threshold (stored in the member cbFolderThresh of the CCAB structure
2778 * pccab passed to FCICreate) is exceeded.
2780 * FCIFlushFolder will be called by FCIFlushFolder automatically before
2781 * any data will be written into the cabinet file.
2784 * hfci [I] An HFCI from FCICreate
2785 * pfnfcignc [I] A pointer to a function which gets information about
2787 * pfnfcis [IO] A pointer to a function which will report status
2788 * information about the compression process
2791 * On success, returns TRUE
2792 * On failure, returns FALSE
2798 BOOL __cdecl FCIFlushFolder(
2800 PFNFCIGETNEXTCABINET pfnfcignc,
2801 PFNFCISTATUS pfnfcis)
2803 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2805 if (!p_fci_internal) return FALSE;
2806 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
2811 /***********************************************************************
2812 * FCIFlushCabinet (CABINET.13)
2814 * FCIFlushCabinet stores the data which has been added by FCIAddFile
2815 * into the cabinet file. If the maximum cabinet size (stored in the
2816 * member cb of the CCAB structure pccab passed to FCICreate) has been
2817 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
2818 * The remaining data still has to be flushed manually by calling
2821 * After FCIFlushCabinet has been called (manually) FCIAddFile must
2822 * NOT be called again. Then hfci has to be released by FCIDestroy.
2825 * hfci [I] An HFCI from FCICreate
2826 * fGetNextCab [I] Whether you want to add additional files to a
2827 * cabinet set (TRUE) or whether you want to
2828 * finalize it (FALSE)
2829 * pfnfcignc [I] A pointer to a function which gets information about
2831 * pfnfcis [IO] A pointer to a function which will report status
2832 * information about the compression process
2835 * On success, returns TRUE
2836 * On failure, returns FALSE
2842 BOOL __cdecl FCIFlushCabinet(
2845 PFNFCIGETNEXTCABINET pfnfcignc,
2846 PFNFCISTATUS pfnfcis)
2848 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2850 if (!p_fci_internal) return FALSE;
2852 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2854 while( p_fci_internal->sizeFileCFFILE1>0 ||
2855 p_fci_internal->sizeFileCFFILE2>0 ) {
2856 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
2863 /***********************************************************************
2864 * FCIDestroy (CABINET.14)
2866 * Frees a handle created by FCICreate.
2867 * Only reason for failure would be an invalid handle.
2870 * hfci [I] The HFCI to free
2876 BOOL __cdecl FCIDestroy(HFCI hfci)
2879 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
2881 if (!p_fci_internal) return FALSE;
2883 /* before hfci can be removed all temporary files must be closed */
2885 p_fci_internal->magic = 0;
2887 p_fci_internal->close( p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv);
2888 /* TODO error handling of err */
2889 p_fci_internal->delete( p_fci_internal->szFileNameCFDATA1, &err,
2890 p_fci_internal->pv);
2891 /* TODO error handling of err */
2892 p_fci_internal->close( p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv);
2893 /* TODO error handling of err */
2894 p_fci_internal->delete( p_fci_internal->szFileNameCFFILE1, &err,
2895 p_fci_internal->pv);
2896 /* TODO error handling of err */
2897 p_fci_internal->close( p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv);
2898 /* TODO error handling of err */
2899 p_fci_internal->delete( p_fci_internal->szFileNameCFDATA2, &err,
2900 p_fci_internal->pv);
2901 /* TODO error handling of err */
2902 p_fci_internal->close( p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv);
2903 /* TODO error handling of err */
2904 p_fci_internal->delete( p_fci_internal->szFileNameCFFILE2, &err,
2905 p_fci_internal->pv);
2906 /* TODO error handling of err */
2907 p_fci_internal->close( p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv);
2908 /* TODO error handling of err */
2909 p_fci_internal->delete( p_fci_internal->szFileNameCFFOLDER, &err,
2910 p_fci_internal->pv);
2911 /* TODO error handling of err */
2913 /* data in and out buffers have to be removed */
2914 if (p_fci_internal->data_in!=NULL)
2915 p_fci_internal->free(p_fci_internal->data_in);
2916 if (p_fci_internal->data_out!=NULL)
2917 p_fci_internal->free(p_fci_internal->data_out);
2919 /* hfci can now be removed */
2920 p_fci_internal->free(hfci);