fci.c 57.2 KB
Newer Older
1 2 3 4
/*
 * File Compression Interface
 *
 * Copyright 2002 Patrik Stridvall
5
 * Copyright 2005 Gerold Jens Wucherpfennig
6
 * Copyright 2011 Alexandre Julliard
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 26
/*

There is still some work to be done:

27
- unknown behaviour if files>=2GB or cabinet >=4GB
28 29 30 31 32
- check if the maximum size for a cabinet is too small to store any data
- call pfnfcignc on exactly the same position as MS FCIAddFile in every case

*/

33
#include <assert.h>
34
#include <stdarg.h>
35 36
#include <stdio.h>
#include <string.h>
37 38
#include <sys/stat.h>
#include <fcntl.h>
39

40
#include "windef.h"
41 42
#include "winbase.h"
#include "winerror.h"
43
#include "winternl.h"
44
#include "fci.h"
45
#include "zlib.h"
46
#include "cabinet.h"
47
#include "wine/list.h"
48 49
#include "wine/debug.h"

50
WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
51 52 53 54 55 56 57 58 59 60

#ifdef WORDS_BIGENDIAN
#define fci_endian_ulong(x) RtlUlongByteSwap(x)
#define fci_endian_uword(x) RtlUshortByteSwap(x)
#else
#define fci_endian_ulong(x) (x)
#define fci_endian_uword(x) (x)
#endif


61 62 63 64 65 66 67 68 69 70 71
typedef struct {
  cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
  cab_ULONG reserved1;
  cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/
  cab_ULONG reserved2;
  cab_ULONG coffFiles;    /* offset to first CFFILE section */
  cab_ULONG reserved3;
  cab_UBYTE versionMinor; /* 3 */
  cab_UBYTE versionMajor; /* 1 */
  cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/
  cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/
Austin English's avatar
Austin English committed
72
  cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
73 74 75 76 77 78 79 80 81 82
  cab_UWORD setID;        /* identification number of all cabinets in a set*/
  cab_UWORD iCabinet;     /* number of the cabinet in a set */
  /* additional area if "flags" were set*/
} CFHEADER; /* minimum 36 bytes */

typedef struct {
  cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
  cab_UWORD cCFData;      /* number of this folder's CFDATA sections */
  cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
  /* additional area if reserve flag was set */
83
} CFFOLDER; /* minimum 8 bytes */
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

typedef struct {
  cab_ULONG cbFile;          /* size of the uncompressed file in bytes */
  cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
  cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */
                             /* for special values see below this structure*/
  cab_UWORD date;            /* last modification date*/
  cab_UWORD time;            /* last modification time*/
  cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */
  /* ... and a C string with the name of the file */
} CFFILE; /* 16 bytes + name of file */


typedef struct {
  cab_ULONG csum;          /* checksum of this entry*/
  cab_UWORD cbData;        /* number of compressed bytes  */
  cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */
  /* optional reserved area */
  /* compressed data */
} CFDATA;

105 106 107 108 109 110
struct temp_file
{
    INT_PTR   handle;
    char      name[CB_MAX_FILENAME];
};

111 112
struct folder
{
113 114 115 116 117 118
    struct list      entry;
    struct list      files_list;
    struct list      blocks_list;
    struct temp_file data;
    cab_ULONG        data_start;
    cab_UWORD        data_count;
119
    TCOMP            compression;
120
};
121

122 123 124 125 126 127 128 129 130 131 132 133
struct file
{
    struct list entry;
    cab_ULONG   size;    /* uncompressed size */
    cab_ULONG   offset;  /* offset in folder */
    cab_UWORD   folder;  /* index of folder */
    cab_UWORD   date;
    cab_UWORD   time;
    cab_UWORD   attribs;
    char        name[1];
};

134 135 136 137 138 139 140
struct data_block
{
    struct list entry;
    cab_UWORD   compressed;
    cab_UWORD   uncompressed;
};

141
typedef struct FCI_Int
142 143
{
  unsigned int       magic;
144
  PERF               perf;
145 146 147 148 149 150 151 152 153 154
  PFNFCIFILEPLACED   fileplaced;
  PFNFCIALLOC        alloc;
  PFNFCIFREE         free;
  PFNFCIOPEN         open;
  PFNFCIREAD         read;
  PFNFCIWRITE        write;
  PFNFCICLOSE        close;
  PFNFCISEEK         seek;
  PFNFCIDELETE       delete;
  PFNFCIGETTEMPFILE  gettemp;
155
  CCAB               ccab;
156 157 158 159 160 161 162 163
  PCCAB              pccab;
  BOOL               fPrevCab;
  BOOL               fNextCab;
  BOOL               fSplitFolder;
  cab_ULONG          statusFolderCopied;
  cab_ULONG          statusFolderTotal;
  BOOL               fGetNextCabInVain;
  void               *pv;
164 165 166 167
  char               szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
  char               szPrevDisk[CB_MAX_DISK_NAME];   /* disk name of previous cabinet */
  unsigned char      data_in[CAB_BLOCKMAX];          /* uncompressed data blocks */
  unsigned char      data_out[2 * CAB_BLOCKMAX];     /* compressed data blocks */
168 169 170 171 172
  cab_UWORD          cdata_in;
  ULONG              cCompressedBytesInFolder;
  cab_UWORD          cFolders;
  cab_UWORD          cFiles;
  cab_ULONG          cDataBlocks;
173
  cab_ULONG          cbFileRemainder; /* uncompressed, yet to be written data */
174
               /* of spanned file of a spanning folder of a spanning cabinet */
175
  struct temp_file   data;
176 177
  BOOL               fNewPrevious;
  cab_ULONG          estimatedCabinetSize;
178
  struct list        folders_list;
179
  struct list        files_list;
180
  struct list        blocks_list;
181
  cab_ULONG          folders_size;
182 183 184 185
  cab_ULONG          files_size;          /* size of files not yet assigned to a folder */
  cab_ULONG          placed_files_size;   /* size of files already placed into a folder */
  cab_ULONG          pending_data_size;   /* size of data not yet assigned to a folder */
  cab_ULONG          folders_data_size;   /* total size of data contained in the current folders */
186 187
  TCOMP              compression;
  cab_UWORD        (*compress)(struct FCI_Int *);
188 189 190 191
} FCI_Int;

#define FCI_INT_MAGIC 0xfcfcfc05

192 193 194 195 196 197 198 199
static void set_error( FCI_Int *fci, int oper, int err )
{
    fci->perf->erfOper = oper;
    fci->perf->erfType = err;
    fci->perf->fError = TRUE;
    if (err) SetLastError( err );
}

200 201 202 203
static FCI_Int *get_fci_ptr( HFCI hfci )
{
    FCI_Int *fci= (FCI_Int *)hfci;

204
    if (!fci || fci->magic != FCI_INT_MAGIC)
205 206 207 208 209 210 211
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return NULL;
    }
    return fci;
}

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
/* compute the cabinet header size */
static cab_ULONG get_header_size( FCI_Int *fci )
{
    cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;

    if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
        ret += 4;

    if (fci->fPrevCab)
        ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;

    if (fci->fNextCab)
        ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;

    return ret;
}

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
{
    int err;

    if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
    {
        set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
        return FALSE;
    }
    if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
                                   _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    return TRUE;
}

static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
{
    int err;

    if (file->handle == -1) return TRUE;
    if (fci->close( file->handle, &err, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    file->handle = -1;
    if (fci->delete( file->name, &err, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    return TRUE;
}

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
static struct file *add_file( FCI_Int *fci, const char *filename )
{
    unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
    struct file *file = fci->alloc( size );

    if (!file)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
    file->size    = 0;
    file->offset  = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
    file->folder  = fci->cFolders;
    file->date    = 0;
    file->time    = 0;
    file->attribs = 0;
    strcpy( file->name, filename );
    list_add_tail( &fci->files_list, &file->entry );
284
    fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    return file;
}

static struct file *copy_file( FCI_Int *fci, const struct file *orig )
{
    unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
    struct file *file = fci->alloc( size );

    if (!file)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
    memcpy( file, orig, size );
    return file;
}

static void free_file( FCI_Int *fci, struct file *file )
{
    list_remove( &file->entry );
    fci->free( file );
}

308 309
/* create a new data block for the data in fci->data_in */
static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
310
{
311 312
    int err;
    struct data_block *block;
313

314 315
    if (!fci->cdata_in) return TRUE;

316 317
    if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;

318
    if (!(block = fci->alloc( sizeof(*block) )))
319 320
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
321
        return FALSE;
322
    }
323 324 325 326 327 328 329 330 331 332 333 334
    block->uncompressed = fci->cdata_in;
    block->compressed   = fci->compress( fci );

    if (fci->write( fci->data.handle, fci->data_out,
                    block->compressed, &err, fci->pv ) != block->compressed)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        fci->free( block );
        return FALSE;
    }

    fci->cdata_in = 0;
335
    fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
336
    fci->cCompressedBytesInFolder += block->compressed;
337
    fci->cDataBlocks++;
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
    list_add_tail( &fci->blocks_list, &block->entry );

    if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_USER_ABORT, 0 );
        return FALSE;
    }
    return TRUE;
}

/* add compressed blocks for all the data that can be read from the file */
static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
                           PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
{
    int err, len;
    INT_PTR handle;
    struct file *file;

    if (!(file = add_file( fci, filename ))) return FALSE;

    handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
    if (handle == -1)
    {
        free_file( fci, file );
        set_error( fci, FCIERR_OPEN_SRC, err );
        return FALSE;
    }
    if (execute) file->attribs |= _A_EXEC;

    for (;;)
    {
        len = fci->read( handle, fci->data_in + fci->cdata_in,
                         CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
        if (!len) break;

        if (len == -1)
        {
            set_error( fci, FCIERR_READ_SRC, err );
            return FALSE;
        }
        file->size += len;
        fci->cdata_in += len;
        if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
    }
    fci->close( handle, &err, fci->pv );
    return TRUE;
384 385 386 387 388 389 390 391
}

static void free_data_block( FCI_Int *fci, struct data_block *block )
{
    list_remove( &block->entry );
    fci->free( block );
}

392 393 394 395 396 397 398 399 400
static struct folder *add_folder( FCI_Int *fci )
{
    struct folder *folder = fci->alloc( sizeof(*folder) );

    if (!folder)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
401 402 403
    folder->data.handle = -1;
    folder->data_start  = fci->folders_data_size;
    folder->data_count  = 0;
404
    folder->compression = fci->compression;
405
    list_init( &folder->files_list );
406
    list_init( &folder->blocks_list );
407
    list_add_tail( &fci->folders_list, &folder->entry );
408
    fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
409 410 411 412
    fci->cFolders++;
    return folder;
}

413 414
static void free_folder( FCI_Int *fci, struct folder *folder )
{
415 416
    struct file *file, *file_next;
    struct data_block *block, *block_next;
417

418 419 420 421 422
    LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
        free_file( fci, file );
    LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
        free_data_block( fci, block );
    close_temp_file( fci, &folder->data );
423 424 425 426
    list_remove( &folder->entry );
    fci->free( folder );
}

427 428 429 430 431 432 433 434 435 436 437 438
/* reset state for the next cabinet file once the current one has been flushed */
static void reset_cabinet( FCI_Int *fci )
{
    struct folder *folder, *folder_next;

    LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
        free_folder( fci, folder );

    fci->cFolders          = 0;
    fci->cFiles            = 0;
    fci->folders_size      = 0;
    fci->placed_files_size = 0;
439
    fci->folders_data_size = 0;
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
}

static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
{
  cab_ULONG     csum;
  cab_ULONG     ul;
  int           cUlong;
  const BYTE    *pb;

  csum = seed;
  cUlong = cb / 4;
  pb = pv;

  while (cUlong-- > 0) {
    ul = *pb++;
    ul |= (((cab_ULONG)(*pb++)) <<  8);
    ul |= (((cab_ULONG)(*pb++)) << 16);
    ul |= (((cab_ULONG)(*pb++)) << 24);
    csum ^= ul;
  }

  ul = 0;
  switch (cb % 4) {
    case 3:
      ul |= (((ULONG)(*pb++)) << 16);
465
      /* fall through */
466 467
    case 2:
      ul |= (((ULONG)(*pb++)) <<  8);
468
      /* fall through */
469 470
    case 1:
      ul |= *pb;
471
      /* fall through */
472 473 474 475 476 477 478 479
    default:
      break;
  }
  csum ^= ul;

  return csum;
}

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
/* copy all remaining data block to a new temp file */
static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
                              struct temp_file *temp, PFNFCISTATUS status_callback )
{
    struct data_block *block;
    int err;

    if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    if (!create_temp_file( fci, temp )) return FALSE;

    LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
    {
        if (fci->read( handle, fci->data_out, block->compressed,
                       &err, fci->pv ) != block->compressed)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_TEMP_FILE, err );
            return FALSE;
        }
        if (fci->write( temp->handle, fci->data_out, block->compressed,
                        &err, fci->pv ) != block->compressed)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_TEMP_FILE, err );
            return FALSE;
        }
510
        fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
511 512 513 514 515 516 517 518 519 520 521 522 523
        fci->statusFolderCopied += block->compressed;

        if (status_callback( statusFolder, fci->statusFolderCopied,
                             fci->statusFolderTotal, fci->pv) == -1)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_USER_ABORT, 0 );
            return FALSE;
        }
    }
    return TRUE;
}

524
/* write all folders to disk and remove them from the list */
525
static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
526
{
527
    struct folder *folder;
528
    int err;
529
    CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
530
    cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
531 532 533

    memset( cffolder, 0, folder_size );

534 535
    /* write the folders */
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
536 537 538 539 540 541 542
    {
        cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
        cffolder->cCFData      = fci_endian_uword( folder->data_count );
        cffolder->typeCompress = fci_endian_uword( folder->compression );
        if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
        {
            set_error( fci, FCIERR_CAB_FILE, err );
543
            return FALSE;
544
        }
545
    }
546
    return TRUE;
547 548 549 550 551 552 553 554 555
}

/* write all the files to the cabinet file */
static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
{
    cab_ULONG file_size;
    struct folder *folder;
    struct file *file;
    int err;
556
    CFFILE *cffile = (CFFILE *)fci->data_out;
557

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
    {
        LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
        {
            cffile->cbFile          = fci_endian_ulong( file->size );
            cffile->uoffFolderStart = fci_endian_ulong( file->offset );
            cffile->iFolder         = fci_endian_uword( file->folder );
            cffile->date            = fci_endian_uword( file->date );
            cffile->time            = fci_endian_uword( file->time );
            cffile->attribs         = fci_endian_uword( file->attribs );
            lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
            file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
            if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
            {
                set_error( fci, FCIERR_CAB_FILE, err );
573
                return FALSE;
574 575 576 577 578
            }
            if (!fci->fSplitFolder)
            {
                fci->statusFolderCopied = 0;
                /* TODO TEST THIS further */
579
                fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
580 581 582 583 584 585 586
            }
            fci->statusFolderCopied += file_size;
            /* report status about copied size of folder */
            if (status_callback( statusFolder, fci->statusFolderCopied,
                                 fci->statusFolderTotal, fci->pv ) == -1)
            {
                set_error( fci, FCIERR_USER_ABORT, 0 );
587
                return FALSE;
588 589 590
            }
        }
    }
591
    return TRUE;
592 593
}

594 595 596
/* write all data blocks to the cabinet file */
static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
{
597
    struct folder *folder;
598 599 600 601 602 603 604 605 606 607 608
    struct data_block *block;
    int err, len;
    CFDATA *cfdata;
    void *data;
    cab_UWORD header_size;

    header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
    cfdata = (CFDATA *)fci->data_out;
    memset( cfdata, 0, header_size );
    data = (char *)cfdata + header_size;

609
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
610
    {
611
        if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
612 613 614 615
        {
            set_error( fci, FCIERR_CAB_FILE, err );
            return FALSE;
        }
616
        LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
617
        {
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
            len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
            if (len != block->compressed) return FALSE;

            cfdata->cbData = fci_endian_uword( block->compressed );
            cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
            cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
                                                               header_size - FIELD_OFFSET(CFDATA, cbData),
                                                               fci_get_checksum( data, len, 0 )));

            fci->statusFolderCopied += len;
            len += header_size;
            if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
            {
                set_error( fci, FCIERR_CAB_FILE, err );
                return FALSE;
            }
            if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
            {
                set_error( fci, FCIERR_USER_ABORT, 0 );
                return FALSE;
            }
639 640 641 642 643
        }
    }
    return TRUE;
}

644
/* write the cabinet file to disk */
645
static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
646 647 648
{
    char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
    int err;
649
    char *ptr;
650
    INT_PTR handle;
651
    CFHEADER *cfheader = (CFHEADER *)fci->data_out;
652 653
    cab_UWORD flags = 0;
    cab_ULONG header_size = get_header_size( fci );
654 655
    cab_ULONG total_size = header_size + fci->folders_size +
                           fci->placed_files_size + fci->folders_data_size;
656

657
    assert( header_size <= sizeof(fci->data_out) );
658 659 660 661 662 663 664 665
    memset( cfheader, 0, header_size );

    if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
    if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
    if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
      flags |= cfheadRESERVE_PRESENT;

    memcpy( cfheader->signature, "!CAB", 4 );
666
    cfheader->cbCabinet    = fci_endian_ulong( total_size );
667 668 669 670 671 672 673
    cfheader->coffFiles    = fci_endian_ulong( header_size + fci->folders_size );
    cfheader->versionMinor = 3;
    cfheader->versionMajor = 1;
    cfheader->cFolders     = fci_endian_uword( fci->cFolders );
    cfheader->cFiles       = fci_endian_uword( fci->cFiles );
    cfheader->flags        = fci_endian_uword( flags );
    cfheader->setID        = fci_endian_uword( fci->ccab.setID );
674
    cfheader->iCabinet     = fci_endian_uword( fci->ccab.iCab );
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
    ptr = (char *)(cfheader + 1);

    if (flags & cfheadRESERVE_PRESENT)
    {
        struct
        {
            cab_UWORD cbCFHeader;
            cab_UBYTE cbCFFolder;
            cab_UBYTE cbCFData;
        } *reserve = (void *)ptr;

        reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
        reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
        reserve->cbCFData   = fci->ccab.cbReserveCFData;
        ptr = (char *)(reserve + 1);
    }
    ptr += fci->ccab.cbReserveCFHeader;

    if (flags & cfheadPREV_CABINET)
    {
        strcpy( ptr, fci->szPrevCab );
        ptr += strlen( ptr ) + 1;
        strcpy( ptr, fci->szPrevDisk );
        ptr += strlen( ptr ) + 1;
    }

    if (flags & cfheadNEXT_CABINET)
    {
        strcpy( ptr, fci->pccab->szCab );
        ptr += strlen( ptr ) + 1;
        strcpy( ptr, fci->pccab->szDisk );
        ptr += strlen( ptr ) + 1;
    }

    assert( ptr - (char *)cfheader == header_size );

    strcpy( filename, fci->ccab.szCabPath );
    strcat( filename, fci->ccab.szCab );

    if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
                             _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
718
        return FALSE;
719 720 721 722 723 724 725 726 727 728 729
    }

    if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }

    /* add size of header size of all CFFOLDERs and size of all CFFILEs */
    header_size += fci->placed_files_size + fci->folders_size;
    if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
730 731
    if (!write_files( fci, handle, status_callback )) goto failed;
    if (!write_data_blocks( fci, handle, status_callback )) goto failed;
732

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
    /* update the signature */
    if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }
    memcpy( cfheader->signature, "MSCF", 4 );
    if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }
    fci->close( handle, &err, fci->pv );

    reset_cabinet( fci );
    status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
    return TRUE;
750 751 752 753

failed:
    fci->close( handle, &err, fci->pv );
    fci->delete( filename, &err, fci->pv );
754
    return FALSE;
755 756
}

757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
/* add all pending data blocks folder */
static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
                                PFNFCISTATUS status_callback )
{
    struct data_block *block, *new, *next;
    BOOL split_block = FALSE;
    cab_ULONG current_size, start_pos = 0;

    *payload = 0;
    current_size = get_header_size( fci ) + fci->folders_size +
                   fci->files_size + fci->placed_files_size + fci->folders_data_size;

    /* move the temp file into the folder structure */
    folder->data = fci->data;
    fci->data.handle = -1;
772
    fci->pending_data_size = 0;
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829

    LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
    {
        /* No more CFDATA fits into the cabinet under construction */
        /* So don't try to store more data into it */
        if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
                              current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
            break;

        if (!(new = fci->alloc( sizeof(*new) )))
        {
            set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
            return FALSE;
        }
        /* Is cabinet with new CFDATA too large? Then data block has to be split */
        if( fci->fNextCab &&
            (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
             block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
        {
            /* Modify the size of the compressed data to store only a part of the */
            /* data block into the current cabinet. This is done to prevent */
            /* that the maximum cabinet size will be exceeded. The remainder */
            /* will be stored into the next following cabinet. */

            new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
                                              sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
            new->uncompressed = 0; /* on split blocks of data this is zero */
            block->compressed -= new->compressed;
            split_block = TRUE;
        }
        else
        {
            new->compressed   = block->compressed;
            new->uncompressed = block->uncompressed;
        }

        start_pos += new->compressed;
        current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
        fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
        fci->statusFolderCopied += new->compressed;
        (*payload) += new->uncompressed;

        list_add_tail( &folder->blocks_list, &new->entry );
        folder->data_count++;

        /* report status with pfnfcis about copied size of folder */
        if (status_callback( statusFolder, fci->statusFolderCopied,
                             fci->statusFolderTotal, fci->pv ) == -1)
        {
            set_error( fci, FCIERR_USER_ABORT, 0 );
            return FALSE;
        }
        if (split_block) break;
        free_data_block( fci, block );
        fci->cDataBlocks--;
    }

830
    if (list_empty( &fci->blocks_list )) return TRUE;
831 832 833
    return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
}

834 835 836 837
/* add all pending files to folder */
static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
{
    cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
838
    cab_ULONG cbFileRemainder = 0;
839 840 841 842 843 844 845
    struct file *file, *next;

    LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
    {
        cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;

        /* fnfilfnfildest: placed file on cabinet */
846 847
        fci->fileplaced( &fci->ccab, file->name, file->size,
                         (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
848 849 850

        sizeOfFilesPrev = sizeOfFiles;
        /* set complete size of all processed files */
851
        if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainder != 0)
852
        {
853 854
            sizeOfFiles += fci->cbFileRemainder;
            fci->cbFileRemainder = 0;
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
        }
        else sizeOfFiles += file->size;

        /* check if spanned file fits into this cabinet folder */
        if (sizeOfFiles > payload)
        {
            if (file->folder == cffileCONTINUED_FROM_PREV)
                file->folder = cffileCONTINUED_PREV_AND_NEXT;
            else
                file->folder = cffileCONTINUED_TO_NEXT;
        }

        list_remove( &file->entry );
        list_add_tail( &folder->files_list, &file->entry );
        fci->placed_files_size += size;
        fci->cFiles++;

        /* This is only true for files which will be written into the */
        /* next cabinet of the spanning folder */
        if (sizeOfFiles > payload)
        {
            /* add a copy back onto the list */
            if (!(file = copy_file( fci, file ))) return FALSE;
            list_add_before( &next->entry, &file->entry );

            /* Files which data will be partially written into the current cabinet */
            if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
            {
                if (sizeOfFilesPrev <= payload)
                {
                    /* The size of the uncompressed, data of a spanning file in a */
                    /* spanning data */
887
                    cbFileRemainder = sizeOfFiles - payload;
888 889 890 891 892 893 894 895 896 897
                }
                file->folder = cffileCONTINUED_FROM_PREV;
            }
            else file->folder = 0;
        }
        else
        {
            fci->files_size -= size;
        }
    }
898
    fci->cbFileRemainder = cbFileRemainder;
899 900 901
    return TRUE;
}

902 903 904 905 906 907
static cab_UWORD compress_NONE( FCI_Int *fci )
{
    memcpy( fci->data_out, fci->data_in, fci->cdata_in );
    return fci->cdata_in;
}

908 909 910 911 912 913 914 915 916
static void *zalloc( void *opaque, unsigned int items, unsigned int size )
{
    FCI_Int *fci = opaque;
    return fci->alloc( items * size );
}

static void zfree( void *opaque, void *ptr )
{
    FCI_Int *fci = opaque;
917
    fci->free( ptr );
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
}

static cab_UWORD compress_MSZIP( FCI_Int *fci )
{
    z_stream stream;

    stream.zalloc = zalloc;
    stream.zfree  = zfree;
    stream.opaque = fci;
    if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return 0;
    }
    stream.next_in   = fci->data_in;
    stream.avail_in  = fci->cdata_in;
    stream.next_out  = fci->data_out + 2;
935
    stream.avail_out = sizeof(fci->data_out) - 2;
936 937 938 939 940 941 942 943
    /* insert the signature */
    fci->data_out[0] = 'C';
    fci->data_out[1] = 'K';
    deflate( &stream, Z_FINISH );
    deflateEnd( &stream );
    return stream.total_out + 2;
}

944

945 946
/***********************************************************************
 *		FCICreate (CABINET.10)
947
 *
948 949
 * FCICreate is provided with several callbacks and
 * returns a handle which can be used to create cabinet files.
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
 *
 * PARAMS
 *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
 *                    returns an error condition, error information may
 *                    be found here as well as from GetLastError.
 *   pfnfiledest [I]  A pointer to a function which is called when a file
 *                    is placed. Only useful for subsequent cabinet files.
 *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
 *                    the same interface as malloc.
 *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
 *                    same interface as free.
 *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
 *                    the same interface as _open.
 *   pfnread     [I]  A pointer to a function which reads from a file into
 *                    a caller-provided buffer.  Uses the same interface
965
 *                    as _read.
966 967 968 969 970 971 972 973 974
 *   pfnwrite    [I]  A pointer to a function which writes to a file from
 *                    a caller-provided buffer.  Uses the same interface
 *                    as _write.
 *   pfnclose    [I]  A pointer to a function which closes a file handle.
 *                    Uses the same interface as _close.
 *   pfnseek     [I]  A pointer to a function which seeks in a file.
 *                    Uses the same interface as _lseek.
 *   pfndelete   [I]  A pointer to a function which deletes a file.
 *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
975 976
 *                    temporary file.
 *   pccab       [I]  A pointer to an initialized CCAB structure.
977 978 979 980 981 982 983 984 985 986 987 988
 *   pv          [I]  A pointer to an application-defined notification
 *                    function which will be passed to other FCI functions
 *                    as a parameter.
 *
 * RETURNS
 *   On success, returns an FCI handle of type HFCI.
 *   On failure, the NULL file handle is returned. Error
 *   info can be retrieved from perf.
 *
 * INCLUDES
 *   fci.h
 *
989 990 991
 */
HFCI __cdecl FCICreate(
	PERF perf,
992 993 994
	PFNFCIFILEPLACED   pfnfiledest,
	PFNFCIALLOC        pfnalloc,
	PFNFCIFREE         pfnfree,
995 996 997 998 999 1000 1001 1002 1003 1004
	PFNFCIOPEN         pfnopen,
	PFNFCIREAD         pfnread,
	PFNFCIWRITE        pfnwrite,
	PFNFCICLOSE        pfnclose,
	PFNFCISEEK         pfnseek,
	PFNFCIDELETE       pfndelete,
	PFNFCIGETTEMPFILE  pfnfcigtf,
	PCCAB              pccab,
	void *pv)
{
1005
  FCI_Int *p_fci_internal;
1006

1007 1008 1009 1010 1011
  if (!perf) {
    SetLastError(ERROR_BAD_ARGUMENTS);
    return NULL;
  }
  if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1012 1013
      (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
      (!pfnfcigtf) || (!pccab)) {
1014
    perf->erfOper = FCIERR_NONE;
1015
    perf->erfType = ERROR_BAD_ARGUMENTS;
1016 1017
    perf->fError = TRUE;

1018 1019 1020 1021
    SetLastError(ERROR_BAD_ARGUMENTS);
    return NULL;
  }

1022
  if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1023 1024 1025
    perf->erfOper = FCIERR_ALLOC_FAIL;
    perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
    perf->fError = TRUE;
1026

1027
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1028
    return NULL;
1029 1030
  }

1031
  memset(p_fci_internal, 0, sizeof(FCI_Int));
1032
  p_fci_internal->magic = FCI_INT_MAGIC;
1033
  p_fci_internal->perf = perf;
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
  p_fci_internal->fileplaced = pfnfiledest;
  p_fci_internal->alloc = pfnalloc;
  p_fci_internal->free = pfnfree;
  p_fci_internal->open = pfnopen;
  p_fci_internal->read = pfnread;
  p_fci_internal->write = pfnwrite;
  p_fci_internal->close = pfnclose;
  p_fci_internal->seek = pfnseek;
  p_fci_internal->delete = pfndelete;
  p_fci_internal->gettemp = pfnfcigtf;
1044
  p_fci_internal->ccab = *pccab;
1045 1046
  p_fci_internal->pccab = pccab;
  p_fci_internal->pv = pv;
1047
  p_fci_internal->data.handle = -1;
1048
  p_fci_internal->compress = compress_NONE;
1049 1050

  list_init( &p_fci_internal->folders_list );
1051
  list_init( &p_fci_internal->files_list );
1052
  list_init( &p_fci_internal->blocks_list );
1053

1054 1055
  memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
  memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1056

1057 1058
  return (HFCI)p_fci_internal;
}
1059 1060 1061 1062




1063
static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1064 1065 1066 1067
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1068 1069
  cab_ULONG payload;
  cab_ULONG read_result;
1070
  struct folder *folder;
1071

1072
  if ((!pfnfcignc) || (!pfnfcis)) {
1073
    set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1074
    return FALSE;
1075
  }
1076

1077 1078
  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab ){
1079
    /* internal error */
1080
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1081 1082 1083 1084 1085
    return FALSE;
  }

  /* If there was no FCIAddFile or FCIFlushFolder has already been called */
  /* this function will return TRUE */
1086
  if( p_fci_internal->files_size == 0 ) {
1087
    if ( p_fci_internal->pending_data_size != 0 ) {
1088
      /* error handling */
1089
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1090 1091 1092 1093
      return FALSE;
    }
    return TRUE;
  }
1094

1095
  /* FCIFlushFolder has already been called... */
1096
  if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1097 1098 1099
    return TRUE;
  }

1100 1101
  /* This can be set already, because it makes only a difference */
  /* when the current function exits with return FALSE */
1102 1103 1104
  p_fci_internal->fSplitFolder=FALSE;

  /* START of COPY */
1105
  if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1106 1107 1108 1109 1110

  /* reset to get the number of data blocks of this folder which are */
  /* actually in this cabinet ( at least partially ) */
  p_fci_internal->cDataBlocks=0;

1111 1112 1113
  p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
      sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
      p_fci_internal->placed_files_size+
1114
      p_fci_internal->folders_data_size + p_fci_internal->files_size+
1115
      p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1116 1117 1118 1119 1120 1121
  p_fci_internal->statusFolderCopied = 0;

  /* report status with pfnfcis about copied size of folder */
  if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
      p_fci_internal->statusFolderTotal, /* TODO total folder size */
      p_fci_internal->pv) == -1) {
1122
    set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1123
    return FALSE;
1124
  }
1125

1126
  /* USE the variable read_result */
1127
  read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1128
      p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1129

1130
  if(p_fci_internal->files_size!=0) {
1131
    read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
  }

  /* Check if multiple cabinets have to be created. */

  /* Might be too much data for the maximum allowed cabinet size.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
      (
        (
1146
          p_fci_internal->ccab.cb < read_result +
1147
          p_fci_internal->pending_data_size +
1148
          p_fci_internal->files_size +
1149 1150 1151 1152 1153 1154 1155 1156
          CB_MAX_CABINET_NAME +   /* next cabinet name */
          CB_MAX_DISK_NAME        /* next disk name */
        ) || fGetNextCab
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1157 1158 1159
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1160
        p_fci_internal->pv)) {
1161
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1162 1163 1164
      return FALSE;
    }

1165
    /* Skip a few lines of code. This is caught by the next if. */
1166 1167 1168 1169 1170 1171 1172 1173
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  /* too much data for cabinet */
  if( (p_fci_internal->fGetNextCabInVain ||
        p_fci_internal->fNextCab ) &&
      (
        (
1174
          p_fci_internal->ccab.cb < read_result +
1175
          p_fci_internal->pending_data_size +
1176
          p_fci_internal->files_size +
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
          strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
          strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
        ) || fGetNextCab
      )
  ) {
    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;

    /* return FALSE if there is not enough space left*/
    /* this should never happen */
1187
    if (p_fci_internal->ccab.cb <=
1188
        p_fci_internal->files_size +
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
        read_result +
        strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
        strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
    ) {

      return FALSE;
    }

    /* the folder will be split across cabinets */
    p_fci_internal->fSplitFolder=TRUE;

  } else {
    /* this should never happen */
    if (p_fci_internal->fNextCab) {
1203
      /* internal error */
1204
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1205 1206 1207 1208
      return FALSE;
    }
  }

1209
  if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1210 1211
  if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
  if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1212 1213 1214 1215 1216 1217

  /* reset CFFolder specific information */
  p_fci_internal->cDataBlocks=0;
  p_fci_internal->cCompressedBytesInFolder=0;

  return TRUE;
1218
}
1219 1220 1221 1222




1223
static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1224 1225 1226 1227
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1228
  cab_ULONG read_result=0;
1229 1230 1231 1232
  BOOL returntrue=FALSE;

  /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */

1233
  /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1234
  if( p_fci_internal->files_size==0 && fGetNextCab ) {
1235 1236 1237
    returntrue=TRUE;
  }

1238
  if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1239 1240 1241 1242 1243 1244
    /* TODO set error */
    return FALSE;
  }

  if(returntrue) return TRUE;

1245
  if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1246
       (p_fci_internal->folders_size==0 &&
1247 1248
         (p_fci_internal->files_size!=0 ||
          p_fci_internal->placed_files_size!=0 )
1249 1250 1251
     ) )
  {
      /* error */
1252
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1253 1254 1255
      return FALSE;
  }

1256
  /* create the cabinet */
1257
  if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1258 1259 1260 1261 1262 1263 1264 1265

  p_fci_internal->fPrevCab=TRUE;
  /* The sections szPrevCab and szPrevDisk are not being updated, because */
  /* MS CABINET.DLL always puts the first cabinet name and disk into them */

  if (p_fci_internal->fNextCab) {
    p_fci_internal->fNextCab=FALSE;

1266
    if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1267
      /* THIS CAN NEVER HAPPEN */
1268
      /* set error code */
1269
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1270 1271 1272
      return FALSE;
    }

1273 1274 1275 1276 1277 1278 1279 1280
    if( p_fci_internal->fNewPrevious ) {
      memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
        CB_MAX_CABINET_NAME);
      memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
        CB_MAX_DISK_NAME);
      p_fci_internal->fNewPrevious=FALSE;
    }
    p_fci_internal->ccab = *p_fci_internal->pccab;
1281 1282

    /* REUSE the variable read_result */
1283 1284 1285
    read_result=get_header_size( p_fci_internal );
    if(p_fci_internal->files_size!=0) {
        read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1286
    }
1287
    read_result+= p_fci_internal->pending_data_size +
1288
      p_fci_internal->files_size + p_fci_internal->folders_data_size +
1289
      p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1290 1291 1292 1293
      sizeof(CFFOLDER); /* set size of new CFFolder entry */

    /* too much data for the maximum size of a cabinet */
    if( p_fci_internal->fGetNextCabInVain==FALSE &&
1294
        p_fci_internal->ccab.cb < read_result ) {
1295
      return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1296 1297 1298 1299 1300 1301 1302 1303 1304
    }

    /* Might be too much data for the maximum size of a cabinet.*/
    /* When any further data will be added later, it might not */
    /* be possible to flush the cabinet, because there might */
    /* not be enough space to store the name of the following */
    /* cabinet and name of the corresponding disk. */
    /* So take care of this and get the name of the next cabinet */
    if (p_fci_internal->fGetNextCabInVain==FALSE && (
1305
      p_fci_internal->ccab.cb < read_result +
1306 1307 1308 1309 1310
      CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
    )) {
      /* increment cabinet index */
      ++(p_fci_internal->pccab->iCab);
      /* get name of next cabinet */
1311 1312 1313
      p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
      if (!(*pfnfcignc)(p_fci_internal->pccab,
          p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1314
          p_fci_internal->pv)) {
1315
        /* error handling */
1316
        set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1317 1318
        return FALSE;
      }
1319
      /* Skip a few lines of code. This is caught by the next if. */
1320 1321 1322 1323 1324
      p_fci_internal->fGetNextCabInVain=TRUE;
    }

    /* too much data for cabinet */
    if (p_fci_internal->fGetNextCabInVain && (
1325 1326 1327
        p_fci_internal->ccab.cb < read_result +
        strlen(p_fci_internal->ccab.szCab)+1+
        strlen(p_fci_internal->ccab.szDisk)+1
1328 1329 1330
    )) {
      p_fci_internal->fGetNextCabInVain=FALSE;
      p_fci_internal->fNextCab=TRUE;
1331
      return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1332 1333 1334
    }

    /* if the FolderThreshold has been reached flush the folder automatically */
1335
    if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1336
        return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1337

1338
    if( p_fci_internal->files_size>0 ) {
1339
      if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1340 1341 1342 1343
      p_fci_internal->fNewPrevious=TRUE;
    }
  } else {
    p_fci_internal->fNewPrevious=FALSE;
1344
    if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1345
      /* THIS MAY NEVER HAPPEN */
1346
      /* set error structures */
1347
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
      return FALSE;
    }
  }

  return TRUE;
} /* end of fci_flush_cabinet */





/***********************************************************************
 *		FCIAddFile (CABINET.11)
 *
 * FCIAddFile adds a file to the to be created cabinet file
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   pszSourceFile [I]  A pointer to a C string which contains the name and
 *                      location of the file which will be added to the cabinet
 *   pszFileName   [I]  A pointer to a C string which contains the name under
 *                      which the file will be stored in the cabinet
 *   fExecute      [I]  A boolean value which indicates if the file should be
 *                      executed after extraction of self extracting
 *                      executables
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *   pfnfcioi      [I]  A pointer to a function which reports file attributes
 *                      and time and date information
 *   typeCompress  [I]  Compression type
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIAddFile(
	HFCI                  hfci,
	char                 *pszSourceFile,
	char                 *pszFileName,
	BOOL                  fExecute,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis,
	PFNFCIGETOPENINFO     pfnfcigoi,
	TCOMP                 typeCompress)
{
  cab_ULONG read_result;
1400
  FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1401

1402
  if (!p_fci_internal) return FALSE;
1403 1404 1405

  if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
      (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1406
    set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1407 1408 1409
    return FALSE;
  }

1410 1411 1412 1413 1414
  if (typeCompress != p_fci_internal->compression)
  {
      if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
      switch (typeCompress)
      {
1415 1416 1417 1418
      case tcompTYPE_MSZIP:
          p_fci_internal->compression = tcompTYPE_MSZIP;
          p_fci_internal->compress    = compress_MSZIP;
          break;
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
      default:
          FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
          /* fall through */
      case tcompTYPE_NONE:
          p_fci_internal->compression = tcompTYPE_NONE;
          p_fci_internal->compress    = compress_NONE;
          break;
      }
  }

1429 1430 1431
  /* TODO check if pszSourceFile??? */

  if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1432
    /* internal error */
1433
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1434 1435 1436 1437
    return FALSE;
  }

  if(p_fci_internal->fNextCab) {
1438
    /* internal error */
1439
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1440 1441 1442 1443
    return FALSE;
  }

  /* REUSE the variable read_result */
1444
  read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1445 1446

  read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1447
    p_fci_internal->files_size + p_fci_internal->folders_data_size +
1448
    p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
    sizeof(CFFOLDER); /* size of new CFFolder entry */

  /* Might be too much data for the maximum size of a cabinet.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
1459
      ( p_fci_internal->ccab.cb < read_result +
1460 1461 1462 1463 1464 1465
        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1466 1467 1468
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1469
        p_fci_internal->pv)) {
1470
      /* error handling */
1471
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1472 1473
      return FALSE;
    }
1474
    /* Skip a few lines of code. This is caught by the next if. */
1475 1476 1477 1478 1479 1480 1481
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab
  ) {
    /* THIS CAN NEVER HAPPEN */
1482
    /* set error code */
1483
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1484 1485 1486 1487 1488 1489
    return FALSE;
  }

  /* too much data for cabinet */
  if( p_fci_internal->fGetNextCabInVain &&
     (
1490
      p_fci_internal->ccab.cb < read_result +
1491 1492 1493 1494 1495
      strlen(p_fci_internal->pccab->szCab)+1+
      strlen(p_fci_internal->pccab->szDisk)+1
  )) {
    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;
1496
    if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1497 1498 1499 1500
  }

  if( p_fci_internal->fNextCab ) {
    /* THIS MAY NEVER HAPPEN */
1501
    /* set error code */
1502
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1503 1504 1505
    return FALSE;
  }

1506
  if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1507 1508 1509
      return FALSE;

  /* REUSE the variable read_result */
1510
  read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1511
  read_result+= p_fci_internal->pending_data_size +
1512
    p_fci_internal->files_size + p_fci_internal->folders_data_size +
1513
    p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1514 1515 1516 1517 1518 1519
    sizeof(CFFOLDER); /* set size of new CFFolder entry */

  /* too much data for the maximum size of a cabinet */
  /* (ignoring the unflushed data block) */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE && /* this is always the case */
1520
      p_fci_internal->ccab.cb < read_result ) {
1521
    return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
  }

  /* Might be too much data for the maximum size of a cabinet.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  /* (ignoring the unflushed data block) */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
1533
      ( p_fci_internal->ccab.cb < read_result +
1534 1535 1536 1537 1538 1539
        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1540 1541 1542
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1543
        p_fci_internal->pv)) {
1544
      /* error handling */
1545
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1546 1547
      return FALSE;
    }
1548
    /* Skip a few lines of code. This is caught by the next if. */
1549 1550 1551 1552 1553 1554 1555
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab
  ) {
    /* THIS CAN NEVER HAPPEN */
1556
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1557 1558 1559 1560 1561 1562
    return FALSE;
  }

  /* too much data for cabinet */
  if( (p_fci_internal->fGetNextCabInVain ||
      p_fci_internal->fNextCab) && (
1563
      p_fci_internal->ccab.cb < read_result +
1564 1565 1566 1567 1568 1569
      strlen(p_fci_internal->pccab->szCab)+1+
      strlen(p_fci_internal->pccab->szDisk)+1
  )) {

    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;
1570
    return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1571 1572 1573 1574
  }

  if( p_fci_internal->fNextCab ) {
    /* THIS MAY NEVER HAPPEN */
1575
    /* set error code */
1576
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1577 1578 1579 1580
    return FALSE;
  }

  /* if the FolderThreshold has been reached flush the folder automatically */
1581
  if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
      return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);

  return TRUE;
} /* end of FCIAddFile */





/***********************************************************************
 *		FCIFlushFolder (CABINET.12)
 *
 * FCIFlushFolder completes the CFFolder structure under construction.
 *
Austin English's avatar
Austin English committed
1596
 * All further data which is added by FCIAddFile will be associated to
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
 * the next CFFolder structure.
 *
 * FCIFlushFolder will be called by FCIAddFile automatically if the
 * threshold (stored in the member cbFolderThresh of the CCAB structure
 * pccab passed to FCICreate) is exceeded.
 *
 * FCIFlushFolder will be called by FCIFlushFolder automatically before
 * any data will be written into the cabinet file.
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIFlushFolder(
	HFCI                  hfci,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1626 1627 1628 1629 1630
    FCI_Int *p_fci_internal = get_fci_ptr( hfci );

    if (!p_fci_internal) return FALSE;
    return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
}
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670



/***********************************************************************
 *		FCIFlushCabinet (CABINET.13)
 *
 * FCIFlushCabinet stores the data which has been added by FCIAddFile
 * into the cabinet file. If the maximum cabinet size (stored in the
 * member cb of the CCAB structure pccab passed to FCICreate) has been
 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
 * The remaining data still has to be flushed manually by calling
 * FCIFlushCabinet.
 *
 * After FCIFlushCabinet has been called (manually) FCIAddFile must
 * NOT be called again. Then hfci has to be released by FCIDestroy.
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   fGetNextCab   [I]  Whether you want to add additional files to a
 *                      cabinet set (TRUE) or whether you want to
 *                      finalize it (FALSE)
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIFlushCabinet(
	HFCI                  hfci,
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1671
  FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1672

1673 1674 1675
  if (!p_fci_internal) return FALSE;

  if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1676

1677 1678
  while( p_fci_internal->files_size>0 ||
         p_fci_internal->placed_files_size>0 ) {
1679
    if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1680 1681 1682
  }

  return TRUE;
1683
}
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700


/***********************************************************************
 *		FCIDestroy (CABINET.14)
 *
 * Frees a handle created by FCICreate.
 * Only reason for failure would be an invalid handle.
 *
 * PARAMS
 *   hfci [I] The HFCI to free
 *
 * RETURNS
 *   TRUE for success
 *   FALSE for failure
 */
BOOL __cdecl FCIDestroy(HFCI hfci)
{
1701
    struct folder *folder, *folder_next;
1702
    struct file *file, *file_next;
1703
    struct data_block *block, *block_next;
1704 1705 1706
    FCI_Int *p_fci_internal = get_fci_ptr( hfci );

    if (!p_fci_internal) return FALSE;
1707 1708 1709

    /* before hfci can be removed all temporary files must be closed */
    /* and deleted */
1710
    p_fci_internal->magic = 0;
1711

1712 1713
    LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
    {
1714 1715 1716 1717 1718
        free_folder( p_fci_internal, folder );
    }
    LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
    {
        free_file( p_fci_internal, file );
1719
    }
1720 1721 1722 1723
    LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
    {
        free_data_block( p_fci_internal, block );
    }
1724

1725
    close_temp_file( p_fci_internal, &p_fci_internal->data );
1726 1727

    /* hfci can now be removed */
1728
    p_fci_internal->free(hfci);
1729
    return TRUE;
1730
}