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