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