msvcrt: Added _fseeki64_nolock implementation.
[wine.git] / dlls / cabinet / fci.c
blob70d4f3f170f864d2122ce1949541dc7078e29948
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 - 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
35 #include "config.h"
37 #include <assert.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #ifdef HAVE_ZLIB
42 # include <zlib.h>
43 #endif
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winerror.h"
48 #include "winternl.h"
49 #include "fci.h"
50 #include "cabinet.h"
51 #include "wine/list.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
56 #ifdef WORDS_BIGENDIAN
57 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
58 #define fci_endian_uword(x) RtlUshortByteSwap(x)
59 #else
60 #define fci_endian_ulong(x) (x)
61 #define fci_endian_uword(x) (x)
62 #endif
65 typedef struct {
66 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
67 cab_ULONG reserved1;
68 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
69 cab_ULONG reserved2;
70 cab_ULONG coffFiles; /* offset to first CFFILE section */
71 cab_ULONG reserved3;
72 cab_UBYTE versionMinor; /* 3 */
73 cab_UBYTE versionMajor; /* 1 */
74 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
75 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
76 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
77 cab_UWORD setID; /* identification number of all cabinets in a set*/
78 cab_UWORD iCabinet; /* number of the cabinet in a set */
79 /* additional area if "flags" were set*/
80 } CFHEADER; /* minimum 36 bytes */
82 typedef struct {
83 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
84 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
85 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
86 /* additional area if reserve flag was set */
87 } CFFOLDER; /* minimum 8 bytes */
89 typedef struct {
90 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
91 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
92 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
93 /* for special values see below this structure*/
94 cab_UWORD date; /* last modification date*/
95 cab_UWORD time; /* last modification time*/
96 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
97 /* ... and a C string with the name of the file */
98 } CFFILE; /* 16 bytes + name of file */
101 typedef struct {
102 cab_ULONG csum; /* checksum of this entry*/
103 cab_UWORD cbData; /* number of compressed bytes */
104 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
105 /* optional reserved area */
106 /* compressed data */
107 } CFDATA;
109 struct temp_file
111 INT_PTR handle;
112 char name[CB_MAX_FILENAME];
115 struct folder
117 struct list entry;
118 struct list files_list;
119 struct list blocks_list;
120 struct temp_file data;
121 cab_ULONG data_start;
122 cab_UWORD data_count;
123 TCOMP compression;
126 struct file
128 struct list entry;
129 cab_ULONG size; /* uncompressed size */
130 cab_ULONG offset; /* offset in folder */
131 cab_UWORD folder; /* index of folder */
132 cab_UWORD date;
133 cab_UWORD time;
134 cab_UWORD attribs;
135 char name[1];
138 struct data_block
140 struct list entry;
141 cab_UWORD compressed;
142 cab_UWORD uncompressed;
145 typedef struct FCI_Int
147 unsigned int magic;
148 PERF perf;
149 PFNFCIFILEPLACED fileplaced;
150 PFNFCIALLOC alloc;
151 PFNFCIFREE free;
152 PFNFCIOPEN open;
153 PFNFCIREAD read;
154 PFNFCIWRITE write;
155 PFNFCICLOSE close;
156 PFNFCISEEK seek;
157 PFNFCIDELETE delete;
158 PFNFCIGETTEMPFILE gettemp;
159 CCAB ccab;
160 PCCAB pccab;
161 BOOL fPrevCab;
162 BOOL fNextCab;
163 BOOL fSplitFolder;
164 cab_ULONG statusFolderCopied;
165 cab_ULONG statusFolderTotal;
166 BOOL fGetNextCabInVain;
167 void *pv;
168 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
169 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
170 unsigned char data_in[CAB_BLOCKMAX]; /* uncompressed data blocks */
171 unsigned char data_out[2 * CAB_BLOCKMAX]; /* compressed data blocks */
172 cab_UWORD cdata_in;
173 ULONG cCompressedBytesInFolder;
174 cab_UWORD cFolders;
175 cab_UWORD cFiles;
176 cab_ULONG cDataBlocks;
177 cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */
178 /* of spanned file of a spanning folder of a spanning cabinet */
179 struct temp_file data;
180 BOOL fNewPrevious;
181 cab_ULONG estimatedCabinetSize;
182 struct list folders_list;
183 struct list files_list;
184 struct list blocks_list;
185 cab_ULONG folders_size;
186 cab_ULONG files_size; /* size of files not yet assigned to a folder */
187 cab_ULONG placed_files_size; /* size of files already placed into a folder */
188 cab_ULONG pending_data_size; /* size of data not yet assigned to a folder */
189 cab_ULONG folders_data_size; /* total size of data contained in the current folders */
190 TCOMP compression;
191 cab_UWORD (*compress)(struct FCI_Int *);
192 } FCI_Int;
194 #define FCI_INT_MAGIC 0xfcfcfc05
196 static void set_error( FCI_Int *fci, int oper, int err )
198 fci->perf->erfOper = oper;
199 fci->perf->erfType = err;
200 fci->perf->fError = TRUE;
201 if (err) SetLastError( err );
204 static FCI_Int *get_fci_ptr( HFCI hfci )
206 FCI_Int *fci= (FCI_Int *)hfci;
208 if (!fci || fci->magic != FCI_INT_MAGIC)
210 SetLastError( ERROR_INVALID_HANDLE );
211 return NULL;
213 return fci;
216 /* compute the cabinet header size */
217 static cab_ULONG get_header_size( FCI_Int *fci )
219 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
221 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
222 ret += 4;
224 if (fci->fPrevCab)
225 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
227 if (fci->fNextCab)
228 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
230 return ret;
233 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
235 int err;
237 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
239 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
240 return FALSE;
242 if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
243 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
245 set_error( fci, FCIERR_TEMP_FILE, err );
246 return FALSE;
248 return TRUE;
251 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
253 int err;
255 if (file->handle == -1) return TRUE;
256 if (fci->close( file->handle, &err, fci->pv ) == -1)
258 set_error( fci, FCIERR_TEMP_FILE, err );
259 return FALSE;
261 file->handle = -1;
262 if (fci->delete( file->name, &err, fci->pv ) == -1)
264 set_error( fci, FCIERR_TEMP_FILE, err );
265 return FALSE;
267 return TRUE;
270 static struct file *add_file( FCI_Int *fci, const char *filename )
272 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
273 struct file *file = fci->alloc( size );
275 if (!file)
277 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
278 return NULL;
280 file->size = 0;
281 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
282 file->folder = fci->cFolders;
283 file->date = 0;
284 file->time = 0;
285 file->attribs = 0;
286 strcpy( file->name, filename );
287 list_add_tail( &fci->files_list, &file->entry );
288 fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
289 return file;
292 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
294 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
295 struct file *file = fci->alloc( size );
297 if (!file)
299 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
300 return NULL;
302 memcpy( file, orig, size );
303 return file;
306 static void free_file( FCI_Int *fci, struct file *file )
308 list_remove( &file->entry );
309 fci->free( file );
312 /* create a new data block for the data in fci->data_in */
313 static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
315 int err;
316 struct data_block *block;
318 if (!fci->cdata_in) return TRUE;
320 if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
322 if (!(block = fci->alloc( sizeof(*block) )))
324 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
325 return FALSE;
327 block->uncompressed = fci->cdata_in;
328 block->compressed = fci->compress( fci );
330 if (fci->write( fci->data.handle, fci->data_out,
331 block->compressed, &err, fci->pv ) != block->compressed)
333 set_error( fci, FCIERR_TEMP_FILE, err );
334 fci->free( block );
335 return FALSE;
338 fci->cdata_in = 0;
339 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
340 fci->cCompressedBytesInFolder += block->compressed;
341 fci->cDataBlocks++;
342 list_add_tail( &fci->blocks_list, &block->entry );
344 if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
346 set_error( fci, FCIERR_USER_ABORT, 0 );
347 return FALSE;
349 return TRUE;
352 /* add compressed blocks for all the data that can be read from the file */
353 static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
354 PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
356 int err, len;
357 INT_PTR handle;
358 struct file *file;
360 if (!(file = add_file( fci, filename ))) return FALSE;
362 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
363 if (handle == -1)
365 free_file( fci, file );
366 set_error( fci, FCIERR_OPEN_SRC, err );
367 return FALSE;
369 if (execute) file->attribs |= _A_EXEC;
371 for (;;)
373 len = fci->read( handle, fci->data_in + fci->cdata_in,
374 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
375 if (!len) break;
377 if (len == -1)
379 set_error( fci, FCIERR_READ_SRC, err );
380 return FALSE;
382 file->size += len;
383 fci->cdata_in += len;
384 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
386 fci->close( handle, &err, fci->pv );
387 return TRUE;
390 static void free_data_block( FCI_Int *fci, struct data_block *block )
392 list_remove( &block->entry );
393 fci->free( block );
396 static struct folder *add_folder( FCI_Int *fci )
398 struct folder *folder = fci->alloc( sizeof(*folder) );
400 if (!folder)
402 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
403 return NULL;
405 folder->data.handle = -1;
406 folder->data_start = fci->folders_data_size;
407 folder->data_count = 0;
408 folder->compression = fci->compression;
409 list_init( &folder->files_list );
410 list_init( &folder->blocks_list );
411 list_add_tail( &fci->folders_list, &folder->entry );
412 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
413 fci->cFolders++;
414 return folder;
417 static void free_folder( FCI_Int *fci, struct folder *folder )
419 struct file *file, *file_next;
420 struct data_block *block, *block_next;
422 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
423 free_file( fci, file );
424 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
425 free_data_block( fci, block );
426 close_temp_file( fci, &folder->data );
427 list_remove( &folder->entry );
428 fci->free( folder );
431 /* reset state for the next cabinet file once the current one has been flushed */
432 static void reset_cabinet( FCI_Int *fci )
434 struct folder *folder, *folder_next;
436 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
437 free_folder( fci, folder );
439 fci->cFolders = 0;
440 fci->cFiles = 0;
441 fci->folders_size = 0;
442 fci->placed_files_size = 0;
443 fci->folders_data_size = 0;
446 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
448 cab_ULONG csum;
449 cab_ULONG ul;
450 int cUlong;
451 const BYTE *pb;
453 csum = seed;
454 cUlong = cb / 4;
455 pb = pv;
457 while (cUlong-- > 0) {
458 ul = *pb++;
459 ul |= (((cab_ULONG)(*pb++)) << 8);
460 ul |= (((cab_ULONG)(*pb++)) << 16);
461 ul |= (((cab_ULONG)(*pb++)) << 24);
462 csum ^= ul;
465 ul = 0;
466 switch (cb % 4) {
467 case 3:
468 ul |= (((ULONG)(*pb++)) << 16);
469 /* fall through */
470 case 2:
471 ul |= (((ULONG)(*pb++)) << 8);
472 /* fall through */
473 case 1:
474 ul |= *pb;
475 /* fall through */
476 default:
477 break;
479 csum ^= ul;
481 return csum;
484 /* copy all remaining data block to a new temp file */
485 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
486 struct temp_file *temp, PFNFCISTATUS status_callback )
488 struct data_block *block;
489 int err;
491 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
493 set_error( fci, FCIERR_TEMP_FILE, err );
494 return FALSE;
496 if (!create_temp_file( fci, temp )) return FALSE;
498 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
500 if (fci->read( handle, fci->data_out, block->compressed,
501 &err, fci->pv ) != block->compressed)
503 close_temp_file( fci, temp );
504 set_error( fci, FCIERR_TEMP_FILE, err );
505 return FALSE;
507 if (fci->write( temp->handle, fci->data_out, block->compressed,
508 &err, fci->pv ) != block->compressed)
510 close_temp_file( fci, temp );
511 set_error( fci, FCIERR_TEMP_FILE, err );
512 return FALSE;
514 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
515 fci->statusFolderCopied += block->compressed;
517 if (status_callback( statusFolder, fci->statusFolderCopied,
518 fci->statusFolderTotal, fci->pv) == -1)
520 close_temp_file( fci, temp );
521 set_error( fci, FCIERR_USER_ABORT, 0 );
522 return FALSE;
525 return TRUE;
528 /* write all folders to disk and remove them from the list */
529 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
531 struct folder *folder;
532 int err;
533 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
534 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
536 memset( cffolder, 0, folder_size );
538 /* write the folders */
539 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
541 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
542 cffolder->cCFData = fci_endian_uword( folder->data_count );
543 cffolder->typeCompress = fci_endian_uword( folder->compression );
544 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
546 set_error( fci, FCIERR_CAB_FILE, err );
547 return FALSE;
550 return TRUE;
553 /* write all the files to the cabinet file */
554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
556 cab_ULONG file_size;
557 struct folder *folder;
558 struct file *file;
559 int err;
560 CFFILE *cffile = (CFFILE *)fci->data_out;
562 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
564 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
566 cffile->cbFile = fci_endian_ulong( file->size );
567 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
568 cffile->iFolder = fci_endian_uword( file->folder );
569 cffile->date = fci_endian_uword( file->date );
570 cffile->time = fci_endian_uword( file->time );
571 cffile->attribs = fci_endian_uword( file->attribs );
572 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
573 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
574 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
576 set_error( fci, FCIERR_CAB_FILE, err );
577 return FALSE;
579 if (!fci->fSplitFolder)
581 fci->statusFolderCopied = 0;
582 /* TODO TEST THIS further */
583 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
585 fci->statusFolderCopied += file_size;
586 /* report status about copied size of folder */
587 if (status_callback( statusFolder, fci->statusFolderCopied,
588 fci->statusFolderTotal, fci->pv ) == -1)
590 set_error( fci, FCIERR_USER_ABORT, 0 );
591 return FALSE;
595 return TRUE;
598 /* write all data blocks to the cabinet file */
599 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
601 struct folder *folder;
602 struct data_block *block;
603 int err, len;
604 CFDATA *cfdata;
605 void *data;
606 cab_UWORD header_size;
608 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
609 cfdata = (CFDATA *)fci->data_out;
610 memset( cfdata, 0, header_size );
611 data = (char *)cfdata + header_size;
613 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
615 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
617 set_error( fci, FCIERR_CAB_FILE, err );
618 return FALSE;
620 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
622 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
623 if (len != block->compressed) return FALSE;
625 cfdata->cbData = fci_endian_uword( block->compressed );
626 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
627 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
628 header_size - FIELD_OFFSET(CFDATA, cbData),
629 fci_get_checksum( data, len, 0 )));
631 fci->statusFolderCopied += len;
632 len += header_size;
633 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
635 set_error( fci, FCIERR_CAB_FILE, err );
636 return FALSE;
638 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
640 set_error( fci, FCIERR_USER_ABORT, 0 );
641 return FALSE;
645 return TRUE;
648 /* write the cabinet file to disk */
649 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
651 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
652 int err;
653 char *ptr;
654 INT_PTR handle;
655 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
656 cab_UWORD flags = 0;
657 cab_ULONG header_size = get_header_size( fci );
658 cab_ULONG total_size = header_size + fci->folders_size +
659 fci->placed_files_size + fci->folders_data_size;
661 assert( header_size <= sizeof(fci->data_out) );
662 memset( cfheader, 0, header_size );
664 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
665 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
666 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
667 flags |= cfheadRESERVE_PRESENT;
669 memcpy( cfheader->signature, "!CAB", 4 );
670 cfheader->cbCabinet = fci_endian_ulong( total_size );
671 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
672 cfheader->versionMinor = 3;
673 cfheader->versionMajor = 1;
674 cfheader->cFolders = fci_endian_uword( fci->cFolders );
675 cfheader->cFiles = fci_endian_uword( fci->cFiles );
676 cfheader->flags = fci_endian_uword( flags );
677 cfheader->setID = fci_endian_uword( fci->ccab.setID );
678 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
679 ptr = (char *)(cfheader + 1);
681 if (flags & cfheadRESERVE_PRESENT)
683 struct
685 cab_UWORD cbCFHeader;
686 cab_UBYTE cbCFFolder;
687 cab_UBYTE cbCFData;
688 } *reserve = (void *)ptr;
690 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
691 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
692 reserve->cbCFData = fci->ccab.cbReserveCFData;
693 ptr = (char *)(reserve + 1);
695 ptr += fci->ccab.cbReserveCFHeader;
697 if (flags & cfheadPREV_CABINET)
699 strcpy( ptr, fci->szPrevCab );
700 ptr += strlen( ptr ) + 1;
701 strcpy( ptr, fci->szPrevDisk );
702 ptr += strlen( ptr ) + 1;
705 if (flags & cfheadNEXT_CABINET)
707 strcpy( ptr, fci->pccab->szCab );
708 ptr += strlen( ptr ) + 1;
709 strcpy( ptr, fci->pccab->szDisk );
710 ptr += strlen( ptr ) + 1;
713 assert( ptr - (char *)cfheader == header_size );
715 strcpy( filename, fci->ccab.szCabPath );
716 strcat( filename, fci->ccab.szCab );
718 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
719 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
721 set_error( fci, FCIERR_CAB_FILE, err );
722 return FALSE;
725 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
727 set_error( fci, FCIERR_CAB_FILE, err );
728 goto failed;
731 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
732 header_size += fci->placed_files_size + fci->folders_size;
733 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
734 if (!write_files( fci, handle, status_callback )) goto failed;
735 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
737 /* update the signature */
738 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
740 set_error( fci, FCIERR_CAB_FILE, err );
741 goto failed;
743 memcpy( cfheader->signature, "MSCF", 4 );
744 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
746 set_error( fci, FCIERR_CAB_FILE, err );
747 goto failed;
749 fci->close( handle, &err, fci->pv );
751 reset_cabinet( fci );
752 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
753 return TRUE;
755 failed:
756 fci->close( handle, &err, fci->pv );
757 fci->delete( filename, &err, fci->pv );
758 return FALSE;
761 /* add all pending data blocks folder */
762 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
763 PFNFCISTATUS status_callback )
765 struct data_block *block, *new, *next;
766 BOOL split_block = FALSE;
767 cab_ULONG current_size, start_pos = 0;
769 *payload = 0;
770 current_size = get_header_size( fci ) + fci->folders_size +
771 fci->files_size + fci->placed_files_size + fci->folders_data_size;
773 /* move the temp file into the folder structure */
774 folder->data = fci->data;
775 fci->data.handle = -1;
776 fci->pending_data_size = 0;
778 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
780 /* No more CFDATA fits into the cabinet under construction */
781 /* So don't try to store more data into it */
782 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
783 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
784 break;
786 if (!(new = fci->alloc( sizeof(*new) )))
788 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
789 return FALSE;
791 /* Is cabinet with new CFDATA too large? Then data block has to be split */
792 if( fci->fNextCab &&
793 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
794 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
796 /* Modify the size of the compressed data to store only a part of the */
797 /* data block into the current cabinet. This is done to prevent */
798 /* that the maximum cabinet size will be exceeded. The remainder */
799 /* will be stored into the next following cabinet. */
801 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
802 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
803 new->uncompressed = 0; /* on split blocks of data this is zero */
804 block->compressed -= new->compressed;
805 split_block = TRUE;
807 else
809 new->compressed = block->compressed;
810 new->uncompressed = block->uncompressed;
813 start_pos += new->compressed;
814 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
815 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
816 fci->statusFolderCopied += new->compressed;
817 (*payload) += new->uncompressed;
819 list_add_tail( &folder->blocks_list, &new->entry );
820 folder->data_count++;
822 /* report status with pfnfcis about copied size of folder */
823 if (status_callback( statusFolder, fci->statusFolderCopied,
824 fci->statusFolderTotal, fci->pv ) == -1)
826 set_error( fci, FCIERR_USER_ABORT, 0 );
827 return FALSE;
829 if (split_block) break;
830 free_data_block( fci, block );
831 fci->cDataBlocks--;
834 if (list_empty( &fci->blocks_list )) return TRUE;
835 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
838 /* add all pending files to folder */
839 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
841 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
842 cab_ULONG cbFileRemainer = 0;
843 struct file *file, *next;
845 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
847 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
849 /* fnfilfnfildest: placed file on cabinet */
850 fci->fileplaced( &fci->ccab, file->name, file->size,
851 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
853 sizeOfFilesPrev = sizeOfFiles;
854 /* set complete size of all processed files */
855 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
857 sizeOfFiles += fci->cbFileRemainer;
858 fci->cbFileRemainer = 0;
860 else sizeOfFiles += file->size;
862 /* check if spanned file fits into this cabinet folder */
863 if (sizeOfFiles > payload)
865 if (file->folder == cffileCONTINUED_FROM_PREV)
866 file->folder = cffileCONTINUED_PREV_AND_NEXT;
867 else
868 file->folder = cffileCONTINUED_TO_NEXT;
871 list_remove( &file->entry );
872 list_add_tail( &folder->files_list, &file->entry );
873 fci->placed_files_size += size;
874 fci->cFiles++;
876 /* This is only true for files which will be written into the */
877 /* next cabinet of the spanning folder */
878 if (sizeOfFiles > payload)
880 /* add a copy back onto the list */
881 if (!(file = copy_file( fci, file ))) return FALSE;
882 list_add_before( &next->entry, &file->entry );
884 /* Files which data will be partially written into the current cabinet */
885 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
887 if (sizeOfFilesPrev <= payload)
889 /* The size of the uncompressed, data of a spanning file in a */
890 /* spanning data */
891 cbFileRemainer = sizeOfFiles - payload;
893 file->folder = cffileCONTINUED_FROM_PREV;
895 else file->folder = 0;
897 else
899 fci->files_size -= size;
902 fci->cbFileRemainer = cbFileRemainer;
903 return TRUE;
906 static cab_UWORD compress_NONE( FCI_Int *fci )
908 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
909 return fci->cdata_in;
912 #ifdef HAVE_ZLIB
914 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
916 FCI_Int *fci = opaque;
917 return fci->alloc( items * size );
920 static void zfree( void *opaque, void *ptr )
922 FCI_Int *fci = opaque;
923 fci->free( ptr );
926 static cab_UWORD compress_MSZIP( FCI_Int *fci )
928 z_stream stream;
930 stream.zalloc = zalloc;
931 stream.zfree = zfree;
932 stream.opaque = fci;
933 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
935 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
936 return 0;
938 stream.next_in = fci->data_in;
939 stream.avail_in = fci->cdata_in;
940 stream.next_out = fci->data_out + 2;
941 stream.avail_out = sizeof(fci->data_out) - 2;
942 /* insert the signature */
943 fci->data_out[0] = 'C';
944 fci->data_out[1] = 'K';
945 deflate( &stream, Z_FINISH );
946 deflateEnd( &stream );
947 return stream.total_out + 2;
950 #endif /* HAVE_ZLIB */
953 /***********************************************************************
954 * FCICreate (CABINET.10)
956 * FCICreate is provided with several callbacks and
957 * returns a handle which can be used to create cabinet files.
959 * PARAMS
960 * perf [IO] A pointer to an ERF structure. When FCICreate
961 * returns an error condition, error information may
962 * be found here as well as from GetLastError.
963 * pfnfiledest [I] A pointer to a function which is called when a file
964 * is placed. Only useful for subsequent cabinet files.
965 * pfnalloc [I] A pointer to a function which allocates ram. Uses
966 * the same interface as malloc.
967 * pfnfree [I] A pointer to a function which frees ram. Uses the
968 * same interface as free.
969 * pfnopen [I] A pointer to a function which opens a file. Uses
970 * the same interface as _open.
971 * pfnread [I] A pointer to a function which reads from a file into
972 * a caller-provided buffer. Uses the same interface
973 * as _read.
974 * pfnwrite [I] A pointer to a function which writes to a file from
975 * a caller-provided buffer. Uses the same interface
976 * as _write.
977 * pfnclose [I] A pointer to a function which closes a file handle.
978 * Uses the same interface as _close.
979 * pfnseek [I] A pointer to a function which seeks in a file.
980 * Uses the same interface as _lseek.
981 * pfndelete [I] A pointer to a function which deletes a file.
982 * pfnfcigtf [I] A pointer to a function which gets the name of a
983 * temporary file.
984 * pccab [I] A pointer to an initialized CCAB structure.
985 * pv [I] A pointer to an application-defined notification
986 * function which will be passed to other FCI functions
987 * as a parameter.
989 * RETURNS
990 * On success, returns an FCI handle of type HFCI.
991 * On failure, the NULL file handle is returned. Error
992 * info can be retrieved from perf.
994 * INCLUDES
995 * fci.h
998 HFCI __cdecl FCICreate(
999 PERF perf,
1000 PFNFCIFILEPLACED pfnfiledest,
1001 PFNFCIALLOC pfnalloc,
1002 PFNFCIFREE pfnfree,
1003 PFNFCIOPEN pfnopen,
1004 PFNFCIREAD pfnread,
1005 PFNFCIWRITE pfnwrite,
1006 PFNFCICLOSE pfnclose,
1007 PFNFCISEEK pfnseek,
1008 PFNFCIDELETE pfndelete,
1009 PFNFCIGETTEMPFILE pfnfcigtf,
1010 PCCAB pccab,
1011 void *pv)
1013 FCI_Int *p_fci_internal;
1015 if (!perf) {
1016 SetLastError(ERROR_BAD_ARGUMENTS);
1017 return NULL;
1019 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1020 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1021 (!pfnfcigtf) || (!pccab)) {
1022 perf->erfOper = FCIERR_NONE;
1023 perf->erfType = ERROR_BAD_ARGUMENTS;
1024 perf->fError = TRUE;
1026 SetLastError(ERROR_BAD_ARGUMENTS);
1027 return NULL;
1030 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1031 perf->erfOper = FCIERR_ALLOC_FAIL;
1032 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1033 perf->fError = TRUE;
1035 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1036 return NULL;
1039 p_fci_internal->magic = FCI_INT_MAGIC;
1040 p_fci_internal->perf = perf;
1041 p_fci_internal->fileplaced = pfnfiledest;
1042 p_fci_internal->alloc = pfnalloc;
1043 p_fci_internal->free = pfnfree;
1044 p_fci_internal->open = pfnopen;
1045 p_fci_internal->read = pfnread;
1046 p_fci_internal->write = pfnwrite;
1047 p_fci_internal->close = pfnclose;
1048 p_fci_internal->seek = pfnseek;
1049 p_fci_internal->delete = pfndelete;
1050 p_fci_internal->gettemp = pfnfcigtf;
1051 p_fci_internal->ccab = *pccab;
1052 p_fci_internal->pccab = pccab;
1053 p_fci_internal->fPrevCab = FALSE;
1054 p_fci_internal->fNextCab = FALSE;
1055 p_fci_internal->fSplitFolder = FALSE;
1056 p_fci_internal->fGetNextCabInVain = FALSE;
1057 p_fci_internal->pv = pv;
1058 p_fci_internal->cdata_in = 0;
1059 p_fci_internal->cCompressedBytesInFolder = 0;
1060 p_fci_internal->cFolders = 0;
1061 p_fci_internal->cFiles = 0;
1062 p_fci_internal->cDataBlocks = 0;
1063 p_fci_internal->data.handle = -1;
1064 p_fci_internal->fNewPrevious = FALSE;
1065 p_fci_internal->estimatedCabinetSize = 0;
1066 p_fci_internal->statusFolderTotal = 0;
1067 p_fci_internal->folders_size = 0;
1068 p_fci_internal->files_size = 0;
1069 p_fci_internal->placed_files_size = 0;
1070 p_fci_internal->pending_data_size = 0;
1071 p_fci_internal->folders_data_size = 0;
1072 p_fci_internal->compression = tcompTYPE_NONE;
1073 p_fci_internal->compress = compress_NONE;
1075 list_init( &p_fci_internal->folders_list );
1076 list_init( &p_fci_internal->files_list );
1077 list_init( &p_fci_internal->blocks_list );
1079 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1080 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1082 return (HFCI)p_fci_internal;
1088 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1089 BOOL fGetNextCab,
1090 PFNFCIGETNEXTCABINET pfnfcignc,
1091 PFNFCISTATUS pfnfcis)
1093 cab_ULONG payload;
1094 cab_ULONG read_result;
1095 struct folder *folder;
1097 if ((!pfnfcignc) || (!pfnfcis)) {
1098 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1099 return FALSE;
1102 if( p_fci_internal->fGetNextCabInVain &&
1103 p_fci_internal->fNextCab ){
1104 /* internal error */
1105 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1106 return FALSE;
1109 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1110 /* this function will return TRUE */
1111 if( p_fci_internal->files_size == 0 ) {
1112 if ( p_fci_internal->pending_data_size != 0 ) {
1113 /* error handling */
1114 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1115 return FALSE;
1117 return TRUE;
1120 /* FCIFlushFolder has already been called... */
1121 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1122 return TRUE;
1125 /* This can be set already, because it makes only a difference */
1126 /* when the current function exits with return FALSE */
1127 p_fci_internal->fSplitFolder=FALSE;
1129 /* START of COPY */
1130 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1132 /* reset to get the number of data blocks of this folder which are */
1133 /* actually in this cabinet ( at least partially ) */
1134 p_fci_internal->cDataBlocks=0;
1136 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1137 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1138 p_fci_internal->placed_files_size+
1139 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1140 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1141 p_fci_internal->statusFolderCopied = 0;
1143 /* report status with pfnfcis about copied size of folder */
1144 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1145 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1146 p_fci_internal->pv) == -1) {
1147 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1148 return FALSE;
1151 /* USE the variable read_result */
1152 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1153 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1155 if(p_fci_internal->files_size!=0) {
1156 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1159 /* Check if multiple cabinets have to be created. */
1161 /* Might be too much data for the maximum allowed cabinet size.*/
1162 /* When any further data will be added later, it might not */
1163 /* be possible to flush the cabinet, because there might */
1164 /* not be enough space to store the name of the following */
1165 /* cabinet and name of the corresponding disk. */
1166 /* So take care of this and get the name of the next cabinet */
1167 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1168 p_fci_internal->fNextCab==FALSE &&
1171 p_fci_internal->ccab.cb < read_result +
1172 p_fci_internal->pending_data_size +
1173 p_fci_internal->files_size +
1174 CB_MAX_CABINET_NAME + /* next cabinet name */
1175 CB_MAX_DISK_NAME /* next disk name */
1176 ) || fGetNextCab
1179 /* increment cabinet index */
1180 ++(p_fci_internal->pccab->iCab);
1181 /* get name of next cabinet */
1182 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1183 if (!(*pfnfcignc)(p_fci_internal->pccab,
1184 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1185 p_fci_internal->pv)) {
1186 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1187 return FALSE;
1190 /* Skip a few lines of code. This is caught by the next if. */
1191 p_fci_internal->fGetNextCabInVain=TRUE;
1194 /* too much data for cabinet */
1195 if( (p_fci_internal->fGetNextCabInVain ||
1196 p_fci_internal->fNextCab ) &&
1199 p_fci_internal->ccab.cb < read_result +
1200 p_fci_internal->pending_data_size +
1201 p_fci_internal->files_size +
1202 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1203 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1204 ) || fGetNextCab
1207 p_fci_internal->fGetNextCabInVain=FALSE;
1208 p_fci_internal->fNextCab=TRUE;
1210 /* return FALSE if there is not enough space left*/
1211 /* this should never happen */
1212 if (p_fci_internal->ccab.cb <=
1213 p_fci_internal->files_size +
1214 read_result +
1215 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1216 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1219 return FALSE;
1222 /* the folder will be split across cabinets */
1223 p_fci_internal->fSplitFolder=TRUE;
1225 } else {
1226 /* this should never happen */
1227 if (p_fci_internal->fNextCab) {
1228 /* internal error */
1229 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1230 return FALSE;
1234 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1235 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1236 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1238 /* reset CFFolder specific information */
1239 p_fci_internal->cDataBlocks=0;
1240 p_fci_internal->cCompressedBytesInFolder=0;
1242 return TRUE;
1248 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1249 BOOL fGetNextCab,
1250 PFNFCIGETNEXTCABINET pfnfcignc,
1251 PFNFCISTATUS pfnfcis)
1253 cab_ULONG read_result=0;
1254 BOOL returntrue=FALSE;
1256 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1258 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1259 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1260 returntrue=TRUE;
1263 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1264 /* TODO set error */
1265 return FALSE;
1268 if(returntrue) return TRUE;
1270 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1271 (p_fci_internal->folders_size==0 &&
1272 (p_fci_internal->files_size!=0 ||
1273 p_fci_internal->placed_files_size!=0 )
1276 /* error */
1277 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1278 return FALSE;
1281 /* create the cabinet */
1282 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1284 p_fci_internal->fPrevCab=TRUE;
1285 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1286 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1288 if (p_fci_internal->fNextCab) {
1289 p_fci_internal->fNextCab=FALSE;
1291 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1292 /* THIS CAN NEVER HAPPEN */
1293 /* set error code */
1294 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1295 return FALSE;
1298 if( p_fci_internal->fNewPrevious ) {
1299 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1300 CB_MAX_CABINET_NAME);
1301 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1302 CB_MAX_DISK_NAME);
1303 p_fci_internal->fNewPrevious=FALSE;
1305 p_fci_internal->ccab = *p_fci_internal->pccab;
1307 /* REUSE the variable read_result */
1308 read_result=get_header_size( p_fci_internal );
1309 if(p_fci_internal->files_size!=0) {
1310 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1312 read_result+= p_fci_internal->pending_data_size +
1313 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1314 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1315 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1317 /* too much data for the maximum size of a cabinet */
1318 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1319 p_fci_internal->ccab.cb < read_result ) {
1320 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1323 /* Might be too much data for the maximum size of a cabinet.*/
1324 /* When any further data will be added later, it might not */
1325 /* be possible to flush the cabinet, because there might */
1326 /* not be enough space to store the name of the following */
1327 /* cabinet and name of the corresponding disk. */
1328 /* So take care of this and get the name of the next cabinet */
1329 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1330 p_fci_internal->ccab.cb < read_result +
1331 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1332 )) {
1333 /* increment cabinet index */
1334 ++(p_fci_internal->pccab->iCab);
1335 /* get name of next cabinet */
1336 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1337 if (!(*pfnfcignc)(p_fci_internal->pccab,
1338 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1339 p_fci_internal->pv)) {
1340 /* error handling */
1341 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1342 return FALSE;
1344 /* Skip a few lines of code. This is caught by the next if. */
1345 p_fci_internal->fGetNextCabInVain=TRUE;
1348 /* too much data for cabinet */
1349 if (p_fci_internal->fGetNextCabInVain && (
1350 p_fci_internal->ccab.cb < read_result +
1351 strlen(p_fci_internal->ccab.szCab)+1+
1352 strlen(p_fci_internal->ccab.szDisk)+1
1353 )) {
1354 p_fci_internal->fGetNextCabInVain=FALSE;
1355 p_fci_internal->fNextCab=TRUE;
1356 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1359 /* if the FolderThreshold has been reached flush the folder automatically */
1360 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1361 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1363 if( p_fci_internal->files_size>0 ) {
1364 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1365 p_fci_internal->fNewPrevious=TRUE;
1367 } else {
1368 p_fci_internal->fNewPrevious=FALSE;
1369 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1370 /* THIS MAY NEVER HAPPEN */
1371 /* set error structures */
1372 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1373 return FALSE;
1377 return TRUE;
1378 } /* end of fci_flush_cabinet */
1384 /***********************************************************************
1385 * FCIAddFile (CABINET.11)
1387 * FCIAddFile adds a file to the to be created cabinet file
1389 * PARAMS
1390 * hfci [I] An HFCI from FCICreate
1391 * pszSourceFile [I] A pointer to a C string which contains the name and
1392 * location of the file which will be added to the cabinet
1393 * pszFileName [I] A pointer to a C string which contains the name under
1394 * which the file will be stored in the cabinet
1395 * fExecute [I] A boolean value which indicates if the file should be
1396 * executed after extraction of self extracting
1397 * executables
1398 * pfnfcignc [I] A pointer to a function which gets information about
1399 * the next cabinet
1400 * pfnfcis [IO] A pointer to a function which will report status
1401 * information about the compression process
1402 * pfnfcioi [I] A pointer to a function which reports file attributes
1403 * and time and date information
1404 * typeCompress [I] Compression type
1406 * RETURNS
1407 * On success, returns TRUE
1408 * On failure, returns FALSE
1410 * INCLUDES
1411 * fci.h
1414 BOOL __cdecl FCIAddFile(
1415 HFCI hfci,
1416 char *pszSourceFile,
1417 char *pszFileName,
1418 BOOL fExecute,
1419 PFNFCIGETNEXTCABINET pfnfcignc,
1420 PFNFCISTATUS pfnfcis,
1421 PFNFCIGETOPENINFO pfnfcigoi,
1422 TCOMP typeCompress)
1424 cab_ULONG read_result;
1425 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1427 if (!p_fci_internal) return FALSE;
1429 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1430 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1431 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1432 return FALSE;
1435 if (typeCompress != p_fci_internal->compression)
1437 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1438 switch (typeCompress)
1440 case tcompTYPE_MSZIP:
1441 #ifdef HAVE_ZLIB
1442 p_fci_internal->compression = tcompTYPE_MSZIP;
1443 p_fci_internal->compress = compress_MSZIP;
1444 break;
1445 #endif
1446 default:
1447 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1448 /* fall through */
1449 case tcompTYPE_NONE:
1450 p_fci_internal->compression = tcompTYPE_NONE;
1451 p_fci_internal->compress = compress_NONE;
1452 break;
1456 /* TODO check if pszSourceFile??? */
1458 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1459 /* internal error */
1460 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1461 return FALSE;
1464 if(p_fci_internal->fNextCab) {
1465 /* internal error */
1466 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1467 return FALSE;
1470 /* REUSE the variable read_result */
1471 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1473 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1474 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1475 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1476 sizeof(CFFOLDER); /* size of new CFFolder entry */
1478 /* Might be too much data for the maximum size of a cabinet.*/
1479 /* When any further data will be added later, it might not */
1480 /* be possible to flush the cabinet, because there might */
1481 /* not be enough space to store the name of the following */
1482 /* cabinet and name of the corresponding disk. */
1483 /* So take care of this and get the name of the next cabinet */
1484 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1485 p_fci_internal->fNextCab==FALSE &&
1486 ( p_fci_internal->ccab.cb < read_result +
1487 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1490 /* increment cabinet index */
1491 ++(p_fci_internal->pccab->iCab);
1492 /* get name of next cabinet */
1493 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1494 if (!(*pfnfcignc)(p_fci_internal->pccab,
1495 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1496 p_fci_internal->pv)) {
1497 /* error handling */
1498 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1499 return FALSE;
1501 /* Skip a few lines of code. This is caught by the next if. */
1502 p_fci_internal->fGetNextCabInVain=TRUE;
1505 if( p_fci_internal->fGetNextCabInVain &&
1506 p_fci_internal->fNextCab
1508 /* THIS CAN NEVER HAPPEN */
1509 /* set error code */
1510 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1511 return FALSE;
1514 /* too much data for cabinet */
1515 if( p_fci_internal->fGetNextCabInVain &&
1517 p_fci_internal->ccab.cb < read_result +
1518 strlen(p_fci_internal->pccab->szCab)+1+
1519 strlen(p_fci_internal->pccab->szDisk)+1
1520 )) {
1521 p_fci_internal->fGetNextCabInVain=FALSE;
1522 p_fci_internal->fNextCab=TRUE;
1523 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1526 if( p_fci_internal->fNextCab ) {
1527 /* THIS MAY NEVER HAPPEN */
1528 /* set error code */
1529 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1530 return FALSE;
1533 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1534 return FALSE;
1536 /* REUSE the variable read_result */
1537 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1538 read_result+= p_fci_internal->pending_data_size +
1539 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1540 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1541 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1543 /* too much data for the maximum size of a cabinet */
1544 /* (ignoring the unflushed data block) */
1545 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1546 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1547 p_fci_internal->ccab.cb < read_result ) {
1548 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1551 /* Might be too much data for the maximum size of a cabinet.*/
1552 /* When any further data will be added later, it might not */
1553 /* be possible to flush the cabinet, because there might */
1554 /* not be enough space to store the name of the following */
1555 /* cabinet and name of the corresponding disk. */
1556 /* So take care of this and get the name of the next cabinet */
1557 /* (ignoring the unflushed data block) */
1558 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1559 p_fci_internal->fNextCab==FALSE &&
1560 ( p_fci_internal->ccab.cb < read_result +
1561 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1564 /* increment cabinet index */
1565 ++(p_fci_internal->pccab->iCab);
1566 /* get name of next cabinet */
1567 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1568 if (!(*pfnfcignc)(p_fci_internal->pccab,
1569 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1570 p_fci_internal->pv)) {
1571 /* error handling */
1572 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1573 return FALSE;
1575 /* Skip a few lines of code. This is caught by the next if. */
1576 p_fci_internal->fGetNextCabInVain=TRUE;
1579 if( p_fci_internal->fGetNextCabInVain &&
1580 p_fci_internal->fNextCab
1582 /* THIS CAN NEVER HAPPEN */
1583 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1584 return FALSE;
1587 /* too much data for cabinet */
1588 if( (p_fci_internal->fGetNextCabInVain ||
1589 p_fci_internal->fNextCab) && (
1590 p_fci_internal->ccab.cb < read_result +
1591 strlen(p_fci_internal->pccab->szCab)+1+
1592 strlen(p_fci_internal->pccab->szDisk)+1
1593 )) {
1595 p_fci_internal->fGetNextCabInVain=FALSE;
1596 p_fci_internal->fNextCab=TRUE;
1597 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1600 if( p_fci_internal->fNextCab ) {
1601 /* THIS MAY NEVER HAPPEN */
1602 /* set error code */
1603 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1604 return FALSE;
1607 /* if the FolderThreshold has been reached flush the folder automatically */
1608 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1609 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1611 return TRUE;
1612 } /* end of FCIAddFile */
1618 /***********************************************************************
1619 * FCIFlushFolder (CABINET.12)
1621 * FCIFlushFolder completes the CFFolder structure under construction.
1623 * All further data which is added by FCIAddFile will be associated to
1624 * the next CFFolder structure.
1626 * FCIFlushFolder will be called by FCIAddFile automatically if the
1627 * threshold (stored in the member cbFolderThresh of the CCAB structure
1628 * pccab passed to FCICreate) is exceeded.
1630 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1631 * any data will be written into the cabinet file.
1633 * PARAMS
1634 * hfci [I] An HFCI from FCICreate
1635 * pfnfcignc [I] A pointer to a function which gets information about
1636 * the next cabinet
1637 * pfnfcis [IO] A pointer to a function which will report status
1638 * information about the compression process
1640 * RETURNS
1641 * On success, returns TRUE
1642 * On failure, returns FALSE
1644 * INCLUDES
1645 * fci.h
1648 BOOL __cdecl FCIFlushFolder(
1649 HFCI hfci,
1650 PFNFCIGETNEXTCABINET pfnfcignc,
1651 PFNFCISTATUS pfnfcis)
1653 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1655 if (!p_fci_internal) return FALSE;
1656 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1661 /***********************************************************************
1662 * FCIFlushCabinet (CABINET.13)
1664 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1665 * into the cabinet file. If the maximum cabinet size (stored in the
1666 * member cb of the CCAB structure pccab passed to FCICreate) has been
1667 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1668 * The remaining data still has to be flushed manually by calling
1669 * FCIFlushCabinet.
1671 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1672 * NOT be called again. Then hfci has to be released by FCIDestroy.
1674 * PARAMS
1675 * hfci [I] An HFCI from FCICreate
1676 * fGetNextCab [I] Whether you want to add additional files to a
1677 * cabinet set (TRUE) or whether you want to
1678 * finalize it (FALSE)
1679 * pfnfcignc [I] A pointer to a function which gets information about
1680 * the next cabinet
1681 * pfnfcis [IO] A pointer to a function which will report status
1682 * information about the compression process
1684 * RETURNS
1685 * On success, returns TRUE
1686 * On failure, returns FALSE
1688 * INCLUDES
1689 * fci.h
1692 BOOL __cdecl FCIFlushCabinet(
1693 HFCI hfci,
1694 BOOL fGetNextCab,
1695 PFNFCIGETNEXTCABINET pfnfcignc,
1696 PFNFCISTATUS pfnfcis)
1698 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1700 if (!p_fci_internal) return FALSE;
1702 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1704 while( p_fci_internal->files_size>0 ||
1705 p_fci_internal->placed_files_size>0 ) {
1706 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1709 return TRUE;
1713 /***********************************************************************
1714 * FCIDestroy (CABINET.14)
1716 * Frees a handle created by FCICreate.
1717 * Only reason for failure would be an invalid handle.
1719 * PARAMS
1720 * hfci [I] The HFCI to free
1722 * RETURNS
1723 * TRUE for success
1724 * FALSE for failure
1726 BOOL __cdecl FCIDestroy(HFCI hfci)
1728 struct folder *folder, *folder_next;
1729 struct file *file, *file_next;
1730 struct data_block *block, *block_next;
1731 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1733 if (!p_fci_internal) return FALSE;
1735 /* before hfci can be removed all temporary files must be closed */
1736 /* and deleted */
1737 p_fci_internal->magic = 0;
1739 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1741 free_folder( p_fci_internal, folder );
1743 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1745 free_file( p_fci_internal, file );
1747 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1749 free_data_block( p_fci_internal, block );
1752 close_temp_file( p_fci_internal, &p_fci_internal->data );
1754 /* hfci can now be removed */
1755 p_fci_internal->free(hfci);
1756 return TRUE;