Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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 memset(p_fci_internal, 0, sizeof(FCI_Int));
1028 p_fci_internal->magic = FCI_INT_MAGIC;
1029 p_fci_internal->perf = perf;
1030 p_fci_internal->fileplaced = pfnfiledest;
1031 p_fci_internal->alloc = pfnalloc;
1032 p_fci_internal->free = pfnfree;
1033 p_fci_internal->open = pfnopen;
1034 p_fci_internal->read = pfnread;
1035 p_fci_internal->write = pfnwrite;
1036 p_fci_internal->close = pfnclose;
1037 p_fci_internal->seek = pfnseek;
1038 p_fci_internal->delete = pfndelete;
1039 p_fci_internal->gettemp = pfnfcigtf;
1040 p_fci_internal->ccab = *pccab;
1041 p_fci_internal->pccab = pccab;
1042 p_fci_internal->pv = pv;
1043 p_fci_internal->data.handle = -1;
1044 p_fci_internal->compress = compress_NONE;
1045
1046 list_init( &p_fci_internal->folders_list );
1047 list_init( &p_fci_internal->files_list );
1048 list_init( &p_fci_internal->blocks_list );
1049
1050 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
1051 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1052
1053 return (HFCI)p_fci_internal;
1054 }
1055
1056
1057
1058
1059 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1060 BOOL fGetNextCab,
1061 PFNFCIGETNEXTCABINET pfnfcignc,
1062 PFNFCISTATUS pfnfcis)
1063 {
1064 cab_ULONG payload;
1065 cab_ULONG read_result;
1066 struct folder *folder;
1067
1068 if ((!pfnfcignc) || (!pfnfcis)) {
1069 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1070 return FALSE;
1071 }
1072
1073 if( p_fci_internal->fGetNextCabInVain &&
1074 p_fci_internal->fNextCab ){
1075 /* internal error */
1076 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1077 return FALSE;
1078 }
1079
1080 /* If there was no FCIAddFile or FCIFlushFolder has already been called */
1081 /* this function will return TRUE */
1082 if( p_fci_internal->files_size == 0 ) {
1083 if ( p_fci_internal->pending_data_size != 0 ) {
1084 /* error handling */
1085 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1086 return FALSE;
1087 }
1088 return TRUE;
1089 }
1090
1091 /* FCIFlushFolder has already been called... */
1092 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1093 return TRUE;
1094 }
1095
1096 /* This can be set already, because it makes only a difference */
1097 /* when the current function exits with return FALSE */
1098 p_fci_internal->fSplitFolder=FALSE;
1099
1100 /* START of COPY */
1101 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1102
1103 /* reset to get the number of data blocks of this folder which are */
1104 /* actually in this cabinet ( at least partially ) */
1105 p_fci_internal->cDataBlocks=0;
1106
1107 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
1108 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
1109 p_fci_internal->placed_files_size+
1110 p_fci_internal->folders_data_size + p_fci_internal->files_size+
1111 p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1112 p_fci_internal->statusFolderCopied = 0;
1113
1114 /* report status with pfnfcis about copied size of folder */
1115 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
1116 p_fci_internal->statusFolderTotal, /* TODO total folder size */
1117 p_fci_internal->pv) == -1) {
1118 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1119 return FALSE;
1120 }
1121
1122 /* USE the variable read_result */
1123 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1124 p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1125
1126 if(p_fci_internal->files_size!=0) {
1127 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1128 }
1129
1130 /* Check if multiple cabinets have to be created. */
1131
1132 /* Might be too much data for the maximum allowed cabinet size.*/
1133 /* When any further data will be added later, it might not */
1134 /* be possible to flush the cabinet, because there might */
1135 /* not be enough space to store the name of the following */
1136 /* cabinet and name of the corresponding disk. */
1137 /* So take care of this and get the name of the next cabinet */
1138 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1139 p_fci_internal->fNextCab==FALSE &&
1140 (
1141 (
1142 p_fci_internal->ccab.cb < read_result +
1143 p_fci_internal->pending_data_size +
1144 p_fci_internal->files_size +
1145 CB_MAX_CABINET_NAME + /* next cabinet name */
1146 CB_MAX_DISK_NAME /* next disk name */
1147 ) || fGetNextCab
1148 )
1149 ) {
1150 /* increment cabinet index */
1151 ++(p_fci_internal->pccab->iCab);
1152 /* get name of next cabinet */
1153 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1154 if (!(*pfnfcignc)(p_fci_internal->pccab,
1155 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1156 p_fci_internal->pv)) {
1157 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1158 return FALSE;
1159 }
1160
1161 /* Skip a few lines of code. This is caught by the next if. */
1162 p_fci_internal->fGetNextCabInVain=TRUE;
1163 }
1164
1165 /* too much data for cabinet */
1166 if( (p_fci_internal->fGetNextCabInVain ||
1167 p_fci_internal->fNextCab ) &&
1168 (
1169 (
1170 p_fci_internal->ccab.cb < read_result +
1171 p_fci_internal->pending_data_size +
1172 p_fci_internal->files_size +
1173 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1174 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1175 ) || fGetNextCab
1176 )
1177 ) {
1178 p_fci_internal->fGetNextCabInVain=FALSE;
1179 p_fci_internal->fNextCab=TRUE;
1180
1181 /* return FALSE if there is not enough space left*/
1182 /* this should never happen */
1183 if (p_fci_internal->ccab.cb <=
1184 p_fci_internal->files_size +
1185 read_result +
1186 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
1187 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */
1188 ) {
1189
1190 return FALSE;
1191 }
1192
1193 /* the folder will be split across cabinets */
1194 p_fci_internal->fSplitFolder=TRUE;
1195
1196 } else {
1197 /* this should never happen */
1198 if (p_fci_internal->fNextCab) {
1199 /* internal error */
1200 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1201 return FALSE;
1202 }
1203 }
1204
1205 if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1206 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
1207 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1208
1209 /* reset CFFolder specific information */
1210 p_fci_internal->cDataBlocks=0;
1211 p_fci_internal->cCompressedBytesInFolder=0;
1212
1213 return TRUE;
1214 }
1215
1216
1217
1218
1219 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1220 BOOL fGetNextCab,
1221 PFNFCIGETNEXTCABINET pfnfcignc,
1222 PFNFCISTATUS pfnfcis)
1223 {
1224 cab_ULONG read_result=0;
1225 BOOL returntrue=FALSE;
1226
1227 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
1228
1229 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1230 if( p_fci_internal->files_size==0 && fGetNextCab ) {
1231 returntrue=TRUE;
1232 }
1233
1234 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1235 /* TODO set error */
1236 return FALSE;
1237 }
1238
1239 if(returntrue) return TRUE;
1240
1241 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1242 (p_fci_internal->folders_size==0 &&
1243 (p_fci_internal->files_size!=0 ||
1244 p_fci_internal->placed_files_size!=0 )
1245 ) )
1246 {
1247 /* error */
1248 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1249 return FALSE;
1250 }
1251
1252 /* create the cabinet */
1253 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1254
1255 p_fci_internal->fPrevCab=TRUE;
1256 /* The sections szPrevCab and szPrevDisk are not being updated, because */
1257 /* MS CABINET.DLL always puts the first cabinet name and disk into them */
1258
1259 if (p_fci_internal->fNextCab) {
1260 p_fci_internal->fNextCab=FALSE;
1261
1262 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1263 /* THIS CAN NEVER HAPPEN */
1264 /* set error code */
1265 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1266 return FALSE;
1267 }
1268
1269 if( p_fci_internal->fNewPrevious ) {
1270 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
1271 CB_MAX_CABINET_NAME);
1272 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
1273 CB_MAX_DISK_NAME);
1274 p_fci_internal->fNewPrevious=FALSE;
1275 }
1276 p_fci_internal->ccab = *p_fci_internal->pccab;
1277
1278 /* REUSE the variable read_result */
1279 read_result=get_header_size( p_fci_internal );
1280 if(p_fci_internal->files_size!=0) {
1281 read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1282 }
1283 read_result+= p_fci_internal->pending_data_size +
1284 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1285 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1286 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1287
1288 /* too much data for the maximum size of a cabinet */
1289 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1290 p_fci_internal->ccab.cb < read_result ) {
1291 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1292 }
1293
1294 /* Might be too much data for the maximum size of a cabinet.*/
1295 /* When any further data will be added later, it might not */
1296 /* be possible to flush the cabinet, because there might */
1297 /* not be enough space to store the name of the following */
1298 /* cabinet and name of the corresponding disk. */
1299 /* So take care of this and get the name of the next cabinet */
1300 if (p_fci_internal->fGetNextCabInVain==FALSE && (
1301 p_fci_internal->ccab.cb < read_result +
1302 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1303 )) {
1304 /* increment cabinet index */
1305 ++(p_fci_internal->pccab->iCab);
1306 /* get name of next cabinet */
1307 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1308 if (!(*pfnfcignc)(p_fci_internal->pccab,
1309 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1310 p_fci_internal->pv)) {
1311 /* error handling */
1312 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1313 return FALSE;
1314 }
1315 /* Skip a few lines of code. This is caught by the next if. */
1316 p_fci_internal->fGetNextCabInVain=TRUE;
1317 }
1318
1319 /* too much data for cabinet */
1320 if (p_fci_internal->fGetNextCabInVain && (
1321 p_fci_internal->ccab.cb < read_result +
1322 strlen(p_fci_internal->ccab.szCab)+1+
1323 strlen(p_fci_internal->ccab.szDisk)+1
1324 )) {
1325 p_fci_internal->fGetNextCabInVain=FALSE;
1326 p_fci_internal->fNextCab=TRUE;
1327 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1328 }
1329
1330 /* if the FolderThreshold has been reached flush the folder automatically */
1331 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1332 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1333
1334 if( p_fci_internal->files_size>0 ) {
1335 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1336 p_fci_internal->fNewPrevious=TRUE;
1337 }
1338 } else {
1339 p_fci_internal->fNewPrevious=FALSE;
1340 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1341 /* THIS MAY NEVER HAPPEN */
1342 /* set error structures */
1343 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1344 return FALSE;
1345 }
1346 }
1347
1348 return TRUE;
1349 } /* end of fci_flush_cabinet */
1350
1351
1352
1353
1354
1355 /***********************************************************************
1356 * FCIAddFile (CABINET.11)
1357 *
1358 * FCIAddFile adds a file to the to be created cabinet file
1359 *
1360 * PARAMS
1361 * hfci [I] An HFCI from FCICreate
1362 * pszSourceFile [I] A pointer to a C string which contains the name and
1363 * location of the file which will be added to the cabinet
1364 * pszFileName [I] A pointer to a C string which contains the name under
1365 * which the file will be stored in the cabinet
1366 * fExecute [I] A boolean value which indicates if the file should be
1367 * executed after extraction of self extracting
1368 * executables
1369 * pfnfcignc [I] A pointer to a function which gets information about
1370 * the next cabinet
1371 * pfnfcis [IO] A pointer to a function which will report status
1372 * information about the compression process
1373 * pfnfcioi [I] A pointer to a function which reports file attributes
1374 * and time and date information
1375 * typeCompress [I] Compression type
1376 *
1377 * RETURNS
1378 * On success, returns TRUE
1379 * On failure, returns FALSE
1380 *
1381 * INCLUDES
1382 * fci.h
1383 *
1384 */
1385 BOOL __cdecl FCIAddFile(
1386 HFCI hfci,
1387 char *pszSourceFile,
1388 char *pszFileName,
1389 BOOL fExecute,
1390 PFNFCIGETNEXTCABINET pfnfcignc,
1391 PFNFCISTATUS pfnfcis,
1392 PFNFCIGETOPENINFO pfnfcigoi,
1393 TCOMP typeCompress)
1394 {
1395 cab_ULONG read_result;
1396 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1397
1398 if (!p_fci_internal) return FALSE;
1399
1400 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
1401 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1402 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1403 return FALSE;
1404 }
1405
1406 if (typeCompress != p_fci_internal->compression)
1407 {
1408 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
1409 switch (typeCompress)
1410 {
1411 case tcompTYPE_MSZIP:
1412 #ifdef HAVE_ZLIB
1413 p_fci_internal->compression = tcompTYPE_MSZIP;
1414 p_fci_internal->compress = compress_MSZIP;
1415 break;
1416 #endif
1417 default:
1418 FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
1419 /* fall through */
1420 case tcompTYPE_NONE:
1421 p_fci_internal->compression = tcompTYPE_NONE;
1422 p_fci_internal->compress = compress_NONE;
1423 break;
1424 }
1425 }
1426
1427 /* TODO check if pszSourceFile??? */
1428
1429 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1430 /* internal error */
1431 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1432 return FALSE;
1433 }
1434
1435 if(p_fci_internal->fNextCab) {
1436 /* internal error */
1437 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1438 return FALSE;
1439 }
1440
1441 /* REUSE the variable read_result */
1442 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1443
1444 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1445 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1446 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1447 sizeof(CFFOLDER); /* size of new CFFolder entry */
1448
1449 /* Might be too much data for the maximum size of a cabinet.*/
1450 /* When any further data will be added later, it might not */
1451 /* be possible to flush the cabinet, because there might */
1452 /* not be enough space to store the name of the following */
1453 /* cabinet and name of the corresponding disk. */
1454 /* So take care of this and get the name of the next cabinet */
1455 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1456 p_fci_internal->fNextCab==FALSE &&
1457 ( p_fci_internal->ccab.cb < read_result +
1458 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1459 )
1460 ) {
1461 /* increment cabinet index */
1462 ++(p_fci_internal->pccab->iCab);
1463 /* get name of next cabinet */
1464 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1465 if (!(*pfnfcignc)(p_fci_internal->pccab,
1466 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1467 p_fci_internal->pv)) {
1468 /* error handling */
1469 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1470 return FALSE;
1471 }
1472 /* Skip a few lines of code. This is caught by the next if. */
1473 p_fci_internal->fGetNextCabInVain=TRUE;
1474 }
1475
1476 if( p_fci_internal->fGetNextCabInVain &&
1477 p_fci_internal->fNextCab
1478 ) {
1479 /* THIS CAN NEVER HAPPEN */
1480 /* set error code */
1481 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1482 return FALSE;
1483 }
1484
1485 /* too much data for cabinet */
1486 if( p_fci_internal->fGetNextCabInVain &&
1487 (
1488 p_fci_internal->ccab.cb < read_result +
1489 strlen(p_fci_internal->pccab->szCab)+1+
1490 strlen(p_fci_internal->pccab->szDisk)+1
1491 )) {
1492 p_fci_internal->fGetNextCabInVain=FALSE;
1493 p_fci_internal->fNextCab=TRUE;
1494 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1495 }
1496
1497 if( p_fci_internal->fNextCab ) {
1498 /* THIS MAY NEVER HAPPEN */
1499 /* set error code */
1500 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1501 return FALSE;
1502 }
1503
1504 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1505 return FALSE;
1506
1507 /* REUSE the variable read_result */
1508 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1509 read_result+= p_fci_internal->pending_data_size +
1510 p_fci_internal->files_size + p_fci_internal->folders_data_size +
1511 p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1512 sizeof(CFFOLDER); /* set size of new CFFolder entry */
1513
1514 /* too much data for the maximum size of a cabinet */
1515 /* (ignoring the unflushed data block) */
1516 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1517 p_fci_internal->fNextCab==FALSE && /* this is always the case */
1518 p_fci_internal->ccab.cb < read_result ) {
1519 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1520 }
1521
1522 /* Might be too much data for the maximum size of a cabinet.*/
1523 /* When any further data will be added later, it might not */
1524 /* be possible to flush the cabinet, because there might */
1525 /* not be enough space to store the name of the following */
1526 /* cabinet and name of the corresponding disk. */
1527 /* So take care of this and get the name of the next cabinet */
1528 /* (ignoring the unflushed data block) */
1529 if( p_fci_internal->fGetNextCabInVain==FALSE &&
1530 p_fci_internal->fNextCab==FALSE &&
1531 ( p_fci_internal->ccab.cb < read_result +
1532 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
1533 )
1534 ) {
1535 /* increment cabinet index */
1536 ++(p_fci_internal->pccab->iCab);
1537 /* get name of next cabinet */
1538 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
1539 if (!(*pfnfcignc)(p_fci_internal->pccab,
1540 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1541 p_fci_internal->pv)) {
1542 /* error handling */
1543 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1544 return FALSE;
1545 }
1546 /* Skip a few lines of code. This is caught by the next if. */
1547 p_fci_internal->fGetNextCabInVain=TRUE;
1548 }
1549
1550 if( p_fci_internal->fGetNextCabInVain &&
1551 p_fci_internal->fNextCab
1552 ) {
1553 /* THIS CAN NEVER HAPPEN */
1554 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1555 return FALSE;
1556 }
1557
1558 /* too much data for cabinet */
1559 if( (p_fci_internal->fGetNextCabInVain ||
1560 p_fci_internal->fNextCab) && (
1561 p_fci_internal->ccab.cb < read_result +
1562 strlen(p_fci_internal->pccab->szCab)+1+
1563 strlen(p_fci_internal->pccab->szDisk)+1
1564 )) {
1565
1566 p_fci_internal->fGetNextCabInVain=FALSE;
1567 p_fci_internal->fNextCab=TRUE;
1568 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1569 }
1570
1571 if( p_fci_internal->fNextCab ) {
1572 /* THIS MAY NEVER HAPPEN */
1573 /* set error code */
1574 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1575 return FALSE;
1576 }
1577
1578 /* if the FolderThreshold has been reached flush the folder automatically */
1579 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1580 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
1581
1582 return TRUE;
1583 } /* end of FCIAddFile */
1584
1585
1586
1587
1588
1589 /***********************************************************************
1590 * FCIFlushFolder (CABINET.12)
1591 *
1592 * FCIFlushFolder completes the CFFolder structure under construction.
1593 *
1594 * All further data which is added by FCIAddFile will be associated to
1595 * the next CFFolder structure.
1596 *
1597 * FCIFlushFolder will be called by FCIAddFile automatically if the
1598 * threshold (stored in the member cbFolderThresh of the CCAB structure
1599 * pccab passed to FCICreate) is exceeded.
1600 *
1601 * FCIFlushFolder will be called by FCIFlushFolder automatically before
1602 * any data will be written into the cabinet file.
1603 *
1604 * PARAMS
1605 * hfci [I] An HFCI from FCICreate
1606 * pfnfcignc [I] A pointer to a function which gets information about
1607 * the next cabinet
1608 * pfnfcis [IO] A pointer to a function which will report status
1609 * information about the compression process
1610 *
1611 * RETURNS
1612 * On success, returns TRUE
1613 * On failure, returns FALSE
1614 *
1615 * INCLUDES
1616 * fci.h
1617 *
1618 */
1619 BOOL __cdecl FCIFlushFolder(
1620 HFCI hfci,
1621 PFNFCIGETNEXTCABINET pfnfcignc,
1622 PFNFCISTATUS pfnfcis)
1623 {
1624 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1625
1626 if (!p_fci_internal) return FALSE;
1627 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
1628 }
1629
1630
1631
1632 /***********************************************************************
1633 * FCIFlushCabinet (CABINET.13)
1634 *
1635 * FCIFlushCabinet stores the data which has been added by FCIAddFile
1636 * into the cabinet file. If the maximum cabinet size (stored in the
1637 * member cb of the CCAB structure pccab passed to FCICreate) has been
1638 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
1639 * The remaining data still has to be flushed manually by calling
1640 * FCIFlushCabinet.
1641 *
1642 * After FCIFlushCabinet has been called (manually) FCIAddFile must
1643 * NOT be called again. Then hfci has to be released by FCIDestroy.
1644 *
1645 * PARAMS
1646 * hfci [I] An HFCI from FCICreate
1647 * fGetNextCab [I] Whether you want to add additional files to a
1648 * cabinet set (TRUE) or whether you want to
1649 * finalize it (FALSE)
1650 * pfnfcignc [I] A pointer to a function which gets information about
1651 * the next cabinet
1652 * pfnfcis [IO] A pointer to a function which will report status
1653 * information about the compression process
1654 *
1655 * RETURNS
1656 * On success, returns TRUE
1657 * On failure, returns FALSE
1658 *
1659 * INCLUDES
1660 * fci.h
1661 *
1662 */
1663 BOOL __cdecl FCIFlushCabinet(
1664 HFCI hfci,
1665 BOOL fGetNextCab,
1666 PFNFCIGETNEXTCABINET pfnfcignc,
1667 PFNFCISTATUS pfnfcis)
1668 {
1669 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1670
1671 if (!p_fci_internal) return FALSE;
1672
1673 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1674
1675 while( p_fci_internal->files_size>0 ||
1676 p_fci_internal->placed_files_size>0 ) {
1677 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1678 }
1679
1680 return TRUE;
1681 }
1682
1683
1684 /***********************************************************************
1685 * FCIDestroy (CABINET.14)
1686 *
1687 * Frees a handle created by FCICreate.
1688 * Only reason for failure would be an invalid handle.
1689 *
1690 * PARAMS
1691 * hfci [I] The HFCI to free
1692 *
1693 * RETURNS
1694 * TRUE for success
1695 * FALSE for failure
1696 */
1697 BOOL __cdecl FCIDestroy(HFCI hfci)
1698 {
1699 struct folder *folder, *folder_next;
1700 struct file *file, *file_next;
1701 struct data_block *block, *block_next;
1702 FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1703
1704 if (!p_fci_internal) return FALSE;
1705
1706 /* before hfci can be removed all temporary files must be closed */
1707 /* and deleted */
1708 p_fci_internal->magic = 0;
1709
1710 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
1711 {
1712 free_folder( p_fci_internal, folder );
1713 }
1714 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
1715 {
1716 free_file( p_fci_internal, file );
1717 }
1718 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
1719 {
1720 free_data_block( p_fci_internal, block );
1721 }
1722
1723 close_temp_file( p_fci_internal, &p_fci_internal->data );
1724
1725 /* hfci can now be removed */
1726 p_fci_internal->free(hfci);
1727 return TRUE;
1728 }