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