rpcrt4: Add stubs for RpcNetworkInqProtseqs.
[wine/multimedia.git] / dlls / cabinet / fci.c
blob82d94ab4f670681c8fa1763b2f5dd09d092a7b9b
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 case 2:
470 ul |= (((ULONG)(*pb++)) << 8);
471 case 1:
472 ul |= *pb;
473 default:
474 break;
476 csum ^= ul;
478 return csum;
481 /* copy all remaining data block to a new temp file */
482 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
483 struct temp_file *temp, PFNFCISTATUS status_callback )
485 struct data_block *block;
486 int err;
488 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
490 set_error( fci, FCIERR_TEMP_FILE, err );
491 return FALSE;
493 if (!create_temp_file( fci, temp )) return FALSE;
495 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
497 if (fci->read( handle, fci->data_out, block->compressed,
498 &err, fci->pv ) != block->compressed)
500 close_temp_file( fci, temp );
501 set_error( fci, FCIERR_TEMP_FILE, err );
502 return FALSE;
504 if (fci->write( temp->handle, fci->data_out, block->compressed,
505 &err, fci->pv ) != block->compressed)
507 close_temp_file( fci, temp );
508 set_error( fci, FCIERR_TEMP_FILE, err );
509 return FALSE;
511 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
512 fci->statusFolderCopied += block->compressed;
514 if (status_callback( statusFolder, fci->statusFolderCopied,
515 fci->statusFolderTotal, fci->pv) == -1)
517 close_temp_file( fci, temp );
518 set_error( fci, FCIERR_USER_ABORT, 0 );
519 return FALSE;
522 return TRUE;
525 /* write all folders to disk and remove them from the list */
526 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
528 struct folder *folder;
529 int err;
530 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
531 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
533 memset( cffolder, 0, folder_size );
535 /* write the folders */
536 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
538 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
539 cffolder->cCFData = fci_endian_uword( folder->data_count );
540 cffolder->typeCompress = fci_endian_uword( folder->compression );
541 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
543 set_error( fci, FCIERR_CAB_FILE, err );
544 return FALSE;
547 return TRUE;
550 /* write all the files to the cabinet file */
551 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
553 cab_ULONG file_size;
554 struct folder *folder;
555 struct file *file;
556 int err;
557 CFFILE *cffile = (CFFILE *)fci->data_out;
559 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
561 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
563 cffile->cbFile = fci_endian_ulong( file->size );
564 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
565 cffile->iFolder = fci_endian_uword( file->folder );
566 cffile->date = fci_endian_uword( file->date );
567 cffile->time = fci_endian_uword( file->time );
568 cffile->attribs = fci_endian_uword( file->attribs );
569 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
570 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
571 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
573 set_error( fci, FCIERR_CAB_FILE, err );
574 return FALSE;
576 if (!fci->fSplitFolder)
578 fci->statusFolderCopied = 0;
579 /* TODO TEST THIS further */
580 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
582 fci->statusFolderCopied += file_size;
583 /* report status about copied size of folder */
584 if (status_callback( statusFolder, fci->statusFolderCopied,
585 fci->statusFolderTotal, fci->pv ) == -1)
587 set_error( fci, FCIERR_USER_ABORT, 0 );
588 return FALSE;
592 return TRUE;
595 /* write all data blocks to the cabinet file */
596 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
598 struct folder *folder;
599 struct data_block *block;
600 int err, len;
601 CFDATA *cfdata;
602 void *data;
603 cab_UWORD header_size;
605 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
606 cfdata = (CFDATA *)fci->data_out;
607 memset( cfdata, 0, header_size );
608 data = (char *)cfdata + header_size;
610 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
612 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
614 set_error( fci, FCIERR_CAB_FILE, err );
615 return FALSE;
617 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
619 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
620 if (len != block->compressed) return FALSE;
622 cfdata->cbData = fci_endian_uword( block->compressed );
623 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
624 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
625 header_size - FIELD_OFFSET(CFDATA, cbData),
626 fci_get_checksum( data, len, 0 )));
628 fci->statusFolderCopied += len;
629 len += header_size;
630 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
632 set_error( fci, FCIERR_CAB_FILE, err );
633 return FALSE;
635 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
637 set_error( fci, FCIERR_USER_ABORT, 0 );
638 return FALSE;
642 return TRUE;
645 /* write the cabinet file to disk */
646 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
648 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
649 int err;
650 char *ptr;
651 INT_PTR handle;
652 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
653 cab_UWORD flags = 0;
654 cab_ULONG header_size = get_header_size( fci );
655 cab_ULONG total_size = header_size + fci->folders_size +
656 fci->placed_files_size + fci->folders_data_size;
658 assert( header_size <= sizeof(fci->data_out) );
659 memset( cfheader, 0, header_size );
661 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
662 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
663 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
664 flags |= cfheadRESERVE_PRESENT;
666 memcpy( cfheader->signature, "!CAB", 4 );
667 cfheader->cbCabinet = fci_endian_ulong( total_size );
668 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
669 cfheader->versionMinor = 3;
670 cfheader->versionMajor = 1;
671 cfheader->cFolders = fci_endian_uword( fci->cFolders );
672 cfheader->cFiles = fci_endian_uword( fci->cFiles );
673 cfheader->flags = fci_endian_uword( flags );
674 cfheader->setID = fci_endian_uword( fci->ccab.setID );
675 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
676 ptr = (char *)(cfheader + 1);
678 if (flags & cfheadRESERVE_PRESENT)
680 struct
682 cab_UWORD cbCFHeader;
683 cab_UBYTE cbCFFolder;
684 cab_UBYTE cbCFData;
685 } *reserve = (void *)ptr;
687 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
688 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
689 reserve->cbCFData = fci->ccab.cbReserveCFData;
690 ptr = (char *)(reserve + 1);
692 ptr += fci->ccab.cbReserveCFHeader;
694 if (flags & cfheadPREV_CABINET)
696 strcpy( ptr, fci->szPrevCab );
697 ptr += strlen( ptr ) + 1;
698 strcpy( ptr, fci->szPrevDisk );
699 ptr += strlen( ptr ) + 1;
702 if (flags & cfheadNEXT_CABINET)
704 strcpy( ptr, fci->pccab->szCab );
705 ptr += strlen( ptr ) + 1;
706 strcpy( ptr, fci->pccab->szDisk );
707 ptr += strlen( ptr ) + 1;
710 assert( ptr - (char *)cfheader == header_size );
712 strcpy( filename, fci->ccab.szCabPath );
713 strcat( filename, fci->ccab.szCab );
715 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
716 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
718 set_error( fci, FCIERR_CAB_FILE, err );
719 return FALSE;
722 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
724 set_error( fci, FCIERR_CAB_FILE, err );
725 goto failed;
728 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
729 header_size += fci->placed_files_size + fci->folders_size;
730 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
731 if (!write_files( fci, handle, status_callback )) goto failed;
732 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
734 /* update the signature */
735 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
737 set_error( fci, FCIERR_CAB_FILE, err );
738 goto failed;
740 memcpy( cfheader->signature, "MSCF", 4 );
741 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
743 set_error( fci, FCIERR_CAB_FILE, err );
744 goto failed;
746 fci->close( handle, &err, fci->pv );
748 reset_cabinet( fci );
749 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
750 return TRUE;
752 failed:
753 fci->close( handle, &err, fci->pv );
754 fci->delete( filename, &err, fci->pv );
755 return FALSE;
758 /* add all pending data blocks folder */
759 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
760 PFNFCISTATUS status_callback )
762 struct data_block *block, *new, *next;
763 BOOL split_block = FALSE;
764 cab_ULONG current_size, start_pos = 0;
766 *payload = 0;
767 current_size = get_header_size( fci ) + fci->folders_size +
768 fci->files_size + fci->placed_files_size + fci->folders_data_size;
770 /* move the temp file into the folder structure */
771 folder->data = fci->data;
772 fci->data.handle = -1;
773 fci->pending_data_size = 0;
775 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
777 /* No more CFDATA fits into the cabinet under construction */
778 /* So don't try to store more data into it */
779 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
780 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
781 break;
783 if (!(new = fci->alloc( sizeof(*new) )))
785 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
786 return FALSE;
788 /* Is cabinet with new CFDATA too large? Then data block has to be split */
789 if( fci->fNextCab &&
790 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
791 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
793 /* Modify the size of the compressed data to store only a part of the */
794 /* data block into the current cabinet. This is done to prevent */
795 /* that the maximum cabinet size will be exceeded. The remainder */
796 /* will be stored into the next following cabinet. */
798 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
799 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
800 new->uncompressed = 0; /* on split blocks of data this is zero */
801 block->compressed -= new->compressed;
802 split_block = TRUE;
804 else
806 new->compressed = block->compressed;
807 new->uncompressed = block->uncompressed;
810 start_pos += new->compressed;
811 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
812 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
813 fci->statusFolderCopied += new->compressed;
814 (*payload) += new->uncompressed;
816 list_add_tail( &folder->blocks_list, &new->entry );
817 folder->data_count++;
819 /* report status with pfnfcis about copied size of folder */
820 if (status_callback( statusFolder, fci->statusFolderCopied,
821 fci->statusFolderTotal, fci->pv ) == -1)
823 set_error( fci, FCIERR_USER_ABORT, 0 );
824 return FALSE;
826 if (split_block) break;
827 free_data_block( fci, block );
828 fci->cDataBlocks--;
831 if (list_empty( &fci->blocks_list )) return TRUE;
832 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
835 /* add all pending files to folder */
836 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
838 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
839 cab_ULONG cbFileRemainer = 0;
840 struct file *file, *next;
842 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
844 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
846 /* fnfilfnfildest: placed file on cabinet */
847 fci->fileplaced( &fci->ccab, file->name, file->size,
848 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
850 sizeOfFilesPrev = sizeOfFiles;
851 /* set complete size of all processed files */
852 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
854 sizeOfFiles += fci->cbFileRemainer;
855 fci->cbFileRemainer = 0;
857 else sizeOfFiles += file->size;
859 /* check if spanned file fits into this cabinet folder */
860 if (sizeOfFiles > payload)
862 if (file->folder == cffileCONTINUED_FROM_PREV)
863 file->folder = cffileCONTINUED_PREV_AND_NEXT;
864 else
865 file->folder = cffileCONTINUED_TO_NEXT;
868 list_remove( &file->entry );
869 list_add_tail( &folder->files_list, &file->entry );
870 fci->placed_files_size += size;
871 fci->cFiles++;
873 /* This is only true for files which will be written into the */
874 /* next cabinet of the spanning folder */
875 if (sizeOfFiles > payload)
877 /* add a copy back onto the list */
878 if (!(file = copy_file( fci, file ))) return FALSE;
879 list_add_before( &next->entry, &file->entry );
881 /* Files which data will be partially written into the current cabinet */
882 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
884 if (sizeOfFilesPrev <= payload)
886 /* The size of the uncompressed, data of a spanning file in a */
887 /* spanning data */
888 cbFileRemainer = sizeOfFiles - payload;
890 file->folder = cffileCONTINUED_FROM_PREV;
892 else file->folder = 0;
894 else
896 fci->files_size -= size;
899 fci->cbFileRemainer = cbFileRemainer;
900 return TRUE;
903 static cab_UWORD compress_NONE( FCI_Int *fci )
905 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
906 return fci->cdata_in;
909 #ifdef HAVE_ZLIB
911 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
913 FCI_Int *fci = opaque;
914 return fci->alloc( items * size );
917 static void zfree( void *opaque, void *ptr )
919 FCI_Int *fci = opaque;
920 return fci->free( ptr );
923 static cab_UWORD compress_MSZIP( FCI_Int *fci )
925 z_stream stream;
927 stream.zalloc = zalloc;
928 stream.zfree = zfree;
929 stream.opaque = fci;
930 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
932 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
933 return 0;
935 stream.next_in = fci->data_in;
936 stream.avail_in = fci->cdata_in;
937 stream.next_out = fci->data_out + 2;
938 stream.avail_out = sizeof(fci->data_out) - 2;
939 /* insert the signature */
940 fci->data_out[0] = 'C';
941 fci->data_out[1] = 'K';
942 deflate( &stream, Z_FINISH );
943 deflateEnd( &stream );
944 return stream.total_out + 2;
947 #endif /* HAVE_ZLIB */
950 /***********************************************************************
951 * FCICreate (CABINET.10)
953 * FCICreate is provided with several callbacks and
954 * returns a handle which can be used to create cabinet files.
956 * PARAMS
957 * perf [IO] A pointer to an ERF structure. When FCICreate
958 * returns an error condition, error information may
959 * be found here as well as from GetLastError.
960 * pfnfiledest [I] A pointer to a function which is called when a file
961 * is placed. Only useful for subsequent cabinet files.
962 * pfnalloc [I] A pointer to a function which allocates ram. Uses
963 * the same interface as malloc.
964 * pfnfree [I] A pointer to a function which frees ram. Uses the
965 * same interface as free.
966 * pfnopen [I] A pointer to a function which opens a file. Uses
967 * the same interface as _open.
968 * pfnread [I] A pointer to a function which reads from a file into
969 * a caller-provided buffer. Uses the same interface
970 * as _read.
971 * pfnwrite [I] A pointer to a function which writes to a file from
972 * a caller-provided buffer. Uses the same interface
973 * as _write.
974 * pfnclose [I] A pointer to a function which closes a file handle.
975 * Uses the same interface as _close.
976 * pfnseek [I] A pointer to a function which seeks in a file.
977 * Uses the same interface as _lseek.
978 * pfndelete [I] A pointer to a function which deletes a file.
979 * pfnfcigtf [I] A pointer to a function which gets the name of a
980 * temporary file.
981 * pccab [I] A pointer to an initialized CCAB structure.
982 * pv [I] A pointer to an application-defined notification
983 * function which will be passed to other FCI functions
984 * as a parameter.
986 * RETURNS
987 * On success, returns an FCI handle of type HFCI.
988 * On failure, the NULL file handle is returned. Error
989 * info can be retrieved from perf.
991 * INCLUDES
992 * fci.h
995 HFCI __cdecl FCICreate(
996 PERF perf,
997 PFNFCIFILEPLACED pfnfiledest,
998 PFNFCIALLOC pfnalloc,
999 PFNFCIFREE pfnfree,
1000 PFNFCIOPEN pfnopen,
1001 PFNFCIREAD pfnread,
1002 PFNFCIWRITE pfnwrite,
1003 PFNFCICLOSE pfnclose,
1004 PFNFCISEEK pfnseek,
1005 PFNFCIDELETE pfndelete,
1006 PFNFCIGETTEMPFILE pfnfcigtf,
1007 PCCAB pccab,
1008 void *pv)
1010 FCI_Int *p_fci_internal;
1012 if (!perf) {
1013 SetLastError(ERROR_BAD_ARGUMENTS);
1014 return NULL;
1016 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1017 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1018 (!pfnfcigtf) || (!pccab)) {
1019 perf->erfOper = FCIERR_NONE;
1020 perf->erfType = ERROR_BAD_ARGUMENTS;
1021 perf->fError = TRUE;
1023 SetLastError(ERROR_BAD_ARGUMENTS);
1024 return NULL;
1027 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1028 perf->erfOper = FCIERR_ALLOC_FAIL;
1029 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1030 perf->fError = TRUE;
1032 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1033 return NULL;
1036 p_fci_internal->magic = FCI_INT_MAGIC;
1037 p_fci_internal->perf = perf;
1038 p_fci_internal->fileplaced = pfnfiledest;
1039 p_fci_internal->alloc = pfnalloc;
1040 p_fci_internal->free = pfnfree;
1041 p_fci_internal->open = pfnopen;
1042 p_fci_internal->read = pfnread;
1043 p_fci_internal->write = pfnwrite;
1044 p_fci_internal->close = pfnclose;
1045 p_fci_internal->seek = pfnseek;
1046 p_fci_internal->delete = pfndelete;
1047 p_fci_internal->gettemp = pfnfcigtf;
1048 p_fci_internal->ccab = *pccab;
1049 p_fci_internal->pccab = pccab;
1050 p_fci_internal->fPrevCab = FALSE;
1051 p_fci_internal->fNextCab = FALSE;
1052 p_fci_internal->fSplitFolder = FALSE;
1053 p_fci_internal->fGetNextCabInVain = FALSE;
1054 p_fci_internal->pv = pv;
1055 p_fci_internal->cdata_in = 0;
1056 p_fci_internal->cCompressedBytesInFolder = 0;
1057 p_fci_internal->cFolders = 0;
1058 p_fci_internal->cFiles = 0;
1059 p_fci_internal->cDataBlocks = 0;
1060 p_fci_internal->data.handle = -1;
1061 p_fci_internal->fNewPrevious = FALSE;
1062 p_fci_internal->estimatedCabinetSize = 0;
1063 p_fci_internal->statusFolderTotal = 0;
1064 p_fci_internal->folders_size = 0;
1065 p_fci_internal->files_size = 0;
1066 p_fci_internal->placed_files_size = 0;
1067 p_fci_internal->pending_data_size = 0;
1068 p_fci_internal->folders_data_size = 0;
1069 p_fci_internal->compression = tcompTYPE_NONE;
1070 p_fci_internal->compress = compress_NONE;
1072 list_init( &p_fci_internal->folders_list );
1073 list_init( &p_fci_internal->files_list );
1074 list_init( &p_fci_internal->blocks_list );
1076 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1077 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1079 return (HFCI)p_fci_internal;
1085 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1086 BOOL fGetNextCab,
1087 PFNFCIGETNEXTCABINET pfnfcignc,
1088 PFNFCISTATUS pfnfcis)
1090 cab_ULONG payload;
1091 cab_ULONG read_result;
1092 struct folder *folder;
1094 if ((!pfnfcignc) || (!pfnfcis)) {
1095 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1096 return FALSE;
1099 if( p_fci_internal->fGetNextCabInVain &&
1100 p_fci_internal->fNextCab ){
1101 /* internal error */
1102 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1103 return FALSE;
1106 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1107 /* this function will return TRUE */
1108 if( p_fci_internal->files_size == 0 ) {
1109 if ( p_fci_internal->pending_data_size != 0 ) {
1110 /* error handling */
1111 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1112 return FALSE;
1114 return TRUE;
1117 /* FCIFlushFolder has already been called... */
1118 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1119 return TRUE;
1122 /* This can be set already, because it makes only a difference */
1123 /* when the current function exits with return FALSE */
1124 p_fci_internal->fSplitFolder=FALSE;
1126 /* START of COPY */
1127 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1129 /* reset to get the number of data blocks of this folder which are */
1130 /* actually in this cabinet ( at least partially ) */
1131 p_fci_internal->cDataBlocks=0;
1133 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1134 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1135 p_fci_internal->placed_files_size+
1136 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1137 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1138 p_fci_internal->statusFolderCopied = 0;
1140 /* report status with pfnfcis about copied size of folder */
1141 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1142 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1143 p_fci_internal->pv) == -1) {
1144 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1145 return FALSE;
1148 /* USE the variable read_result */
1149 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1150 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1152 if(p_fci_internal->files_size!=0) {
1153 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1156 /* Check if multiple cabinets have to be created. */
1158 /* Might be too much data for the maximum allowed cabinet size.*/
1159 /* When any further data will be added later, it might not */
1160 /* be possible to flush the cabinet, because there might */
1161 /* not be enough space to store the name of the following */
1162 /* cabinet and name of the corresponding disk. */
1163 /* So take care of this and get the name of the next cabinet */
1164 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1165 p_fci_internal->fNextCab==FALSE &&
1168 p_fci_internal->ccab.cb < read_result +
1169 p_fci_internal->pending_data_size +
1170 p_fci_internal->files_size +
1171 CB_MAX_CABINET_NAME + /* next cabinet name */
1172 CB_MAX_DISK_NAME /* next disk name */
1173 ) || fGetNextCab
1176 /* increment cabinet index */
1177 ++(p_fci_internal->pccab->iCab);
1178 /* get name of next cabinet */
1179 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1180 if (!(*pfnfcignc)(p_fci_internal->pccab,
1181 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1182 p_fci_internal->pv)) {
1183 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1184 return FALSE;
1187 /* Skip a few lines of code. This is caught by the next if. */
1188 p_fci_internal->fGetNextCabInVain=TRUE;
1191 /* too much data for cabinet */
1192 if( (p_fci_internal->fGetNextCabInVain ||
1193 p_fci_internal->fNextCab ) &&
1196 p_fci_internal->ccab.cb < read_result +
1197 p_fci_internal->pending_data_size +
1198 p_fci_internal->files_size +
1199 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1200 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1201 ) || fGetNextCab
1204 p_fci_internal->fGetNextCabInVain=FALSE;
1205 p_fci_internal->fNextCab=TRUE;
1207 /* return FALSE if there is not enough space left*/
1208 /* this should never happen */
1209 if (p_fci_internal->ccab.cb <=
1210 p_fci_internal->files_size +
1211 read_result +
1212 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1213 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1216 return FALSE;
1219 /* the folder will be split across cabinets */
1220 p_fci_internal->fSplitFolder=TRUE;
1222 } else {
1223 /* this should never happen */
1224 if (p_fci_internal->fNextCab) {
1225 /* internal error */
1226 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1227 return FALSE;
1231 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1232 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1233 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1235 /* reset CFFolder specific information */
1236 p_fci_internal->cDataBlocks=0;
1237 p_fci_internal->cCompressedBytesInFolder=0;
1239 return TRUE;
1245 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1246 BOOL fGetNextCab,
1247 PFNFCIGETNEXTCABINET pfnfcignc,
1248 PFNFCISTATUS pfnfcis)
1250 cab_ULONG read_result=0;
1251 BOOL returntrue=FALSE;
1253 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1255 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1256 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1257 returntrue=TRUE;
1260 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1261 /* TODO set error */
1262 return FALSE;
1265 if(returntrue) return TRUE;
1267 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1268 (p_fci_internal->folders_size==0 &&
1269 (p_fci_internal->files_size!=0 ||
1270 p_fci_internal->placed_files_size!=0 )
1273 /* error */
1274 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1275 return FALSE;
1278 /* create the cabinet */
1279 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1281 p_fci_internal->fPrevCab=TRUE;
1282 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1283 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1285 if (p_fci_internal->fNextCab) {
1286 p_fci_internal->fNextCab=FALSE;
1288 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1289 /* THIS CAN NEVER HAPPEN */
1290 /* set error code */
1291 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1292 return FALSE;
1295 if( p_fci_internal->fNewPrevious ) {
1296 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1297 CB_MAX_CABINET_NAME);
1298 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1299 CB_MAX_DISK_NAME);
1300 p_fci_internal->fNewPrevious=FALSE;
1302 p_fci_internal->ccab = *p_fci_internal->pccab;
1304 /* REUSE the variable read_result */
1305 read_result=get_header_size( p_fci_internal );
1306 if(p_fci_internal->files_size!=0) {
1307 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1309 read_result+= p_fci_internal->pending_data_size +
1310 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1311 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1312 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1314 /* too much data for the maximum size of a cabinet */
1315 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1316 p_fci_internal->ccab.cb < read_result ) {
1317 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1320 /* Might be too much data for the maximum size of a cabinet.*/
1321 /* When any further data will be added later, it might not */
1322 /* be possible to flush the cabinet, because there might */
1323 /* not be enough space to store the name of the following */
1324 /* cabinet and name of the corresponding disk. */
1325 /* So take care of this and get the name of the next cabinet */
1326 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1327 p_fci_internal->ccab.cb < read_result +
1328 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1329 )) {
1330 /* increment cabinet index */
1331 ++(p_fci_internal->pccab->iCab);
1332 /* get name of next cabinet */
1333 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1334 if (!(*pfnfcignc)(p_fci_internal->pccab,
1335 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1336 p_fci_internal->pv)) {
1337 /* error handling */
1338 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1339 return FALSE;
1341 /* Skip a few lines of code. This is caught by the next if. */
1342 p_fci_internal->fGetNextCabInVain=TRUE;
1345 /* too much data for cabinet */
1346 if (p_fci_internal->fGetNextCabInVain && (
1347 p_fci_internal->ccab.cb < read_result +
1348 strlen(p_fci_internal->ccab.szCab)+1+
1349 strlen(p_fci_internal->ccab.szDisk)+1
1350 )) {
1351 p_fci_internal->fGetNextCabInVain=FALSE;
1352 p_fci_internal->fNextCab=TRUE;
1353 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1356 /* if the FolderThreshold has been reached flush the folder automatically */
1357 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1358 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1360 if( p_fci_internal->files_size>0 ) {
1361 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1362 p_fci_internal->fNewPrevious=TRUE;
1364 } else {
1365 p_fci_internal->fNewPrevious=FALSE;
1366 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1367 /* THIS MAY NEVER HAPPEN */
1368 /* set error structures */
1369 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1370 return FALSE;
1374 return TRUE;
1375 } /* end of fci_flush_cabinet */
1381 /***********************************************************************
1382 * FCIAddFile (CABINET.11)
1384 * FCIAddFile adds a file to the to be created cabinet file
1386 * PARAMS
1387 * hfci [I] An HFCI from FCICreate
1388 * pszSourceFile [I] A pointer to a C string which contains the name and
1389 * location of the file which will be added to the cabinet
1390 * pszFileName [I] A pointer to a C string which contains the name under
1391 * which the file will be stored in the cabinet
1392 * fExecute [I] A boolean value which indicates if the file should be
1393 * executed after extraction of self extracting
1394 * executables
1395 * pfnfcignc [I] A pointer to a function which gets information about
1396 * the next cabinet
1397 * pfnfcis [IO] A pointer to a function which will report status
1398 * information about the compression process
1399 * pfnfcioi [I] A pointer to a function which reports file attributes
1400 * and time and date information
1401 * typeCompress [I] Compression type
1403 * RETURNS
1404 * On success, returns TRUE
1405 * On failure, returns FALSE
1407 * INCLUDES
1408 * fci.h
1411 BOOL __cdecl FCIAddFile(
1412 HFCI hfci,
1413 char *pszSourceFile,
1414 char *pszFileName,
1415 BOOL fExecute,
1416 PFNFCIGETNEXTCABINET pfnfcignc,
1417 PFNFCISTATUS pfnfcis,
1418 PFNFCIGETOPENINFO pfnfcigoi,
1419 TCOMP typeCompress)
1421 cab_ULONG read_result;
1422 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1424 if (!p_fci_internal) return FALSE;
1426 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1427 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1428 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1429 return FALSE;
1432 if (typeCompress != p_fci_internal->compression)
1434 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1435 switch (typeCompress)
1437 case tcompTYPE_MSZIP:
1438 #ifdef HAVE_ZLIB
1439 p_fci_internal->compression = tcompTYPE_MSZIP;
1440 p_fci_internal->compress = compress_MSZIP;
1441 break;
1442 #endif
1443 default:
1444 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1445 /* fall through */
1446 case tcompTYPE_NONE:
1447 p_fci_internal->compression = tcompTYPE_NONE;
1448 p_fci_internal->compress = compress_NONE;
1449 break;
1453 /* TODO check if pszSourceFile??? */
1455 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1456 /* internal error */
1457 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1458 return FALSE;
1461 if(p_fci_internal->fNextCab) {
1462 /* internal error */
1463 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1464 return FALSE;
1467 /* REUSE the variable read_result */
1468 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1470 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1471 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1472 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1473 sizeof(CFFOLDER); /* size of new CFFolder entry */
1475 /* Might be too much data for the maximum size of a cabinet.*/
1476 /* When any further data will be added later, it might not */
1477 /* be possible to flush the cabinet, because there might */
1478 /* not be enough space to store the name of the following */
1479 /* cabinet and name of the corresponding disk. */
1480 /* So take care of this and get the name of the next cabinet */
1481 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1482 p_fci_internal->fNextCab==FALSE &&
1483 ( p_fci_internal->ccab.cb < read_result +
1484 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1487 /* increment cabinet index */
1488 ++(p_fci_internal->pccab->iCab);
1489 /* get name of next cabinet */
1490 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1491 if (!(*pfnfcignc)(p_fci_internal->pccab,
1492 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1493 p_fci_internal->pv)) {
1494 /* error handling */
1495 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1496 return FALSE;
1498 /* Skip a few lines of code. This is caught by the next if. */
1499 p_fci_internal->fGetNextCabInVain=TRUE;
1502 if( p_fci_internal->fGetNextCabInVain &&
1503 p_fci_internal->fNextCab
1505 /* THIS CAN NEVER HAPPEN */
1506 /* set error code */
1507 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1508 return FALSE;
1511 /* too much data for cabinet */
1512 if( p_fci_internal->fGetNextCabInVain &&
1514 p_fci_internal->ccab.cb < read_result +
1515 strlen(p_fci_internal->pccab->szCab)+1+
1516 strlen(p_fci_internal->pccab->szDisk)+1
1517 )) {
1518 p_fci_internal->fGetNextCabInVain=FALSE;
1519 p_fci_internal->fNextCab=TRUE;
1520 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1523 if( p_fci_internal->fNextCab ) {
1524 /* THIS MAY NEVER HAPPEN */
1525 /* set error code */
1526 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1527 return FALSE;
1530 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1531 return FALSE;
1533 /* REUSE the variable read_result */
1534 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1535 read_result+= p_fci_internal->pending_data_size +
1536 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1537 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1538 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1540 /* too much data for the maximum size of a cabinet */
1541 /* (ignoring the unflushed data block) */
1542 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1543 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1544 p_fci_internal->ccab.cb < read_result ) {
1545 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1548 /* Might be too much data for the maximum size of a cabinet.*/
1549 /* When any further data will be added later, it might not */
1550 /* be possible to flush the cabinet, because there might */
1551 /* not be enough space to store the name of the following */
1552 /* cabinet and name of the corresponding disk. */
1553 /* So take care of this and get the name of the next cabinet */
1554 /* (ignoring the unflushed data block) */
1555 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1556 p_fci_internal->fNextCab==FALSE &&
1557 ( p_fci_internal->ccab.cb < read_result +
1558 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1561 /* increment cabinet index */
1562 ++(p_fci_internal->pccab->iCab);
1563 /* get name of next cabinet */
1564 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1565 if (!(*pfnfcignc)(p_fci_internal->pccab,
1566 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1567 p_fci_internal->pv)) {
1568 /* error handling */
1569 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1570 return FALSE;
1572 /* Skip a few lines of code. This is caught by the next if. */
1573 p_fci_internal->fGetNextCabInVain=TRUE;
1576 if( p_fci_internal->fGetNextCabInVain &&
1577 p_fci_internal->fNextCab
1579 /* THIS CAN NEVER HAPPEN */
1580 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1581 return FALSE;
1584 /* too much data for cabinet */
1585 if( (p_fci_internal->fGetNextCabInVain ||
1586 p_fci_internal->fNextCab) && (
1587 p_fci_internal->ccab.cb < read_result +
1588 strlen(p_fci_internal->pccab->szCab)+1+
1589 strlen(p_fci_internal->pccab->szDisk)+1
1590 )) {
1592 p_fci_internal->fGetNextCabInVain=FALSE;
1593 p_fci_internal->fNextCab=TRUE;
1594 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1597 if( p_fci_internal->fNextCab ) {
1598 /* THIS MAY NEVER HAPPEN */
1599 /* set error code */
1600 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1601 return FALSE;
1604 /* if the FolderThreshold has been reached flush the folder automatically */
1605 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1606 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1608 return TRUE;
1609 } /* end of FCIAddFile */
1615 /***********************************************************************
1616 * FCIFlushFolder (CABINET.12)
1618 * FCIFlushFolder completes the CFFolder structure under construction.
1620 * All further data which is added by FCIAddFile will be associated to
1621 * the next CFFolder structure.
1623 * FCIFlushFolder will be called by FCIAddFile automatically if the
1624 * threshold (stored in the member cbFolderThresh of the CCAB structure
1625 * pccab passed to FCICreate) is exceeded.
1627 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1628 * any data will be written into the cabinet file.
1630 * PARAMS
1631 * hfci [I] An HFCI from FCICreate
1632 * pfnfcignc [I] A pointer to a function which gets information about
1633 * the next cabinet
1634 * pfnfcis [IO] A pointer to a function which will report status
1635 * information about the compression process
1637 * RETURNS
1638 * On success, returns TRUE
1639 * On failure, returns FALSE
1641 * INCLUDES
1642 * fci.h
1645 BOOL __cdecl FCIFlushFolder(
1646 HFCI hfci,
1647 PFNFCIGETNEXTCABINET pfnfcignc,
1648 PFNFCISTATUS pfnfcis)
1650 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1652 if (!p_fci_internal) return FALSE;
1653 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1658 /***********************************************************************
1659 * FCIFlushCabinet (CABINET.13)
1661 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1662 * into the cabinet file. If the maximum cabinet size (stored in the
1663 * member cb of the CCAB structure pccab passed to FCICreate) has been
1664 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1665 * The remaining data still has to be flushed manually by calling
1666 * FCIFlushCabinet.
1668 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1669 * NOT be called again. Then hfci has to be released by FCIDestroy.
1671 * PARAMS
1672 * hfci [I] An HFCI from FCICreate
1673 * fGetNextCab [I] Whether you want to add additional files to a
1674 * cabinet set (TRUE) or whether you want to
1675 * finalize it (FALSE)
1676 * pfnfcignc [I] A pointer to a function which gets information about
1677 * the next cabinet
1678 * pfnfcis [IO] A pointer to a function which will report status
1679 * information about the compression process
1681 * RETURNS
1682 * On success, returns TRUE
1683 * On failure, returns FALSE
1685 * INCLUDES
1686 * fci.h
1689 BOOL __cdecl FCIFlushCabinet(
1690 HFCI hfci,
1691 BOOL fGetNextCab,
1692 PFNFCIGETNEXTCABINET pfnfcignc,
1693 PFNFCISTATUS pfnfcis)
1695 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1697 if (!p_fci_internal) return FALSE;
1699 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1701 while( p_fci_internal->files_size>0 ||
1702 p_fci_internal->placed_files_size>0 ) {
1703 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1706 return TRUE;
1710 /***********************************************************************
1711 * FCIDestroy (CABINET.14)
1713 * Frees a handle created by FCICreate.
1714 * Only reason for failure would be an invalid handle.
1716 * PARAMS
1717 * hfci [I] The HFCI to free
1719 * RETURNS
1720 * TRUE for success
1721 * FALSE for failure
1723 BOOL __cdecl FCIDestroy(HFCI hfci)
1725 struct folder *folder, *folder_next;
1726 struct file *file, *file_next;
1727 struct data_block *block, *block_next;
1728 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1730 if (!p_fci_internal) return FALSE;
1732 /* before hfci can be removed all temporary files must be closed */
1733 /* and deleted */
1734 p_fci_internal->magic = 0;
1736 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1738 free_folder( p_fci_internal, folder );
1740 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1742 free_file( p_fci_internal, file );
1744 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1746 free_data_block( p_fci_internal, block );
1749 close_temp_file( p_fci_internal, &p_fci_internal->data );
1751 /* hfci can now be removed */
1752 p_fci_internal->free(hfci);
1753 return TRUE;