* Sync up to trunk head (r64894).
[reactos.git] / dll / win32 / cabinet / fci.c
1 /*
2 * File Compression Interface
3 *
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2005 Gerold Jens Wucherpfennig
6 * Copyright 2011 Alexandre Julliard
7 *
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.
12 *
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.
17 *
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
21 */
22
23 /*
24
25 There is still some work to be done:
26
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
30
31 */
32
33 #include "cabinet.h"
34
35 #include <assert.h>
36 #include <fci.h>
37
38 #ifdef HAVE_ZLIB
39 # include <zlib.h>
40 #endif
41
42 #include <wine/list.h>
43
44 #ifdef WORDS_BIGENDIAN
45 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
46 #define fci_endian_uword(x) RtlUshortByteSwap(x)
47 #else
48 #define fci_endian_ulong(x) (x)
49 #define fci_endian_uword(x) (x)
50 #endif
51
52
53 typedef struct {
54 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
55 cab_ULONG reserved1;
56 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/
57 cab_ULONG reserved2;
58 cab_ULONG coffFiles; /* offset to first CFFILE section */
59 cab_ULONG reserved3;
60 cab_UBYTE versionMinor; /* 3 */
61 cab_UBYTE versionMajor; /* 1 */
62 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/
63 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/
64 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
65 cab_UWORD setID; /* identification number of all cabinets in a set*/
66 cab_UWORD iCabinet; /* number of the cabinet in a set */
67 /* additional area if "flags" were set*/
68 } CFHEADER; /* minimum 36 bytes */
69
70 typedef struct {
71 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
72 cab_UWORD cCFData; /* number of this folder's CFDATA sections */
73 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
74 /* additional area if reserve flag was set */
75 } CFFOLDER; /* minimum 8 bytes */
76
77 typedef struct {
78 cab_ULONG cbFile; /* size of the uncompressed file in bytes */
79 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
80 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
81 /* for special values see below this structure*/
82 cab_UWORD date; /* last modification date*/
83 cab_UWORD time; /* last modification time*/
84 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
85 /* ... and a C string with the name of the file */
86 } CFFILE; /* 16 bytes + name of file */
87
88
89 typedef struct {
90 cab_ULONG csum; /* checksum of this entry*/
91 cab_UWORD cbData; /* number of compressed bytes */
92 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
93 /* optional reserved area */
94 /* compressed data */
95 } CFDATA;
96
97 struct temp_file
98 {
99 INT_PTR handle;
100 char name[CB_MAX_FILENAME];
101 };
102
103 struct folder
104 {
105 struct list entry;
106 struct list files_list;
107 struct list blocks_list;
108 struct temp_file data;
109 cab_ULONG data_start;
110 cab_UWORD data_count;
111 TCOMP compression;
112 };
113
114 struct file
115 {
116 struct list entry;
117 cab_ULONG size; /* uncompressed size */
118 cab_ULONG offset; /* offset in folder */
119 cab_UWORD folder; /* index of folder */
120 cab_UWORD date;
121 cab_UWORD time;
122 cab_UWORD attribs;
123 char name[1];
124 };
125
126 struct data_block
127 {
128 struct list entry;
129 cab_UWORD compressed;
130 cab_UWORD uncompressed;
131 };
132
133 typedef struct FCI_Int
134 {
135 unsigned int magic;
136 PERF perf;
137 PFNFCIFILEPLACED fileplaced;
138 PFNFCIALLOC alloc;
139 PFNFCIFREE free;
140 PFNFCIOPEN open;
141 PFNFCIREAD read;
142 PFNFCIWRITE write;
143 PFNFCICLOSE close;
144 PFNFCISEEK seek;
145 PFNFCIDELETE delete;
146 PFNFCIGETTEMPFILE gettemp;
147 CCAB ccab;
148 PCCAB pccab;
149 BOOL fPrevCab;
150 BOOL fNextCab;
151 BOOL fSplitFolder;
152 cab_ULONG statusFolderCopied;
153 cab_ULONG statusFolderTotal;
154 BOOL fGetNextCabInVain;
155 void *pv;
156 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
157 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */
158 unsigned char data_in[CAB_BLOCKMAX]; /* uncompressed data blocks */
159 unsigned char data_out[2 * CAB_BLOCKMAX]; /* compressed data blocks */
160 cab_UWORD cdata_in;
161 ULONG cCompressedBytesInFolder;
162 cab_UWORD cFolders;
163 cab_UWORD cFiles;
164 cab_ULONG cDataBlocks;
165 cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */
166 /* of spanned file of a spanning folder of a spanning cabinet */
167 struct temp_file data;
168 BOOL fNewPrevious;
169 cab_ULONG estimatedCabinetSize;
170 struct list folders_list;
171 struct list files_list;
172 struct list blocks_list;
173 cab_ULONG folders_size;
174 cab_ULONG files_size; /* size of files not yet assigned to a folder */
175 cab_ULONG placed_files_size; /* size of files already placed into a folder */
176 cab_ULONG pending_data_size; /* size of data not yet assigned to a folder */
177 cab_ULONG folders_data_size; /* total size of data contained in the current folders */
178 TCOMP compression;
179 cab_UWORD (*compress)(struct FCI_Int *);
180 } FCI_Int;
181
182 #define FCI_INT_MAGIC 0xfcfcfc05
183
184 static void set_error( FCI_Int *fci, int oper, int err )
185 {
186 fci->perf->erfOper = oper;
187 fci->perf->erfType = err;
188 fci->perf->fError = TRUE;
189 if (err) SetLastError( err );
190 }
191
192 static FCI_Int *get_fci_ptr( HFCI hfci )
193 {
194 FCI_Int *fci= (FCI_Int *)hfci;
195
196 if (!fci || fci->magic != FCI_INT_MAGIC)
197 {
198 SetLastError( ERROR_INVALID_HANDLE );
199 return NULL;
200 }
201 return fci;
202 }
203
204 /* compute the cabinet header size */
205 static cab_ULONG get_header_size( FCI_Int *fci )
206 {
207 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
208
209 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
210 ret += 4;
211
212 if (fci->fPrevCab)
213 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
214
215 if (fci->fNextCab)
216 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
217
218 return ret;
219 }
220
221 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
222 {
223 int err;
224
225 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
226 {
227 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
228 return FALSE;
229 }
230 if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
231 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
232 {
233 set_error( fci, FCIERR_TEMP_FILE, err );
234 return FALSE;
235 }
236 return TRUE;
237 }
238
239 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
240 {
241 int err;
242
243 if (file->handle == -1) return TRUE;
244 if (fci->close( file->handle, &err, fci->pv ) == -1)
245 {
246 set_error( fci, FCIERR_TEMP_FILE, err );
247 return FALSE;
248 }
249 file->handle = -1;
250 if (fci->delete( file->name, &err, fci->pv ) == -1)
251 {
252 set_error( fci, FCIERR_TEMP_FILE, err );
253 return FALSE;
254 }
255 return TRUE;
256 }
257
258 static struct file *add_file( FCI_Int *fci, const char *filename )
259 {
260 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
261 struct file *file = fci->alloc( size );
262
263 if (!file)
264 {
265 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
266 return NULL;
267 }
268 file->size = 0;
269 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
270 file->folder = fci->cFolders;
271 file->date = 0;
272 file->time = 0;
273 file->attribs = 0;
274 strcpy( file->name, filename );
275 list_add_tail( &fci->files_list, &file->entry );
276 fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
277 return file;
278 }
279
280 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
281 {
282 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
283 struct file *file = fci->alloc( size );
284
285 if (!file)
286 {
287 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
288 return NULL;
289 }
290 memcpy( file, orig, size );
291 return file;
292 }
293
294 static void free_file( FCI_Int *fci, struct file *file )
295 {
296 list_remove( &file->entry );
297 fci->free( file );
298 }
299
300 /* create a new data block for the data in fci->data_in */
301 static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
302 {
303 int err;
304 struct data_block *block;
305
306 if (!fci->cdata_in) return TRUE;
307
308 if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
309
310 if (!(block = fci->alloc( sizeof(*block) )))
311 {
312 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
313 return FALSE;
314 }
315 block->uncompressed = fci->cdata_in;
316 block->compressed = fci->compress( fci );
317
318 if (fci->write( fci->data.handle, fci->data_out,
319 block->compressed, &err, fci->pv ) != block->compressed)
320 {
321 set_error( fci, FCIERR_TEMP_FILE, err );
322 fci->free( block );
323 return FALSE;
324 }
325
326 fci->cdata_in = 0;
327 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
328 fci->cCompressedBytesInFolder += block->compressed;
329 fci->cDataBlocks++;
330 list_add_tail( &fci->blocks_list, &block->entry );
331
332 if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
333 {
334 set_error( fci, FCIERR_USER_ABORT, 0 );
335 return FALSE;
336 }
337 return TRUE;
338 }
339
340 /* add compressed blocks for all the data that can be read from the file */
341 static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
342 PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
343 {
344 int err, len;
345 INT_PTR handle;
346 struct file *file;
347
348 if (!(file = add_file( fci, filename ))) return FALSE;
349
350 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
351 if (handle == -1)
352 {
353 free_file( fci, file );
354 set_error( fci, FCIERR_OPEN_SRC, err );
355 return FALSE;
356 }
357 if (execute) file->attribs |= _A_EXEC;
358
359 for (;;)
360 {
361 len = fci->read( handle, fci->data_in + fci->cdata_in,
362 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
363 if (!len) break;
364
365 if (len == -1)
366 {
367 set_error( fci, FCIERR_READ_SRC, err );
368 return FALSE;
369 }
370 file->size += len;
371 fci->cdata_in += len;
372 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
373 }
374 fci->close( handle, &err, fci->pv );
375 return TRUE;
376 }
377
378 static void free_data_block( FCI_Int *fci, struct data_block *block )
379 {
380 list_remove( &block->entry );
381 fci->free( block );
382 }
383
384 static struct folder *add_folder( FCI_Int *fci )
385 {
386 struct folder *folder = fci->alloc( sizeof(*folder) );
387
388 if (!folder)
389 {
390 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
391 return NULL;
392 }
393 folder->data.handle = -1;
394 folder->data_start = fci->folders_data_size;
395 folder->data_count = 0;
396 folder->compression = fci->compression;
397 list_init( &folder->files_list );
398 list_init( &folder->blocks_list );
399 list_add_tail( &fci->folders_list, &folder->entry );
400 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
401 fci->cFolders++;
402 return folder;
403 }
404
405 static void free_folder( FCI_Int *fci, struct folder *folder )
406 {
407 struct file *file, *file_next;
408 struct data_block *block, *block_next;
409
410 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
411 free_file( fci, file );
412 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
413 free_data_block( fci, block );
414 close_temp_file( fci, &folder->data );
415 list_remove( &folder->entry );
416 fci->free( folder );
417 }
418
419 /* reset state for the next cabinet file once the current one has been flushed */
420 static void reset_cabinet( FCI_Int *fci )
421 {
422 struct folder *folder, *folder_next;
423
424 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
425 free_folder( fci, folder );
426
427 fci->cFolders = 0;
428 fci->cFiles = 0;
429 fci->folders_size = 0;
430 fci->placed_files_size = 0;
431 fci->folders_data_size = 0;
432 }
433
434 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
435 {
436 cab_ULONG csum;
437 cab_ULONG ul;
438 int cUlong;
439 const BYTE *pb;
440
441 csum = seed;
442 cUlong = cb / 4;
443 pb = pv;
444
445 while (cUlong-- > 0) {
446 ul = *pb++;
447 ul |= (((cab_ULONG)(*pb++)) << 8);
448 ul |= (((cab_ULONG)(*pb++)) << 16);
449 ul |= (((cab_ULONG)(*pb++)) << 24);
450 csum ^= ul;
451 }
452
453 ul = 0;
454 switch (cb % 4) {
455 case 3:
456 ul |= (((ULONG)(*pb++)) << 16);
457 /* fall through */
458 case 2:
459 ul |= (((ULONG)(*pb++)) << 8);
460 /* fall through */
461 case 1:
462 ul |= *pb;
463 /* fall through */
464 default:
465 break;
466 }
467 csum ^= ul;
468
469 return csum;
470 }
471
472 /* copy all remaining data block to a new temp file */
473 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
474 struct temp_file *temp, PFNFCISTATUS status_callback )
475 {
476 struct data_block *block;
477 int err;
478
479 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
480 {
481 set_error( fci, FCIERR_TEMP_FILE, err );
482 return FALSE;
483 }
484 if (!create_temp_file( fci, temp )) return FALSE;
485
486 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
487 {
488 if (fci->read( handle, fci->data_out, block->compressed,
489 &err, fci->pv ) != block->compressed)
490 {
491 close_temp_file( fci, temp );
492 set_error( fci, FCIERR_TEMP_FILE, err );
493 return FALSE;
494 }
495 if (fci->write( temp->handle, fci->data_out, block->compressed,
496 &err, fci->pv ) != block->compressed)
497 {
498 close_temp_file( fci, temp );
499 set_error( fci, FCIERR_TEMP_FILE, err );
500 return FALSE;
501 }
502 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
503 fci->statusFolderCopied += block->compressed;
504
505 if (status_callback( statusFolder, fci->statusFolderCopied,
506 fci->statusFolderTotal, fci->pv) == -1)
507 {
508 close_temp_file( fci, temp );
509 set_error( fci, FCIERR_USER_ABORT, 0 );
510 return FALSE;
511 }
512 }
513 return TRUE;
514 }
515
516 /* write all folders to disk and remove them from the list */
517 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
518 {
519 struct folder *folder;
520 int err;
521 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
522 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
523
524 memset( cffolder, 0, folder_size );
525
526 /* write the folders */
527 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
528 {
529 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
530 cffolder->cCFData = fci_endian_uword( folder->data_count );
531 cffolder->typeCompress = fci_endian_uword( folder->compression );
532 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
533 {
534 set_error( fci, FCIERR_CAB_FILE, err );
535 return FALSE;
536 }
537 }
538 return TRUE;
539 }
540
541 /* write all the files to the cabinet file */
542 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
543 {
544 cab_ULONG file_size;
545 struct folder *folder;
546 struct file *file;
547 int err;
548 CFFILE *cffile = (CFFILE *)fci->data_out;
549
550 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
551 {
552 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
553 {
554 cffile->cbFile = fci_endian_ulong( file->size );
555 cffile->uoffFolderStart = fci_endian_ulong( file->offset );
556 cffile->iFolder = fci_endian_uword( file->folder );
557 cffile->date = fci_endian_uword( file->date );
558 cffile->time = fci_endian_uword( file->time );
559 cffile->attribs = fci_endian_uword( file->attribs );
560 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
561 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
562 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
563 {
564 set_error( fci, FCIERR_CAB_FILE, err );
565 return FALSE;
566 }
567 if (!fci->fSplitFolder)
568 {
569 fci->statusFolderCopied = 0;
570 /* TODO TEST THIS further */
571 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
572 }
573 fci->statusFolderCopied += file_size;
574 /* report status about copied size of folder */
575 if (status_callback( statusFolder, fci->statusFolderCopied,
576 fci->statusFolderTotal, fci->pv ) == -1)
577 {
578 set_error( fci, FCIERR_USER_ABORT, 0 );
579 return FALSE;
580 }
581 }
582 }
583 return TRUE;
584 }
585
586 /* write all data blocks to the cabinet file */
587 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
588 {
589 struct folder *folder;
590 struct data_block *block;
591 int err, len;
592 CFDATA *cfdata;
593 void *data;
594 cab_UWORD header_size;
595
596 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
597 cfdata = (CFDATA *)fci->data_out;
598 memset( cfdata, 0, header_size );
599 data = (char *)cfdata + header_size;
600
601 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
602 {
603 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
604 {
605 set_error( fci, FCIERR_CAB_FILE, err );
606 return FALSE;
607 }
608 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
609 {
610 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
611 if (len != block->compressed) return FALSE;
612
613 cfdata->cbData = fci_endian_uword( block->compressed );
614 cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
615 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
616 header_size - FIELD_OFFSET(CFDATA, cbData),
617 fci_get_checksum( data, len, 0 )));
618
619 fci->statusFolderCopied += len;
620 len += header_size;
621 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
622 {
623 set_error( fci, FCIERR_CAB_FILE, err );
624 return FALSE;
625 }
626 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
627 {
628 set_error( fci, FCIERR_USER_ABORT, 0 );
629 return FALSE;
630 }
631 }
632 }
633 return TRUE;
634 }
635
636 /* write the cabinet file to disk */
637 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
638 {
639 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
640 int err;
641 char *ptr;
642 INT_PTR handle;
643 CFHEADER *cfheader = (CFHEADER *)fci->data_out;
644 cab_UWORD flags = 0;
645 cab_ULONG header_size = get_header_size( fci );
646 cab_ULONG total_size = header_size + fci->folders_size +
647 fci->placed_files_size + fci->folders_data_size;
648
649 assert( header_size <= sizeof(fci->data_out) );
650 memset( cfheader, 0, header_size );
651
652 if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
653 if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
654 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
655 flags |= cfheadRESERVE_PRESENT;
656
657 memcpy( cfheader->signature, "!CAB", 4 );
658 cfheader->cbCabinet = fci_endian_ulong( total_size );
659 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size );
660 cfheader->versionMinor = 3;
661 cfheader->versionMajor = 1;
662 cfheader->cFolders = fci_endian_uword( fci->cFolders );
663 cfheader->cFiles = fci_endian_uword( fci->cFiles );
664 cfheader->flags = fci_endian_uword( flags );
665 cfheader->setID = fci_endian_uword( fci->ccab.setID );
666 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab );
667 ptr = (char *)(cfheader + 1);
668
669 if (flags & cfheadRESERVE_PRESENT)
670 {
671 struct
672 {
673 cab_UWORD cbCFHeader;
674 cab_UBYTE cbCFFolder;
675 cab_UBYTE cbCFData;
676 } *reserve = (void *)ptr;
677
678 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
679 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
680 reserve->cbCFData = fci->ccab.cbReserveCFData;
681 ptr = (char *)(reserve + 1);
682 }
683 ptr += fci->ccab.cbReserveCFHeader;
684
685 if (flags & cfheadPREV_CABINET)
686 {
687 strcpy( ptr, fci->szPrevCab );
688 ptr += strlen( ptr ) + 1;
689 strcpy( ptr, fci->szPrevDisk );
690 ptr += strlen( ptr ) + 1;
691 }
692
693 if (flags & cfheadNEXT_CABINET)
694 {
695 strcpy( ptr, fci->pccab->szCab );
696 ptr += strlen( ptr ) + 1;
697 strcpy( ptr, fci->pccab->szDisk );
698 ptr += strlen( ptr ) + 1;
699 }
700
701 assert( ptr - (char *)cfheader == header_size );
702
703 strcpy( filename, fci->ccab.szCabPath );
704 strcat( filename, fci->ccab.szCab );
705
706 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
707 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
708 {
709 set_error( fci, FCIERR_CAB_FILE, err );
710 return FALSE;
711 }
712
713 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
714 {
715 set_error( fci, FCIERR_CAB_FILE, err );
716 goto failed;
717 }
718
719 /* add size of header size of all CFFOLDERs and size of all CFFILEs */
720 header_size += fci->placed_files_size + fci->folders_size;
721 if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
722 if (!write_files( fci, handle, status_callback )) goto failed;
723 if (!write_data_blocks( fci, handle, status_callback )) goto failed;
724
725 /* update the signature */
726 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
727 {
728 set_error( fci, FCIERR_CAB_FILE, err );
729 goto failed;
730 }
731 memcpy( cfheader->signature, "MSCF", 4 );
732 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
733 {
734 set_error( fci, FCIERR_CAB_FILE, err );
735 goto failed;
736 }
737 fci->close( handle, &err, fci->pv );
738
739 reset_cabinet( fci );
740 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
741 return TRUE;
742
743 failed:
744 fci->close( handle, &err, fci->pv );
745 fci->delete( filename, &err, fci->pv );
746 return FALSE;
747 }
748
749 /* add all pending data blocks folder */
750 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
751 PFNFCISTATUS status_callback )
752 {
753 struct data_block *block, *new, *next;
754 BOOL split_block = FALSE;
755 cab_ULONG current_size, start_pos = 0;
756
757 *payload = 0;
758 current_size = get_header_size( fci ) + fci->folders_size +
759 fci->files_size + fci->placed_files_size + fci->folders_data_size;
760
761 /* move the temp file into the folder structure */
762 folder->data = fci->data;
763 fci->data.handle = -1;
764 fci->pending_data_size = 0;
765
766 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
767 {
768 /* No more CFDATA fits into the cabinet under construction */
769 /* So don't try to store more data into it */
770 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
771 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
772 break;
773
774 if (!(new = fci->alloc( sizeof(*new) )))
775 {
776 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
777 return FALSE;
778 }
779 /* Is cabinet with new CFDATA too large? Then data block has to be split */
780 if( fci->fNextCab &&
781 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
782 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
783 {
784 /* Modify the size of the compressed data to store only a part of the */
785 /* data block into the current cabinet. This is done to prevent */
786 /* that the maximum cabinet size will be exceeded. The remainder */
787 /* will be stored into the next following cabinet. */
788
789 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
790 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
791 new->uncompressed = 0; /* on split blocks of data this is zero */
792 block->compressed -= new->compressed;
793 split_block = TRUE;
794 }
795 else
796 {
797 new->compressed = block->compressed;
798 new->uncompressed = block->uncompressed;
799 }
800
801 start_pos += new->compressed;
802 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
803 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
804 fci->statusFolderCopied += new->compressed;
805 (*payload) += new->uncompressed;
806
807 list_add_tail( &folder->blocks_list, &new->entry );
808 folder->data_count++;
809
810 /* report status with pfnfcis about copied size of folder */
811 if (status_callback( statusFolder, fci->statusFolderCopied,
812 fci->statusFolderTotal, fci->pv ) == -1)
813 {
814 set_error( fci, FCIERR_USER_ABORT, 0 );
815 return FALSE;
816 }
817 if (split_block) break;
818 free_data_block( fci, block );
819 fci->cDataBlocks--;
820 }
821
822 if (list_empty( &fci->blocks_list )) return TRUE;
823 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
824 }
825
826 /* add all pending files to folder */
827 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
828 {
829 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
830 cab_ULONG cbFileRemainer = 0;
831 struct file *file, *next;
832
833 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
834 {
835 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
836
837 /* fnfilfnfildest: placed file on cabinet */
838 fci->fileplaced( &fci->ccab, file->name, file->size,
839 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
840
841 sizeOfFilesPrev = sizeOfFiles;
842 /* set complete size of all processed files */
843 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
844 {
845 sizeOfFiles += fci->cbFileRemainer;
846 fci->cbFileRemainer = 0;
847 }
848 else sizeOfFiles += file->size;
849
850 /* check if spanned file fits into this cabinet folder */
851 if (sizeOfFiles > payload)
852 {
853 if (file->folder == cffileCONTINUED_FROM_PREV)
854 file->folder = cffileCONTINUED_PREV_AND_NEXT;
855 else
856 file->folder = cffileCONTINUED_TO_NEXT;
857 }
858
859 list_remove( &file->entry );
860 list_add_tail( &folder->files_list, &file->entry );
861 fci->placed_files_size += size;
862 fci->cFiles++;
863
864 /* This is only true for files which will be written into the */
865 /* next cabinet of the spanning folder */
866 if (sizeOfFiles > payload)
867 {
868 /* add a copy back onto the list */
869 if (!(file = copy_file( fci, file ))) return FALSE;
870 list_add_before( &next->entry, &file->entry );
871
872 /* Files which data will be partially written into the current cabinet */
873 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
874 {
875 if (sizeOfFilesPrev <= payload)
876 {
877 /* The size of the uncompressed, data of a spanning file in a */
878 /* spanning data */
879 cbFileRemainer = sizeOfFiles - payload;
880 }
881 file->folder = cffileCONTINUED_FROM_PREV;
882 }
883 else file->folder = 0;
884 }
885 else
886 {
887 fci->files_size -= size;
888 }
889 }
890 fci->cbFileRemainer = cbFileRemainer;
891 return TRUE;
892 }
893
894 static cab_UWORD compress_NONE( FCI_Int *fci )
895 {
896 memcpy( fci->data_out, fci->data_in, fci->cdata_in );
897 return fci->cdata_in;
898 }
899
900 #ifdef HAVE_ZLIB
901
902 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
903 {
904 FCI_Int *fci = opaque;
905 return fci->alloc( items * size );
906 }
907
908 static void zfree( void *opaque, void *ptr )
909 {
910 FCI_Int *fci = opaque;
911 fci->free( ptr );
912 }
913
914 static cab_UWORD compress_MSZIP( FCI_Int *fci )
915 {
916 z_stream stream;
917
918 stream.zalloc = zalloc;
919 stream.zfree = zfree;
920 stream.opaque = fci;
921 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
922 {
923 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
924 return 0;
925 }
926 stream.next_in = fci->data_in;
927 stream.avail_in = fci->cdata_in;
928 stream.next_out = fci->data_out + 2;
929 stream.avail_out = sizeof(fci->data_out) - 2;
930 /* insert the signature */
931 fci->data_out[0] = 'C';
932 fci->data_out[1] = 'K';
933 deflate( &stream, Z_FINISH );
934 deflateEnd( &stream );
935 return stream.total_out + 2;
936 }
937
938 #endif /* HAVE_ZLIB */
939
940
941 /***********************************************************************
942 * FCICreate (CABINET.10)
943 *
944 * FCICreate is provided with several callbacks and
945 * returns a handle which can be used to create cabinet files.
946 *
947 * PARAMS
948 * perf [IO] A pointer to an ERF structure. When FCICreate
949 * returns an error condition, error information may
950 * be found here as well as from GetLastError.
951 * pfnfiledest [I] A pointer to a function which is called when a file
952 * is placed. Only useful for subsequent cabinet files.
953 * pfnalloc [I] A pointer to a function which allocates ram. Uses
954 * the same interface as malloc.
955 * pfnfree [I] A pointer to a function which frees ram. Uses the
956 * same interface as free.
957 * pfnopen [I] A pointer to a function which opens a file. Uses
958 * the same interface as _open.
959 * pfnread [I] A pointer to a function which reads from a file into
960 * a caller-provided buffer. Uses the same interface
961 * as _read.
962 * pfnwrite [I] A pointer to a function which writes to a file from
963 * a caller-provided buffer. Uses the same interface
964 * as _write.
965 * pfnclose [I] A pointer to a function which closes a file handle.
966 * Uses the same interface as _close.
967 * pfnseek [I] A pointer to a function which seeks in a file.
968 * Uses the same interface as _lseek.
969 * pfndelete [I] A pointer to a function which deletes a file.
970 * pfnfcigtf [I] A pointer to a function which gets the name of a
971 * temporary file.
972 * pccab [I] A pointer to an initialized CCAB structure.
973 * pv [I] A pointer to an application-defined notification
974 * function which will be passed to other FCI functions
975 * as a parameter.
976 *
977 * RETURNS
978 * On success, returns an FCI handle of type HFCI.
979 * On failure, the NULL file handle is returned. Error
980 * info can be retrieved from perf.
981 *
982 * INCLUDES
983 * fci.h
984 *
985 */
986 HFCI __cdecl FCICreate(
987 PERF perf,
988 PFNFCIFILEPLACED pfnfiledest,
989 PFNFCIALLOC pfnalloc,
990 PFNFCIFREE pfnfree,
991 PFNFCIOPEN pfnopen,
992 PFNFCIREAD pfnread,
993 PFNFCIWRITE pfnwrite,
994 PFNFCICLOSE pfnclose,
995 PFNFCISEEK pfnseek,
996 PFNFCIDELETE pfndelete,
997 PFNFCIGETTEMPFILE pfnfcigtf,
998 PCCAB pccab,
999 void *pv)
1000 {
1001 FCI_Int *p_fci_internal;
1002
1003 if (!perf) {
1004 SetLastError(ERROR_BAD_ARGUMENTS);
1005 return NULL;
1006 }
1007 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1008 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
1009 (!pfnfcigtf) || (!pccab)) {
1010 perf->erfOper = FCIERR_NONE;
1011 perf->erfType = ERROR_BAD_ARGUMENTS;
1012 perf->fError = TRUE;
1013
1014 SetLastError(ERROR_BAD_ARGUMENTS);
1015 return NULL;
1016 }
1017
1018 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1019 perf->erfOper = FCIERR_ALLOC_FAIL;
1020 perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
1021 perf->fError = TRUE;
1022
1023 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1024 return NULL;
1025 }
1026
1027 p_fci_internal->magic = FCI_INT_MAGIC;
1028 p_fci_internal->perf = perf;
1029 p_fci_internal->fileplaced = pfnfiledest;
1030 p_fci_internal->alloc = pfnalloc;
1031 p_fci_internal->free = pfnfree;
1032 p_fci_internal->open = pfnopen;
1033 p_fci_internal->read = pfnread;
1034 p_fci_internal->write = pfnwrite;
1035 p_fci_internal->close = pfnclose;
1036 p_fci_internal->seek = pfnseek;
1037 p_fci_internal->delete = pfndelete;
1038 p_fci_internal->gettemp = pfnfcigtf;
1039 p_fci_internal->ccab = *pccab;
1040 p_fci_internal->pccab = pccab;
1041 p_fci_internal->fPrevCab = FALSE;
1042 p_fci_internal->fNextCab = FALSE;
1043 p_fci_internal->fSplitFolder = FALSE;
1044 p_fci_internal->fGetNextCabInVain = FALSE;
1045 p_fci_internal->pv = pv;
1046 p_fci_internal->cdata_in = 0;
1047 p_fci_internal->cCompressedBytesInFolder = 0;
1048 p_fci_internal->cFolders = 0;
1049 p_fci_internal->cFiles = 0;
1050 p_fci_internal->cDataBlocks = 0;
1051 p_fci_internal->data.handle = -1;
1052 p_fci_internal->fNewPrevious = FALSE;
1053 p_fci_internal->estimatedCabinetSize = 0;
1054 p_fci_internal->statusFolderTotal = 0;
1055 p_fci_internal->folders_size = 0;
1056 p_fci_internal->files_size = 0;
1057 p_fci_internal->placed_files_size = 0;
1058 p_fci_internal->pending_data_size = 0;
1059 p_fci_internal->folders_data_size = 0;
1060 p_fci_internal->compression = tcompTYPE_NONE;
1061 p_fci_internal->compress = compress_NONE;
1062
1063 list_init( &p_fci_internal->folders_list );
1064 list_init( &p_fci_internal->files_list );
1065 list_init( &p_fci_internal->blocks_list );
1066
1067 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1068 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1069
1070 return (HFCI)p_fci_internal;
1071 }
1072
1073
1074
1075
1076 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1077 BOOL fGetNextCab,
1078 PFNFCIGETNEXTCABINET pfnfcignc,
1079 PFNFCISTATUS pfnfcis)
1080 {
1081 cab_ULONG payload;
1082 cab_ULONG read_result;
1083 struct folder *folder;
1084
1085 if ((!pfnfcignc) || (!pfnfcis)) {
1086 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1087 return FALSE;
1088 }
1089
1090 if( p_fci_internal->fGetNextCabInVain &&
1091 p_fci_internal->fNextCab ){
1092 /* internal error */
1093 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1094 return FALSE;
1095 }
1096
1097 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1098 /* this function will return TRUE */
1099 if( p_fci_internal->files_size == 0 ) {
1100 if ( p_fci_internal->pending_data_size != 0 ) {
1101 /* error handling */
1102 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1103 return FALSE;
1104 }
1105 return TRUE;
1106 }
1107
1108 /* FCIFlushFolder has already been called... */
1109 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1110 return TRUE;
1111 }
1112
1113 /* This can be set already, because it makes only a difference */
1114 /* when the current function exits with return FALSE */
1115 p_fci_internal->fSplitFolder=FALSE;
1116
1117 /* START of COPY */
1118 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1119
1120 /* reset to get the number of data blocks of this folder which are */
1121 /* actually in this cabinet ( at least partially ) */
1122 p_fci_internal->cDataBlocks=0;
1123
1124 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1125 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1126 p_fci_internal->placed_files_size+
1127 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1128 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1129 p_fci_internal->statusFolderCopied = 0;
1130
1131 /* report status with pfnfcis about copied size of folder */
1132 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1133 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1134 p_fci_internal->pv) == -1) {
1135 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1136 return FALSE;
1137 }
1138
1139 /* USE the variable read_result */
1140 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1141 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1142
1143 if(p_fci_internal->files_size!=0) {
1144 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1145 }
1146
1147 /* Check if multiple cabinets have to be created. */
1148
1149 /* Might be too much data for the maximum allowed cabinet size.*/
1150 /* When any further data will be added later, it might not */
1151 /* be possible to flush the cabinet, because there might */
1152 /* not be enough space to store the name of the following */
1153 /* cabinet and name of the corresponding disk. */
1154 /* So take care of this and get the name of the next cabinet */
1155 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1156 p_fci_internal->fNextCab==FALSE &&
1157 (
1158 (
1159 p_fci_internal->ccab.cb < read_result +
1160 p_fci_internal->pending_data_size +
1161 p_fci_internal->files_size +
1162 CB_MAX_CABINET_NAME + /* next cabinet name */
1163 CB_MAX_DISK_NAME /* next disk name */
1164 ) || fGetNextCab
1165 )
1166 ) {
1167 /* increment cabinet index */
1168 ++(p_fci_internal->pccab->iCab);
1169 /* get name of next cabinet */
1170 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1171 if (!(*pfnfcignc)(p_fci_internal->pccab,
1172 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1173 p_fci_internal->pv)) {
1174 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1175 return FALSE;
1176 }
1177
1178 /* Skip a few lines of code. This is caught by the next if. */
1179 p_fci_internal->fGetNextCabInVain=TRUE;
1180 }
1181
1182 /* too much data for cabinet */
1183 if( (p_fci_internal->fGetNextCabInVain ||
1184 p_fci_internal->fNextCab ) &&
1185 (
1186 (
1187 p_fci_internal->ccab.cb < read_result +
1188 p_fci_internal->pending_data_size +
1189 p_fci_internal->files_size +
1190 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1191 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1192 ) || fGetNextCab
1193 )
1194 ) {
1195 p_fci_internal->fGetNextCabInVain=FALSE;
1196 p_fci_internal->fNextCab=TRUE;
1197
1198 /* return FALSE if there is not enough space left*/
1199 /* this should never happen */
1200 if (p_fci_internal->ccab.cb <=
1201 p_fci_internal->files_size +
1202 read_result +
1203 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1204 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1205 ) {
1206
1207 return FALSE;
1208 }
1209
1210 /* the folder will be split across cabinets */
1211 p_fci_internal->fSplitFolder=TRUE;
1212
1213 } else {
1214 /* this should never happen */
1215 if (p_fci_internal->fNextCab) {
1216 /* internal error */
1217 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1218 return FALSE;
1219 }
1220 }
1221
1222 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1223 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1224 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1225
1226 /* reset CFFolder specific information */
1227 p_fci_internal->cDataBlocks=0;
1228 p_fci_internal->cCompressedBytesInFolder=0;
1229
1230 return TRUE;
1231 }
1232
1233
1234
1235
1236 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1237 BOOL fGetNextCab,
1238 PFNFCIGETNEXTCABINET pfnfcignc,
1239 PFNFCISTATUS pfnfcis)
1240 {
1241 cab_ULONG read_result=0;
1242 BOOL returntrue=FALSE;
1243
1244 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1245
1246 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1247 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1248 returntrue=TRUE;
1249 }
1250
1251 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1252 /* TODO set error */
1253 return FALSE;
1254 }
1255
1256 if(returntrue) return TRUE;
1257
1258 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1259 (p_fci_internal->folders_size==0 &&
1260 (p_fci_internal->files_size!=0 ||
1261 p_fci_internal->placed_files_size!=0 )
1262 ) )
1263 {
1264 /* error */
1265 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1266 return FALSE;
1267 }
1268
1269 /* create the cabinet */
1270 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1271
1272 p_fci_internal->fPrevCab=TRUE;
1273 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1274 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1275
1276 if (p_fci_internal->fNextCab) {
1277 p_fci_internal->fNextCab=FALSE;
1278
1279 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1280 /* THIS CAN NEVER HAPPEN */
1281 /* set error code */
1282 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1283 return FALSE;
1284 }
1285
1286 if( p_fci_internal->fNewPrevious ) {
1287 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1288 CB_MAX_CABINET_NAME);
1289 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1290 CB_MAX_DISK_NAME);
1291 p_fci_internal->fNewPrevious=FALSE;
1292 }
1293 p_fci_internal->ccab = *p_fci_internal->pccab;
1294
1295 /* REUSE the variable read_result */
1296 read_result=get_header_size( p_fci_internal );
1297 if(p_fci_internal->files_size!=0) {
1298 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1299 }
1300 read_result+= p_fci_internal->pending_data_size +
1301 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1302 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1303 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1304
1305 /* too much data for the maximum size of a cabinet */
1306 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1307 p_fci_internal->ccab.cb < read_result ) {
1308 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1309 }
1310
1311 /* Might be too much data for the maximum size of a cabinet.*/
1312 /* When any further data will be added later, it might not */
1313 /* be possible to flush the cabinet, because there might */
1314 /* not be enough space to store the name of the following */
1315 /* cabinet and name of the corresponding disk. */
1316 /* So take care of this and get the name of the next cabinet */
1317 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1318 p_fci_internal->ccab.cb < read_result +
1319 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1320 )) {
1321 /* increment cabinet index */
1322 ++(p_fci_internal->pccab->iCab);
1323 /* get name of next cabinet */
1324 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1325 if (!(*pfnfcignc)(p_fci_internal->pccab,
1326 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1327 p_fci_internal->pv)) {
1328 /* error handling */
1329 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1330 return FALSE;
1331 }
1332 /* Skip a few lines of code. This is caught by the next if. */
1333 p_fci_internal->fGetNextCabInVain=TRUE;
1334 }
1335
1336 /* too much data for cabinet */
1337 if (p_fci_internal->fGetNextCabInVain && (
1338 p_fci_internal->ccab.cb < read_result +
1339 strlen(p_fci_internal->ccab.szCab)+1+
1340 strlen(p_fci_internal->ccab.szDisk)+1
1341 )) {
1342 p_fci_internal->fGetNextCabInVain=FALSE;
1343 p_fci_internal->fNextCab=TRUE;
1344 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1345 }
1346
1347 /* if the FolderThreshold has been reached flush the folder automatically */
1348 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1349 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1350
1351 if( p_fci_internal->files_size>0 ) {
1352 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1353 p_fci_internal->fNewPrevious=TRUE;
1354 }
1355 } else {
1356 p_fci_internal->fNewPrevious=FALSE;
1357 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1358 /* THIS MAY NEVER HAPPEN */
1359 /* set error structures */
1360 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1361 return FALSE;
1362 }
1363 }
1364
1365 return TRUE;
1366 } /* end of fci_flush_cabinet */
1367
1368
1369
1370
1371
1372 /***********************************************************************
1373 * FCIAddFile (CABINET.11)
1374 *
1375 * FCIAddFile adds a file to the to be created cabinet file
1376 *
1377 * PARAMS
1378 * hfci [I] An HFCI from FCICreate
1379 * pszSourceFile [I] A pointer to a C string which contains the name and
1380 * location of the file which will be added to the cabinet
1381 * pszFileName [I] A pointer to a C string which contains the name under
1382 * which the file will be stored in the cabinet
1383 * fExecute [I] A boolean value which indicates if the file should be
1384 * executed after extraction of self extracting
1385 * executables
1386 * pfnfcignc [I] A pointer to a function which gets information about
1387 * the next cabinet
1388 * pfnfcis [IO] A pointer to a function which will report status
1389 * information about the compression process
1390 * pfnfcioi [I] A pointer to a function which reports file attributes
1391 * and time and date information
1392 * typeCompress [I] Compression type
1393 *
1394 * RETURNS
1395 * On success, returns TRUE
1396 * On failure, returns FALSE
1397 *
1398 * INCLUDES
1399 * fci.h
1400 *
1401 */
1402 BOOL __cdecl FCIAddFile(
1403 HFCI hfci,
1404 char *pszSourceFile,
1405 char *pszFileName,
1406 BOOL fExecute,
1407 PFNFCIGETNEXTCABINET pfnfcignc,
1408 PFNFCISTATUS pfnfcis,
1409 PFNFCIGETOPENINFO pfnfcigoi,
1410 TCOMP typeCompress)
1411 {
1412 cab_ULONG read_result;
1413 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1414
1415 if (!p_fci_internal) return FALSE;
1416
1417 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1418 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1419 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1420 return FALSE;
1421 }
1422
1423 if (typeCompress != p_fci_internal->compression)
1424 {
1425 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1426 switch (typeCompress)
1427 {
1428 case tcompTYPE_MSZIP:
1429 #ifdef HAVE_ZLIB
1430 p_fci_internal->compression = tcompTYPE_MSZIP;
1431 p_fci_internal->compress = compress_MSZIP;
1432 break;
1433 #endif
1434 default:
1435 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1436 /* fall through */
1437 case tcompTYPE_NONE:
1438 p_fci_internal->compression = tcompTYPE_NONE;
1439 p_fci_internal->compress = compress_NONE;
1440 break;
1441 }
1442 }
1443
1444 /* TODO check if pszSourceFile??? */
1445
1446 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1447 /* internal error */
1448 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1449 return FALSE;
1450 }
1451
1452 if(p_fci_internal->fNextCab) {
1453 /* internal error */
1454 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1455 return FALSE;
1456 }
1457
1458 /* REUSE the variable read_result */
1459 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1460
1461 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1462 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1463 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1464 sizeof(CFFOLDER); /* size of new CFFolder entry */
1465
1466 /* Might be too much data for the maximum size of a cabinet.*/
1467 /* When any further data will be added later, it might not */
1468 /* be possible to flush the cabinet, because there might */
1469 /* not be enough space to store the name of the following */
1470 /* cabinet and name of the corresponding disk. */
1471 /* So take care of this and get the name of the next cabinet */
1472 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1473 p_fci_internal->fNextCab==FALSE &&
1474 ( p_fci_internal->ccab.cb < read_result +
1475 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1476 )
1477 ) {
1478 /* increment cabinet index */
1479 ++(p_fci_internal->pccab->iCab);
1480 /* get name of next cabinet */
1481 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1482 if (!(*pfnfcignc)(p_fci_internal->pccab,
1483 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1484 p_fci_internal->pv)) {
1485 /* error handling */
1486 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1487 return FALSE;
1488 }
1489 /* Skip a few lines of code. This is caught by the next if. */
1490 p_fci_internal->fGetNextCabInVain=TRUE;
1491 }
1492
1493 if( p_fci_internal->fGetNextCabInVain &&
1494 p_fci_internal->fNextCab
1495 ) {
1496 /* THIS CAN NEVER HAPPEN */
1497 /* set error code */
1498 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1499 return FALSE;
1500 }
1501
1502 /* too much data for cabinet */
1503 if( p_fci_internal->fGetNextCabInVain &&
1504 (
1505 p_fci_internal->ccab.cb < read_result +
1506 strlen(p_fci_internal->pccab->szCab)+1+
1507 strlen(p_fci_internal->pccab->szDisk)+1
1508 )) {
1509 p_fci_internal->fGetNextCabInVain=FALSE;
1510 p_fci_internal->fNextCab=TRUE;
1511 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1512 }
1513
1514 if( p_fci_internal->fNextCab ) {
1515 /* THIS MAY NEVER HAPPEN */
1516 /* set error code */
1517 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1518 return FALSE;
1519 }
1520
1521 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1522 return FALSE;
1523
1524 /* REUSE the variable read_result */
1525 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1526 read_result+= p_fci_internal->pending_data_size +
1527 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1528 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1529 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1530
1531 /* too much data for the maximum size of a cabinet */
1532 /* (ignoring the unflushed data block) */
1533 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1534 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1535 p_fci_internal->ccab.cb < read_result ) {
1536 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1537 }
1538
1539 /* Might be too much data for the maximum size of a cabinet.*/
1540 /* When any further data will be added later, it might not */
1541 /* be possible to flush the cabinet, because there might */
1542 /* not be enough space to store the name of the following */
1543 /* cabinet and name of the corresponding disk. */
1544 /* So take care of this and get the name of the next cabinet */
1545 /* (ignoring the unflushed data block) */
1546 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1547 p_fci_internal->fNextCab==FALSE &&
1548 ( p_fci_internal->ccab.cb < read_result +
1549 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1550 )
1551 ) {
1552 /* increment cabinet index */
1553 ++(p_fci_internal->pccab->iCab);
1554 /* get name of next cabinet */
1555 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1556 if (!(*pfnfcignc)(p_fci_internal->pccab,
1557 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1558 p_fci_internal->pv)) {
1559 /* error handling */
1560 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1561 return FALSE;
1562 }
1563 /* Skip a few lines of code. This is caught by the next if. */
1564 p_fci_internal->fGetNextCabInVain=TRUE;
1565 }
1566
1567 if( p_fci_internal->fGetNextCabInVain &&
1568 p_fci_internal->fNextCab
1569 ) {
1570 /* THIS CAN NEVER HAPPEN */
1571 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1572 return FALSE;
1573 }
1574
1575 /* too much data for cabinet */
1576 if( (p_fci_internal->fGetNextCabInVain ||
1577 p_fci_internal->fNextCab) && (
1578 p_fci_internal->ccab.cb < read_result +
1579 strlen(p_fci_internal->pccab->szCab)+1+
1580 strlen(p_fci_internal->pccab->szDisk)+1
1581 )) {
1582
1583 p_fci_internal->fGetNextCabInVain=FALSE;
1584 p_fci_internal->fNextCab=TRUE;
1585 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1586 }
1587
1588 if( p_fci_internal->fNextCab ) {
1589 /* THIS MAY NEVER HAPPEN */
1590 /* set error code */
1591 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1592 return FALSE;
1593 }
1594
1595 /* if the FolderThreshold has been reached flush the folder automatically */
1596 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1597 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1598
1599 return TRUE;
1600 } /* end of FCIAddFile */
1601
1602
1603
1604
1605
1606 /***********************************************************************
1607 * FCIFlushFolder (CABINET.12)
1608 *
1609 * FCIFlushFolder completes the CFFolder structure under construction.
1610 *
1611 * All further data which is added by FCIAddFile will be associated to
1612 * the next CFFolder structure.
1613 *
1614 * FCIFlushFolder will be called by FCIAddFile automatically if the
1615 * threshold (stored in the member cbFolderThresh of the CCAB structure
1616 * pccab passed to FCICreate) is exceeded.
1617 *
1618 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1619 * any data will be written into the cabinet file.
1620 *
1621 * PARAMS
1622 * hfci [I] An HFCI from FCICreate
1623 * pfnfcignc [I] A pointer to a function which gets information about
1624 * the next cabinet
1625 * pfnfcis [IO] A pointer to a function which will report status
1626 * information about the compression process
1627 *
1628 * RETURNS
1629 * On success, returns TRUE
1630 * On failure, returns FALSE
1631 *
1632 * INCLUDES
1633 * fci.h
1634 *
1635 */
1636 BOOL __cdecl FCIFlushFolder(
1637 HFCI hfci,
1638 PFNFCIGETNEXTCABINET pfnfcignc,
1639 PFNFCISTATUS pfnfcis)
1640 {
1641 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1642
1643 if (!p_fci_internal) return FALSE;
1644 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1645 }
1646
1647
1648
1649 /***********************************************************************
1650 * FCIFlushCabinet (CABINET.13)
1651 *
1652 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1653 * into the cabinet file. If the maximum cabinet size (stored in the
1654 * member cb of the CCAB structure pccab passed to FCICreate) has been
1655 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1656 * The remaining data still has to be flushed manually by calling
1657 * FCIFlushCabinet.
1658 *
1659 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1660 * NOT be called again. Then hfci has to be released by FCIDestroy.
1661 *
1662 * PARAMS
1663 * hfci [I] An HFCI from FCICreate
1664 * fGetNextCab [I] Whether you want to add additional files to a
1665 * cabinet set (TRUE) or whether you want to
1666 * finalize it (FALSE)
1667 * pfnfcignc [I] A pointer to a function which gets information about
1668 * the next cabinet
1669 * pfnfcis [IO] A pointer to a function which will report status
1670 * information about the compression process
1671 *
1672 * RETURNS
1673 * On success, returns TRUE
1674 * On failure, returns FALSE
1675 *
1676 * INCLUDES
1677 * fci.h
1678 *
1679 */
1680 BOOL __cdecl FCIFlushCabinet(
1681 HFCI hfci,
1682 BOOL fGetNextCab,
1683 PFNFCIGETNEXTCABINET pfnfcignc,
1684 PFNFCISTATUS pfnfcis)
1685 {
1686 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1687
1688 if (!p_fci_internal) return FALSE;
1689
1690 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1691
1692 while( p_fci_internal->files_size>0 ||
1693 p_fci_internal->placed_files_size>0 ) {
1694 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1695 }
1696
1697 return TRUE;
1698 }
1699
1700
1701 /***********************************************************************
1702 * FCIDestroy (CABINET.14)
1703 *
1704 * Frees a handle created by FCICreate.
1705 * Only reason for failure would be an invalid handle.
1706 *
1707 * PARAMS
1708 * hfci [I] The HFCI to free
1709 *
1710 * RETURNS
1711 * TRUE for success
1712 * FALSE for failure
1713 */
1714 BOOL __cdecl FCIDestroy(HFCI hfci)
1715 {
1716 struct folder *folder, *folder_next;
1717 struct file *file, *file_next;
1718 struct data_block *block, *block_next;
1719 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1720
1721 if (!p_fci_internal) return FALSE;
1722
1723 /* before hfci can be removed all temporary files must be closed */
1724 /* and deleted */
1725 p_fci_internal->magic = 0;
1726
1727 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1728 {
1729 free_folder( p_fci_internal, folder );
1730 }
1731 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1732 {
1733 free_file( p_fci_internal, file );
1734 }
1735 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1736 {
1737 free_data_block( p_fci_internal, block );
1738 }
1739
1740 close_temp_file( p_fci_internal, &p_fci_internal->data );
1741
1742 /* hfci can now be removed */
1743 p_fci_internal->free(hfci);
1744 return TRUE;
1745 }