cabinet: Add support for MSZIP compression.
[wine.git] / dlls / cabinet / fci.c
blob55a024ae0d27119d46daa4caa926a035e9ec05c0
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; /* uncompressed data blocks */
171 cab_UWORD cdata_in;
172 unsigned char *data_out; /* compressed data blocks */
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 /* make sure we have buffers */
361 if (!fci->data_in && !(fci->data_in = fci->alloc( CB_MAX_CHUNK )))
363 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
364 return FALSE;
366 if (!fci->data_out && !(fci->data_out = fci->alloc( 2 * CB_MAX_CHUNK )))
368 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
369 return FALSE;
372 if (!(file = add_file( fci, filename ))) return FALSE;
374 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
375 if (handle == -1)
377 free_file( fci, file );
378 set_error( fci, FCIERR_OPEN_SRC, err );
379 return FALSE;
381 if (execute) file->attribs |= _A_EXEC;
383 for (;;)
385 len = fci->read( handle, fci->data_in + fci->cdata_in,
386 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
387 if (!len) break;
389 if (len == -1)
391 set_error( fci, FCIERR_READ_SRC, err );
392 return FALSE;
394 file->size += len;
395 fci->cdata_in += len;
396 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
398 fci->close( handle, &err, fci->pv );
399 return TRUE;
402 static void free_data_block( FCI_Int *fci, struct data_block *block )
404 list_remove( &block->entry );
405 fci->free( block );
408 static struct folder *add_folder( FCI_Int *fci )
410 struct folder *folder = fci->alloc( sizeof(*folder) );
412 if (!folder)
414 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
415 return NULL;
417 folder->data.handle = -1;
418 folder->data_start = fci->folders_data_size;
419 folder->data_count = 0;
420 folder->compression = fci->compression;
421 list_init( &folder->files_list );
422 list_init( &folder->blocks_list );
423 list_add_tail( &fci->folders_list, &folder->entry );
424 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
425 fci->cFolders++;
426 return folder;
429 static void free_folder( FCI_Int *fci, struct folder *folder )
431 struct file *file, *file_next;
432 struct data_block *block, *block_next;
434 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
435 free_file( fci, file );
436 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
437 free_data_block( fci, block );
438 close_temp_file( fci, &folder->data );
439 list_remove( &folder->entry );
440 fci->free( folder );
443 /* reset state for the next cabinet file once the current one has been flushed */
444 static void reset_cabinet( FCI_Int *fci )
446 struct folder *folder, *folder_next;
448 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
449 free_folder( fci, folder );
451 fci->cFolders = 0;
452 fci->cFiles = 0;
453 fci->folders_size = 0;
454 fci->placed_files_size = 0;
455 fci->folders_data_size = 0;
458 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
460 cab_ULONG csum;
461 cab_ULONG ul;
462 int cUlong;
463 const BYTE *pb;
465 csum = seed;
466 cUlong = cb / 4;
467 pb = pv;
469 while (cUlong-- > 0) {
470 ul = *pb++;
471 ul |= (((cab_ULONG)(*pb++)) << 8);
472 ul |= (((cab_ULONG)(*pb++)) << 16);
473 ul |= (((cab_ULONG)(*pb++)) << 24);
474 csum ^= ul;
477 ul = 0;
478 switch (cb % 4) {
479 case 3:
480 ul |= (((ULONG)(*pb++)) << 16);
481 case 2:
482 ul |= (((ULONG)(*pb++)) << 8);
483 case 1:
484 ul |= *pb;
485 default:
486 break;
488 csum ^= ul;
490 return csum;
493 /* copy all remaining data block to a new temp file */
494 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
495 struct temp_file *temp, PFNFCISTATUS status_callback )
497 struct data_block *block;
498 int err;
500 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
502 set_error( fci, FCIERR_TEMP_FILE, err );
503 return FALSE;
505 if (!create_temp_file( fci, temp )) return FALSE;
507 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
509 if (fci->read( handle, fci->data_out, block->compressed,
510 &err, fci->pv ) != block->compressed)
512 close_temp_file( fci, temp );
513 set_error( fci, FCIERR_TEMP_FILE, err );
514 return FALSE;
516 if (fci->write( temp->handle, fci->data_out, block->compressed,
517 &err, fci->pv ) != block->compressed)
519 close_temp_file( fci, temp );
520 set_error( fci, FCIERR_TEMP_FILE, err );
521 return FALSE;
523 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
524 fci->statusFolderCopied += block->compressed;
526 if (status_callback( statusFolder, fci->statusFolderCopied,
527 fci->statusFolderTotal, fci->pv) == -1)
529 close_temp_file( fci, temp );
530 set_error( fci, FCIERR_USER_ABORT, 0 );
531 return FALSE;
534 return TRUE;
537 /* write all folders to disk and remove them from the list */
538 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
540 struct folder *folder;
541 int err;
542 BOOL ret = TRUE;
543 CFFOLDER *cffolder;
544 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
546 if (!(cffolder = fci->alloc( folder_size )))
548 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
549 return FALSE;
551 memset( cffolder, 0, folder_size );
553 /* write the folders */
554 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
556 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
557 cffolder->cCFData = fci_endian_uword( folder->data_count );
558 cffolder->typeCompress = fci_endian_uword( folder->compression );
559 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
561 set_error( fci, FCIERR_CAB_FILE, err );
562 ret = FALSE;
563 break;
567 fci->free( cffolder );
568 return ret;
571 /* write all the files to the cabinet file */
572 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
574 cab_ULONG file_size;
575 struct folder *folder;
576 struct file *file;
577 int err;
578 BOOL ret = TRUE;
579 CFFILE *cffile;
581 if (!(cffile = fci->alloc( sizeof(CFFILE) + CB_MAX_FILENAME )))
583 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
584 return FALSE;
587 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
589 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
591 cffile->cbFile = fci_endian_ulong( file->size );
592 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
593 cffile->iFolder = fci_endian_uword( file->folder );
594 cffile->date = fci_endian_uword( file->date );
595 cffile->time = fci_endian_uword( file->time );
596 cffile->attribs = fci_endian_uword( file->attribs );
597 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
598 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
599 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
601 set_error( fci, FCIERR_CAB_FILE, err );
602 ret = FALSE;
603 break;
605 if (!fci->fSplitFolder)
607 fci->statusFolderCopied = 0;
608 /* TODO TEST THIS further */
609 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
611 fci->statusFolderCopied += file_size;
612 /* report status about copied size of folder */
613 if (status_callback( statusFolder, fci->statusFolderCopied,
614 fci->statusFolderTotal, fci->pv ) == -1)
616 set_error( fci, FCIERR_USER_ABORT, 0 );
617 ret = FALSE;
618 break;
623 fci->free( cffile );
624 return ret;
627 /* write all data blocks to the cabinet file */
628 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
630 struct folder *folder;
631 struct data_block *block;
632 int err, len;
633 CFDATA *cfdata;
634 void *data;
635 cab_UWORD header_size;
637 if (!fci->data_out) return TRUE;
639 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
640 cfdata = (CFDATA *)fci->data_out;
641 memset( cfdata, 0, header_size );
642 data = (char *)cfdata + header_size;
644 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
646 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
648 set_error( fci, FCIERR_CAB_FILE, err );
649 return FALSE;
651 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
653 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
654 if (len != block->compressed) return FALSE;
656 cfdata->cbData = fci_endian_uword( block->compressed );
657 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
658 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
659 header_size - FIELD_OFFSET(CFDATA, cbData),
660 fci_get_checksum( data, len, 0 )));
662 fci->statusFolderCopied += len;
663 len += header_size;
664 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
666 set_error( fci, FCIERR_CAB_FILE, err );
667 return FALSE;
669 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
671 set_error( fci, FCIERR_USER_ABORT, 0 );
672 return FALSE;
676 return TRUE;
679 /* write the cabinet file to disk */
680 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
682 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
683 int err;
684 char *ptr;
685 INT_PTR handle;
686 CFHEADER *cfheader;
687 cab_UWORD flags = 0;
688 cab_ULONG header_size = get_header_size( fci );
689 cab_ULONG total_size = header_size + fci->folders_size + fci->placed_files_size + fci->folders_data_size;
691 if (!(cfheader = fci->alloc( header_size )))
693 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
694 return FALSE;
696 memset( cfheader, 0, header_size );
698 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
699 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
700 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
701 flags |= cfheadRESERVE_PRESENT;
703 memcpy( cfheader->signature, "!CAB", 4 );
704 cfheader->cbCabinet = fci_endian_ulong( total_size );
705 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
706 cfheader->versionMinor = 3;
707 cfheader->versionMajor = 1;
708 cfheader->cFolders = fci_endian_uword( fci->cFolders );
709 cfheader->cFiles = fci_endian_uword( fci->cFiles );
710 cfheader->flags = fci_endian_uword( flags );
711 cfheader->setID = fci_endian_uword( fci->ccab.setID );
712 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab - 1 );
713 ptr = (char *)(cfheader + 1);
715 if (flags & cfheadRESERVE_PRESENT)
717 struct
719 cab_UWORD cbCFHeader;
720 cab_UBYTE cbCFFolder;
721 cab_UBYTE cbCFData;
722 } *reserve = (void *)ptr;
724 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
725 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
726 reserve->cbCFData = fci->ccab.cbReserveCFData;
727 ptr = (char *)(reserve + 1);
729 ptr += fci->ccab.cbReserveCFHeader;
731 if (flags & cfheadPREV_CABINET)
733 strcpy( ptr, fci->szPrevCab );
734 ptr += strlen( ptr ) + 1;
735 strcpy( ptr, fci->szPrevDisk );
736 ptr += strlen( ptr ) + 1;
739 if (flags & cfheadNEXT_CABINET)
741 strcpy( ptr, fci->pccab->szCab );
742 ptr += strlen( ptr ) + 1;
743 strcpy( ptr, fci->pccab->szDisk );
744 ptr += strlen( ptr ) + 1;
747 assert( ptr - (char *)cfheader == header_size );
749 strcpy( filename, fci->ccab.szCabPath );
750 strcat( filename, fci->ccab.szCab );
752 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
753 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
755 set_error( fci, FCIERR_CAB_FILE, err );
756 fci->free( cfheader );
757 return FALSE;
760 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
762 set_error( fci, FCIERR_CAB_FILE, err );
763 goto failed;
766 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
767 header_size += fci->placed_files_size + fci->folders_size;
768 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
769 if (!write_files( fci, handle, status_callback )) goto failed;
770 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
772 /* update the signature */
773 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
775 set_error( fci, FCIERR_CAB_FILE, err );
776 goto failed;
778 memcpy( cfheader->signature, "MSCF", 4 );
779 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
781 set_error( fci, FCIERR_CAB_FILE, err );
782 goto failed;
784 fci->close( handle, &err, fci->pv );
785 fci->free( cfheader );
787 reset_cabinet( fci );
788 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
789 return TRUE;
791 failed:
792 fci->close( handle, &err, fci->pv );
793 fci->delete( filename, &err, fci->pv );
794 fci->free( cfheader );
795 return FALSE;
798 /* add all pending data blocks folder */
799 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
800 PFNFCISTATUS status_callback )
802 struct data_block *block, *new, *next;
803 BOOL split_block = FALSE;
804 cab_ULONG current_size, start_pos = 0;
806 *payload = 0;
807 current_size = get_header_size( fci ) + fci->folders_size +
808 fci->files_size + fci->placed_files_size + fci->folders_data_size;
810 /* move the temp file into the folder structure */
811 folder->data = fci->data;
812 fci->data.handle = -1;
813 fci->pending_data_size = 0;
815 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
817 /* No more CFDATA fits into the cabinet under construction */
818 /* So don't try to store more data into it */
819 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
820 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
821 break;
823 if (!(new = fci->alloc( sizeof(*new) )))
825 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
826 return FALSE;
828 /* Is cabinet with new CFDATA too large? Then data block has to be split */
829 if( fci->fNextCab &&
830 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
831 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
833 /* Modify the size of the compressed data to store only a part of the */
834 /* data block into the current cabinet. This is done to prevent */
835 /* that the maximum cabinet size will be exceeded. The remainder */
836 /* will be stored into the next following cabinet. */
838 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
839 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
840 new->uncompressed = 0; /* on split blocks of data this is zero */
841 block->compressed -= new->compressed;
842 split_block = TRUE;
844 else
846 new->compressed = block->compressed;
847 new->uncompressed = block->uncompressed;
850 start_pos += new->compressed;
851 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
852 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
853 fci->statusFolderCopied += new->compressed;
854 (*payload) += new->uncompressed;
856 list_add_tail( &folder->blocks_list, &new->entry );
857 folder->data_count++;
859 /* report status with pfnfcis about copied size of folder */
860 if (status_callback( statusFolder, fci->statusFolderCopied,
861 fci->statusFolderTotal, fci->pv ) == -1)
863 set_error( fci, FCIERR_USER_ABORT, 0 );
864 return FALSE;
866 if (split_block) break;
867 free_data_block( fci, block );
868 fci->cDataBlocks--;
871 if (list_empty( &fci->blocks_list )) return TRUE;
872 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
875 /* add all pending files to folder */
876 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
878 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
879 cab_ULONG cbFileRemainer = 0;
880 struct file *file, *next;
882 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
884 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
886 /* fnfilfnfildest: placed file on cabinet */
887 fci->fileplaced( &fci->ccab, file->name, file->size,
888 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
890 sizeOfFilesPrev = sizeOfFiles;
891 /* set complete size of all processed files */
892 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
894 sizeOfFiles += fci->cbFileRemainer;
895 fci->cbFileRemainer = 0;
897 else sizeOfFiles += file->size;
899 /* check if spanned file fits into this cabinet folder */
900 if (sizeOfFiles > payload)
902 if (file->folder == cffileCONTINUED_FROM_PREV)
903 file->folder = cffileCONTINUED_PREV_AND_NEXT;
904 else
905 file->folder = cffileCONTINUED_TO_NEXT;
908 list_remove( &file->entry );
909 list_add_tail( &folder->files_list, &file->entry );
910 fci->placed_files_size += size;
911 fci->cFiles++;
913 /* This is only true for files which will be written into the */
914 /* next cabinet of the spanning folder */
915 if (sizeOfFiles > payload)
917 /* add a copy back onto the list */
918 if (!(file = copy_file( fci, file ))) return FALSE;
919 list_add_before( &next->entry, &file->entry );
921 /* Files which data will be partially written into the current cabinet */
922 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
924 if (sizeOfFilesPrev <= payload)
926 /* The size of the uncompressed, data of a spanning file in a */
927 /* spanning data */
928 cbFileRemainer = sizeOfFiles - payload;
930 file->folder = cffileCONTINUED_FROM_PREV;
932 else file->folder = 0;
934 else
936 fci->files_size -= size;
939 fci->cbFileRemainer = cbFileRemainer;
940 return TRUE;
943 static cab_UWORD compress_NONE( FCI_Int *fci )
945 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
946 return fci->cdata_in;
949 #ifdef HAVE_ZLIB
951 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
953 FCI_Int *fci = opaque;
954 return fci->alloc( items * size );
957 static void zfree( void *opaque, void *ptr )
959 FCI_Int *fci = opaque;
960 return fci->free( ptr );
963 static cab_UWORD compress_MSZIP( FCI_Int *fci )
965 z_stream stream;
967 stream.zalloc = zalloc;
968 stream.zfree = zfree;
969 stream.opaque = fci;
970 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
972 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
973 return 0;
975 stream.next_in = fci->data_in;
976 stream.avail_in = fci->cdata_in;
977 stream.next_out = fci->data_out + 2;
978 stream.avail_out = 2 * CB_MAX_CHUNK - 2;
979 /* insert the signature */
980 fci->data_out[0] = 'C';
981 fci->data_out[1] = 'K';
982 deflate( &stream, Z_FINISH );
983 deflateEnd( &stream );
984 return stream.total_out + 2;
987 #endif /* HAVE_ZLIB */
990 /***********************************************************************
991 * FCICreate (CABINET.10)
993 * FCICreate is provided with several callbacks and
994 * returns a handle which can be used to create cabinet files.
996 * PARAMS
997 * perf [IO] A pointer to an ERF structure. When FCICreate
998 * returns an error condition, error information may
999 * be found here as well as from GetLastError.
1000 * pfnfiledest [I] A pointer to a function which is called when a file
1001 * is placed. Only useful for subsequent cabinet files.
1002 * pfnalloc [I] A pointer to a function which allocates ram. Uses
1003 * the same interface as malloc.
1004 * pfnfree [I] A pointer to a function which frees ram. Uses the
1005 * same interface as free.
1006 * pfnopen [I] A pointer to a function which opens a file. Uses
1007 * the same interface as _open.
1008 * pfnread [I] A pointer to a function which reads from a file into
1009 * a caller-provided buffer. Uses the same interface
1010 * as _read.
1011 * pfnwrite [I] A pointer to a function which writes to a file from
1012 * a caller-provided buffer. Uses the same interface
1013 * as _write.
1014 * pfnclose [I] A pointer to a function which closes a file handle.
1015 * Uses the same interface as _close.
1016 * pfnseek [I] A pointer to a function which seeks in a file.
1017 * Uses the same interface as _lseek.
1018 * pfndelete [I] A pointer to a function which deletes a file.
1019 * pfnfcigtf [I] A pointer to a function which gets the name of a
1020 * temporary file.
1021 * pccab [I] A pointer to an initialized CCAB structure.
1022 * pv [I] A pointer to an application-defined notification
1023 * function which will be passed to other FCI functions
1024 * as a parameter.
1026 * RETURNS
1027 * On success, returns an FCI handle of type HFCI.
1028 * On failure, the NULL file handle is returned. Error
1029 * info can be retrieved from perf.
1031 * INCLUDES
1032 * fci.h
1035 HFCI __cdecl FCICreate(
1036 PERF perf,
1037 PFNFCIFILEPLACED pfnfiledest,
1038 PFNFCIALLOC pfnalloc,
1039 PFNFCIFREE pfnfree,
1040 PFNFCIOPEN pfnopen,
1041 PFNFCIREAD pfnread,
1042 PFNFCIWRITE pfnwrite,
1043 PFNFCICLOSE pfnclose,
1044 PFNFCISEEK pfnseek,
1045 PFNFCIDELETE pfndelete,
1046 PFNFCIGETTEMPFILE pfnfcigtf,
1047 PCCAB pccab,
1048 void *pv)
1050 FCI_Int *p_fci_internal;
1052 if (!perf) {
1053 SetLastError(ERROR_BAD_ARGUMENTS);
1054 return NULL;
1056 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1057 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1058 (!pfnfcigtf) || (!pccab)) {
1059 perf->erfOper = FCIERR_NONE;
1060 perf->erfType = ERROR_BAD_ARGUMENTS;
1061 perf->fError = TRUE;
1063 SetLastError(ERROR_BAD_ARGUMENTS);
1064 return NULL;
1067 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1068 perf->erfOper = FCIERR_ALLOC_FAIL;
1069 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1070 perf->fError = TRUE;
1072 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1073 return NULL;
1076 p_fci_internal->magic = FCI_INT_MAGIC;
1077 p_fci_internal->perf = perf;
1078 p_fci_internal->fileplaced = pfnfiledest;
1079 p_fci_internal->alloc = pfnalloc;
1080 p_fci_internal->free = pfnfree;
1081 p_fci_internal->open = pfnopen;
1082 p_fci_internal->read = pfnread;
1083 p_fci_internal->write = pfnwrite;
1084 p_fci_internal->close = pfnclose;
1085 p_fci_internal->seek = pfnseek;
1086 p_fci_internal->delete = pfndelete;
1087 p_fci_internal->gettemp = pfnfcigtf;
1088 p_fci_internal->ccab = *pccab;
1089 p_fci_internal->pccab = pccab;
1090 p_fci_internal->fPrevCab = FALSE;
1091 p_fci_internal->fNextCab = FALSE;
1092 p_fci_internal->fSplitFolder = FALSE;
1093 p_fci_internal->fGetNextCabInVain = FALSE;
1094 p_fci_internal->pv = pv;
1095 p_fci_internal->data_in = NULL;
1096 p_fci_internal->cdata_in = 0;
1097 p_fci_internal->data_out = NULL;
1098 p_fci_internal->cCompressedBytesInFolder = 0;
1099 p_fci_internal->cFolders = 0;
1100 p_fci_internal->cFiles = 0;
1101 p_fci_internal->cDataBlocks = 0;
1102 p_fci_internal->data.handle = -1;
1103 p_fci_internal->fNewPrevious = FALSE;
1104 p_fci_internal->estimatedCabinetSize = 0;
1105 p_fci_internal->statusFolderTotal = 0;
1106 p_fci_internal->folders_size = 0;
1107 p_fci_internal->files_size = 0;
1108 p_fci_internal->placed_files_size = 0;
1109 p_fci_internal->pending_data_size = 0;
1110 p_fci_internal->folders_data_size = 0;
1111 p_fci_internal->compression = tcompTYPE_NONE;
1112 p_fci_internal->compress = compress_NONE;
1114 list_init( &p_fci_internal->folders_list );
1115 list_init( &p_fci_internal->files_list );
1116 list_init( &p_fci_internal->blocks_list );
1118 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1119 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1121 return (HFCI)p_fci_internal;
1127 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1128 BOOL fGetNextCab,
1129 PFNFCIGETNEXTCABINET pfnfcignc,
1130 PFNFCISTATUS pfnfcis)
1132 cab_ULONG payload;
1133 cab_ULONG read_result;
1134 struct folder *folder;
1136 if ((!pfnfcignc) || (!pfnfcis)) {
1137 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1138 return FALSE;
1141 if( p_fci_internal->fGetNextCabInVain &&
1142 p_fci_internal->fNextCab ){
1143 /* internal error */
1144 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1145 return FALSE;
1148 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1149 /* this function will return TRUE */
1150 if( p_fci_internal->files_size == 0 ) {
1151 if ( p_fci_internal->pending_data_size != 0 ) {
1152 /* error handling */
1153 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1154 return FALSE;
1156 return TRUE;
1159 if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) {
1160 /* error handling */
1161 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1162 return FALSE;
1165 /* FCIFlushFolder has already been called... */
1166 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1167 return TRUE;
1170 /* This can be set already, because it makes only a difference */
1171 /* when the current function exits with return FALSE */
1172 p_fci_internal->fSplitFolder=FALSE;
1174 /* START of COPY */
1175 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1177 /* reset to get the number of data blocks of this folder which are */
1178 /* actually in this cabinet ( at least partially ) */
1179 p_fci_internal->cDataBlocks=0;
1181 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1182 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1183 p_fci_internal->placed_files_size+
1184 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1185 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1186 p_fci_internal->statusFolderCopied = 0;
1188 /* report status with pfnfcis about copied size of folder */
1189 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1190 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1191 p_fci_internal->pv) == -1) {
1192 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1193 return FALSE;
1196 /* USE the variable read_result */
1197 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1198 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1200 if(p_fci_internal->files_size!=0) {
1201 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1204 /* Check if multiple cabinets have to be created. */
1206 /* Might be too much data for the maximum allowed cabinet size.*/
1207 /* When any further data will be added later, it might not */
1208 /* be possible to flush the cabinet, because there might */
1209 /* not be enough space to store the name of the following */
1210 /* cabinet and name of the corresponding disk. */
1211 /* So take care of this and get the name of the next cabinet */
1212 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1213 p_fci_internal->fNextCab==FALSE &&
1216 p_fci_internal->ccab.cb < read_result +
1217 p_fci_internal->pending_data_size +
1218 p_fci_internal->files_size +
1219 CB_MAX_CABINET_NAME + /* next cabinet name */
1220 CB_MAX_DISK_NAME /* next disk name */
1221 ) || fGetNextCab
1224 /* increment cabinet index */
1225 ++(p_fci_internal->pccab->iCab);
1226 /* get name of next cabinet */
1227 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1228 if (!(*pfnfcignc)(p_fci_internal->pccab,
1229 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1230 p_fci_internal->pv)) {
1231 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1232 return FALSE;
1235 /* Skip a few lines of code. This is caught by the next if. */
1236 p_fci_internal->fGetNextCabInVain=TRUE;
1239 /* too much data for cabinet */
1240 if( (p_fci_internal->fGetNextCabInVain ||
1241 p_fci_internal->fNextCab ) &&
1244 p_fci_internal->ccab.cb < read_result +
1245 p_fci_internal->pending_data_size +
1246 p_fci_internal->files_size +
1247 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1248 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1249 ) || fGetNextCab
1252 p_fci_internal->fGetNextCabInVain=FALSE;
1253 p_fci_internal->fNextCab=TRUE;
1255 /* return FALSE if there is not enough space left*/
1256 /* this should never happen */
1257 if (p_fci_internal->ccab.cb <=
1258 p_fci_internal->files_size +
1259 read_result +
1260 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1261 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1264 return FALSE;
1267 /* the folder will be split across cabinets */
1268 p_fci_internal->fSplitFolder=TRUE;
1270 } else {
1271 /* this should never happen */
1272 if (p_fci_internal->fNextCab) {
1273 /* internal error */
1274 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1275 return FALSE;
1279 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1280 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1281 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1283 /* reset CFFolder specific information */
1284 p_fci_internal->cDataBlocks=0;
1285 p_fci_internal->cCompressedBytesInFolder=0;
1287 return TRUE;
1293 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1294 BOOL fGetNextCab,
1295 PFNFCIGETNEXTCABINET pfnfcignc,
1296 PFNFCISTATUS pfnfcis)
1298 cab_ULONG read_result=0;
1299 BOOL returntrue=FALSE;
1301 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1303 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1304 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1305 returntrue=TRUE;
1308 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1309 /* TODO set error */
1310 return FALSE;
1313 if(returntrue) return TRUE;
1315 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1316 (p_fci_internal->folders_size==0 &&
1317 (p_fci_internal->files_size!=0 ||
1318 p_fci_internal->placed_files_size!=0 )
1321 /* error */
1322 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1323 return FALSE;
1326 /* create the cabinet */
1327 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1329 p_fci_internal->fPrevCab=TRUE;
1330 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1331 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1333 if (p_fci_internal->fNextCab) {
1334 p_fci_internal->fNextCab=FALSE;
1336 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1337 /* THIS CAN NEVER HAPPEN */
1338 /* set error code */
1339 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1340 return FALSE;
1343 if( p_fci_internal->fNewPrevious ) {
1344 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1345 CB_MAX_CABINET_NAME);
1346 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1347 CB_MAX_DISK_NAME);
1348 p_fci_internal->fNewPrevious=FALSE;
1350 p_fci_internal->ccab = *p_fci_internal->pccab;
1352 /* REUSE the variable read_result */
1353 read_result=get_header_size( p_fci_internal );
1354 if(p_fci_internal->files_size!=0) {
1355 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1357 read_result+= p_fci_internal->pending_data_size +
1358 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1359 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1360 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1362 /* too much data for the maximum size of a cabinet */
1363 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1364 p_fci_internal->ccab.cb < read_result ) {
1365 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1368 /* Might be too much data for the maximum size of a cabinet.*/
1369 /* When any further data will be added later, it might not */
1370 /* be possible to flush the cabinet, because there might */
1371 /* not be enough space to store the name of the following */
1372 /* cabinet and name of the corresponding disk. */
1373 /* So take care of this and get the name of the next cabinet */
1374 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1375 p_fci_internal->ccab.cb < read_result +
1376 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1377 )) {
1378 /* increment cabinet index */
1379 ++(p_fci_internal->pccab->iCab);
1380 /* get name of next cabinet */
1381 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1382 if (!(*pfnfcignc)(p_fci_internal->pccab,
1383 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1384 p_fci_internal->pv)) {
1385 /* error handling */
1386 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1387 return FALSE;
1389 /* Skip a few lines of code. This is caught by the next if. */
1390 p_fci_internal->fGetNextCabInVain=TRUE;
1393 /* too much data for cabinet */
1394 if (p_fci_internal->fGetNextCabInVain && (
1395 p_fci_internal->ccab.cb < read_result +
1396 strlen(p_fci_internal->ccab.szCab)+1+
1397 strlen(p_fci_internal->ccab.szDisk)+1
1398 )) {
1399 p_fci_internal->fGetNextCabInVain=FALSE;
1400 p_fci_internal->fNextCab=TRUE;
1401 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1404 /* if the FolderThreshold has been reached flush the folder automatically */
1405 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1406 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1408 if( p_fci_internal->files_size>0 ) {
1409 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1410 p_fci_internal->fNewPrevious=TRUE;
1412 } else {
1413 p_fci_internal->fNewPrevious=FALSE;
1414 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1415 /* THIS MAY NEVER HAPPEN */
1416 /* set error structures */
1417 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1418 return FALSE;
1422 return TRUE;
1423 } /* end of fci_flush_cabinet */
1429 /***********************************************************************
1430 * FCIAddFile (CABINET.11)
1432 * FCIAddFile adds a file to the to be created cabinet file
1434 * PARAMS
1435 * hfci [I] An HFCI from FCICreate
1436 * pszSourceFile [I] A pointer to a C string which contains the name and
1437 * location of the file which will be added to the cabinet
1438 * pszFileName [I] A pointer to a C string which contains the name under
1439 * which the file will be stored in the cabinet
1440 * fExecute [I] A boolean value which indicates if the file should be
1441 * executed after extraction of self extracting
1442 * executables
1443 * pfnfcignc [I] A pointer to a function which gets information about
1444 * the next cabinet
1445 * pfnfcis [IO] A pointer to a function which will report status
1446 * information about the compression process
1447 * pfnfcioi [I] A pointer to a function which reports file attributes
1448 * and time and date information
1449 * typeCompress [I] Compression type
1451 * RETURNS
1452 * On success, returns TRUE
1453 * On failure, returns FALSE
1455 * INCLUDES
1456 * fci.h
1459 BOOL __cdecl FCIAddFile(
1460 HFCI hfci,
1461 char *pszSourceFile,
1462 char *pszFileName,
1463 BOOL fExecute,
1464 PFNFCIGETNEXTCABINET pfnfcignc,
1465 PFNFCISTATUS pfnfcis,
1466 PFNFCIGETOPENINFO pfnfcigoi,
1467 TCOMP typeCompress)
1469 cab_ULONG read_result;
1470 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1472 if (!p_fci_internal) return FALSE;
1474 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1475 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1476 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1477 return FALSE;
1480 if (typeCompress != p_fci_internal->compression)
1482 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1483 switch (typeCompress)
1485 case tcompTYPE_MSZIP:
1486 #ifdef HAVE_ZLIB
1487 p_fci_internal->compression = tcompTYPE_MSZIP;
1488 p_fci_internal->compress = compress_MSZIP;
1489 break;
1490 #endif
1491 default:
1492 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1493 /* fall through */
1494 case tcompTYPE_NONE:
1495 p_fci_internal->compression = tcompTYPE_NONE;
1496 p_fci_internal->compress = compress_NONE;
1497 break;
1501 /* TODO check if pszSourceFile??? */
1503 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1504 /* internal error */
1505 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1506 return FALSE;
1509 if(p_fci_internal->fNextCab) {
1510 /* internal error */
1511 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1512 return FALSE;
1515 /* REUSE the variable read_result */
1516 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1518 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1519 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1520 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1521 sizeof(CFFOLDER); /* size of new CFFolder entry */
1523 /* Might be too much data for the maximum size of a cabinet.*/
1524 /* When any further data will be added later, it might not */
1525 /* be possible to flush the cabinet, because there might */
1526 /* not be enough space to store the name of the following */
1527 /* cabinet and name of the corresponding disk. */
1528 /* So take care of this and get the name of the next cabinet */
1529 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1530 p_fci_internal->fNextCab==FALSE &&
1531 ( p_fci_internal->ccab.cb < read_result +
1532 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1535 /* increment cabinet index */
1536 ++(p_fci_internal->pccab->iCab);
1537 /* get name of next cabinet */
1538 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1539 if (!(*pfnfcignc)(p_fci_internal->pccab,
1540 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1541 p_fci_internal->pv)) {
1542 /* error handling */
1543 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1544 return FALSE;
1546 /* Skip a few lines of code. This is caught by the next if. */
1547 p_fci_internal->fGetNextCabInVain=TRUE;
1550 if( p_fci_internal->fGetNextCabInVain &&
1551 p_fci_internal->fNextCab
1553 /* THIS CAN NEVER HAPPEN */
1554 /* set error code */
1555 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1556 return FALSE;
1559 /* too much data for cabinet */
1560 if( p_fci_internal->fGetNextCabInVain &&
1562 p_fci_internal->ccab.cb < read_result +
1563 strlen(p_fci_internal->pccab->szCab)+1+
1564 strlen(p_fci_internal->pccab->szDisk)+1
1565 )) {
1566 p_fci_internal->fGetNextCabInVain=FALSE;
1567 p_fci_internal->fNextCab=TRUE;
1568 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1571 if( p_fci_internal->fNextCab ) {
1572 /* THIS MAY NEVER HAPPEN */
1573 /* set error code */
1574 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1575 return FALSE;
1578 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1579 return FALSE;
1581 /* REUSE the variable read_result */
1582 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1583 read_result+= p_fci_internal->pending_data_size +
1584 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1585 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1586 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1588 /* too much data for the maximum size of a cabinet */
1589 /* (ignoring the unflushed data block) */
1590 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1591 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1592 p_fci_internal->ccab.cb < read_result ) {
1593 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1596 /* Might be too much data for the maximum size of a cabinet.*/
1597 /* When any further data will be added later, it might not */
1598 /* be possible to flush the cabinet, because there might */
1599 /* not be enough space to store the name of the following */
1600 /* cabinet and name of the corresponding disk. */
1601 /* So take care of this and get the name of the next cabinet */
1602 /* (ignoring the unflushed data block) */
1603 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1604 p_fci_internal->fNextCab==FALSE &&
1605 ( p_fci_internal->ccab.cb < read_result +
1606 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1609 /* increment cabinet index */
1610 ++(p_fci_internal->pccab->iCab);
1611 /* get name of next cabinet */
1612 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1613 if (!(*pfnfcignc)(p_fci_internal->pccab,
1614 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1615 p_fci_internal->pv)) {
1616 /* error handling */
1617 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1618 return FALSE;
1620 /* Skip a few lines of code. This is caught by the next if. */
1621 p_fci_internal->fGetNextCabInVain=TRUE;
1624 if( p_fci_internal->fGetNextCabInVain &&
1625 p_fci_internal->fNextCab
1627 /* THIS CAN NEVER HAPPEN */
1628 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1629 return FALSE;
1632 /* too much data for cabinet */
1633 if( (p_fci_internal->fGetNextCabInVain ||
1634 p_fci_internal->fNextCab) && (
1635 p_fci_internal->ccab.cb < read_result +
1636 strlen(p_fci_internal->pccab->szCab)+1+
1637 strlen(p_fci_internal->pccab->szDisk)+1
1638 )) {
1640 p_fci_internal->fGetNextCabInVain=FALSE;
1641 p_fci_internal->fNextCab=TRUE;
1642 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1645 if( p_fci_internal->fNextCab ) {
1646 /* THIS MAY NEVER HAPPEN */
1647 /* set error code */
1648 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1649 return FALSE;
1652 /* if the FolderThreshold has been reached flush the folder automatically */
1653 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1654 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1656 return TRUE;
1657 } /* end of FCIAddFile */
1663 /***********************************************************************
1664 * FCIFlushFolder (CABINET.12)
1666 * FCIFlushFolder completes the CFFolder structure under construction.
1668 * All further data which is added by FCIAddFile will be associated to
1669 * the next CFFolder structure.
1671 * FCIFlushFolder will be called by FCIAddFile automatically if the
1672 * threshold (stored in the member cbFolderThresh of the CCAB structure
1673 * pccab passed to FCICreate) is exceeded.
1675 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1676 * any data will be written into the cabinet file.
1678 * PARAMS
1679 * hfci [I] An HFCI from FCICreate
1680 * pfnfcignc [I] A pointer to a function which gets information about
1681 * the next cabinet
1682 * pfnfcis [IO] A pointer to a function which will report status
1683 * information about the compression process
1685 * RETURNS
1686 * On success, returns TRUE
1687 * On failure, returns FALSE
1689 * INCLUDES
1690 * fci.h
1693 BOOL __cdecl FCIFlushFolder(
1694 HFCI hfci,
1695 PFNFCIGETNEXTCABINET pfnfcignc,
1696 PFNFCISTATUS pfnfcis)
1698 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1700 if (!p_fci_internal) return FALSE;
1701 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1706 /***********************************************************************
1707 * FCIFlushCabinet (CABINET.13)
1709 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1710 * into the cabinet file. If the maximum cabinet size (stored in the
1711 * member cb of the CCAB structure pccab passed to FCICreate) has been
1712 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1713 * The remaining data still has to be flushed manually by calling
1714 * FCIFlushCabinet.
1716 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1717 * NOT be called again. Then hfci has to be released by FCIDestroy.
1719 * PARAMS
1720 * hfci [I] An HFCI from FCICreate
1721 * fGetNextCab [I] Whether you want to add additional files to a
1722 * cabinet set (TRUE) or whether you want to
1723 * finalize it (FALSE)
1724 * pfnfcignc [I] A pointer to a function which gets information about
1725 * the next cabinet
1726 * pfnfcis [IO] A pointer to a function which will report status
1727 * information about the compression process
1729 * RETURNS
1730 * On success, returns TRUE
1731 * On failure, returns FALSE
1733 * INCLUDES
1734 * fci.h
1737 BOOL __cdecl FCIFlushCabinet(
1738 HFCI hfci,
1739 BOOL fGetNextCab,
1740 PFNFCIGETNEXTCABINET pfnfcignc,
1741 PFNFCISTATUS pfnfcis)
1743 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1745 if (!p_fci_internal) return FALSE;
1747 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1749 while( p_fci_internal->files_size>0 ||
1750 p_fci_internal->placed_files_size>0 ) {
1751 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1754 return TRUE;
1758 /***********************************************************************
1759 * FCIDestroy (CABINET.14)
1761 * Frees a handle created by FCICreate.
1762 * Only reason for failure would be an invalid handle.
1764 * PARAMS
1765 * hfci [I] The HFCI to free
1767 * RETURNS
1768 * TRUE for success
1769 * FALSE for failure
1771 BOOL __cdecl FCIDestroy(HFCI hfci)
1773 struct folder *folder, *folder_next;
1774 struct file *file, *file_next;
1775 struct data_block *block, *block_next;
1776 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1778 if (!p_fci_internal) return FALSE;
1780 /* before hfci can be removed all temporary files must be closed */
1781 /* and deleted */
1782 p_fci_internal->magic = 0;
1784 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1786 free_folder( p_fci_internal, folder );
1788 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1790 free_file( p_fci_internal, file );
1792 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1794 free_data_block( p_fci_internal, block );
1797 close_temp_file( p_fci_internal, &p_fci_internal->data );
1799 /* data in and out buffers have to be removed */
1800 if (p_fci_internal->data_in!=NULL)
1801 p_fci_internal->free(p_fci_internal->data_in);
1802 if (p_fci_internal->data_out!=NULL)
1803 p_fci_internal->free(p_fci_internal->data_out);
1805 /* hfci can now be removed */
1806 p_fci_internal->free(hfci);
1807 return TRUE;