ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

fci.c
Go to the documentation of this file.
00001 /*
00002  * File Compression Interface
00003  *
00004  * Copyright 2002 Patrik Stridvall
00005  * Copyright 2005 Gerold Jens Wucherpfennig
00006  * Copyright 2011 Alexandre Julliard
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 /*
00024 
00025 There is still some work to be done:
00026 
00027 - unknown behaviour if files>=2GB or cabinet >=4GB
00028 - check if the maximum size for a cabinet is too small to store any data
00029 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case
00030 
00031 */
00032 
00033 
00034 
00035 #include "config.h"
00036 
00037 #include <assert.h>
00038 #include <stdarg.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #ifdef HAVE_ZLIB
00042 # include <zlib.h>
00043 #endif
00044 
00045 #include "windef.h"
00046 #include "winbase.h"
00047 #include "winerror.h"
00048 #include "winternl.h"
00049 #include "fci.h"
00050 #include "cabinet.h"
00051 #include "wine/list.h"
00052 #include "wine/debug.h"
00053 
00054 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
00055 
00056 #ifdef WORDS_BIGENDIAN
00057 #define fci_endian_ulong(x) RtlUlongByteSwap(x)
00058 #define fci_endian_uword(x) RtlUshortByteSwap(x)
00059 #else
00060 #define fci_endian_ulong(x) (x)
00061 #define fci_endian_uword(x) (x)
00062 #endif
00063 
00064 
00065 typedef struct {
00066   cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
00067   cab_ULONG reserved1;
00068   cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/
00069   cab_ULONG reserved2;
00070   cab_ULONG coffFiles;    /* offset to first CFFILE section */
00071   cab_ULONG reserved3;
00072   cab_UBYTE versionMinor; /* 3 */
00073   cab_UBYTE versionMajor; /* 1 */
00074   cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/
00075   cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/
00076   cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
00077   cab_UWORD setID;        /* identification number of all cabinets in a set*/
00078   cab_UWORD iCabinet;     /* number of the cabinet in a set */
00079   /* additional area if "flags" were set*/
00080 } CFHEADER; /* minimum 36 bytes */
00081 
00082 typedef struct {
00083   cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
00084   cab_UWORD cCFData;      /* number of this folder's CFDATA sections */
00085   cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
00086   /* additional area if reserve flag was set */
00087 } CFFOLDER; /* minimum 8 bytes */
00088 
00089 typedef struct {
00090   cab_ULONG cbFile;          /* size of the uncompressed file in bytes */
00091   cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
00092   cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */
00093                              /* for special values see below this structure*/
00094   cab_UWORD date;            /* last modification date*/
00095   cab_UWORD time;            /* last modification time*/
00096   cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */
00097   /* ... and a C string with the name of the file */
00098 } CFFILE; /* 16 bytes + name of file */
00099 
00100 
00101 typedef struct {
00102   cab_ULONG csum;          /* checksum of this entry*/
00103   cab_UWORD cbData;        /* number of compressed bytes  */
00104   cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */
00105   /* optional reserved area */
00106   /* compressed data */
00107 } CFDATA;
00108 
00109 struct temp_file
00110 {
00111     INT_PTR   handle;
00112     char      name[CB_MAX_FILENAME];
00113 };
00114 
00115 struct folder
00116 {
00117     struct list      entry;
00118     struct list      files_list;
00119     struct list      blocks_list;
00120     struct temp_file data;
00121     cab_ULONG        data_start;
00122     cab_UWORD        data_count;
00123     TCOMP            compression;
00124 };
00125 
00126 struct file
00127 {
00128     struct list entry;
00129     cab_ULONG   size;    /* uncompressed size */
00130     cab_ULONG   offset;  /* offset in folder */
00131     cab_UWORD   folder;  /* index of folder */
00132     cab_UWORD   date;
00133     cab_UWORD   time;
00134     cab_UWORD   attribs;
00135     char        name[1];
00136 };
00137 
00138 struct data_block
00139 {
00140     struct list entry;
00141     cab_UWORD   compressed;
00142     cab_UWORD   uncompressed;
00143 };
00144 
00145 typedef struct FCI_Int
00146 {
00147   unsigned int       magic;
00148   PERF               perf;
00149   PFNFCIFILEPLACED   fileplaced;
00150   PFNFCIALLOC        alloc;
00151   PFNFCIFREE         free;
00152   PFNFCIOPEN         open;
00153   PFNFCIREAD         read;
00154   PFNFCIWRITE        write;
00155   PFNFCICLOSE        close;
00156   PFNFCISEEK         seek;
00157   PFNFCIDELETE       delete;
00158   PFNFCIGETTEMPFILE  gettemp;
00159   CCAB               ccab;
00160   PCCAB              pccab;
00161   BOOL               fPrevCab;
00162   BOOL               fNextCab;
00163   BOOL               fSplitFolder;
00164   cab_ULONG          statusFolderCopied;
00165   cab_ULONG          statusFolderTotal;
00166   BOOL               fGetNextCabInVain;
00167   void               *pv;
00168   char               szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
00169   char               szPrevDisk[CB_MAX_DISK_NAME];   /* disk name of previous cabinet */
00170   unsigned char      data_in[CAB_BLOCKMAX];          /* uncompressed data blocks */
00171   unsigned char      data_out[2 * CAB_BLOCKMAX];     /* compressed data blocks */
00172   cab_UWORD          cdata_in;
00173   ULONG              cCompressedBytesInFolder;
00174   cab_UWORD          cFolders;
00175   cab_UWORD          cFiles;
00176   cab_ULONG          cDataBlocks;
00177   cab_ULONG          cbFileRemainer; /* uncompressed, yet to be written data */
00178                /* of spanned file of a spanning folder of a spanning cabinet */
00179   struct temp_file   data;
00180   BOOL               fNewPrevious;
00181   cab_ULONG          estimatedCabinetSize;
00182   struct list        folders_list;
00183   struct list        files_list;
00184   struct list        blocks_list;
00185   cab_ULONG          folders_size;
00186   cab_ULONG          files_size;          /* size of files not yet assigned to a folder */
00187   cab_ULONG          placed_files_size;   /* size of files already placed into a folder */
00188   cab_ULONG          pending_data_size;   /* size of data not yet assigned to a folder */
00189   cab_ULONG          folders_data_size;   /* total size of data contained in the current folders */
00190   TCOMP              compression;
00191   cab_UWORD        (*compress)(struct FCI_Int *);
00192 } FCI_Int;
00193 
00194 #define FCI_INT_MAGIC 0xfcfcfc05
00195 
00196 static void set_error( FCI_Int *fci, int oper, int err )
00197 {
00198     fci->perf->erfOper = oper;
00199     fci->perf->erfType = err;
00200     fci->perf->fError = TRUE;
00201     if (err) SetLastError( err );
00202 }
00203 
00204 static FCI_Int *get_fci_ptr( HFCI hfci )
00205 {
00206     FCI_Int *fci= (FCI_Int *)hfci;
00207 
00208     if (!fci || fci->magic != FCI_INT_MAGIC)
00209     {
00210         SetLastError( ERROR_INVALID_HANDLE );
00211         return NULL;
00212     }
00213     return fci;
00214 }
00215 
00216 /* compute the cabinet header size */
00217 static cab_ULONG get_header_size( FCI_Int *fci )
00218 {
00219     cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;
00220 
00221     if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
00222         ret += 4;
00223 
00224     if (fci->fPrevCab)
00225         ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;
00226 
00227     if (fci->fNextCab)
00228         ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;
00229 
00230     return ret;
00231 }
00232 
00233 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
00234 {
00235     int err;
00236 
00237     if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
00238     {
00239         set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
00240         return FALSE;
00241     }
00242     if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
00243                                    _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
00244     {
00245         set_error( fci, FCIERR_TEMP_FILE, err );
00246         return FALSE;
00247     }
00248     return TRUE;
00249 }
00250 
00251 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
00252 {
00253     int err;
00254 
00255     if (file->handle == -1) return TRUE;
00256     if (fci->close( file->handle, &err, fci->pv ) == -1)
00257     {
00258         set_error( fci, FCIERR_TEMP_FILE, err );
00259         return FALSE;
00260     }
00261     file->handle = -1;
00262     if (fci->delete( file->name, &err, fci->pv ) == -1)
00263     {
00264         set_error( fci, FCIERR_TEMP_FILE, err );
00265         return FALSE;
00266     }
00267     return TRUE;
00268 }
00269 
00270 static struct file *add_file( FCI_Int *fci, const char *filename )
00271 {
00272     unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
00273     struct file *file = fci->alloc( size );
00274 
00275     if (!file)
00276     {
00277         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00278         return NULL;
00279     }
00280     file->size    = 0;
00281     file->offset  = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
00282     file->folder  = fci->cFolders;
00283     file->date    = 0;
00284     file->time    = 0;
00285     file->attribs = 0;
00286     strcpy( file->name, filename );
00287     list_add_tail( &fci->files_list, &file->entry );
00288     fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
00289     return file;
00290 }
00291 
00292 static struct file *copy_file( FCI_Int *fci, const struct file *orig )
00293 {
00294     unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
00295     struct file *file = fci->alloc( size );
00296 
00297     if (!file)
00298     {
00299         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00300         return NULL;
00301     }
00302     memcpy( file, orig, size );
00303     return file;
00304 }
00305 
00306 static void free_file( FCI_Int *fci, struct file *file )
00307 {
00308     list_remove( &file->entry );
00309     fci->free( file );
00310 }
00311 
00312 /* create a new data block for the data in fci->data_in */
00313 static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
00314 {
00315     int err;
00316     struct data_block *block;
00317 
00318     if (!fci->cdata_in) return TRUE;
00319 
00320     if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;
00321 
00322     if (!(block = fci->alloc( sizeof(*block) )))
00323     {
00324         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00325         return FALSE;
00326     }
00327     block->uncompressed = fci->cdata_in;
00328     block->compressed   = fci->compress( fci );
00329 
00330     if (fci->write( fci->data.handle, fci->data_out,
00331                     block->compressed, &err, fci->pv ) != block->compressed)
00332     {
00333         set_error( fci, FCIERR_TEMP_FILE, err );
00334         fci->free( block );
00335         return FALSE;
00336     }
00337 
00338     fci->cdata_in = 0;
00339     fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
00340     fci->cCompressedBytesInFolder += block->compressed;
00341     fci->cDataBlocks++;
00342     list_add_tail( &fci->blocks_list, &block->entry );
00343 
00344     if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
00345     {
00346         set_error( fci, FCIERR_USER_ABORT, 0 );
00347         return FALSE;
00348     }
00349     return TRUE;
00350 }
00351 
00352 /* add compressed blocks for all the data that can be read from the file */
00353 static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
00354                            PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
00355 {
00356     int err, len;
00357     INT_PTR handle;
00358     struct file *file;
00359 
00360     if (!(file = add_file( fci, filename ))) return FALSE;
00361 
00362     handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
00363     if (handle == -1)
00364     {
00365         free_file( fci, file );
00366         set_error( fci, FCIERR_OPEN_SRC, err );
00367         return FALSE;
00368     }
00369     if (execute) file->attribs |= _A_EXEC;
00370 
00371     for (;;)
00372     {
00373         len = fci->read( handle, fci->data_in + fci->cdata_in,
00374                          CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
00375         if (!len) break;
00376 
00377         if (len == -1)
00378         {
00379             set_error( fci, FCIERR_READ_SRC, err );
00380             return FALSE;
00381         }
00382         file->size += len;
00383         fci->cdata_in += len;
00384         if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
00385     }
00386     fci->close( handle, &err, fci->pv );
00387     return TRUE;
00388 }
00389 
00390 static void free_data_block( FCI_Int *fci, struct data_block *block )
00391 {
00392     list_remove( &block->entry );
00393     fci->free( block );
00394 }
00395 
00396 static struct folder *add_folder( FCI_Int *fci )
00397 {
00398     struct folder *folder = fci->alloc( sizeof(*folder) );
00399 
00400     if (!folder)
00401     {
00402         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00403         return NULL;
00404     }
00405     folder->data.handle = -1;
00406     folder->data_start  = fci->folders_data_size;
00407     folder->data_count  = 0;
00408     folder->compression = fci->compression;
00409     list_init( &folder->files_list );
00410     list_init( &folder->blocks_list );
00411     list_add_tail( &fci->folders_list, &folder->entry );
00412     fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
00413     fci->cFolders++;
00414     return folder;
00415 }
00416 
00417 static void free_folder( FCI_Int *fci, struct folder *folder )
00418 {
00419     struct file *file, *file_next;
00420     struct data_block *block, *block_next;
00421 
00422     LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
00423         free_file( fci, file );
00424     LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
00425         free_data_block( fci, block );
00426     close_temp_file( fci, &folder->data );
00427     list_remove( &folder->entry );
00428     fci->free( folder );
00429 }
00430 
00431 /* reset state for the next cabinet file once the current one has been flushed */
00432 static void reset_cabinet( FCI_Int *fci )
00433 {
00434     struct folder *folder, *folder_next;
00435 
00436     LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
00437         free_folder( fci, folder );
00438 
00439     fci->cFolders          = 0;
00440     fci->cFiles            = 0;
00441     fci->folders_size      = 0;
00442     fci->placed_files_size = 0;
00443     fci->folders_data_size = 0;
00444 }
00445 
00446 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
00447 {
00448   cab_ULONG     csum;
00449   cab_ULONG     ul;
00450   int           cUlong;
00451   const BYTE    *pb;
00452 
00453   csum = seed;
00454   cUlong = cb / 4;
00455   pb = pv;
00456 
00457   while (cUlong-- > 0) {
00458     ul = *pb++;
00459     ul |= (((cab_ULONG)(*pb++)) <<  8);
00460     ul |= (((cab_ULONG)(*pb++)) << 16);
00461     ul |= (((cab_ULONG)(*pb++)) << 24);
00462     csum ^= ul;
00463   }
00464 
00465   ul = 0;
00466   switch (cb % 4) {
00467     case 3:
00468       ul |= (((ULONG)(*pb++)) << 16);
00469       /* fall through */
00470     case 2:
00471       ul |= (((ULONG)(*pb++)) <<  8);
00472       /* fall through */
00473     case 1:
00474       ul |= *pb;
00475       /* fall through */
00476     default:
00477       break;
00478   }
00479   csum ^= ul;
00480 
00481   return csum;
00482 }
00483 
00484 /* copy all remaining data block to a new temp file */
00485 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
00486                               struct temp_file *temp, PFNFCISTATUS status_callback )
00487 {
00488     struct data_block *block;
00489     int err;
00490 
00491     if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
00492     {
00493         set_error( fci, FCIERR_TEMP_FILE, err );
00494         return FALSE;
00495     }
00496     if (!create_temp_file( fci, temp )) return FALSE;
00497 
00498     LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
00499     {
00500         if (fci->read( handle, fci->data_out, block->compressed,
00501                        &err, fci->pv ) != block->compressed)
00502         {
00503             close_temp_file( fci, temp );
00504             set_error( fci, FCIERR_TEMP_FILE, err );
00505             return FALSE;
00506         }
00507         if (fci->write( temp->handle, fci->data_out, block->compressed,
00508                         &err, fci->pv ) != block->compressed)
00509         {
00510             close_temp_file( fci, temp );
00511             set_error( fci, FCIERR_TEMP_FILE, err );
00512             return FALSE;
00513         }
00514         fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
00515         fci->statusFolderCopied += block->compressed;
00516 
00517         if (status_callback( statusFolder, fci->statusFolderCopied,
00518                              fci->statusFolderTotal, fci->pv) == -1)
00519         {
00520             close_temp_file( fci, temp );
00521             set_error( fci, FCIERR_USER_ABORT, 0 );
00522             return FALSE;
00523         }
00524     }
00525     return TRUE;
00526 }
00527 
00528 /* write all folders to disk and remove them from the list */
00529 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
00530 {
00531     struct folder *folder;
00532     int err;
00533     CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
00534     cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
00535 
00536     memset( cffolder, 0, folder_size );
00537 
00538     /* write the folders */
00539     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
00540     {
00541         cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
00542         cffolder->cCFData      = fci_endian_uword( folder->data_count );
00543         cffolder->typeCompress = fci_endian_uword( folder->compression );
00544         if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
00545         {
00546             set_error( fci, FCIERR_CAB_FILE, err );
00547             return FALSE;
00548         }
00549     }
00550     return TRUE;
00551 }
00552 
00553 /* write all the files to the cabinet file */
00554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
00555 {
00556     cab_ULONG file_size;
00557     struct folder *folder;
00558     struct file *file;
00559     int err;
00560     CFFILE *cffile = (CFFILE *)fci->data_out;
00561 
00562     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
00563     {
00564         LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
00565         {
00566             cffile->cbFile          = fci_endian_ulong( file->size );
00567             cffile->uoffFolderStart = fci_endian_ulong( file->offset );
00568             cffile->iFolder         = fci_endian_uword( file->folder );
00569             cffile->date            = fci_endian_uword( file->date );
00570             cffile->time            = fci_endian_uword( file->time );
00571             cffile->attribs         = fci_endian_uword( file->attribs );
00572             lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
00573             file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
00574             if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
00575             {
00576                 set_error( fci, FCIERR_CAB_FILE, err );
00577                 return FALSE;
00578             }
00579             if (!fci->fSplitFolder)
00580             {
00581                 fci->statusFolderCopied = 0;
00582                 /* TODO TEST THIS further */
00583                 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
00584             }
00585             fci->statusFolderCopied += file_size;
00586             /* report status about copied size of folder */
00587             if (status_callback( statusFolder, fci->statusFolderCopied,
00588                                  fci->statusFolderTotal, fci->pv ) == -1)
00589             {
00590                 set_error( fci, FCIERR_USER_ABORT, 0 );
00591                 return FALSE;
00592             }
00593         }
00594     }
00595     return TRUE;
00596 }
00597 
00598 /* write all data blocks to the cabinet file */
00599 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
00600 {
00601     struct folder *folder;
00602     struct data_block *block;
00603     int err, len;
00604     CFDATA *cfdata;
00605     void *data;
00606     cab_UWORD header_size;
00607 
00608     header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
00609     cfdata = (CFDATA *)fci->data_out;
00610     memset( cfdata, 0, header_size );
00611     data = (char *)cfdata + header_size;
00612 
00613     LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
00614     {
00615         if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
00616         {
00617             set_error( fci, FCIERR_CAB_FILE, err );
00618             return FALSE;
00619         }
00620         LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
00621         {
00622             len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
00623             if (len != block->compressed) return FALSE;
00624 
00625             cfdata->cbData = fci_endian_uword( block->compressed );
00626             cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
00627             cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
00628                                                                header_size - FIELD_OFFSET(CFDATA, cbData),
00629                                                                fci_get_checksum( data, len, 0 )));
00630 
00631             fci->statusFolderCopied += len;
00632             len += header_size;
00633             if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
00634             {
00635                 set_error( fci, FCIERR_CAB_FILE, err );
00636                 return FALSE;
00637             }
00638             if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
00639             {
00640                 set_error( fci, FCIERR_USER_ABORT, 0 );
00641                 return FALSE;
00642             }
00643         }
00644     }
00645     return TRUE;
00646 }
00647 
00648 /* write the cabinet file to disk */
00649 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
00650 {
00651     char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
00652     int err;
00653     char *ptr;
00654     INT_PTR handle;
00655     CFHEADER *cfheader = (CFHEADER *)fci->data_out;
00656     cab_UWORD flags = 0;
00657     cab_ULONG header_size = get_header_size( fci );
00658     cab_ULONG total_size = header_size + fci->folders_size +
00659                            fci->placed_files_size + fci->folders_data_size;
00660 
00661     assert( header_size <= sizeof(fci->data_out) );
00662     memset( cfheader, 0, header_size );
00663 
00664     if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
00665     if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
00666     if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
00667       flags |= cfheadRESERVE_PRESENT;
00668 
00669     memcpy( cfheader->signature, "!CAB", 4 );
00670     cfheader->cbCabinet    = fci_endian_ulong( total_size );
00671     cfheader->coffFiles    = fci_endian_ulong( header_size + fci->folders_size );
00672     cfheader->versionMinor = 3;
00673     cfheader->versionMajor = 1;
00674     cfheader->cFolders     = fci_endian_uword( fci->cFolders );
00675     cfheader->cFiles       = fci_endian_uword( fci->cFiles );
00676     cfheader->flags        = fci_endian_uword( flags );
00677     cfheader->setID        = fci_endian_uword( fci->ccab.setID );
00678     cfheader->iCabinet     = fci_endian_uword( fci->ccab.iCab );
00679     ptr = (char *)(cfheader + 1);
00680 
00681     if (flags & cfheadRESERVE_PRESENT)
00682     {
00683         struct
00684         {
00685             cab_UWORD cbCFHeader;
00686             cab_UBYTE cbCFFolder;
00687             cab_UBYTE cbCFData;
00688         } *reserve = (void *)ptr;
00689 
00690         reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
00691         reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
00692         reserve->cbCFData   = fci->ccab.cbReserveCFData;
00693         ptr = (char *)(reserve + 1);
00694     }
00695     ptr += fci->ccab.cbReserveCFHeader;
00696 
00697     if (flags & cfheadPREV_CABINET)
00698     {
00699         strcpy( ptr, fci->szPrevCab );
00700         ptr += strlen( ptr ) + 1;
00701         strcpy( ptr, fci->szPrevDisk );
00702         ptr += strlen( ptr ) + 1;
00703     }
00704 
00705     if (flags & cfheadNEXT_CABINET)
00706     {
00707         strcpy( ptr, fci->pccab->szCab );
00708         ptr += strlen( ptr ) + 1;
00709         strcpy( ptr, fci->pccab->szDisk );
00710         ptr += strlen( ptr ) + 1;
00711     }
00712 
00713     assert( ptr - (char *)cfheader == header_size );
00714 
00715     strcpy( filename, fci->ccab.szCabPath );
00716     strcat( filename, fci->ccab.szCab );
00717 
00718     if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
00719                              _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
00720     {
00721         set_error( fci, FCIERR_CAB_FILE, err );
00722         return FALSE;
00723     }
00724 
00725     if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
00726     {
00727         set_error( fci, FCIERR_CAB_FILE, err );
00728         goto failed;
00729     }
00730 
00731     /* add size of header size of all CFFOLDERs and size of all CFFILEs */
00732     header_size += fci->placed_files_size + fci->folders_size;
00733     if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
00734     if (!write_files( fci, handle, status_callback )) goto failed;
00735     if (!write_data_blocks( fci, handle, status_callback )) goto failed;
00736 
00737     /* update the signature */
00738     if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
00739     {
00740         set_error( fci, FCIERR_CAB_FILE, err );
00741         goto failed;
00742     }
00743     memcpy( cfheader->signature, "MSCF", 4 );
00744     if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
00745     {
00746         set_error( fci, FCIERR_CAB_FILE, err );
00747         goto failed;
00748     }
00749     fci->close( handle, &err, fci->pv );
00750 
00751     reset_cabinet( fci );
00752     status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
00753     return TRUE;
00754 
00755 failed:
00756     fci->close( handle, &err, fci->pv );
00757     fci->delete( filename, &err, fci->pv );
00758     return FALSE;
00759 }
00760 
00761 /* add all pending data blocks folder */
00762 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
00763                                 PFNFCISTATUS status_callback )
00764 {
00765     struct data_block *block, *new, *next;
00766     BOOL split_block = FALSE;
00767     cab_ULONG current_size, start_pos = 0;
00768 
00769     *payload = 0;
00770     current_size = get_header_size( fci ) + fci->folders_size +
00771                    fci->files_size + fci->placed_files_size + fci->folders_data_size;
00772 
00773     /* move the temp file into the folder structure */
00774     folder->data = fci->data;
00775     fci->data.handle = -1;
00776     fci->pending_data_size = 0;
00777 
00778     LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
00779     {
00780         /* No more CFDATA fits into the cabinet under construction */
00781         /* So don't try to store more data into it */
00782         if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
00783                               current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
00784             break;
00785 
00786         if (!(new = fci->alloc( sizeof(*new) )))
00787         {
00788             set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00789             return FALSE;
00790         }
00791         /* Is cabinet with new CFDATA too large? Then data block has to be split */
00792         if( fci->fNextCab &&
00793             (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
00794              block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
00795         {
00796             /* Modify the size of the compressed data to store only a part of the */
00797             /* data block into the current cabinet. This is done to prevent */
00798             /* that the maximum cabinet size will be exceeded. The remainder */
00799             /* will be stored into the next following cabinet. */
00800 
00801             new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
00802                                               sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
00803             new->uncompressed = 0; /* on split blocks of data this is zero */
00804             block->compressed -= new->compressed;
00805             split_block = TRUE;
00806         }
00807         else
00808         {
00809             new->compressed   = block->compressed;
00810             new->uncompressed = block->uncompressed;
00811         }
00812 
00813         start_pos += new->compressed;
00814         current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
00815         fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
00816         fci->statusFolderCopied += new->compressed;
00817         (*payload) += new->uncompressed;
00818 
00819         list_add_tail( &folder->blocks_list, &new->entry );
00820         folder->data_count++;
00821 
00822         /* report status with pfnfcis about copied size of folder */
00823         if (status_callback( statusFolder, fci->statusFolderCopied,
00824                              fci->statusFolderTotal, fci->pv ) == -1)
00825         {
00826             set_error( fci, FCIERR_USER_ABORT, 0 );
00827             return FALSE;
00828         }
00829         if (split_block) break;
00830         free_data_block( fci, block );
00831         fci->cDataBlocks--;
00832     }
00833 
00834     if (list_empty( &fci->blocks_list )) return TRUE;
00835     return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
00836 }
00837 
00838 /* add all pending files to folder */
00839 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
00840 {
00841     cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
00842     cab_ULONG cbFileRemainer = 0;
00843     struct file *file, *next;
00844 
00845     LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
00846     {
00847         cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;
00848 
00849         /* fnfilfnfildest: placed file on cabinet */
00850         fci->fileplaced( &fci->ccab, file->name, file->size,
00851                          (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
00852 
00853         sizeOfFilesPrev = sizeOfFiles;
00854         /* set complete size of all processed files */
00855         if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
00856         {
00857             sizeOfFiles += fci->cbFileRemainer;
00858             fci->cbFileRemainer = 0;
00859         }
00860         else sizeOfFiles += file->size;
00861 
00862         /* check if spanned file fits into this cabinet folder */
00863         if (sizeOfFiles > payload)
00864         {
00865             if (file->folder == cffileCONTINUED_FROM_PREV)
00866                 file->folder = cffileCONTINUED_PREV_AND_NEXT;
00867             else
00868                 file->folder = cffileCONTINUED_TO_NEXT;
00869         }
00870 
00871         list_remove( &file->entry );
00872         list_add_tail( &folder->files_list, &file->entry );
00873         fci->placed_files_size += size;
00874         fci->cFiles++;
00875 
00876         /* This is only true for files which will be written into the */
00877         /* next cabinet of the spanning folder */
00878         if (sizeOfFiles > payload)
00879         {
00880             /* add a copy back onto the list */
00881             if (!(file = copy_file( fci, file ))) return FALSE;
00882             list_add_before( &next->entry, &file->entry );
00883 
00884             /* Files which data will be partially written into the current cabinet */
00885             if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
00886             {
00887                 if (sizeOfFilesPrev <= payload)
00888                 {
00889                     /* The size of the uncompressed, data of a spanning file in a */
00890                     /* spanning data */
00891                     cbFileRemainer = sizeOfFiles - payload;
00892                 }
00893                 file->folder = cffileCONTINUED_FROM_PREV;
00894             }
00895             else file->folder = 0;
00896         }
00897         else
00898         {
00899             fci->files_size -= size;
00900         }
00901     }
00902     fci->cbFileRemainer = cbFileRemainer;
00903     return TRUE;
00904 }
00905 
00906 static cab_UWORD compress_NONE( FCI_Int *fci )
00907 {
00908     memcpy( fci->data_out, fci->data_in, fci->cdata_in );
00909     return fci->cdata_in;
00910 }
00911 
00912 #ifdef HAVE_ZLIB
00913 
00914 static void *zalloc( void *opaque, unsigned int items, unsigned int size )
00915 {
00916     FCI_Int *fci = opaque;
00917     return fci->alloc( items * size );
00918 }
00919 
00920 static void zfree( void *opaque, void *ptr )
00921 {
00922     FCI_Int *fci = opaque;
00923     fci->free( ptr );
00924 }
00925 
00926 static cab_UWORD compress_MSZIP( FCI_Int *fci )
00927 {
00928     z_stream stream;
00929 
00930     stream.zalloc = zalloc;
00931     stream.zfree  = zfree;
00932     stream.opaque = fci;
00933     if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
00934     {
00935         set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
00936         return 0;
00937     }
00938     stream.next_in   = fci->data_in;
00939     stream.avail_in  = fci->cdata_in;
00940     stream.next_out  = fci->data_out + 2;
00941     stream.avail_out = sizeof(fci->data_out) - 2;
00942     /* insert the signature */
00943     fci->data_out[0] = 'C';
00944     fci->data_out[1] = 'K';
00945     deflate( &stream, Z_FINISH );
00946     deflateEnd( &stream );
00947     return stream.total_out + 2;
00948 }
00949 
00950 #endif  /* HAVE_ZLIB */
00951 
00952 
00953 /***********************************************************************
00954  *      FCICreate (CABINET.10)
00955  *
00956  * FCICreate is provided with several callbacks and
00957  * returns a handle which can be used to create cabinet files.
00958  *
00959  * PARAMS
00960  *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
00961  *                    returns an error condition, error information may
00962  *                    be found here as well as from GetLastError.
00963  *   pfnfiledest [I]  A pointer to a function which is called when a file
00964  *                    is placed. Only useful for subsequent cabinet files.
00965  *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
00966  *                    the same interface as malloc.
00967  *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
00968  *                    same interface as free.
00969  *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
00970  *                    the same interface as _open.
00971  *   pfnread     [I]  A pointer to a function which reads from a file into
00972  *                    a caller-provided buffer.  Uses the same interface
00973  *                    as _read.
00974  *   pfnwrite    [I]  A pointer to a function which writes to a file from
00975  *                    a caller-provided buffer.  Uses the same interface
00976  *                    as _write.
00977  *   pfnclose    [I]  A pointer to a function which closes a file handle.
00978  *                    Uses the same interface as _close.
00979  *   pfnseek     [I]  A pointer to a function which seeks in a file.
00980  *                    Uses the same interface as _lseek.
00981  *   pfndelete   [I]  A pointer to a function which deletes a file.
00982  *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
00983  *                    temporary file.
00984  *   pccab       [I]  A pointer to an initialized CCAB structure.
00985  *   pv          [I]  A pointer to an application-defined notification
00986  *                    function which will be passed to other FCI functions
00987  *                    as a parameter.
00988  *
00989  * RETURNS
00990  *   On success, returns an FCI handle of type HFCI.
00991  *   On failure, the NULL file handle is returned. Error
00992  *   info can be retrieved from perf.
00993  *
00994  * INCLUDES
00995  *   fci.h
00996  *
00997  */
00998 HFCI __cdecl FCICreate(
00999     PERF perf,
01000     PFNFCIFILEPLACED   pfnfiledest,
01001     PFNFCIALLOC        pfnalloc,
01002     PFNFCIFREE         pfnfree,
01003     PFNFCIOPEN         pfnopen,
01004     PFNFCIREAD         pfnread,
01005     PFNFCIWRITE        pfnwrite,
01006     PFNFCICLOSE        pfnclose,
01007     PFNFCISEEK         pfnseek,
01008     PFNFCIDELETE       pfndelete,
01009     PFNFCIGETTEMPFILE  pfnfcigtf,
01010     PCCAB              pccab,
01011     void *pv)
01012 {
01013   FCI_Int *p_fci_internal;
01014 
01015   if (!perf) {
01016     SetLastError(ERROR_BAD_ARGUMENTS);
01017     return NULL;
01018   }
01019   if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
01020       (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
01021       (!pfnfcigtf) || (!pccab)) {
01022     perf->erfOper = FCIERR_NONE;
01023     perf->erfType = ERROR_BAD_ARGUMENTS;
01024     perf->fError = TRUE;
01025 
01026     SetLastError(ERROR_BAD_ARGUMENTS);
01027     return NULL;
01028   }
01029 
01030   if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
01031     perf->erfOper = FCIERR_ALLOC_FAIL;
01032     perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
01033     perf->fError = TRUE;
01034 
01035     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01036     return NULL;
01037   }
01038 
01039   p_fci_internal->magic = FCI_INT_MAGIC;
01040   p_fci_internal->perf = perf;
01041   p_fci_internal->fileplaced = pfnfiledest;
01042   p_fci_internal->alloc = pfnalloc;
01043   p_fci_internal->free = pfnfree;
01044   p_fci_internal->open = pfnopen;
01045   p_fci_internal->read = pfnread;
01046   p_fci_internal->write = pfnwrite;
01047   p_fci_internal->close = pfnclose;
01048   p_fci_internal->seek = pfnseek;
01049   p_fci_internal->delete = pfndelete;
01050   p_fci_internal->gettemp = pfnfcigtf;
01051   p_fci_internal->ccab = *pccab;
01052   p_fci_internal->pccab = pccab;
01053   p_fci_internal->fPrevCab = FALSE;
01054   p_fci_internal->fNextCab = FALSE;
01055   p_fci_internal->fSplitFolder = FALSE;
01056   p_fci_internal->fGetNextCabInVain = FALSE;
01057   p_fci_internal->pv = pv;
01058   p_fci_internal->cdata_in = 0;
01059   p_fci_internal->cCompressedBytesInFolder = 0;
01060   p_fci_internal->cFolders = 0;
01061   p_fci_internal->cFiles = 0;
01062   p_fci_internal->cDataBlocks = 0;
01063   p_fci_internal->data.handle = -1;
01064   p_fci_internal->fNewPrevious = FALSE;
01065   p_fci_internal->estimatedCabinetSize = 0;
01066   p_fci_internal->statusFolderTotal = 0;
01067   p_fci_internal->folders_size = 0;
01068   p_fci_internal->files_size = 0;
01069   p_fci_internal->placed_files_size = 0;
01070   p_fci_internal->pending_data_size = 0;
01071   p_fci_internal->folders_data_size = 0;
01072   p_fci_internal->compression = tcompTYPE_NONE;
01073   p_fci_internal->compress = compress_NONE;
01074 
01075   list_init( &p_fci_internal->folders_list );
01076   list_init( &p_fci_internal->files_list );
01077   list_init( &p_fci_internal->blocks_list );
01078 
01079   memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
01080   memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
01081 
01082   return (HFCI)p_fci_internal;
01083 }
01084 
01085 
01086 
01087 
01088 static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
01089     BOOL                  fGetNextCab,
01090     PFNFCIGETNEXTCABINET  pfnfcignc,
01091     PFNFCISTATUS          pfnfcis)
01092 {
01093   cab_ULONG payload;
01094   cab_ULONG read_result;
01095   struct folder *folder;
01096 
01097   if ((!pfnfcignc) || (!pfnfcis)) {
01098     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
01099     return FALSE;
01100   }
01101 
01102   if( p_fci_internal->fGetNextCabInVain &&
01103       p_fci_internal->fNextCab ){
01104     /* internal error */
01105     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01106     return FALSE;
01107   }
01108 
01109   /* If there was no FCIAddFile or FCIFlushFolder has already been called */
01110   /* this function will return TRUE */
01111   if( p_fci_internal->files_size == 0 ) {
01112     if ( p_fci_internal->pending_data_size != 0 ) {
01113       /* error handling */
01114       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01115       return FALSE;
01116     }
01117     return TRUE;
01118   }
01119 
01120   /* FCIFlushFolder has already been called... */
01121   if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
01122     return TRUE;
01123   }
01124 
01125   /* This can be set already, because it makes only a difference */
01126   /* when the current function exits with return FALSE */
01127   p_fci_internal->fSplitFolder=FALSE;
01128 
01129   /* START of COPY */
01130   if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
01131 
01132   /* reset to get the number of data blocks of this folder which are */
01133   /* actually in this cabinet ( at least partially ) */
01134   p_fci_internal->cDataBlocks=0;
01135 
01136   p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
01137       sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
01138       p_fci_internal->placed_files_size+
01139       p_fci_internal->folders_data_size + p_fci_internal->files_size+
01140       p_fci_internal->pending_data_size + p_fci_internal->folders_size;
01141   p_fci_internal->statusFolderCopied = 0;
01142 
01143   /* report status with pfnfcis about copied size of folder */
01144   if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
01145       p_fci_internal->statusFolderTotal, /* TODO total folder size */
01146       p_fci_internal->pv) == -1) {
01147     set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
01148     return FALSE;
01149   }
01150 
01151   /* USE the variable read_result */
01152   read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
01153       p_fci_internal->placed_files_size + p_fci_internal->folders_size;
01154 
01155   if(p_fci_internal->files_size!=0) {
01156     read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
01157   }
01158 
01159   /* Check if multiple cabinets have to be created. */
01160 
01161   /* Might be too much data for the maximum allowed cabinet size.*/
01162   /* When any further data will be added later, it might not */
01163   /* be possible to flush the cabinet, because there might */
01164   /* not be enough space to store the name of the following */
01165   /* cabinet and name of the corresponding disk. */
01166   /* So take care of this and get the name of the next cabinet */
01167   if( p_fci_internal->fGetNextCabInVain==FALSE &&
01168       p_fci_internal->fNextCab==FALSE &&
01169       (
01170         (
01171           p_fci_internal->ccab.cb < read_result +
01172           p_fci_internal->pending_data_size +
01173           p_fci_internal->files_size +
01174           CB_MAX_CABINET_NAME +   /* next cabinet name */
01175           CB_MAX_DISK_NAME        /* next disk name */
01176         ) || fGetNextCab
01177       )
01178   ) {
01179     /* increment cabinet index */
01180     ++(p_fci_internal->pccab->iCab);
01181     /* get name of next cabinet */
01182     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
01183     if (!(*pfnfcignc)(p_fci_internal->pccab,
01184         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
01185         p_fci_internal->pv)) {
01186       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
01187       return FALSE;
01188     }
01189 
01190     /* Skip a few lines of code. This is caught by the next if. */
01191     p_fci_internal->fGetNextCabInVain=TRUE;
01192   }
01193 
01194   /* too much data for cabinet */
01195   if( (p_fci_internal->fGetNextCabInVain ||
01196         p_fci_internal->fNextCab ) &&
01197       (
01198         (
01199           p_fci_internal->ccab.cb < read_result +
01200           p_fci_internal->pending_data_size +
01201           p_fci_internal->files_size +
01202           strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
01203           strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
01204         ) || fGetNextCab
01205       )
01206   ) {
01207     p_fci_internal->fGetNextCabInVain=FALSE;
01208     p_fci_internal->fNextCab=TRUE;
01209 
01210     /* return FALSE if there is not enough space left*/
01211     /* this should never happen */
01212     if (p_fci_internal->ccab.cb <=
01213         p_fci_internal->files_size +
01214         read_result +
01215         strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
01216         strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
01217     ) {
01218 
01219       return FALSE;
01220     }
01221 
01222     /* the folder will be split across cabinets */
01223     p_fci_internal->fSplitFolder=TRUE;
01224 
01225   } else {
01226     /* this should never happen */
01227     if (p_fci_internal->fNextCab) {
01228       /* internal error */
01229       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01230       return FALSE;
01231     }
01232   }
01233 
01234   if (!(folder = add_folder( p_fci_internal ))) return FALSE;
01235   if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
01236   if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
01237 
01238   /* reset CFFolder specific information */
01239   p_fci_internal->cDataBlocks=0;
01240   p_fci_internal->cCompressedBytesInFolder=0;
01241 
01242   return TRUE;
01243 }
01244 
01245 
01246 
01247 
01248 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
01249     BOOL                  fGetNextCab,
01250     PFNFCIGETNEXTCABINET  pfnfcignc,
01251     PFNFCISTATUS          pfnfcis)
01252 {
01253   cab_ULONG read_result=0;
01254   BOOL returntrue=FALSE;
01255 
01256   /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */
01257 
01258   /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
01259   if( p_fci_internal->files_size==0 && fGetNextCab ) {
01260     returntrue=TRUE;
01261   }
01262 
01263   if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
01264     /* TODO set error */
01265     return FALSE;
01266   }
01267 
01268   if(returntrue) return TRUE;
01269 
01270   if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
01271        (p_fci_internal->folders_size==0 &&
01272          (p_fci_internal->files_size!=0 ||
01273           p_fci_internal->placed_files_size!=0 )
01274      ) )
01275   {
01276       /* error */
01277       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01278       return FALSE;
01279   }
01280 
01281   /* create the cabinet */
01282   if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
01283 
01284   p_fci_internal->fPrevCab=TRUE;
01285   /* The sections szPrevCab and szPrevDisk are not being updated, because */
01286   /* MS CABINET.DLL always puts the first cabinet name and disk into them */
01287 
01288   if (p_fci_internal->fNextCab) {
01289     p_fci_internal->fNextCab=FALSE;
01290 
01291     if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
01292       /* THIS CAN NEVER HAPPEN */
01293       /* set error code */
01294       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01295       return FALSE;
01296     }
01297 
01298     if( p_fci_internal->fNewPrevious ) {
01299       memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
01300         CB_MAX_CABINET_NAME);
01301       memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
01302         CB_MAX_DISK_NAME);
01303       p_fci_internal->fNewPrevious=FALSE;
01304     }
01305     p_fci_internal->ccab = *p_fci_internal->pccab;
01306 
01307     /* REUSE the variable read_result */
01308     read_result=get_header_size( p_fci_internal );
01309     if(p_fci_internal->files_size!=0) {
01310         read_result+=p_fci_internal->ccab.cbReserveCFFolder;
01311     }
01312     read_result+= p_fci_internal->pending_data_size +
01313       p_fci_internal->files_size + p_fci_internal->folders_data_size +
01314       p_fci_internal->placed_files_size + p_fci_internal->folders_size +
01315       sizeof(CFFOLDER); /* set size of new CFFolder entry */
01316 
01317     /* too much data for the maximum size of a cabinet */
01318     if( p_fci_internal->fGetNextCabInVain==FALSE &&
01319         p_fci_internal->ccab.cb < read_result ) {
01320       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
01321     }
01322 
01323     /* Might be too much data for the maximum size of a cabinet.*/
01324     /* When any further data will be added later, it might not */
01325     /* be possible to flush the cabinet, because there might */
01326     /* not be enough space to store the name of the following */
01327     /* cabinet and name of the corresponding disk. */
01328     /* So take care of this and get the name of the next cabinet */
01329     if (p_fci_internal->fGetNextCabInVain==FALSE && (
01330       p_fci_internal->ccab.cb < read_result +
01331       CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
01332     )) {
01333       /* increment cabinet index */
01334       ++(p_fci_internal->pccab->iCab);
01335       /* get name of next cabinet */
01336       p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
01337       if (!(*pfnfcignc)(p_fci_internal->pccab,
01338           p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
01339           p_fci_internal->pv)) {
01340         /* error handling */
01341         set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
01342         return FALSE;
01343       }
01344       /* Skip a few lines of code. This is caught by the next if. */
01345       p_fci_internal->fGetNextCabInVain=TRUE;
01346     }
01347 
01348     /* too much data for cabinet */
01349     if (p_fci_internal->fGetNextCabInVain && (
01350         p_fci_internal->ccab.cb < read_result +
01351         strlen(p_fci_internal->ccab.szCab)+1+
01352         strlen(p_fci_internal->ccab.szDisk)+1
01353     )) {
01354       p_fci_internal->fGetNextCabInVain=FALSE;
01355       p_fci_internal->fNextCab=TRUE;
01356       return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
01357     }
01358 
01359     /* if the FolderThreshold has been reached flush the folder automatically */
01360     if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
01361         return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
01362 
01363     if( p_fci_internal->files_size>0 ) {
01364       if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
01365       p_fci_internal->fNewPrevious=TRUE;
01366     }
01367   } else {
01368     p_fci_internal->fNewPrevious=FALSE;
01369     if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
01370       /* THIS MAY NEVER HAPPEN */
01371       /* set error structures */
01372       set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01373       return FALSE;
01374     }
01375   }
01376 
01377   return TRUE;
01378 } /* end of fci_flush_cabinet */
01379 
01380 
01381 
01382 
01383 
01384 /***********************************************************************
01385  *      FCIAddFile (CABINET.11)
01386  *
01387  * FCIAddFile adds a file to the to be created cabinet file
01388  *
01389  * PARAMS
01390  *   hfci          [I]  An HFCI from FCICreate
01391  *   pszSourceFile [I]  A pointer to a C string which contains the name and
01392  *                      location of the file which will be added to the cabinet
01393  *   pszFileName   [I]  A pointer to a C string which contains the name under
01394  *                      which the file will be stored in the cabinet
01395  *   fExecute      [I]  A boolean value which indicates if the file should be
01396  *                      executed after extraction of self extracting
01397  *                      executables
01398  *   pfnfcignc     [I]  A pointer to a function which gets information about
01399  *                      the next cabinet
01400  *   pfnfcis      [IO]  A pointer to a function which will report status
01401  *                      information about the compression process
01402  *   pfnfcioi      [I]  A pointer to a function which reports file attributes
01403  *                      and time and date information
01404  *   typeCompress  [I]  Compression type
01405  *
01406  * RETURNS
01407  *   On success, returns TRUE
01408  *   On failure, returns FALSE
01409  *
01410  * INCLUDES
01411  *   fci.h
01412  *
01413  */
01414 BOOL __cdecl FCIAddFile(
01415     HFCI                  hfci,
01416     char                 *pszSourceFile,
01417     char                 *pszFileName,
01418     BOOL                  fExecute,
01419     PFNFCIGETNEXTCABINET  pfnfcignc,
01420     PFNFCISTATUS          pfnfcis,
01421     PFNFCIGETOPENINFO     pfnfcigoi,
01422     TCOMP                 typeCompress)
01423 {
01424   cab_ULONG read_result;
01425   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
01426 
01427   if (!p_fci_internal) return FALSE;
01428 
01429   if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
01430       (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
01431     set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
01432     return FALSE;
01433   }
01434 
01435   if (typeCompress != p_fci_internal->compression)
01436   {
01437       if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
01438       switch (typeCompress)
01439       {
01440       case tcompTYPE_MSZIP:
01441 #ifdef HAVE_ZLIB
01442           p_fci_internal->compression = tcompTYPE_MSZIP;
01443           p_fci_internal->compress    = compress_MSZIP;
01444           break;
01445 #endif
01446       default:
01447           FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
01448           /* fall through */
01449       case tcompTYPE_NONE:
01450           p_fci_internal->compression = tcompTYPE_NONE;
01451           p_fci_internal->compress    = compress_NONE;
01452           break;
01453       }
01454   }
01455 
01456   /* TODO check if pszSourceFile??? */
01457 
01458   if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
01459     /* internal error */
01460     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01461     return FALSE;
01462   }
01463 
01464   if(p_fci_internal->fNextCab) {
01465     /* internal error */
01466     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01467     return FALSE;
01468   }
01469 
01470   /* REUSE the variable read_result */
01471   read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
01472 
01473   read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
01474     p_fci_internal->files_size + p_fci_internal->folders_data_size +
01475     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
01476     sizeof(CFFOLDER); /* size of new CFFolder entry */
01477 
01478   /* Might be too much data for the maximum size of a cabinet.*/
01479   /* When any further data will be added later, it might not */
01480   /* be possible to flush the cabinet, because there might */
01481   /* not be enough space to store the name of the following */
01482   /* cabinet and name of the corresponding disk. */
01483   /* So take care of this and get the name of the next cabinet */
01484   if( p_fci_internal->fGetNextCabInVain==FALSE &&
01485       p_fci_internal->fNextCab==FALSE &&
01486       ( p_fci_internal->ccab.cb < read_result +
01487         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
01488       )
01489   ) {
01490     /* increment cabinet index */
01491     ++(p_fci_internal->pccab->iCab);
01492     /* get name of next cabinet */
01493     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
01494     if (!(*pfnfcignc)(p_fci_internal->pccab,
01495         p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
01496         p_fci_internal->pv)) {
01497       /* error handling */
01498       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
01499       return FALSE;
01500     }
01501     /* Skip a few lines of code. This is caught by the next if. */
01502     p_fci_internal->fGetNextCabInVain=TRUE;
01503   }
01504 
01505   if( p_fci_internal->fGetNextCabInVain &&
01506       p_fci_internal->fNextCab
01507   ) {
01508     /* THIS CAN NEVER HAPPEN */
01509     /* set error code */
01510     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01511     return FALSE;
01512   }
01513 
01514   /* too much data for cabinet */
01515   if( p_fci_internal->fGetNextCabInVain &&
01516      (
01517       p_fci_internal->ccab.cb < read_result +
01518       strlen(p_fci_internal->pccab->szCab)+1+
01519       strlen(p_fci_internal->pccab->szDisk)+1
01520   )) {
01521     p_fci_internal->fGetNextCabInVain=FALSE;
01522     p_fci_internal->fNextCab=TRUE;
01523     if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
01524   }
01525 
01526   if( p_fci_internal->fNextCab ) {
01527     /* THIS MAY NEVER HAPPEN */
01528     /* set error code */
01529     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01530     return FALSE;
01531   }
01532 
01533   if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
01534       return FALSE;
01535 
01536   /* REUSE the variable read_result */
01537   read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
01538   read_result+= p_fci_internal->pending_data_size +
01539     p_fci_internal->files_size + p_fci_internal->folders_data_size +
01540     p_fci_internal->placed_files_size + p_fci_internal->folders_size +
01541     sizeof(CFFOLDER); /* set size of new CFFolder entry */
01542 
01543   /* too much data for the maximum size of a cabinet */
01544   /* (ignoring the unflushed data block) */
01545   if( p_fci_internal->fGetNextCabInVain==FALSE &&
01546       p_fci_internal->fNextCab==FALSE && /* this is always the case */
01547       p_fci_internal->ccab.cb < read_result ) {
01548     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
01549   }
01550 
01551   /* Might be too much data for the maximum size of a cabinet.*/
01552   /* When any further data will be added later, it might not */
01553   /* be possible to flush the cabinet, because there might */
01554   /* not be enough space to store the name of the following */
01555   /* cabinet and name of the corresponding disk. */
01556   /* So take care of this and get the name of the next cabinet */
01557   /* (ignoring the unflushed data block) */
01558   if( p_fci_internal->fGetNextCabInVain==FALSE &&
01559       p_fci_internal->fNextCab==FALSE &&
01560       ( p_fci_internal->ccab.cb < read_result +
01561         CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
01562       )
01563   ) {
01564     /* increment cabinet index */
01565     ++(p_fci_internal->pccab->iCab);
01566     /* get name of next cabinet */
01567     p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
01568     if (!(*pfnfcignc)(p_fci_internal->pccab,
01569         p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
01570         p_fci_internal->pv)) {
01571       /* error handling */
01572       set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
01573       return FALSE;
01574     }
01575     /* Skip a few lines of code. This is caught by the next if. */
01576     p_fci_internal->fGetNextCabInVain=TRUE;
01577   }
01578 
01579   if( p_fci_internal->fGetNextCabInVain &&
01580       p_fci_internal->fNextCab
01581   ) {
01582     /* THIS CAN NEVER HAPPEN */
01583     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01584     return FALSE;
01585   }
01586 
01587   /* too much data for cabinet */
01588   if( (p_fci_internal->fGetNextCabInVain ||
01589       p_fci_internal->fNextCab) && (
01590       p_fci_internal->ccab.cb < read_result +
01591       strlen(p_fci_internal->pccab->szCab)+1+
01592       strlen(p_fci_internal->pccab->szDisk)+1
01593   )) {
01594 
01595     p_fci_internal->fGetNextCabInVain=FALSE;
01596     p_fci_internal->fNextCab=TRUE;
01597     return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
01598   }
01599 
01600   if( p_fci_internal->fNextCab ) {
01601     /* THIS MAY NEVER HAPPEN */
01602     /* set error code */
01603     set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
01604     return FALSE;
01605   }
01606 
01607   /* if the FolderThreshold has been reached flush the folder automatically */
01608   if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
01609       return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);
01610 
01611   return TRUE;
01612 } /* end of FCIAddFile */
01613 
01614 
01615 
01616 
01617 
01618 /***********************************************************************
01619  *      FCIFlushFolder (CABINET.12)
01620  *
01621  * FCIFlushFolder completes the CFFolder structure under construction.
01622  *
01623  * All further data which is added by FCIAddFile will be associated to
01624  * the next CFFolder structure.
01625  *
01626  * FCIFlushFolder will be called by FCIAddFile automatically if the
01627  * threshold (stored in the member cbFolderThresh of the CCAB structure
01628  * pccab passed to FCICreate) is exceeded.
01629  *
01630  * FCIFlushFolder will be called by FCIFlushFolder automatically before
01631  * any data will be written into the cabinet file.
01632  *
01633  * PARAMS
01634  *   hfci          [I]  An HFCI from FCICreate
01635  *   pfnfcignc     [I]  A pointer to a function which gets information about
01636  *                      the next cabinet
01637  *   pfnfcis      [IO]  A pointer to a function which will report status
01638  *                      information about the compression process
01639  *
01640  * RETURNS
01641  *   On success, returns TRUE
01642  *   On failure, returns FALSE
01643  *
01644  * INCLUDES
01645  *   fci.h
01646  *
01647  */
01648 BOOL __cdecl FCIFlushFolder(
01649     HFCI                  hfci,
01650     PFNFCIGETNEXTCABINET  pfnfcignc,
01651     PFNFCISTATUS          pfnfcis)
01652 {
01653     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
01654 
01655     if (!p_fci_internal) return FALSE;
01656     return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
01657 }
01658 
01659 
01660 
01661 /***********************************************************************
01662  *      FCIFlushCabinet (CABINET.13)
01663  *
01664  * FCIFlushCabinet stores the data which has been added by FCIAddFile
01665  * into the cabinet file. If the maximum cabinet size (stored in the
01666  * member cb of the CCAB structure pccab passed to FCICreate) has been
01667  * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
01668  * The remaining data still has to be flushed manually by calling
01669  * FCIFlushCabinet.
01670  *
01671  * After FCIFlushCabinet has been called (manually) FCIAddFile must
01672  * NOT be called again. Then hfci has to be released by FCIDestroy.
01673  *
01674  * PARAMS
01675  *   hfci          [I]  An HFCI from FCICreate
01676  *   fGetNextCab   [I]  Whether you want to add additional files to a
01677  *                      cabinet set (TRUE) or whether you want to
01678  *                      finalize it (FALSE)
01679  *   pfnfcignc     [I]  A pointer to a function which gets information about
01680  *                      the next cabinet
01681  *   pfnfcis      [IO]  A pointer to a function which will report status
01682  *                      information about the compression process
01683  *
01684  * RETURNS
01685  *   On success, returns TRUE
01686  *   On failure, returns FALSE
01687  *
01688  * INCLUDES
01689  *   fci.h
01690  *
01691  */
01692 BOOL __cdecl FCIFlushCabinet(
01693     HFCI                  hfci,
01694     BOOL                  fGetNextCab,
01695     PFNFCIGETNEXTCABINET  pfnfcignc,
01696     PFNFCISTATUS          pfnfcis)
01697 {
01698   FCI_Int *p_fci_internal = get_fci_ptr( hfci );
01699 
01700   if (!p_fci_internal) return FALSE;
01701 
01702   if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
01703 
01704   while( p_fci_internal->files_size>0 ||
01705          p_fci_internal->placed_files_size>0 ) {
01706     if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
01707   }
01708 
01709   return TRUE;
01710 }
01711 
01712 
01713 /***********************************************************************
01714  *      FCIDestroy (CABINET.14)
01715  *
01716  * Frees a handle created by FCICreate.
01717  * Only reason for failure would be an invalid handle.
01718  *
01719  * PARAMS
01720  *   hfci [I] The HFCI to free
01721  *
01722  * RETURNS
01723  *   TRUE for success
01724  *   FALSE for failure
01725  */
01726 BOOL __cdecl FCIDestroy(HFCI hfci)
01727 {
01728     struct folder *folder, *folder_next;
01729     struct file *file, *file_next;
01730     struct data_block *block, *block_next;
01731     FCI_Int *p_fci_internal = get_fci_ptr( hfci );
01732 
01733     if (!p_fci_internal) return FALSE;
01734 
01735     /* before hfci can be removed all temporary files must be closed */
01736     /* and deleted */
01737     p_fci_internal->magic = 0;
01738 
01739     LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
01740     {
01741         free_folder( p_fci_internal, folder );
01742     }
01743     LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
01744     {
01745         free_file( p_fci_internal, file );
01746     }
01747     LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
01748     {
01749         free_data_block( p_fci_internal, block );
01750     }
01751 
01752     close_temp_file( p_fci_internal, &p_fci_internal->data );
01753 
01754     /* hfci can now be removed */
01755     p_fci_internal->free(hfci);
01756     return TRUE;
01757 }

Generated on Mon May 28 2012 04:22:35 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.