| /* |
| * File Compression Interface |
| * |
| * Copyright 2002 Patrik Stridvall |
| * Copyright 2005 Gerold Jens Wucherpfennig |
| * |
| * 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 |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| /* |
| |
| There is still some work to be done: |
| |
| - no real compression yet |
| - unknown behaviour if files>=2GB or cabinet >=4GB |
| - 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 |
| - probably check err |
| |
| */ |
| |
| |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "winternl.h" |
| #include "fci.h" |
| #include "cabinet.h" |
| #include "wine/debug.h" |
| |
| |
| #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 |
| |
| |
| #define fci_set_error(A,B,C) do { \ |
| p_fci_internal->perf->erfOper = A; \ |
| p_fci_internal->perf->erfType = B; \ |
| p_fci_internal->perf->fError = C; \ |
| if (B) SetLastError(B); } while(0) |
| |
| |
| 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*/ |
| cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/ |
| 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 */ |
| } CFFOLDER; /* minimum 8 bytes */ |
| |
| 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; |
| |
| |
| /*********************************************************************** |
| * FCICreate (CABINET.10) |
| * |
| * FCICreate is provided with several callbacks and |
| * returns a handle which can be used to create cabinet files. |
| * |
| * 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 |
| * as _read. |
| * 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 |
| * temporary file. |
| * pccab [I] A pointer to an initialized CCAB structure. |
| * 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 |
| * |
| */ |
| HFCI __cdecl FCICreate( |
| PERF perf, |
| PFNFCIFILEPLACED pfnfiledest, |
| PFNFCIALLOC pfnalloc, |
| PFNFCIFREE pfnfree, |
| PFNFCIOPEN pfnopen, |
| PFNFCIREAD pfnread, |
| PFNFCIWRITE pfnwrite, |
| PFNFCICLOSE pfnclose, |
| PFNFCISEEK pfnseek, |
| PFNFCIDELETE pfndelete, |
| PFNFCIGETTEMPFILE pfnfcigtf, |
| PCCAB pccab, |
| void *pv) |
| { |
| HFCI hfci; |
| int err; |
| PFCI_Int p_fci_internal; |
| |
| if (!perf) { |
| SetLastError(ERROR_BAD_ARGUMENTS); |
| return NULL; |
| } |
| if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) || |
| (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) || |
| (!pfnfcigtf) || (!pccab)) { |
| perf->erfOper = FCIERR_NONE; |
| perf->erfType = ERROR_BAD_ARGUMENTS; |
| perf->fError = TRUE; |
| |
| SetLastError(ERROR_BAD_ARGUMENTS); |
| return NULL; |
| } |
| |
| if (!((hfci = (*pfnalloc)(sizeof(FCI_Int))))) { |
| perf->erfOper = FCIERR_ALLOC_FAIL; |
| perf->erfType = ERROR_NOT_ENOUGH_MEMORY; |
| perf->fError = TRUE; |
| |
| SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return NULL; |
| } |
| |
| p_fci_internal=((PFCI_Int)(hfci)); |
| p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC; |
| p_fci_internal->perf = perf; |
| p_fci_internal->pfnfiledest = pfnfiledest; |
| p_fci_internal->pfnalloc = pfnalloc; |
| p_fci_internal->pfnfree = pfnfree; |
| p_fci_internal->pfnopen = pfnopen; |
| p_fci_internal->pfnread = pfnread; |
| p_fci_internal->pfnwrite = pfnwrite; |
| p_fci_internal->pfnclose = pfnclose; |
| p_fci_internal->pfnseek = pfnseek; |
| p_fci_internal->pfndelete = pfndelete; |
| p_fci_internal->pfnfcigtf = pfnfcigtf; |
| p_fci_internal->pccab = pccab; |
| p_fci_internal->fPrevCab = FALSE; |
| p_fci_internal->fNextCab = FALSE; |
| p_fci_internal->fSplitFolder = FALSE; |
| p_fci_internal->fGetNextCabInVain = FALSE; |
| p_fci_internal->pv = pv; |
| p_fci_internal->data_in = NULL; |
| p_fci_internal->cdata_in = 0; |
| p_fci_internal->data_out = NULL; |
| p_fci_internal->cCompressedBytesInFolder = 0; |
| p_fci_internal->cFolders = 0; |
| p_fci_internal->cFiles = 0; |
| p_fci_internal->cDataBlocks = 0; |
| p_fci_internal->sizeFileCFDATA1 = 0; |
| p_fci_internal->sizeFileCFFILE1 = 0; |
| p_fci_internal->sizeFileCFDATA2 = 0; |
| p_fci_internal->sizeFileCFFILE2 = 0; |
| p_fci_internal->sizeFileCFFOLDER = 0; |
| p_fci_internal->sizeFileCFFOLDER = 0; |
| p_fci_internal->fNewPrevious = FALSE; |
| p_fci_internal->estimatedCabinetSize = 0; |
| p_fci_internal->statusFolderTotal = 0; |
| |
| memset(&p_fci_internal->oldCCAB, 0, sizeof(CCAB)); |
| memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME); |
| memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME); |
| |
| /* CFDATA */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1, |
| CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| |
| p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv); |
| if(p_fci_internal->handleCFDATA1==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* array of all CFFILE in a folder */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1, |
| CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv); |
| if(p_fci_internal->handleCFFILE1==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* CFDATA with checksum and ready to be copied into cabinet */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2, |
| CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv); |
| if(p_fci_internal->handleCFDATA2==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* array of all CFFILE in a folder, ready to be copied into cabinet */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, |
| CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv); |
| if(p_fci_internal->handleCFFILE2==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* array of all CFFILE in a folder, ready to be copied into cabinet */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER, |
| CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv); |
| if(p_fci_internal->handleCFFOLDER==0) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE); |
| return FALSE; |
| } |
| |
| /* TODO close and delete new files when return FALSE */ |
| /* TODO error checking of err */ |
| |
| return hfci; |
| } /* end of FCICreate */ |
| |
| |
| |
| |
| |
| |
| static BOOL fci_flush_data_block (HFCI hfci, int* err, |
| PFNFCISTATUS pfnfcis) { |
| |
| /* attention no hfci checks!!! */ |
| /* attention no checks if there is data available!!! */ |
| CFDATA data; |
| CFDATA* cfdata=&data; |
| char* reserved; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData; |
| UINT i; |
| |
| /* TODO compress the data of p_fci_internal->data_in */ |
| /* and write it to p_fci_internal->data_out */ |
| memcpy(p_fci_internal->data_out, p_fci_internal->data_in, |
| p_fci_internal->cdata_in /* number of bytes to copy */); |
| |
| cfdata->csum=0; /* checksum has to be set later */ |
| /* TODO set realsize of compressed data */ |
| cfdata->cbData = p_fci_internal->cdata_in; |
| cfdata->cbUncomp = p_fci_internal->cdata_in; |
| |
| /* write cfdata to p_fci_internal->handleCFDATA1 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ |
| cfdata, sizeof(*cfdata), err, p_fci_internal->pv) |
| != sizeof(*cfdata) ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata); |
| |
| /* add optional reserved area */ |
| |
| /* This allocation and freeing at each CFData block is a bit */ |
| /* inefficent, but it's harder to forget about freeing the buffer :-). */ |
| /* Reserved areas are used seldom besides that... */ |
| if (cbReserveCFData!=0) { |
| if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| for(i=0;i<cbReserveCFData;) { |
| reserved[i++]='\0'; |
| } |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ |
| reserved, /* memory buffer */ |
| cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != cbReserveCFData ) { |
| PFCI_FREE(hfci, reserved); |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err PFCI_FREE(hfci, reserved)*/ |
| |
| p_fci_internal->sizeFileCFDATA1 += cbReserveCFData; |
| PFCI_FREE(hfci, reserved); |
| } |
| |
| /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| cfdata->cbData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != cfdata->cbData) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFDATA1 += cfdata->cbData; |
| |
| /* reset the offset */ |
| p_fci_internal->cdata_in = 0; |
| p_fci_internal->cCompressedBytesInFolder += cfdata->cbData; |
| |
| /* report status with pfnfcis about uncompressed and compressed file data */ |
| if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp, |
| p_fci_internal->pv) == -1) { |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| |
| ++(p_fci_internal->cDataBlocks); |
| |
| return TRUE; |
| } /* end of fci_flush_data_block */ |
| |
| |
| |
| |
| |
| static cab_ULONG fci_get_checksum(const void *pv, UINT cb, CHECKSUM 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); |
| case 2: |
| ul |= (((ULONG)(*pb++)) << 8); |
| case 1: |
| ul |= *pb++; |
| default: |
| break; |
| } |
| csum ^= ul; |
| |
| return csum; |
| } /* end of fci_get_checksum */ |
| |
| |
| |
| static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData, |
| PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new, |
| cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload) |
| { |
| cab_ULONG read_result; |
| CFDATA* pcfdata=(CFDATA*)buffer; |
| BOOL split_block=FALSE; |
| cab_UWORD savedUncomp=0; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| *payload=0; |
| |
| /* while not all CFDATAs have been copied do */ |
| while(!FALSE) { |
| if( p_fci_internal->fNextCab ) { |
| if( split_block ) { |
| /* internal error should never happen */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| } |
| /* REUSE the variable read_result */ |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result=4; |
| } else { |
| read_result=0; |
| } |
| if (p_fci_internal->fPrevCab) { |
| read_result+=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| /* No more CFDATA fits into the cabinet under construction */ |
| /* So don't try to store more data into it */ |
| if( p_fci_internal->fNextCab && |
| (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| read_result + |
| p_fci_internal->oldCCAB.cbReserveCFHeader + |
| sizeof(CFFOLDER) + |
| p_fci_internal->oldCCAB.cbReserveCFFolder + |
| strlen(p_fci_internal->pccab->szCab)+1 + |
| strlen(p_fci_internal->pccab->szDisk)+1 |
| )) { |
| /* This may never be run for the first time the while loop is entered. |
| Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/ |
| split_block=TRUE; /* In this case split_block is abused to store */ |
| /* the complete data block into the next cabinet and not into the */ |
| /* current one. Originally split_block is the indicator that a */ |
| /* data block has been split across different cabinets. */ |
| } else { |
| |
| /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ |
| read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/ |
| buffer, /* memory buffer */ |
| sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv); |
| if (read_result!=sizeof(CFDATA)+cbReserveCFData) { |
| if (read_result==0) break; /* ALL DATA has been copied */ |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* REUSE buffer p_fci_internal->data_out !!! */ |
| /* read data from p_fci_internal->handleCFDATA1 to */ |
| /* p_fci_internal->data_out */ |
| if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, |
| p_fci_internal->data_out /* memory buffer */, |
| pcfdata->cbData /* number of bytes to copy */, |
| err, p_fci_internal->pv) != pcfdata->cbData ) { |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* if cabinet size is too large */ |
| |
| /* REUSE the variable read_result */ |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result=4; |
| } else { |
| read_result=0; |
| } |
| if (p_fci_internal->fPrevCab) { |
| read_result+=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| |
| /* Is cabinet with new CFDATA too large? Then data block has to be split */ |
| if( p_fci_internal->fNextCab && |
| (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData + |
| pcfdata->cbData + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| read_result + |
| p_fci_internal->oldCCAB.cbReserveCFHeader + |
| sizeof(CFFOLDER) + /* size of new CFFolder entry */ |
| p_fci_internal->oldCCAB.cbReserveCFFolder + |
| strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */ |
| strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */ |
| )) { |
| /* REUSE read_result to save the size of the compressed data */ |
| read_result=pcfdata->cbData; |
| /* 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. */ |
| |
| /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */ |
| /* Substract everything except the size of the block of data */ |
| /* to get it's actual size */ |
| pcfdata->cbData = p_fci_internal->oldCCAB.cb - ( |
| sizeof(CFDATA) + cbReserveCFData + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| p_fci_internal->oldCCAB.cbReserveCFHeader + |
| sizeof(CFFOLDER) + /* set size of new CFFolder entry */ |
| p_fci_internal->oldCCAB.cbReserveCFFolder ); |
| /* substract the size of special header fields */ |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| pcfdata->cbData-=4; |
| } |
| if (p_fci_internal->fPrevCab) { |
| pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 + |
| strlen(p_fci_internal->pccab->szDisk)+1; |
| |
| savedUncomp = pcfdata->cbUncomp; |
| pcfdata->cbUncomp = 0; /* on split blocks of data this is zero */ |
| |
| /* if split_block==TRUE then the above while loop won't */ |
| /* be executed again */ |
| split_block=TRUE; /* split_block is the indicator that */ |
| /* a data block has been split across */ |
| /* different cabinets.*/ |
| } |
| |
| /* This should never happen !!! */ |
| if (pcfdata->cbData==0) { |
| /* set error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* set little endian */ |
| pcfdata->cbData=fci_endian_uword(pcfdata->cbData); |
| pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp); |
| |
| /* get checksum and write to cfdata.csum */ |
| pcfdata->csum = fci_get_checksum( &(pcfdata->cbData), |
| sizeof(CFDATA)+cbReserveCFData - |
| sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/ |
| pcfdata->cbData, 0 ) ); |
| |
| /* set little endian */ |
| pcfdata->csum=fci_endian_ulong(pcfdata->csum); |
| |
| /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ |
| buffer, /* memory buffer */ |
| sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData; |
| |
| /* reset little endian */ |
| pcfdata->cbData=fci_endian_uword(pcfdata->cbData); |
| pcfdata->cbUncomp=fci_endian_uword(pcfdata->cbUncomp); |
| pcfdata->csum=fci_endian_ulong(pcfdata->csum); |
| |
| /* write compressed data into p_fci_internal->handleCFDATA2 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| pcfdata->cbData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != pcfdata->cbData) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData; |
| ++(p_fci_internal->cDataBlocks); |
| p_fci_internal->statusFolderCopied += pcfdata->cbData; |
| (*payload)+=pcfdata->cbUncomp; |
| /* if cabinet size too large and data has been split */ |
| /* write the remainder of the data block to the new CFDATA1 file */ |
| if( split_block ) { /* This does not include the */ |
| /* abused one (just search for "abused" )*/ |
| /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ |
| if (p_fci_internal->fNextCab==FALSE ) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* set cbData to the size of the remainder of the data block */ |
| pcfdata->cbData = read_result - pcfdata->cbData; |
| /*recover former value of cfdata.cbData; read_result will be the offset*/ |
| read_result -= pcfdata->cbData; |
| pcfdata->cbUncomp = savedUncomp; |
| |
| /* reset checksum, it will be computed later */ |
| pcfdata->csum=0; |
| |
| /* write cfdata WITHOUT checksum to handleCFDATA1new */ |
| if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ |
| buffer, /* memory buffer */ |
| sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */ |
| |
| *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; |
| |
| /* write compressed data into handleCFDATA1new */ |
| if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ |
| p_fci_internal->data_out + read_result, /* memory buffer + offset */ |
| /* to last part of split data */ |
| pcfdata->cbData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != pcfdata->cbData) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->statusFolderCopied += pcfdata->cbData; |
| |
| *psizeFileCFDATA1new += pcfdata->cbData; |
| /* the two blocks of the split data block have been written */ |
| /* don't reset split_data yet, because it is still needed see below */ |
| } |
| |
| /* report status with pfnfcis about copied size of folder */ |
| if( (*pfnfcis)(statusFolder, |
| p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/ |
| p_fci_internal->statusFolderTotal, /* total folder size */ |
| p_fci_internal->pv) == -1) { |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| } |
| |
| /* if cabinet size too large */ |
| /* write the remaining data blocks to the new CFDATA1 file */ |
| if ( split_block ) { /* This does include the */ |
| /* abused one (just search for "abused" )*/ |
| if (p_fci_internal->fNextCab==FALSE ) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ |
| while(!FALSE) { |
| /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ |
| read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */ |
| buffer, /* memory buffer */ |
| sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv); |
| if (read_result!=sizeof(CFDATA)+cbReserveCFData) { |
| if (read_result==0) break; /* ALL DATA has been copied */ |
| /* read error */ |
| fci_set_error(FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* REUSE buffer p_fci_internal->data_out !!! */ |
| /* read data from p_fci_internal->handleCFDATA1 to */ |
| /* p_fci_internal->data_out */ |
| if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, |
| p_fci_internal->data_out /* memory buffer */, |
| pcfdata->cbData /* number of bytes to copy */, |
| err, p_fci_internal->pv) != pcfdata->cbData ) { |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE); |
| return FALSE; |
| } |
| /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */ |
| |
| /* write cfdata with checksum to handleCFDATA1new */ |
| if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ |
| buffer, /* memory buffer */ |
| sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err don't forget PFCI_FREE(hfci, reserved) */ |
| |
| *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; |
| |
| /* write compressed data into handleCFDATA1new */ |
| if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| pcfdata->cbData, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != pcfdata->cbData) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| *psizeFileCFDATA1new += pcfdata->cbData; |
| p_fci_internal->statusFolderCopied += pcfdata->cbData; |
| |
| /* report status with pfnfcis about copied size of folder */ |
| if( (*pfnfcis)(statusFolder, |
| p_fci_internal->statusFolderCopied,/*cfdata.cbData(+previous ones)*/ |
| p_fci_internal->statusFolderTotal, /* total folder size */ |
| p_fci_internal->pv) == -1) { |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| |
| } /* end of WHILE */ |
| break; /* jump out of the next while loop */ |
| } /* end of if( split_data ) */ |
| } /* end of WHILE */ |
| return TRUE; |
| } /* end of fci_flushfolder_copy_cfdata */ |
| |
| |
| |
| |
| |
| static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder, |
| cab_ULONG sizeFileCFDATA2old) |
| { |
| CFFOLDER cffolder; |
| UINT i; |
| char* reserved; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| /* absolute offset cannot be set yet, because the size of cabinet header, */ |
| /* the number of CFFOLDERs and the number of CFFILEs may change. */ |
| /* Instead the size of all previous data blocks will be stored and */ |
| /* the remainder of the offset will be added when the cabinet will be */ |
| /* flushed to disk. */ |
| /* This is exactly the way the original CABINET.DLL works!!! */ |
| cffolder.coffCabStart=sizeFileCFDATA2old; |
| |
| /* set the number of this folder's CFDATA sections */ |
| cffolder.cCFData=p_fci_internal->cDataBlocks; |
| /* TODO set compression type */ |
| cffolder.typeCompress = tcompTYPE_NONE; |
| |
| /* write cffolder to p_fci_internal->handleCFFOLDER */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ |
| &cffolder, /* memory buffer */ |
| sizeof(cffolder), /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(cffolder) ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder); |
| |
| /* add optional reserved area */ |
| if (cbReserveCFFolder!=0) { |
| if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| for(i=0;i<cbReserveCFFolder;) { |
| reserved[i++]='\0'; |
| } |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ |
| reserved, /* memory buffer */ |
| cbReserveCFFolder, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != cbReserveCFFolder ) { |
| PFCI_FREE(hfci, reserved); |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder; |
| |
| PFCI_FREE(hfci, reserved); |
| } |
| return TRUE; |
| } /* end of fci_flushfolder_copy_cffolder */ |
| |
| |
| |
| |
| |
| static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new, |
| cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload) |
| { |
| CFFILE cffile; |
| cab_ULONG read_result; |
| cab_ULONG seek=0; |
| cab_ULONG sizeOfFiles=0, sizeOfFilesPrev; |
| BOOL may_be_prev=TRUE; |
| cab_ULONG cbFileRemainer=0; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| /* set seek of p_fci_internal->handleCFFILE1 to 0 */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err, |
| p_fci_internal->pv) !=0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* while not all CFFILE structures have been copied do */ |
| while(!FALSE) { |
| /* REUSE the variable read_result */ |
| /* read data from p_fci_internal->handleCFFILE1 to cffile */ |
| read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */, |
| &cffile, /* memory buffer */ |
| sizeof(cffile), /* number of bytes to copy */ |
| err, p_fci_internal->pv); |
| if( read_result != sizeof(cffile) ) { |
| if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* Microsoft's(R) CABINET.DLL would do a seek to the current! */ |
| /* position. I don't know why so I'll just omit it */ |
| |
| /* read the filename from p_fci_internal->handleCFFILE1 */ |
| /* REUSE the variable read_result AGAIN */ |
| /* REUSE the memory buffer PFCI(hfci)->data_out */ |
| if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/, |
| p_fci_internal->data_out, /* memory buffer */ |
| CB_MAX_FILENAME, /* number of bytes to copy */ |
| err, p_fci_internal->pv) <2) { |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO maybe other checks of read_result */ |
| /* TODO error handling of err */ |
| |
| /* safety */ |
| if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) { |
| /* set error code internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| |
| seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1; |
| |
| /* set seek of p_fci_internal->handleCFFILE1 to end of file name */ |
| /* i.e. seek to the next CFFILE area */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1, |
| seek, /* seek position*/ |
| SEEK_SET ,err, |
| p_fci_internal->pv) |
| != seek) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* fnfilfnfildest: placed file on cabinet */ |
| if (p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain) { |
| PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB), |
| p_fci_internal->data_out, /* the file name*/ |
| cffile.cbFile, /* file size */ |
| (cffile.iFolder==cffileCONTINUED_FROM_PREV), |
| p_fci_internal->pv |
| ); |
| } else { |
| PFCI_FILEPLACED( hfci, p_fci_internal->pccab, |
| p_fci_internal->data_out, /* the file name*/ |
| cffile.cbFile, /* file size */ |
| (cffile.iFolder==cffileCONTINUED_FROM_PREV), |
| p_fci_internal->pv |
| ); |
| } |
| |
| /* Check special iFolder values */ |
| if( cffile.iFolder==cffileCONTINUED_FROM_PREV && |
| p_fci_internal->fPrevCab==FALSE ) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || |
| cffile.iFolder==cffileCONTINUED_TO_NEXT ) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { |
| may_be_prev=FALSE; |
| } |
| if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { |
| may_be_prev=FALSE; |
| } |
| |
| sizeOfFilesPrev=sizeOfFiles; |
| /* Set complete size of all processed files */ |
| if( cffile.iFolder==cffileCONTINUED_FROM_PREV && |
| p_fci_internal->cbFileRemainer!=0 |
| ) { |
| sizeOfFiles+=p_fci_internal->cbFileRemainer; |
| p_fci_internal->cbFileRemainer=0; |
| } else { |
| sizeOfFiles+=cffile.cbFile; |
| } |
| |
| /* Check if spanned file fits into this cabinet folder */ |
| if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) { |
| cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT; |
| } else |
| |
| /* Check if file doesn't fit into this cabinet folder */ |
| if( sizeOfFiles>payload ) { |
| cffile.iFolder=cffileCONTINUED_TO_NEXT; |
| } |
| |
| /* set little endian */ |
| cffile.cbFile=fci_endian_ulong(cffile.cbFile); |
| cffile.uoffFolderStart=fci_endian_ulong(cffile.uoffFolderStart); |
| cffile.iFolder=fci_endian_uword(cffile.iFolder); |
| cffile.date=fci_endian_uword(cffile.date); |
| cffile.time=fci_endian_uword(cffile.time); |
| cffile.attribs=fci_endian_uword(cffile.attribs); |
| |
| /* write cffile to p_fci_internal->handleCFFILE2 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ |
| &cffile, /* memory buffer */ |
| sizeof(cffile), /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(cffile) ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFILE2 += sizeof(cffile); |
| |
| /* reset little endian */ |
| cffile.cbFile=fci_endian_ulong(cffile.cbFile); |
| cffile.uoffFolderStart=fci_endian_ulong(cffile.uoffFolderStart); |
| cffile.iFolder=fci_endian_uword(cffile.iFolder); |
| cffile.date=fci_endian_uword(cffile.date); |
| cffile.time=fci_endian_uword(cffile.time); |
| cffile.attribs=fci_endian_uword(cffile.attribs); |
| |
| /* write file name to p_fci_internal->handleCFFILE2 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1; |
| |
| /* cFiles is used to count all files of a cabinet */ |
| ++(p_fci_internal->cFiles); |
| |
| /* This is only true for files which will be written into the */ |
| /* next cabinet of the spanning folder */ |
| if( sizeOfFiles>payload ) { |
| |
| /* Files which data will be partially written into the current cabinet */ |
| if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || |
| cffile.iFolder==cffileCONTINUED_TO_NEXT |
| ) { |
| if( sizeOfFilesPrev<=payload ) { |
| /* The size of the uncompressed, data of a spanning file in a */ |
| /* spanning data */ |
| cbFileRemainer=sizeOfFiles-payload; |
| } |
| cffile.iFolder=cffileCONTINUED_FROM_PREV; |
| } else { |
| cffile.iFolder=0; |
| } |
| |
| /* write cffile into handleCFFILE1new */ |
| if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ |
| &cffile, /* memory buffer */ |
| sizeof(cffile), /* number of bytes to copy */ |
| err, p_fci_internal->pv) != sizeof(cffile) ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| *psizeFileCFFILE1new += sizeof(cffile); |
| /* write name of file into handleCFFILE1new */ |
| if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ |
| err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1; |
| } |
| |
| } /* END OF while */ |
| p_fci_internal->cbFileRemainer=cbFileRemainer; |
| return TRUE; |
| } /* end of fci_flushfolder_copy_cffile */ |
| |
| |
| |
| |
| static BOOL fci_flush_folder( |
| HFCI hfci, |
| BOOL fGetNextCab, |
| PFNFCIGETNEXTCABINET pfnfcignc, |
| PFNFCISTATUS pfnfcis) |
| { |
| int err; |
| int handleCFDATA1new; /* handle for new temp file */ |
| char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */ |
| int handleCFFILE1new; /* handle for new temp file */ |
| char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */ |
| UINT cbReserveCFData, cbReserveCFFolder; |
| char* reserved; |
| cab_ULONG sizeFileCFDATA1new=0; |
| cab_ULONG sizeFileCFFILE1new=0; |
| cab_ULONG sizeFileCFDATA2old; |
| cab_ULONG payload; |
| cab_ULONG read_result; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| /* test hfci */ |
| if (!REALLY_IS_FCI(hfci)) { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| if ((!pfnfcignc) || (!pfnfcis)) { |
| fci_set_error( FCIERR_NONE, ERROR_BAD_ARGUMENTS, TRUE ); |
| return FALSE; |
| } |
| |
| if( p_fci_internal->fGetNextCabInVain && |
| p_fci_internal->fNextCab ){ |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* If there was no FCIAddFile or FCIFlushFolder has already been called */ |
| /* this function will return TRUE */ |
| if( p_fci_internal->sizeFileCFFILE1 == 0 ) { |
| if ( p_fci_internal->sizeFileCFDATA1 != 0 ) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* FCIFlushFolder has already been called... */ |
| if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) { |
| return TRUE; |
| } |
| |
| /* This can be set already, because it makes only a difference */ |
| /* when the current function exits with return FALSE */ |
| p_fci_internal->fSplitFolder=FALSE; |
| |
| |
| if( p_fci_internal->fGetNextCabInVain || |
| p_fci_internal->fNextCab ){ |
| cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData; |
| cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder; |
| } else { |
| cbReserveCFData = p_fci_internal->pccab->cbReserveCFData; |
| cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder; |
| } |
| |
| /* START of COPY */ |
| /* if there is data in p_fci_internal->data_in */ |
| if (p_fci_internal->cdata_in!=0) { |
| |
| if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; |
| |
| } |
| /* 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; |
| |
| if ( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+ |
| p_fci_internal->oldCCAB.cbReserveCFFolder; |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } else { |
| read_result= p_fci_internal->pccab->cbReserveCFHeader+ |
| p_fci_internal->pccab->cbReserveCFFolder; |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } |
| if (p_fci_internal->fPrevCab) { |
| read_result+=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| if (p_fci_internal->fNextCab) { |
| read_result+=strlen(p_fci_internal->pccab->szCab)+1 + |
| strlen(p_fci_internal->pccab->szDisk)+1; |
| } |
| |
| p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+ |
| sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+ |
| p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+ |
| p_fci_internal->sizeFileCFDATA1 + p_fci_internal->sizeFileCFFOLDER; |
| 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) { |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| |
| /* get a new temp file */ |
| if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err, |
| p_fci_internal->pv); |
| if(handleCFDATA1new==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| |
| |
| /* get a new temp file */ |
| if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) { |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) { |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err, |
| p_fci_internal->pv); |
| if(handleCFFILE1new==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* USE the variable read_result */ |
| if ( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| read_result= p_fci_internal->oldCCAB.cbReserveCFHeader; |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } else { |
| read_result= p_fci_internal->pccab->cbReserveCFHeader; |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } |
| if (p_fci_internal->fPrevCab) { |
| read_result+=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER; |
| |
| if(p_fci_internal->sizeFileCFFILE1!=0) { |
| read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder; |
| } |
| |
| /* 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 && |
| ( |
| ( |
| p_fci_internal->pccab->cb < read_result + |
| p_fci_internal->sizeFileCFDATA1 + |
| p_fci_internal->sizeFileCFFILE1 + |
| CB_MAX_CABINET_NAME + /* next cabinet name */ |
| CB_MAX_DISK_NAME /* next disk name */ |
| ) || fGetNextCab |
| ) |
| ) { |
| /* save CCAB */ |
| memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); |
| /* increment cabinet index */ |
| ++(p_fci_internal->pccab->iCab); |
| /* get name of next cabinet */ |
| p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; |
| if (!(*pfnfcignc)(p_fci_internal->pccab, |
| p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ |
| p_fci_internal->pv)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| |
| /* Skip a few lines of code. This is caught by the next if. */ |
| p_fci_internal->fGetNextCabInVain=TRUE; |
| } |
| |
| /* too much data for cabinet */ |
| if( (p_fci_internal->fGetNextCabInVain || |
| p_fci_internal->fNextCab ) && |
| ( |
| ( |
| p_fci_internal->oldCCAB.cb < read_result + |
| p_fci_internal->sizeFileCFDATA1 + |
| p_fci_internal->sizeFileCFFILE1 + |
| 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 */ |
| if (p_fci_internal->oldCCAB.cb <= |
| p_fci_internal->sizeFileCFFILE1 + |
| read_result + |
| strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ |
| strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ |
| ) { |
| |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* close and delete p_fci_internal->handleCFFILE1 */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| return FALSE; |
| } |
| |
| /* the folder will be split across cabinets */ |
| p_fci_internal->fSplitFolder=TRUE; |
| |
| } else { |
| /* this should never happen */ |
| if (p_fci_internal->fNextCab) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| } |
| |
| /* set seek of p_fci_internal->handleCFDATA1 to 0 */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err, |
| p_fci_internal->pv) !=0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* save size of file CFDATA2 - required for the folder's offset to data */ |
| sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2; |
| |
| if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| |
| if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err, |
| handleCFDATA1new, &sizeFileCFDATA1new, &payload |
| )) { |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_FREE(hfci,reserved); |
| return FALSE; |
| } |
| |
| PFCI_FREE(hfci,reserved); |
| |
| if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder, |
| sizeFileCFDATA2old )) { |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| |
| if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new, |
| &sizeFileCFFILE1new, payload)) { |
| PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| return FALSE; |
| } |
| |
| /* close and delete p_fci_internal->handleCFDATA1 */ |
| PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* put new CFDATA1 into hfci */ |
| memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new, |
| CB_MAX_FILENAME); |
| |
| /* put CFDATA1 file handle */ |
| PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new; |
| /* set file size */ |
| PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new; |
| |
| /* close and delete PFCI_INT(hfci)->handleCFFILE1 */ |
| PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* put new CFFILE1 into hfci */ |
| memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new, |
| CB_MAX_FILENAME); |
| |
| /* put CFFILE1 file handle */ |
| p_fci_internal->handleCFFILE1 = handleCFFILE1new; |
| /* set file size */ |
| p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new; |
| |
| ++(p_fci_internal->cFolders); |
| |
| /* reset CFFolder specific information */ |
| p_fci_internal->cDataBlocks=0; |
| p_fci_internal->cCompressedBytesInFolder=0; |
| |
| return TRUE; |
| } /* end of fci_flush_folder */ |
| |
| |
| |
| |
| static BOOL fci_flush_cabinet( |
| HFCI hfci, |
| BOOL fGetNextCab, |
| PFNFCIGETNEXTCABINET pfnfcignc, |
| PFNFCISTATUS pfnfcis) |
| { |
| int err; |
| CFHEADER cfheader; |
| struct { |
| cab_UWORD cbCFHeader; |
| cab_UBYTE cbCFFolder; |
| cab_UBYTE cbCFData; |
| } cfreserved; |
| CFFOLDER cffolder; |
| cab_ULONG read_result=0; |
| int handleCABINET; /* file handle for cabinet */ |
| char szFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */ |
| UINT cbReserveCFHeader, cbReserveCFFolder, i; |
| char* reserved; |
| BOOL returntrue=FALSE; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */ |
| |
| /* when FCIFlushCabinet was or FCIAddFile hasn't been called */ |
| if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) { |
| returntrue=TRUE; |
| } |
| |
| if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){ |
| /* TODO set error */ |
| return FALSE; |
| } |
| |
| if(returntrue) return TRUE; |
| |
| if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)|| |
| (p_fci_internal->sizeFileCFFOLDER==0 && |
| (p_fci_internal->sizeFileCFFILE1!=0 || |
| p_fci_internal->sizeFileCFFILE2!=0 ) |
| ) ) |
| { |
| /* error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder; |
| cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader; |
| /* safety */ |
| if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH || |
| strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) { |
| /* set error */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| /* get the full name of the cabinet */ |
| memcpy(szFileNameCABINET,p_fci_internal->oldCCAB.szCabPath, |
| CB_MAX_CAB_PATH); |
| memcpy(szFileNameCABINET+strlen(szFileNameCABINET), |
| p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME); |
| } else { |
| cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder; |
| cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader; |
| /* safety */ |
| if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH || |
| strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) { |
| /* set error */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| /* get the full name of the cabinet */ |
| memcpy(szFileNameCABINET,p_fci_internal->pccab->szCabPath, |
| CB_MAX_CAB_PATH); |
| memcpy(szFileNameCABINET+strlen(szFileNameCABINET), |
| p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME); |
| } |
| |
| memcpy(cfheader.signature,"!CAB",4); |
| cfheader.reserved1=0; |
| cfheader.cbCabinet= /* size of the cabinet file in bytes */ |
| sizeof(CFHEADER) + |
| p_fci_internal->sizeFileCFFOLDER + |
| p_fci_internal->sizeFileCFFILE2 + |
| p_fci_internal->sizeFileCFDATA2; |
| |
| if (p_fci_internal->fPrevCab) { |
| cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| if (p_fci_internal->fNextCab) { |
| cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 + |
| strlen(p_fci_internal->pccab->szDisk)+1; |
| } |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader; |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| cfheader.cbCabinet+=4; |
| } |
| } else { |
| cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader; |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| cfheader.cbCabinet+=4; |
| } |
| } |
| |
| if( ( ( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) && |
| cfheader.cbCabinet > p_fci_internal->oldCCAB.cb |
| ) || |
| ( ( p_fci_internal->fNextCab==FALSE && |
| p_fci_internal->fGetNextCabInVain==FALSE ) && |
| cfheader.cbCabinet > p_fci_internal->pccab->cb |
| ) |
| ) |
| { |
| fci_set_error( FCIERR_NONE, ERROR_MORE_DATA, TRUE ); |
| return FALSE; |
| } |
| |
| |
| cfheader.reserved2=0; |
| cfheader.coffFiles= /* offset to first CFFILE section */ |
| cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 - |
| p_fci_internal->sizeFileCFDATA2; |
| |
| cfheader.reserved3=0; |
| cfheader.versionMinor=3; |
| cfheader.versionMajor=1; |
| /* number of CFFOLDER entries in the cabinet */ |
| cfheader.cFolders=p_fci_internal->cFolders; |
| /* number of CFFILE entries in the cabinet */ |
| cfheader.cFiles=p_fci_internal->cFiles; |
| cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved sections */ |
| |
| if( p_fci_internal->fPrevCab ) { |
| cfheader.flags = cfheadPREV_CABINET; |
| } |
| |
| if( p_fci_internal->fNextCab ) { |
| cfheader.flags |= cfheadNEXT_CABINET; |
| } |
| |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| cfheader.flags |= cfheadRESERVE_PRESENT; |
| } |
| cfheader.setID = p_fci_internal->oldCCAB.setID; |
| cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1; |
| } else { |
| if( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| cfheader.flags |= cfheadRESERVE_PRESENT; |
| } |
| cfheader.setID = p_fci_internal->pccab->setID; |
| cfheader.iCabinet = p_fci_internal->pccab->iCab-1; |
| } |
| |
| /* create the cabinet */ |
| handleCABINET = PFCI_OPEN(hfci, szFileNameCABINET, |
| 33538, 384, &err, p_fci_internal->pv ); |
| if(handleCABINET==0){ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* set little endian */ |
| cfheader.reserved1=fci_endian_ulong(cfheader.reserved1); |
| cfheader.cbCabinet=fci_endian_ulong(cfheader.cbCabinet); |
| cfheader.reserved2=fci_endian_ulong(cfheader.reserved2); |
| cfheader.coffFiles=fci_endian_ulong(cfheader.coffFiles); |
| cfheader.reserved3=fci_endian_ulong(cfheader.reserved3); |
| cfheader.cFolders=fci_endian_uword(cfheader.cFolders); |
| cfheader.cFiles=fci_endian_uword(cfheader.cFiles); |
| cfheader.flags=fci_endian_uword(cfheader.flags); |
| cfheader.setID=fci_endian_uword(cfheader.setID); |
| cfheader.iCabinet=fci_endian_uword(cfheader.iCabinet); |
| |
| /* write CFHEADER into cabinet file */ |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| &cfheader, /* memory buffer */ |
| sizeof(cfheader), /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != sizeof(cfheader) ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* reset little endian */ |
| cfheader.reserved1=fci_endian_ulong(cfheader.reserved1); |
| cfheader.cbCabinet=fci_endian_ulong(cfheader.cbCabinet); |
| cfheader.reserved2=fci_endian_ulong(cfheader.reserved2); |
| cfheader.coffFiles=fci_endian_ulong(cfheader.coffFiles); |
| cfheader.reserved3=fci_endian_ulong(cfheader.reserved3); |
| cfheader.cFolders=fci_endian_uword(cfheader.cFolders); |
| cfheader.cFiles=fci_endian_uword(cfheader.cFiles); |
| cfheader.flags=fci_endian_uword(cfheader.flags); |
| cfheader.setID=fci_endian_uword(cfheader.setID); |
| cfheader.iCabinet=fci_endian_uword(cfheader.iCabinet); |
| |
| if( cfheader.flags & cfheadRESERVE_PRESENT ) { |
| /* NOTE: No checks for maximum value overflows as designed by MS!!! */ |
| cfreserved.cbCFHeader = cbReserveCFHeader; |
| cfreserved.cbCFFolder = cbReserveCFFolder; |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData; |
| } else { |
| cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData; |
| } |
| |
| /* set little endian */ |
| cfreserved.cbCFHeader=fci_endian_uword(cfreserved.cbCFHeader); |
| |
| /* write reserved info into cabinet file */ |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| &cfreserved, /* memory buffer */ |
| sizeof(cfreserved), /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != sizeof(cfreserved) ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* reset little endian */ |
| cfreserved.cbCFHeader=fci_endian_uword(cfreserved.cbCFHeader); |
| } |
| |
| /* add optional reserved area */ |
| if (cbReserveCFHeader!=0) { |
| if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| for(i=0;i<cbReserveCFHeader;) { |
| reserved[i++]='\0'; |
| } |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| reserved, /* memory buffer */ |
| cbReserveCFHeader, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != cbReserveCFHeader ) { |
| PFCI_FREE(hfci, reserved); |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| PFCI_FREE(hfci, reserved); |
| } |
| |
| if( cfheader.flags & cfheadPREV_CABINET ) { |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->szPrevCab, /* memory buffer */ |
| strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->szPrevDisk, /* memory buffer */ |
| strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| } |
| |
| if( cfheader.flags & cfheadNEXT_CABINET ) { |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->pccab->szCab, /* memory buffer */ |
| strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->pccab->szDisk, /* memory buffer */ |
| strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| } |
| |
| /* set seek of p_fci_internal->handleCFFOLDER to 0 */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER, |
| 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* while not all CFFOLDER structures have been copied into the cabinet do */ |
| while(!FALSE) { |
| /* use the variable read_result */ |
| /* read cffolder of p_fci_internal->handleCFFOLDER */ |
| read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */ |
| &cffolder, /* memory buffer */ |
| sizeof(cffolder), /* number of bytes to copy */ |
| &err, p_fci_internal->pv); |
| if( read_result != sizeof(cffolder) ) { |
| if( read_result == 0 ) break;/*ALL CFFOLDER structures have been copied*/ |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* add size of header size of all CFFOLDERs and size of all CFFILEs */ |
| cffolder.coffCabStart += |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER); |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader; |
| } else { |
| cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader; |
| } |
| |
| if (p_fci_internal->fPrevCab) { |
| cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 + |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| |
| if (p_fci_internal->fNextCab) { |
| cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 + |
| strlen(p_fci_internal->oldCCAB.szDisk)+1; |
| } |
| |
| if( p_fci_internal->fNextCab || |
| p_fci_internal->fGetNextCabInVain ) { |
| cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader; |
| if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| cffolder.coffCabStart += 4; |
| } |
| } else { |
| cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader; |
| if( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| cffolder.coffCabStart += 4; |
| } |
| } |
| |
| /* set little endian */ |
| cffolder.coffCabStart=fci_endian_ulong(cffolder.coffCabStart); |
| cffolder.cCFData=fci_endian_uword(cffolder.cCFData); |
| cffolder.typeCompress=fci_endian_uword(cffolder.typeCompress); |
| |
| /* write cffolder to cabinet file */ |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| &cffolder, /* memory buffer */ |
| sizeof(cffolder), /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != sizeof(cffolder) ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* reset little endian */ |
| cffolder.coffCabStart=fci_endian_ulong(cffolder.coffCabStart); |
| cffolder.cCFData=fci_endian_uword(cffolder.cCFData); |
| cffolder.typeCompress=fci_endian_uword(cffolder.typeCompress); |
| |
| /* add optional reserved area */ |
| |
| /* This allocation and freeing at each CFFolder block is a bit */ |
| /* inefficient, but it's harder to forget about freeing the buffer :-). */ |
| /* Reserved areas are used seldom besides that... */ |
| if (cbReserveCFFolder!=0) { |
| if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| |
| if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ |
| reserved, /* memory buffer */ |
| cbReserveCFFolder, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != cbReserveCFFolder ) { |
| PFCI_FREE(hfci, reserved); |
| /* read error */ |
| fci_set_error( FCIERR_NONE, ERROR_READ_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| reserved, /* memory buffer */ |
| cbReserveCFFolder, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != cbReserveCFFolder ) { |
| PFCI_FREE(hfci, reserved); |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| PFCI_FREE(hfci, reserved); |
| } |
| |
| } /* END OF while */ |
| |
| /* set seek of p_fci_internal->handleCFFILE2 to 0 */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2, |
| 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* while not all CFFILE structures have been copied to the cabinet do */ |
| while(!FALSE) { |
| /* REUSE the variable read_result */ |
| /* REUSE the buffer p_fci_internal->data_out AGAIN */ |
| /* read a block from p_fci_internal->handleCFFILE2 */ |
| read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */, |
| p_fci_internal->data_out, /* memory buffer */ |
| CB_MAX_CHUNK, /* number of bytes to copy */ |
| &err, p_fci_internal->pv); |
| if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ |
| /* TODO error handling of err */ |
| |
| /* write the block to the cabinet file */ |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| read_result, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != read_result ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| if (p_fci_internal->fSplitFolder==FALSE) { |
| p_fci_internal->statusFolderCopied = 0; |
| /* TODO TEST THIS further */ |
| p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+ |
| p_fci_internal->sizeFileCFFILE2; |
| } |
| p_fci_internal->statusFolderCopied += read_result; |
| |
| /* report status with pfnfcis about copied size of folder */ |
| if( (*pfnfcis)(statusFolder, |
| p_fci_internal->statusFolderCopied, /* length of copied blocks */ |
| p_fci_internal->statusFolderTotal, /* total size of folder */ |
| p_fci_internal->pv) == -1) { |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| |
| } /* END OF while */ |
| |
| /* set seek of p_fci_internal->handleCFDATA2 to 0 */ |
| if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2, |
| 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* reset the number of folders for the next cabinet */ |
| p_fci_internal->cFolders=0; |
| /* reset the number of files for the next cabinet */ |
| p_fci_internal->cFiles=0; |
| |
| /* while not all CFDATA structures have been copied to the cabinet do */ |
| while(!FALSE) { |
| /* REUSE the variable read_result AGAIN */ |
| /* REUSE the buffer p_fci_internal->data_out AGAIN */ |
| /* read a block from p_fci_internal->handleCFDATA2 */ |
| read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */, |
| p_fci_internal->data_out, /* memory buffer */ |
| CB_MAX_CHUNK, /* number of bytes to copy */ |
| &err, p_fci_internal->pv); |
| if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */ |
| /* TODO error handling of err */ |
| |
| /* write the block to the cabinet file */ |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| p_fci_internal->data_out, /* memory buffer */ |
| read_result, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != read_result ) { |
| /* write error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->statusFolderCopied += read_result; |
| /* report status with pfnfcis about copied size of folder */ |
| if( (*pfnfcis)(statusFolder, |
| p_fci_internal->statusFolderCopied, /* length of copied blocks */ |
| p_fci_internal->statusFolderTotal, /* total size of folder */ |
| p_fci_internal->pv) == -1) { |
| /* set error code and abort */ |
| fci_set_error( FCIERR_USER_ABORT, 0, TRUE ); |
| return FALSE; |
| } |
| } /* END OF while */ |
| |
| /* set seek of the cabinet file to 0 */ |
| if( PFCI_SEEK(hfci, handleCABINET, |
| 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { |
| /* wrong return value */ |
| fci_set_error( FCIERR_NONE, ERROR_SEEK, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* write the signature "MSCF" into the cabinet file */ |
| memcpy( cfheader.signature, "MSCF", 4 ); |
| if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ |
| &cfheader, /* memory buffer */ |
| 4, /* number of bytes to copy */ |
| &err, p_fci_internal->pv) != 4 ) { |
| /* wrtie error */ |
| fci_set_error( FCIERR_CAB_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| /* close the cabinet file */ |
| PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| |
| /* COPIED FROM FCIDestroy */ |
| |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* END OF copied from FCIDestroy */ |
| |
| /* get 3 temporary files and open them */ |
| /* write names and handles to hfci */ |
| |
| |
| p_fci_internal->sizeFileCFDATA2 = 0; |
| p_fci_internal->sizeFileCFFILE2 = 0; |
| p_fci_internal->sizeFileCFFOLDER = 0; |
| |
| /* COPIED FROM FCICreate */ |
| |
| /* CFDATA with checksum and ready to be copied into cabinet */ |
| if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2, |
| CB_MAX_FILENAME)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { |
| /* set error code and abort */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv); |
| /* check handle */ |
| if(p_fci_internal->handleCFDATA2==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* array of all CFFILE in a folder, ready to be copied into cabinet */ |
| if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, |
| CB_MAX_FILENAME)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { |
| /* set error code and abort */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv); |
| /* check handle */ |
| if(p_fci_internal->handleCFFILE2==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* array of all CFFILE in a folder, ready to be copied into cabinet */ |
| if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* safety */ |
| if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { |
| /* set error code and abort */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, |
| p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv); |
| /* check handle */ |
| if(p_fci_internal->handleCFFOLDER==0){ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_OPEN_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* TODO error checking of err */ |
| |
| /* END OF copied from FCICreate */ |
| |
| |
| /* TODO close and delete new files when return FALSE */ |
| |
| |
| /* report status with pfnfcis about copied size of folder */ |
| (*pfnfcis)(statusCabinet, |
| p_fci_internal->estimatedCabinetSize, /* estimated cabinet file size */ |
| cfheader.cbCabinet /* real cabinet file size */, p_fci_internal->pv); |
| |
| 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; |
| |
| if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) { |
| /* THIS CAN NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* COPIED FROM FCIAddFile and modified */ |
| |
| /* REUSE the variable read_result */ |
| if (p_fci_internal->fGetNextCabInVain) { |
| read_result=p_fci_internal->oldCCAB.cbReserveCFHeader; |
| if(p_fci_internal->sizeFileCFFILE1!=0) { |
| read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder; |
| } |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } else { |
| read_result=p_fci_internal->pccab->cbReserveCFHeader; |
| if(p_fci_internal->sizeFileCFFILE1!=0) { |
| read_result+=p_fci_internal->pccab->cbReserveCFFolder; |
| } |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } |
| if ( p_fci_internal->fPrevCab ) { |
| read_result+= strlen(p_fci_internal->szPrevCab)+1+ |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| read_result+= p_fci_internal->sizeFileCFDATA1 + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| sizeof(CFFOLDER); /* set size of new CFFolder entry */ |
| |
| if( p_fci_internal->fNewPrevious ) { |
| memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab, |
| CB_MAX_CABINET_NAME); |
| memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk, |
| CB_MAX_DISK_NAME); |
| p_fci_internal->fNewPrevious=FALSE; |
| } |
| |
| /* too much data for the maximum size of a cabinet */ |
| if( p_fci_internal->fGetNextCabInVain==FALSE && |
| p_fci_internal->pccab->cb < read_result ) { |
| return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); |
| } |
| |
| /* 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->pccab->cb < read_result + |
| CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME |
| )) { |
| /* save CCAB */ |
| memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); |
| /* increment cabinet index */ |
| ++(p_fci_internal->pccab->iCab); |
| /* get name of next cabinet */ |
| p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; |
| if (!(*pfnfcignc)(p_fci_internal->pccab, |
| p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ |
| p_fci_internal->pv)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* Skip a few lines of code. This is caught by the next if. */ |
| p_fci_internal->fGetNextCabInVain=TRUE; |
| } |
| |
| /* too much data for cabinet */ |
| if (p_fci_internal->fGetNextCabInVain && ( |
| p_fci_internal->oldCCAB.cb < read_result + |
| strlen(p_fci_internal->oldCCAB.szCab)+1+ |
| strlen(p_fci_internal->oldCCAB.szDisk)+1 |
| )) { |
| p_fci_internal->fGetNextCabInVain=FALSE; |
| p_fci_internal->fNextCab=TRUE; |
| return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); |
| } |
| |
| /* if the FolderThreshold has been reached flush the folder automatically */ |
| if( p_fci_internal->fGetNextCabInVain ) { |
| if( p_fci_internal->cCompressedBytesInFolder >= |
| p_fci_internal->oldCCAB.cbFolderThresh) { |
| return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); |
| } |
| } else { |
| if( p_fci_internal->cCompressedBytesInFolder >= |
| p_fci_internal->pccab->cbFolderThresh) { |
| return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); |
| } |
| } |
| |
| /* END OF COPIED FROM FCIAddFile and modified */ |
| |
| if( p_fci_internal->sizeFileCFFILE1>0 ) { |
| if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE; |
| p_fci_internal->fNewPrevious=TRUE; |
| } |
| } else { |
| p_fci_internal->fNewPrevious=FALSE; |
| if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error structures */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| 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) |
| { |
| int err; |
| CFFILE cffile; |
| cab_ULONG read_result; |
| int file_handle; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| /* test hfci */ |
| if (!REALLY_IS_FCI(hfci)) { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) || |
| (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) { |
| fci_set_error( FCIERR_NONE, ERROR_BAD_ARGUMENTS, TRUE ); |
| return FALSE; |
| } |
| |
| /* TODO check if pszSourceFile??? */ |
| |
| if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| if(p_fci_internal->fNextCab) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| cffile.cbFile=0; /* size of the to be added file*/ |
| /* offset of the uncompressed file in the folder */ |
| cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in; |
| /* number of folder in the cabinet or special 0=first */ |
| cffile.iFolder = p_fci_internal->cFolders; |
| |
| /* allocation of memory */ |
| if (p_fci_internal->data_in==NULL) { |
| if (p_fci_internal->cdata_in!=0) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| if (p_fci_internal->data_out!=NULL) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) { |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| if (p_fci_internal->data_out==NULL) { |
| if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){ |
| fci_set_error( FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY, TRUE ); |
| return FALSE; |
| } |
| } |
| } |
| |
| if (p_fci_internal->data_out==NULL) { |
| PFCI_FREE(hfci,p_fci_internal->data_in); |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* get information about the file */ |
| /* set defaults in case callback doesn't set one or more fields */ |
| cffile.attribs=0; |
| cffile.date=0; |
| cffile.time=0; |
| file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time), |
| &(cffile.attribs), &err, p_fci_internal->pv); |
| /* check file_handle */ |
| if(file_handle==0){ |
| fci_set_error( FCIERR_OPEN_SRC, ERROR_OPEN_FAILED, TRUE ); |
| } |
| /* TODO error handling of err */ |
| |
| if (fExecute) { cffile.attribs |= _A_EXEC; } |
| |
| /* REUSE the variable read_result */ |
| if (p_fci_internal->fGetNextCabInVain) { |
| read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + |
| p_fci_internal->oldCCAB.cbReserveCFFolder; |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } else { |
| read_result=p_fci_internal->pccab->cbReserveCFHeader + |
| p_fci_internal->pccab->cbReserveCFFolder; |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } |
| if ( p_fci_internal->fPrevCab ) { |
| read_result+= strlen(p_fci_internal->szPrevCab)+1+ |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| if ( p_fci_internal->fNextCab ) { /* this is never the case */ |
| read_result+= strlen(p_fci_internal->pccab->szCab)+1+ |
| strlen(p_fci_internal->pccab->szDisk)+1; |
| } |
| |
| read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| 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 && |
| ( p_fci_internal->pccab->cb < read_result + |
| CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME |
| ) |
| ) { |
| /* save CCAB */ |
| memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); |
| /* increment cabinet index */ |
| ++(p_fci_internal->pccab->iCab); |
| /* get name of next cabinet */ |
| p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; |
| if (!(*pfnfcignc)(p_fci_internal->pccab, |
| p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ |
| p_fci_internal->pv)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* Skip a few lines of code. This is caught by the next if. */ |
| p_fci_internal->fGetNextCabInVain=TRUE; |
| } |
| |
| if( p_fci_internal->fGetNextCabInVain && |
| p_fci_internal->fNextCab |
| ) { |
| /* THIS CAN NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* too much data for cabinet */ |
| if( p_fci_internal->fGetNextCabInVain && |
| ( |
| p_fci_internal->oldCCAB.cb < read_result + |
| strlen(p_fci_internal->pccab->szCab)+1+ |
| strlen(p_fci_internal->pccab->szDisk)+1 |
| )) { |
| p_fci_internal->fGetNextCabInVain=FALSE; |
| p_fci_internal->fNextCab=TRUE; |
| if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE; |
| } |
| |
| if( p_fci_internal->fNextCab ) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* read the contents of the file blockwise */ |
| while (!FALSE) { |
| if (p_fci_internal->cdata_in > CAB_BLOCKMAX) { |
| /* internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| read_result = PFCI_READ(hfci, file_handle /* file handle */, |
| (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */, |
| (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */, |
| &err, p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| if( read_result==0 ) break; |
| |
| /* increment the block size */ |
| p_fci_internal->cdata_in += read_result; |
| |
| /* increment the file size */ |
| cffile.cbFile += read_result; |
| |
| if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) { |
| /* report internal error */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| /* write a whole block */ |
| if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) { |
| |
| if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; |
| } |
| } |
| |
| /* close the file from FCIAddFile */ |
| PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* write cffile to p_fci_internal->handleCFFILE1 */ |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ |
| &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) { |
| /* write error */ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFILE1 += sizeof(cffile); |
| |
| /* append the name of file */ |
| if (strlen(pszFileName)>=CB_MAX_FILENAME) { |
| /* IMPOSSIBLE */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_INVALID_DATA, TRUE ); |
| return FALSE; |
| } |
| if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ |
| pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv) |
| != strlen(pszFileName)+1 ) { |
| /* write error */ |
| fci_set_error( FCIERR_TEMP_FILE, ERROR_WRITE_FAULT, TRUE ); |
| return FALSE; |
| } |
| /* TODO error handling of err */ |
| |
| p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1; |
| |
| /* REUSE the variable read_result */ |
| if (p_fci_internal->fGetNextCabInVain || |
| p_fci_internal->fNextCab |
| ) { |
| read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + |
| p_fci_internal->oldCCAB.cbReserveCFFolder; |
| if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || |
| p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } else { |
| read_result=p_fci_internal->pccab->cbReserveCFHeader + |
| p_fci_internal->pccab->cbReserveCFFolder; |
| if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || |
| p_fci_internal->pccab->cbReserveCFFolder != 0 || |
| p_fci_internal->pccab->cbReserveCFData != 0 ) { |
| read_result+=4; |
| } |
| } |
| if ( p_fci_internal->fPrevCab ) { |
| read_result+= strlen(p_fci_internal->szPrevCab)+1+ |
| strlen(p_fci_internal->szPrevDisk)+1; |
| } |
| if ( p_fci_internal->fNextCab ) { /* this is never the case */ |
| read_result+= strlen(p_fci_internal->pccab->szCab)+1+ |
| strlen(p_fci_internal->pccab->szDisk)+1; |
| } |
| read_result+= p_fci_internal->sizeFileCFDATA1 + |
| p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + |
| p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + |
| sizeof(CFHEADER) + |
| 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 */ |
| p_fci_internal->pccab->cb < read_result ) { |
| return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); |
| } |
| |
| /* 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 && |
| ( p_fci_internal->pccab->cb < read_result + |
| CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME |
| ) |
| ) { |
| /* save CCAB */ |
| memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); |
| /* increment cabinet index */ |
| ++(p_fci_internal->pccab->iCab); |
| /* get name of next cabinet */ |
| p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; |
| if (!(*pfnfcignc)(p_fci_internal->pccab, |
| p_fci_internal->estimatedCabinetSize,/* estimated size of cab */ |
| p_fci_internal->pv)) { |
| /* error handling */ |
| fci_set_error( FCIERR_NONE, ERROR_FUNCTION_FAILED, TRUE ); |
| return FALSE; |
| } |
| /* Skip a few lines of code. This is caught by the next if. */ |
| p_fci_internal->fGetNextCabInVain=TRUE; |
| } |
| |
| if( p_fci_internal->fGetNextCabInVain && |
| p_fci_internal->fNextCab |
| ) { |
| /* THIS CAN NEVER HAPPEN */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* too much data for cabinet */ |
| if( (p_fci_internal->fGetNextCabInVain || |
| p_fci_internal->fNextCab) && ( |
| p_fci_internal->oldCCAB.cb < read_result + |
| strlen(p_fci_internal->pccab->szCab)+1+ |
| strlen(p_fci_internal->pccab->szDisk)+1 |
| )) { |
| |
| p_fci_internal->fGetNextCabInVain=FALSE; |
| p_fci_internal->fNextCab=TRUE; |
| return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); |
| } |
| |
| if( p_fci_internal->fNextCab ) { |
| /* THIS MAY NEVER HAPPEN */ |
| /* set error code */ |
| fci_set_error( FCIERR_NONE, ERROR_GEN_FAILURE, TRUE ); |
| return FALSE; |
| } |
| |
| /* if the FolderThreshold has been reached flush the folder automatically */ |
| if( p_fci_internal->fGetNextCabInVain ) { |
| if( p_fci_internal->cCompressedBytesInFolder >= |
| p_fci_internal->oldCCAB.cbFolderThresh) { |
| return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); |
| } |
| } else { |
| if( p_fci_internal->cCompressedBytesInFolder >= |
| p_fci_internal->pccab->cbFolderThresh) { |
| return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); |
| } |
| } |
| |
| return TRUE; |
| } /* end of FCIAddFile */ |
| |
| |
| |
| |
| |
| /*********************************************************************** |
| * FCIFlushFolder (CABINET.12) |
| * |
| * FCIFlushFolder completes the CFFolder structure under construction. |
| * |
| * All further data which is added by FCIAddFile will be associated to |
| * 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) |
| { |
| return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis); |
| } /* end of FCIFlushFolder */ |
| |
| |
| |
| /*********************************************************************** |
| * 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) |
| { |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| |
| if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; |
| |
| while( p_fci_internal->sizeFileCFFILE1>0 || |
| p_fci_internal->sizeFileCFFILE2>0 ) { |
| if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; |
| } |
| |
| return TRUE; |
| } /* end of FCIFlushCabinet */ |
| |
| |
| /*********************************************************************** |
| * 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) |
| { |
| int err; |
| PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); |
| if (REALLY_IS_FCI(hfci)) { |
| |
| /* before hfci can be removed all temporary files must be closed */ |
| /* and deleted */ |
| p_fci_internal->FCI_Intmagic = 0; |
| |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); |
| /* TODO error handling of err */ |
| PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, |
| p_fci_internal->pv); |
| /* TODO error handling of err */ |
| |
| /* data in and out buffers have to be removed */ |
| if (p_fci_internal->data_in!=NULL) |
| PFCI_FREE(hfci, p_fci_internal->data_in); |
| if (p_fci_internal->data_out!=NULL) |
| PFCI_FREE(hfci, p_fci_internal->data_out); |
| |
| /* hfci can now be removed */ |
| PFCI_FREE(hfci, hfci); |
| return TRUE; |
| } else { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| } /* end of FCIDestroy */ |