winex11: Use NtUserBuildHwndList for has_owned_popup implementation.
[wine.git] / dlls / cabinet / fci.c
blobe62399db1ba2878098eef42ebe3c1a806f3c8d67
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
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <zlib.h>
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winerror.h"
44 #include "winternl.h"
45 #include "fci.h"
46 #include "cabinet.h"
47 #include "wine/list.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
52 #ifdef WORDS_BIGENDIAN
53 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
54 #define fci_endian_uword(x) RtlUshortByteSwap(x)
55 #else
56 #define fci_endian_ulong(x) (x)
57 #define fci_endian_uword(x) (x)
58 #endif
61 typedef struct {
62 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
63 cab_ULONG reserved1;
64 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
65 cab_ULONG reserved2;
66 cab_ULONG coffFiles; /* offset to first CFFILE section */
67 cab_ULONG reserved3;
68 cab_UBYTE versionMinor; /* 3 */
69 cab_UBYTE versionMajor; /* 1 */
70 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
71 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
72 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
73 cab_UWORD setID; /* identification number of all cabinets in a set*/
74 cab_UWORD iCabinet; /* number of the cabinet in a set */
75 /* additional area if "flags" were set*/
76 } CFHEADER; /* minimum 36 bytes */
78 typedef struct {
79 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
80 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
81 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
82 /* additional area if reserve flag was set */
83 } CFFOLDER; /* minimum 8 bytes */
85 typedef struct {
86 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
87 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
88 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
89 /* for special values see below this structure*/
90 cab_UWORD date; /* last modification date*/
91 cab_UWORD time; /* last modification time*/
92 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
93 /* ... and a C string with the name of the file */
94 } CFFILE; /* 16 bytes + name of file */
97 typedef struct {
98 cab_ULONG csum; /* checksum of this entry*/
99 cab_UWORD cbData; /* number of compressed bytes */
100 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
101 /* optional reserved area */
102 /* compressed data */
103 } CFDATA;
105 struct temp_file
107 INT_PTR handle;
108 char name[CB_MAX_FILENAME];
111 struct folder
113 struct list entry;
114 struct list files_list;
115 struct list blocks_list;
116 struct temp_file data;
117 cab_ULONG data_start;
118 cab_UWORD data_count;
119 TCOMP compression;
122 struct file
124 struct list entry;
125 cab_ULONG size; /* uncompressed size */
126 cab_ULONG offset; /* offset in folder */
127 cab_UWORD folder; /* index of folder */
128 cab_UWORD date;
129 cab_UWORD time;
130 cab_UWORD attribs;
131 char name[1];
134 struct data_block
136 struct list entry;
137 cab_UWORD compressed;
138 cab_UWORD uncompressed;
141 typedef struct FCI_Int
143 unsigned int magic;
144 PERF perf;
145 PFNFCIFILEPLACED fileplaced;
146 PFNFCIALLOC alloc;
147 PFNFCIFREE free;
148 PFNFCIOPEN open;
149 PFNFCIREAD read;
150 PFNFCIWRITE write;
151 PFNFCICLOSE close;
152 PFNFCISEEK seek;
153 PFNFCIDELETE delete;
154 PFNFCIGETTEMPFILE gettemp;
155 CCAB ccab;
156 PCCAB pccab;
157 BOOL fPrevCab;
158 BOOL fNextCab;
159 BOOL fSplitFolder;
160 cab_ULONG statusFolderCopied;
161 cab_ULONG statusFolderTotal;
162 BOOL fGetNextCabInVain;
163 void *pv;
164 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
165 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
166 unsigned char data_in[CAB_BLOCKMAX]; /* uncompressed data blocks */
167 unsigned char data_out[2 * CAB_BLOCKMAX]; /* compressed data blocks */
168 cab_UWORD cdata_in;
169 ULONG cCompressedBytesInFolder;
170 cab_UWORD cFolders;
171 cab_UWORD cFiles;
172 cab_ULONG cDataBlocks;
173 cab_ULONG cbFileRemainder; /* uncompressed, yet to be written data */
174 /* of spanned file of a spanning folder of a spanning cabinet */
175 struct temp_file data;
176 BOOL fNewPrevious;
177 cab_ULONG estimatedCabinetSize;
178 struct list folders_list;
179 struct list files_list;
180 struct list blocks_list;
181 cab_ULONG folders_size;
182 cab_ULONG files_size; /* size of files not yet assigned to a folder */
183 cab_ULONG placed_files_size; /* size of files already placed into a folder */
184 cab_ULONG pending_data_size; /* size of data not yet assigned to a folder */
185 cab_ULONG folders_data_size; /* total size of data contained in the current folders */
186 TCOMP compression;
187 cab_UWORD (*compress)(struct FCI_Int *);
188 } FCI_Int;
190 #define FCI_INT_MAGIC 0xfcfcfc05
192 static void set_error( FCI_Int *fci, int oper, int err )
194 fci->perf->erfOper = oper;
195 fci->perf->erfType = err;
196 fci->perf->fError = TRUE;
197 if (err) SetLastError( err );
200 static FCI_Int *get_fci_ptr( HFCI hfci )
202 FCI_Int *fci= (FCI_Int *)hfci;
204 if (!fci || fci->magic != FCI_INT_MAGIC)
206 SetLastError( ERROR_INVALID_HANDLE );
207 return NULL;
209 return fci;
212 /* compute the cabinet header size */
213 static cab_ULONG get_header_size( FCI_Int *fci )
215 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
217 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
218 ret += 4;
220 if (fci->fPrevCab)
221 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
223 if (fci->fNextCab)
224 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
226 return ret;
229 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
231 int err;
233 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
235 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
236 return FALSE;
238 if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
239 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
241 set_error( fci, FCIERR_TEMP_FILE, err );
242 return FALSE;
244 return TRUE;
247 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
249 int err;
251 if (file->handle == -1) return TRUE;
252 if (fci->close( file->handle, &err, fci->pv ) == -1)
254 set_error( fci, FCIERR_TEMP_FILE, err );
255 return FALSE;
257 file->handle = -1;
258 if (fci->delete( file->name, &err, fci->pv ) == -1)
260 set_error( fci, FCIERR_TEMP_FILE, err );
261 return FALSE;
263 return TRUE;
266 static struct file *add_file( FCI_Int *fci, const char *filename )
268 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
269 struct file *file = fci->alloc( size );
271 if (!file)
273 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
274 return NULL;
276 file->size = 0;
277 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
278 file->folder = fci->cFolders;
279 file->date = 0;
280 file->time = 0;
281 file->attribs = 0;
282 strcpy( file->name, filename );
283 list_add_tail( &fci->files_list, &file->entry );
284 fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
285 return file;
288 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
290 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
291 struct file *file = fci->alloc( size );
293 if (!file)
295 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
296 return NULL;
298 memcpy( file, orig, size );
299 return file;
302 static void free_file( FCI_Int *fci, struct file *file )
304 list_remove( &file->entry );
305 fci->free( file );
308 /* create a new data block for the data in fci->data_in */
309 static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
311 int err;
312 struct data_block *block;
314 if (!fci->cdata_in) return TRUE;
316 if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
318 if (!(block = fci->alloc( sizeof(*block) )))
320 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
321 return FALSE;
323 block->uncompressed = fci->cdata_in;
324 block->compressed = fci->compress( fci );
326 if (fci->write( fci->data.handle, fci->data_out,
327 block->compressed, &err, fci->pv ) != block->compressed)
329 set_error( fci, FCIERR_TEMP_FILE, err );
330 fci->free( block );
331 return FALSE;
334 fci->cdata_in = 0;
335 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
336 fci->cCompressedBytesInFolder += block->compressed;
337 fci->cDataBlocks++;
338 list_add_tail( &fci->blocks_list, &block->entry );
340 if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
342 set_error( fci, FCIERR_USER_ABORT, 0 );
343 return FALSE;
345 return TRUE;
348 /* add compressed blocks for all the data that can be read from the file */
349 static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
350 PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
352 int err, len;
353 INT_PTR handle;
354 struct file *file;
356 if (!(file = add_file( fci, filename ))) return FALSE;
358 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
359 if (handle == -1)
361 free_file( fci, file );
362 set_error( fci, FCIERR_OPEN_SRC, err );
363 return FALSE;
365 if (execute) file->attribs |= _A_EXEC;
367 for (;;)
369 len = fci->read( handle, fci->data_in + fci->cdata_in,
370 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
371 if (!len) break;
373 if (len == -1)
375 set_error( fci, FCIERR_READ_SRC, err );
376 return FALSE;
378 file->size += len;
379 fci->cdata_in += len;
380 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
382 fci->close( handle, &err, fci->pv );
383 return TRUE;
386 static void free_data_block( FCI_Int *fci, struct data_block *block )
388 list_remove( &block->entry );
389 fci->free( block );
392 static struct folder *add_folder( FCI_Int *fci )
394 struct folder *folder = fci->alloc( sizeof(*folder) );
396 if (!folder)
398 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
399 return NULL;
401 folder->data.handle = -1;
402 folder->data_start = fci->folders_data_size;
403 folder->data_count = 0;
404 folder->compression = fci->compression;
405 list_init( &folder->files_list );
406 list_init( &folder->blocks_list );
407 list_add_tail( &fci->folders_list, &folder->entry );
408 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
409 fci->cFolders++;
410 return folder;
413 static void free_folder( FCI_Int *fci, struct folder *folder )
415 struct file *file, *file_next;
416 struct data_block *block, *block_next;
418 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
419 free_file( fci, file );
420 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
421 free_data_block( fci, block );
422 close_temp_file( fci, &folder->data );
423 list_remove( &folder->entry );
424 fci->free( folder );
427 /* reset state for the next cabinet file once the current one has been flushed */
428 static void reset_cabinet( FCI_Int *fci )
430 struct folder *folder, *folder_next;
432 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
433 free_folder( fci, folder );
435 fci->cFolders = 0;
436 fci->cFiles = 0;
437 fci->folders_size = 0;
438 fci->placed_files_size = 0;
439 fci->folders_data_size = 0;
442 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
444 cab_ULONG csum;
445 cab_ULONG ul;
446 int cUlong;
447 const BYTE *pb;
449 csum = seed;
450 cUlong = cb / 4;
451 pb = pv;
453 while (cUlong-- > 0) {
454 ul = *pb++;
455 ul |= (((cab_ULONG)(*pb++)) << 8);
456 ul |= (((cab_ULONG)(*pb++)) << 16);
457 ul |= (((cab_ULONG)(*pb++)) << 24);
458 csum ^= ul;
461 ul = 0;
462 switch (cb % 4) {
463 case 3:
464 ul |= (((ULONG)(*pb++)) << 16);
465 /* fall through */
466 case 2:
467 ul |= (((ULONG)(*pb++)) << 8);
468 /* fall through */
469 case 1:
470 ul |= *pb;
471 /* fall through */
472 default:
473 break;
475 csum ^= ul;
477 return csum;
480 /* copy all remaining data block to a new temp file */
481 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
482 struct temp_file *temp, PFNFCISTATUS status_callback )
484 struct data_block *block;
485 int err;
487 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
489 set_error( fci, FCIERR_TEMP_FILE, err );
490 return FALSE;
492 if (!create_temp_file( fci, temp )) return FALSE;
494 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
496 if (fci->read( handle, fci->data_out, block->compressed,
497 &err, fci->pv ) != block->compressed)
499 close_temp_file( fci, temp );
500 set_error( fci, FCIERR_TEMP_FILE, err );
501 return FALSE;
503 if (fci->write( temp->handle, fci->data_out, block->compressed,
504 &err, fci->pv ) != block->compressed)
506 close_temp_file( fci, temp );
507 set_error( fci, FCIERR_TEMP_FILE, err );
508 return FALSE;
510 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
511 fci->statusFolderCopied += block->compressed;
513 if (status_callback( statusFolder, fci->statusFolderCopied,
514 fci->statusFolderTotal, fci->pv) == -1)
516 close_temp_file( fci, temp );
517 set_error( fci, FCIERR_USER_ABORT, 0 );
518 return FALSE;
521 return TRUE;
524 /* write all folders to disk and remove them from the list */
525 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
527 struct folder *folder;
528 int err;
529 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
530 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
532 memset( cffolder, 0, folder_size );
534 /* write the folders */
535 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
537 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
538 cffolder->cCFData = fci_endian_uword( folder->data_count );
539 cffolder->typeCompress = fci_endian_uword( folder->compression );
540 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
542 set_error( fci, FCIERR_CAB_FILE, err );
543 return FALSE;
546 return TRUE;
549 /* write all the files to the cabinet file */
550 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
552 cab_ULONG file_size;
553 struct folder *folder;
554 struct file *file;
555 int err;
556 CFFILE *cffile = (CFFILE *)fci->data_out;
558 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
560 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
562 cffile->cbFile = fci_endian_ulong( file->size );
563 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
564 cffile->iFolder = fci_endian_uword( file->folder );
565 cffile->date = fci_endian_uword( file->date );
566 cffile->time = fci_endian_uword( file->time );
567 cffile->attribs = fci_endian_uword( file->attribs );
568 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
569 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
570 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
572 set_error( fci, FCIERR_CAB_FILE, err );
573 return FALSE;
575 if (!fci->fSplitFolder)
577 fci->statusFolderCopied = 0;
578 /* TODO TEST THIS further */
579 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
581 fci->statusFolderCopied += file_size;
582 /* report status about copied size of folder */
583 if (status_callback( statusFolder, fci->statusFolderCopied,
584 fci->statusFolderTotal, fci->pv ) == -1)
586 set_error( fci, FCIERR_USER_ABORT, 0 );
587 return FALSE;
591 return TRUE;
594 /* write all data blocks to the cabinet file */
595 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
597 struct folder *folder;
598 struct data_block *block;
599 int err, len;
600 CFDATA *cfdata;
601 void *data;
602 cab_UWORD header_size;
604 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
605 cfdata = (CFDATA *)fci->data_out;
606 memset( cfdata, 0, header_size );
607 data = (char *)cfdata + header_size;
609 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
611 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
613 set_error( fci, FCIERR_CAB_FILE, err );
614 return FALSE;
616 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
618 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
619 if (len != block->compressed) return FALSE;
621 cfdata->cbData = fci_endian_uword( block->compressed );
622 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
623 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
624 header_size - FIELD_OFFSET(CFDATA, cbData),
625 fci_get_checksum( data, len, 0 )));
627 fci->statusFolderCopied += len;
628 len += header_size;
629 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
631 set_error( fci, FCIERR_CAB_FILE, err );
632 return FALSE;
634 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
636 set_error( fci, FCIERR_USER_ABORT, 0 );
637 return FALSE;
641 return TRUE;
644 /* write the cabinet file to disk */
645 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
647 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
648 int err;
649 char *ptr;
650 INT_PTR handle;
651 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
652 cab_UWORD flags = 0;
653 cab_ULONG header_size = get_header_size( fci );
654 cab_ULONG total_size = header_size + fci->folders_size +
655 fci->placed_files_size + fci->folders_data_size;
657 assert( header_size <= sizeof(fci->data_out) );
658 memset( cfheader, 0, header_size );
660 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
661 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
662 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
663 flags |= cfheadRESERVE_PRESENT;
665 memcpy( cfheader->signature, "!CAB", 4 );
666 cfheader->cbCabinet = fci_endian_ulong( total_size );
667 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
668 cfheader->versionMinor = 3;
669 cfheader->versionMajor = 1;
670 cfheader->cFolders = fci_endian_uword( fci->cFolders );
671 cfheader->cFiles = fci_endian_uword( fci->cFiles );
672 cfheader->flags = fci_endian_uword( flags );
673 cfheader->setID = fci_endian_uword( fci->ccab.setID );
674 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
675 ptr = (char *)(cfheader + 1);
677 if (flags & cfheadRESERVE_PRESENT)
679 struct
681 cab_UWORD cbCFHeader;
682 cab_UBYTE cbCFFolder;
683 cab_UBYTE cbCFData;
684 } *reserve = (void *)ptr;
686 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
687 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
688 reserve->cbCFData = fci->ccab.cbReserveCFData;
689 ptr = (char *)(reserve + 1);
691 ptr += fci->ccab.cbReserveCFHeader;
693 if (flags & cfheadPREV_CABINET)
695 strcpy( ptr, fci->szPrevCab );
696 ptr += strlen( ptr ) + 1;
697 strcpy( ptr, fci->szPrevDisk );
698 ptr += strlen( ptr ) + 1;
701 if (flags & cfheadNEXT_CABINET)
703 strcpy( ptr, fci->pccab->szCab );
704 ptr += strlen( ptr ) + 1;
705 strcpy( ptr, fci->pccab->szDisk );
706 ptr += strlen( ptr ) + 1;
709 assert( ptr - (char *)cfheader == header_size );
711 strcpy( filename, fci->ccab.szCabPath );
712 strcat( filename, fci->ccab.szCab );
714 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
715 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
717 set_error( fci, FCIERR_CAB_FILE, err );
718 return FALSE;
721 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
723 set_error( fci, FCIERR_CAB_FILE, err );
724 goto failed;
727 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
728 header_size += fci->placed_files_size + fci->folders_size;
729 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
730 if (!write_files( fci, handle, status_callback )) goto failed;
731 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
733 /* update the signature */
734 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
736 set_error( fci, FCIERR_CAB_FILE, err );
737 goto failed;
739 memcpy( cfheader->signature, "MSCF", 4 );
740 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
742 set_error( fci, FCIERR_CAB_FILE, err );
743 goto failed;
745 fci->close( handle, &err, fci->pv );
747 reset_cabinet( fci );
748 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
749 return TRUE;
751 failed:
752 fci->close( handle, &err, fci->pv );
753 fci->delete( filename, &err, fci->pv );
754 return FALSE;
757 /* add all pending data blocks folder */
758 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
759 PFNFCISTATUS status_callback )
761 struct data_block *block, *new, *next;
762 BOOL split_block = FALSE;
763 cab_ULONG current_size, start_pos = 0;
765 *payload = 0;
766 current_size = get_header_size( fci ) + fci->folders_size +
767 fci->files_size + fci->placed_files_size + fci->folders_data_size;
769 /* move the temp file into the folder structure */
770 folder->data = fci->data;
771 fci->data.handle = -1;
772 fci->pending_data_size = 0;
774 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
776 /* No more CFDATA fits into the cabinet under construction */
777 /* So don't try to store more data into it */
778 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
779 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
780 break;
782 if (!(new = fci->alloc( sizeof(*new) )))
784 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
785 return FALSE;
787 /* Is cabinet with new CFDATA too large? Then data block has to be split */
788 if( fci->fNextCab &&
789 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
790 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
792 /* Modify the size of the compressed data to store only a part of the */
793 /* data block into the current cabinet. This is done to prevent */
794 /* that the maximum cabinet size will be exceeded. The remainder */
795 /* will be stored into the next following cabinet. */
797 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
798 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
799 new->uncompressed = 0; /* on split blocks of data this is zero */
800 block->compressed -= new->compressed;
801 split_block = TRUE;
803 else
805 new->compressed = block->compressed;
806 new->uncompressed = block->uncompressed;
809 start_pos += new->compressed;
810 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
811 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
812 fci->statusFolderCopied += new->compressed;
813 (*payload) += new->uncompressed;
815 list_add_tail( &folder->blocks_list, &new->entry );
816 folder->data_count++;
818 /* report status with pfnfcis about copied size of folder */
819 if (status_callback( statusFolder, fci->statusFolderCopied,
820 fci->statusFolderTotal, fci->pv ) == -1)
822 set_error( fci, FCIERR_USER_ABORT, 0 );
823 return FALSE;
825 if (split_block) break;
826 free_data_block( fci, block );
827 fci->cDataBlocks--;
830 if (list_empty( &fci->blocks_list )) return TRUE;
831 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
834 /* add all pending files to folder */
835 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
837 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
838 cab_ULONG cbFileRemainder = 0;
839 struct file *file, *next;
841 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
843 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
845 /* fnfilfnfildest: placed file on cabinet */
846 fci->fileplaced( &fci->ccab, file->name, file->size,
847 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
849 sizeOfFilesPrev = sizeOfFiles;
850 /* set complete size of all processed files */
851 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainder != 0)
853 sizeOfFiles += fci->cbFileRemainder;
854 fci->cbFileRemainder = 0;
856 else sizeOfFiles += file->size;
858 /* check if spanned file fits into this cabinet folder */
859 if (sizeOfFiles > payload)
861 if (file->folder == cffileCONTINUED_FROM_PREV)
862 file->folder = cffileCONTINUED_PREV_AND_NEXT;
863 else
864 file->folder = cffileCONTINUED_TO_NEXT;
867 list_remove( &file->entry );
868 list_add_tail( &folder->files_list, &file->entry );
869 fci->placed_files_size += size;
870 fci->cFiles++;
872 /* This is only true for files which will be written into the */
873 /* next cabinet of the spanning folder */
874 if (sizeOfFiles > payload)
876 /* add a copy back onto the list */
877 if (!(file = copy_file( fci, file ))) return FALSE;
878 list_add_before( &next->entry, &file->entry );
880 /* Files which data will be partially written into the current cabinet */
881 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
883 if (sizeOfFilesPrev <= payload)
885 /* The size of the uncompressed, data of a spanning file in a */
886 /* spanning data */
887 cbFileRemainder = sizeOfFiles - payload;
889 file->folder = cffileCONTINUED_FROM_PREV;
891 else file->folder = 0;
893 else
895 fci->files_size -= size;
898 fci->cbFileRemainder = cbFileRemainder;
899 return TRUE;
902 static cab_UWORD compress_NONE( FCI_Int *fci )
904 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
905 return fci->cdata_in;
908 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
910 FCI_Int *fci = opaque;
911 return fci->alloc( items * size );
914 static void zfree( void *opaque, void *ptr )
916 FCI_Int *fci = opaque;
917 fci->free( ptr );
920 static cab_UWORD compress_MSZIP( FCI_Int *fci )
922 z_stream stream;
924 stream.zalloc = zalloc;
925 stream.zfree = zfree;
926 stream.opaque = fci;
927 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
929 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
930 return 0;
932 stream.next_in = fci->data_in;
933 stream.avail_in = fci->cdata_in;
934 stream.next_out = fci->data_out + 2;
935 stream.avail_out = sizeof(fci->data_out) - 2;
936 /* insert the signature */
937 fci->data_out[0] = 'C';
938 fci->data_out[1] = 'K';
939 deflate( &stream, Z_FINISH );
940 deflateEnd( &stream );
941 return stream.total_out + 2;
945 /***********************************************************************
946 * FCICreate (CABINET.10)
948 * FCICreate is provided with several callbacks and
949 * returns a handle which can be used to create cabinet files.
951 * PARAMS
952 * perf [IO] A pointer to an ERF structure. When FCICreate
953 * returns an error condition, error information may
954 * be found here as well as from GetLastError.
955 * pfnfiledest [I] A pointer to a function which is called when a file
956 * is placed. Only useful for subsequent cabinet files.
957 * pfnalloc [I] A pointer to a function which allocates ram. Uses
958 * the same interface as malloc.
959 * pfnfree [I] A pointer to a function which frees ram. Uses the
960 * same interface as free.
961 * pfnopen [I] A pointer to a function which opens a file. Uses
962 * the same interface as _open.
963 * pfnread [I] A pointer to a function which reads from a file into
964 * a caller-provided buffer. Uses the same interface
965 * as _read.
966 * pfnwrite [I] A pointer to a function which writes to a file from
967 * a caller-provided buffer. Uses the same interface
968 * as _write.
969 * pfnclose [I] A pointer to a function which closes a file handle.
970 * Uses the same interface as _close.
971 * pfnseek [I] A pointer to a function which seeks in a file.
972 * Uses the same interface as _lseek.
973 * pfndelete [I] A pointer to a function which deletes a file.
974 * pfnfcigtf [I] A pointer to a function which gets the name of a
975 * temporary file.
976 * pccab [I] A pointer to an initialized CCAB structure.
977 * pv [I] A pointer to an application-defined notification
978 * function which will be passed to other FCI functions
979 * as a parameter.
981 * RETURNS
982 * On success, returns an FCI handle of type HFCI.
983 * On failure, the NULL file handle is returned. Error
984 * info can be retrieved from perf.
986 * INCLUDES
987 * fci.h
990 HFCI __cdecl FCICreate(
991 PERF perf,
992 PFNFCIFILEPLACED pfnfiledest,
993 PFNFCIALLOC pfnalloc,
994 PFNFCIFREE pfnfree,
995 PFNFCIOPEN pfnopen,
996 PFNFCIREAD pfnread,
997 PFNFCIWRITE pfnwrite,
998 PFNFCICLOSE pfnclose,
999 PFNFCISEEK pfnseek,
1000 PFNFCIDELETE pfndelete,
1001 PFNFCIGETTEMPFILE pfnfcigtf,
1002 PCCAB pccab,
1003 void *pv)
1005 FCI_Int *p_fci_internal;
1007 if (!perf) {
1008 SetLastError(ERROR_BAD_ARGUMENTS);
1009 return NULL;
1011 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1012 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1013 (!pfnfcigtf) || (!pccab)) {
1014 perf->erfOper = FCIERR_NONE;
1015 perf->erfType = ERROR_BAD_ARGUMENTS;
1016 perf->fError = TRUE;
1018 SetLastError(ERROR_BAD_ARGUMENTS);
1019 return NULL;
1022 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1023 perf->erfOper = FCIERR_ALLOC_FAIL;
1024 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1025 perf->fError = TRUE;
1027 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1028 return NULL;
1031 memset(p_fci_internal, 0, sizeof(FCI_Int));
1032 p_fci_internal->magic = FCI_INT_MAGIC;
1033 p_fci_internal->perf = perf;
1034 p_fci_internal->fileplaced = pfnfiledest;
1035 p_fci_internal->alloc = pfnalloc;
1036 p_fci_internal->free = pfnfree;
1037 p_fci_internal->open = pfnopen;
1038 p_fci_internal->read = pfnread;
1039 p_fci_internal->write = pfnwrite;
1040 p_fci_internal->close = pfnclose;
1041 p_fci_internal->seek = pfnseek;
1042 p_fci_internal->delete = pfndelete;
1043 p_fci_internal->gettemp = pfnfcigtf;
1044 p_fci_internal->ccab = *pccab;
1045 p_fci_internal->pccab = pccab;
1046 p_fci_internal->pv = pv;
1047 p_fci_internal->data.handle = -1;
1048 p_fci_internal->compress = compress_NONE;
1050 list_init( &p_fci_internal->folders_list );
1051 list_init( &p_fci_internal->files_list );
1052 list_init( &p_fci_internal->blocks_list );
1054 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1055 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1057 return (HFCI)p_fci_internal;
1063 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1064 BOOL fGetNextCab,
1065 PFNFCIGETNEXTCABINET pfnfcignc,
1066 PFNFCISTATUS pfnfcis)
1068 cab_ULONG payload;
1069 cab_ULONG read_result;
1070 struct folder *folder;
1072 if ((!pfnfcignc) || (!pfnfcis)) {
1073 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1074 return FALSE;
1077 if( p_fci_internal->fGetNextCabInVain &&
1078 p_fci_internal->fNextCab ){
1079 /* internal error */
1080 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1081 return FALSE;
1084 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1085 /* this function will return TRUE */
1086 if( p_fci_internal->files_size == 0 ) {
1087 if ( p_fci_internal->pending_data_size != 0 ) {
1088 /* error handling */
1089 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1090 return FALSE;
1092 return TRUE;
1095 /* FCIFlushFolder has already been called... */
1096 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1097 return TRUE;
1100 /* This can be set already, because it makes only a difference */
1101 /* when the current function exits with return FALSE */
1102 p_fci_internal->fSplitFolder=FALSE;
1104 /* START of COPY */
1105 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1107 /* reset to get the number of data blocks of this folder which are */
1108 /* actually in this cabinet ( at least partially ) */
1109 p_fci_internal->cDataBlocks=0;
1111 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1112 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1113 p_fci_internal->placed_files_size+
1114 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1115 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1116 p_fci_internal->statusFolderCopied = 0;
1118 /* report status with pfnfcis about copied size of folder */
1119 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1120 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1121 p_fci_internal->pv) == -1) {
1122 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1123 return FALSE;
1126 /* USE the variable read_result */
1127 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1128 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1130 if(p_fci_internal->files_size!=0) {
1131 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1134 /* Check if multiple cabinets have to be created. */
1136 /* Might be too much data for the maximum allowed cabinet size.*/
1137 /* When any further data will be added later, it might not */
1138 /* be possible to flush the cabinet, because there might */
1139 /* not be enough space to store the name of the following */
1140 /* cabinet and name of the corresponding disk. */
1141 /* So take care of this and get the name of the next cabinet */
1142 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1143 p_fci_internal->fNextCab==FALSE &&
1146 p_fci_internal->ccab.cb < read_result +
1147 p_fci_internal->pending_data_size +
1148 p_fci_internal->files_size +
1149 CB_MAX_CABINET_NAME + /* next cabinet name */
1150 CB_MAX_DISK_NAME /* next disk name */
1151 ) || fGetNextCab
1154 /* increment cabinet index */
1155 ++(p_fci_internal->pccab->iCab);
1156 /* get name of next cabinet */
1157 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1158 if (!(*pfnfcignc)(p_fci_internal->pccab,
1159 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1160 p_fci_internal->pv)) {
1161 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1162 return FALSE;
1165 /* Skip a few lines of code. This is caught by the next if. */
1166 p_fci_internal->fGetNextCabInVain=TRUE;
1169 /* too much data for cabinet */
1170 if( (p_fci_internal->fGetNextCabInVain ||
1171 p_fci_internal->fNextCab ) &&
1174 p_fci_internal->ccab.cb < read_result +
1175 p_fci_internal->pending_data_size +
1176 p_fci_internal->files_size +
1177 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1178 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1179 ) || fGetNextCab
1182 p_fci_internal->fGetNextCabInVain=FALSE;
1183 p_fci_internal->fNextCab=TRUE;
1185 /* return FALSE if there is not enough space left*/
1186 /* this should never happen */
1187 if (p_fci_internal->ccab.cb <=
1188 p_fci_internal->files_size +
1189 read_result +
1190 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1191 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1194 return FALSE;
1197 /* the folder will be split across cabinets */
1198 p_fci_internal->fSplitFolder=TRUE;
1200 } else {
1201 /* this should never happen */
1202 if (p_fci_internal->fNextCab) {
1203 /* internal error */
1204 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1205 return FALSE;
1209 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1210 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1211 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1213 /* reset CFFolder specific information */
1214 p_fci_internal->cDataBlocks=0;
1215 p_fci_internal->cCompressedBytesInFolder=0;
1217 return TRUE;
1223 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1224 BOOL fGetNextCab,
1225 PFNFCIGETNEXTCABINET pfnfcignc,
1226 PFNFCISTATUS pfnfcis)
1228 cab_ULONG read_result=0;
1229 BOOL returntrue=FALSE;
1231 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1233 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1234 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1235 returntrue=TRUE;
1238 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1239 /* TODO set error */
1240 return FALSE;
1243 if(returntrue) return TRUE;
1245 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1246 (p_fci_internal->folders_size==0 &&
1247 (p_fci_internal->files_size!=0 ||
1248 p_fci_internal->placed_files_size!=0 )
1251 /* error */
1252 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1253 return FALSE;
1256 /* create the cabinet */
1257 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1259 p_fci_internal->fPrevCab=TRUE;
1260 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1261 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1263 if (p_fci_internal->fNextCab) {
1264 p_fci_internal->fNextCab=FALSE;
1266 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1267 /* THIS CAN NEVER HAPPEN */
1268 /* set error code */
1269 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1270 return FALSE;
1273 if( p_fci_internal->fNewPrevious ) {
1274 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1275 CB_MAX_CABINET_NAME);
1276 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1277 CB_MAX_DISK_NAME);
1278 p_fci_internal->fNewPrevious=FALSE;
1280 p_fci_internal->ccab = *p_fci_internal->pccab;
1282 /* REUSE the variable read_result */
1283 read_result=get_header_size( p_fci_internal );
1284 if(p_fci_internal->files_size!=0) {
1285 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1287 read_result+= p_fci_internal->pending_data_size +
1288 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1289 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1290 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1292 /* too much data for the maximum size of a cabinet */
1293 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1294 p_fci_internal->ccab.cb < read_result ) {
1295 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1298 /* Might be too much data for the maximum size of a cabinet.*/
1299 /* When any further data will be added later, it might not */
1300 /* be possible to flush the cabinet, because there might */
1301 /* not be enough space to store the name of the following */
1302 /* cabinet and name of the corresponding disk. */
1303 /* So take care of this and get the name of the next cabinet */
1304 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1305 p_fci_internal->ccab.cb < read_result +
1306 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1307 )) {
1308 /* increment cabinet index */
1309 ++(p_fci_internal->pccab->iCab);
1310 /* get name of next cabinet */
1311 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1312 if (!(*pfnfcignc)(p_fci_internal->pccab,
1313 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1314 p_fci_internal->pv)) {
1315 /* error handling */
1316 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1317 return FALSE;
1319 /* Skip a few lines of code. This is caught by the next if. */
1320 p_fci_internal->fGetNextCabInVain=TRUE;
1323 /* too much data for cabinet */
1324 if (p_fci_internal->fGetNextCabInVain && (
1325 p_fci_internal->ccab.cb < read_result +
1326 strlen(p_fci_internal->ccab.szCab)+1+
1327 strlen(p_fci_internal->ccab.szDisk)+1
1328 )) {
1329 p_fci_internal->fGetNextCabInVain=FALSE;
1330 p_fci_internal->fNextCab=TRUE;
1331 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1334 /* if the FolderThreshold has been reached flush the folder automatically */
1335 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1336 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1338 if( p_fci_internal->files_size>0 ) {
1339 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1340 p_fci_internal->fNewPrevious=TRUE;
1342 } else {
1343 p_fci_internal->fNewPrevious=FALSE;
1344 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1345 /* THIS MAY NEVER HAPPEN */
1346 /* set error structures */
1347 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1348 return FALSE;
1352 return TRUE;
1353 } /* end of fci_flush_cabinet */
1359 /***********************************************************************
1360 * FCIAddFile (CABINET.11)
1362 * FCIAddFile adds a file to the to be created cabinet file
1364 * PARAMS
1365 * hfci [I] An HFCI from FCICreate
1366 * pszSourceFile [I] A pointer to a C string which contains the name and
1367 * location of the file which will be added to the cabinet
1368 * pszFileName [I] A pointer to a C string which contains the name under
1369 * which the file will be stored in the cabinet
1370 * fExecute [I] A boolean value which indicates if the file should be
1371 * executed after extraction of self extracting
1372 * executables
1373 * pfnfcignc [I] A pointer to a function which gets information about
1374 * the next cabinet
1375 * pfnfcis [IO] A pointer to a function which will report status
1376 * information about the compression process
1377 * pfnfcioi [I] A pointer to a function which reports file attributes
1378 * and time and date information
1379 * typeCompress [I] Compression type
1381 * RETURNS
1382 * On success, returns TRUE
1383 * On failure, returns FALSE
1385 * INCLUDES
1386 * fci.h
1389 BOOL __cdecl FCIAddFile(
1390 HFCI hfci,
1391 char *pszSourceFile,
1392 char *pszFileName,
1393 BOOL fExecute,
1394 PFNFCIGETNEXTCABINET pfnfcignc,
1395 PFNFCISTATUS pfnfcis,
1396 PFNFCIGETOPENINFO pfnfcigoi,
1397 TCOMP typeCompress)
1399 cab_ULONG read_result;
1400 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1402 if (!p_fci_internal) return FALSE;
1404 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1405 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1406 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1407 return FALSE;
1410 if (typeCompress != p_fci_internal->compression)
1412 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1413 switch (typeCompress)
1415 case tcompTYPE_MSZIP:
1416 p_fci_internal->compression = tcompTYPE_MSZIP;
1417 p_fci_internal->compress = compress_MSZIP;
1418 break;
1419 default:
1420 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1421 /* fall through */
1422 case tcompTYPE_NONE:
1423 p_fci_internal->compression = tcompTYPE_NONE;
1424 p_fci_internal->compress = compress_NONE;
1425 break;
1429 /* TODO check if pszSourceFile??? */
1431 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1432 /* internal error */
1433 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1434 return FALSE;
1437 if(p_fci_internal->fNextCab) {
1438 /* internal error */
1439 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1440 return FALSE;
1443 /* REUSE the variable read_result */
1444 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1446 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1447 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1448 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1449 sizeof(CFFOLDER); /* size of new CFFolder entry */
1451 /* Might be too much data for the maximum size of a cabinet.*/
1452 /* When any further data will be added later, it might not */
1453 /* be possible to flush the cabinet, because there might */
1454 /* not be enough space to store the name of the following */
1455 /* cabinet and name of the corresponding disk. */
1456 /* So take care of this and get the name of the next cabinet */
1457 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1458 p_fci_internal->fNextCab==FALSE &&
1459 ( p_fci_internal->ccab.cb < read_result +
1460 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1463 /* increment cabinet index */
1464 ++(p_fci_internal->pccab->iCab);
1465 /* get name of next cabinet */
1466 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1467 if (!(*pfnfcignc)(p_fci_internal->pccab,
1468 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1469 p_fci_internal->pv)) {
1470 /* error handling */
1471 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1472 return FALSE;
1474 /* Skip a few lines of code. This is caught by the next if. */
1475 p_fci_internal->fGetNextCabInVain=TRUE;
1478 if( p_fci_internal->fGetNextCabInVain &&
1479 p_fci_internal->fNextCab
1481 /* THIS CAN NEVER HAPPEN */
1482 /* set error code */
1483 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1484 return FALSE;
1487 /* too much data for cabinet */
1488 if( p_fci_internal->fGetNextCabInVain &&
1490 p_fci_internal->ccab.cb < read_result +
1491 strlen(p_fci_internal->pccab->szCab)+1+
1492 strlen(p_fci_internal->pccab->szDisk)+1
1493 )) {
1494 p_fci_internal->fGetNextCabInVain=FALSE;
1495 p_fci_internal->fNextCab=TRUE;
1496 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1499 if( p_fci_internal->fNextCab ) {
1500 /* THIS MAY NEVER HAPPEN */
1501 /* set error code */
1502 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1503 return FALSE;
1506 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1507 return FALSE;
1509 /* REUSE the variable read_result */
1510 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1511 read_result+= p_fci_internal->pending_data_size +
1512 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1513 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1514 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1516 /* too much data for the maximum size of a cabinet */
1517 /* (ignoring the unflushed data block) */
1518 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1519 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1520 p_fci_internal->ccab.cb < read_result ) {
1521 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1524 /* Might be too much data for the maximum size of a cabinet.*/
1525 /* When any further data will be added later, it might not */
1526 /* be possible to flush the cabinet, because there might */
1527 /* not be enough space to store the name of the following */
1528 /* cabinet and name of the corresponding disk. */
1529 /* So take care of this and get the name of the next cabinet */
1530 /* (ignoring the unflushed data block) */
1531 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1532 p_fci_internal->fNextCab==FALSE &&
1533 ( p_fci_internal->ccab.cb < read_result +
1534 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1537 /* increment cabinet index */
1538 ++(p_fci_internal->pccab->iCab);
1539 /* get name of next cabinet */
1540 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1541 if (!(*pfnfcignc)(p_fci_internal->pccab,
1542 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1543 p_fci_internal->pv)) {
1544 /* error handling */
1545 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1546 return FALSE;
1548 /* Skip a few lines of code. This is caught by the next if. */
1549 p_fci_internal->fGetNextCabInVain=TRUE;
1552 if( p_fci_internal->fGetNextCabInVain &&
1553 p_fci_internal->fNextCab
1555 /* THIS CAN NEVER HAPPEN */
1556 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1557 return FALSE;
1560 /* too much data for cabinet */
1561 if( (p_fci_internal->fGetNextCabInVain ||
1562 p_fci_internal->fNextCab) && (
1563 p_fci_internal->ccab.cb < read_result +
1564 strlen(p_fci_internal->pccab->szCab)+1+
1565 strlen(p_fci_internal->pccab->szDisk)+1
1566 )) {
1568 p_fci_internal->fGetNextCabInVain=FALSE;
1569 p_fci_internal->fNextCab=TRUE;
1570 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1573 if( p_fci_internal->fNextCab ) {
1574 /* THIS MAY NEVER HAPPEN */
1575 /* set error code */
1576 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1577 return FALSE;
1580 /* if the FolderThreshold has been reached flush the folder automatically */
1581 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1582 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1584 return TRUE;
1585 } /* end of FCIAddFile */
1591 /***********************************************************************
1592 * FCIFlushFolder (CABINET.12)
1594 * FCIFlushFolder completes the CFFolder structure under construction.
1596 * All further data which is added by FCIAddFile will be associated to
1597 * the next CFFolder structure.
1599 * FCIFlushFolder will be called by FCIAddFile automatically if the
1600 * threshold (stored in the member cbFolderThresh of the CCAB structure
1601 * pccab passed to FCICreate) is exceeded.
1603 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1604 * any data will be written into the cabinet file.
1606 * PARAMS
1607 * hfci [I] An HFCI from FCICreate
1608 * pfnfcignc [I] A pointer to a function which gets information about
1609 * the next cabinet
1610 * pfnfcis [IO] A pointer to a function which will report status
1611 * information about the compression process
1613 * RETURNS
1614 * On success, returns TRUE
1615 * On failure, returns FALSE
1617 * INCLUDES
1618 * fci.h
1621 BOOL __cdecl FCIFlushFolder(
1622 HFCI hfci,
1623 PFNFCIGETNEXTCABINET pfnfcignc,
1624 PFNFCISTATUS pfnfcis)
1626 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1628 if (!p_fci_internal) return FALSE;
1629 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1634 /***********************************************************************
1635 * FCIFlushCabinet (CABINET.13)
1637 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1638 * into the cabinet file. If the maximum cabinet size (stored in the
1639 * member cb of the CCAB structure pccab passed to FCICreate) has been
1640 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1641 * The remaining data still has to be flushed manually by calling
1642 * FCIFlushCabinet.
1644 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1645 * NOT be called again. Then hfci has to be released by FCIDestroy.
1647 * PARAMS
1648 * hfci [I] An HFCI from FCICreate
1649 * fGetNextCab [I] Whether you want to add additional files to a
1650 * cabinet set (TRUE) or whether you want to
1651 * finalize it (FALSE)
1652 * pfnfcignc [I] A pointer to a function which gets information about
1653 * the next cabinet
1654 * pfnfcis [IO] A pointer to a function which will report status
1655 * information about the compression process
1657 * RETURNS
1658 * On success, returns TRUE
1659 * On failure, returns FALSE
1661 * INCLUDES
1662 * fci.h
1665 BOOL __cdecl FCIFlushCabinet(
1666 HFCI hfci,
1667 BOOL fGetNextCab,
1668 PFNFCIGETNEXTCABINET pfnfcignc,
1669 PFNFCISTATUS pfnfcis)
1671 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1673 if (!p_fci_internal) return FALSE;
1675 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1677 while( p_fci_internal->files_size>0 ||
1678 p_fci_internal->placed_files_size>0 ) {
1679 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1682 return TRUE;
1686 /***********************************************************************
1687 * FCIDestroy (CABINET.14)
1689 * Frees a handle created by FCICreate.
1690 * Only reason for failure would be an invalid handle.
1692 * PARAMS
1693 * hfci [I] The HFCI to free
1695 * RETURNS
1696 * TRUE for success
1697 * FALSE for failure
1699 BOOL __cdecl FCIDestroy(HFCI hfci)
1701 struct folder *folder, *folder_next;
1702 struct file *file, *file_next;
1703 struct data_block *block, *block_next;
1704 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1706 if (!p_fci_internal) return FALSE;
1708 /* before hfci can be removed all temporary files must be closed */
1709 /* and deleted */
1710 p_fci_internal->magic = 0;
1712 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1714 free_folder( p_fci_internal, folder );
1716 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1718 free_file( p_fci_internal, file );
1720 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1722 free_data_block( p_fci_internal, block );
1725 close_temp_file( p_fci_internal, &p_fci_internal->data );
1727 /* hfci can now be removed */
1728 p_fci_internal->free(hfci);
1729 return TRUE;