diff --git a/dlls/cabinet/cabinet.h b/dlls/cabinet/cabinet.h index 7d38521cecf..bb18ae097ff 100644 --- a/dlls/cabinet/cabinet.h +++ b/dlls/cabinet/cabinet.h @@ -305,7 +305,41 @@ typedef struct { PFNFCIDELETE pfndelete; PFNFCIGETTEMPFILE pfnfcigtf; PCCAB pccab; - void *pv; + BOOL fPrevCab; + BOOL fNextCab; + BOOL fSplitFolder; + cab_ULONG statusFolderCopied; + cab_ULONG statusFolderTotal; + BOOL fGetNextCabInVain; + void *pv; + char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */ + char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */ + CCAB oldCCAB; + char* data_in; /* uncompressed data blocks */ + cab_UWORD cdata_in; + char* data_out; /* compressed data blocks */ + ULONG cCompressedBytesInFolder; + cab_UWORD cFolders; + cab_UWORD cFiles; + cab_ULONG cDataBlocks; + cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */ + /* of spanned file of a spanning folder of a spanning cabinet */ + cab_UBYTE szFileNameCFDATA1[CB_MAX_FILENAME]; + int handleCFDATA1; + cab_UBYTE szFileNameCFFILE1[CB_MAX_FILENAME]; + int handleCFFILE1; + cab_UBYTE szFileNameCFDATA2[CB_MAX_FILENAME]; + int handleCFDATA2; + cab_UBYTE szFileNameCFFILE2[CB_MAX_FILENAME]; + int handleCFFILE2; + cab_UBYTE szFileNameCFFOLDER[CB_MAX_FILENAME]; + int handleCFFOLDER; + cab_ULONG sizeFileCFDATA1; + cab_ULONG sizeFileCFFILE1; + cab_ULONG sizeFileCFDATA2; + cab_ULONG sizeFileCFFILE2; + cab_ULONG sizeFileCFFOLDER; + BOOL fNewPrevious; } FCI_Int, *PFCI_Int; typedef struct { @@ -326,6 +360,18 @@ typedef struct { /* cast an HFDI into a PFDI_Int */ #define PFDI_INT(hfdi) ((PFDI_Int)(hfdi)) +/* quick pfci method invokers */ +#define PFCI_ALLOC(hfdi, size) ((*PFCI_INT(hfdi)->pfnalloc) (size)) +#define PFCI_FREE(hfdi, ptr) ((*PFCI_INT(hfdi)->pfnfree) (ptr)) +#define PFCI_GETTEMPFILE(hfci,name,length) ((*PFCI_INT(hfci)->pfnfcigtf)(name,length,PFCI_INT(hfci)->pv)) +#define PFCI_DELETE(hfci,name,err,pv) ((*PFCI_INT(hfci)->pfndelete)(name,err,pv)) +#define PFCI_OPEN(hfci,name,oflag,pmode,err,pv) ((*PFCI_INT(hfci)->pfnopen)(name,oflag,pmode,err,pv)) +#define PFCI_READ(hfci,hf,memory,cb,err,pv)((*PFCI_INT(hfci)->pfnread)(hf,memory,cb,err,pv)) +#define PFCI_WRITE(hfci,hf,memory,cb,err,pv) ((*PFCI_INT(hfci)->pfnwrite)(hf,memory,cb,err,pv)) +#define PFCI_CLOSE(hfci,hf,err,pv) ((*PFCI_INT(hfci)->pfnclose)(hf,err,pv)) +#define PFCI_SEEK(hfci,hf,dist,seektype,err,pv)((*PFCI_INT(hfci)->pfnseek)(hf,dist,seektype,err,pv)) +#define PFCI_FILEPLACED(hfci,pccab,name,cb,cont,pv)((*PFCI_INT(hfci)->pfnfiledest)(pccab,name,cb,cont,pv)) + /* quickie pfdi method invokers */ #define PFDI_ALLOC(hfdi, size) ((*PFDI_INT(hfdi)->pfnalloc) (size)) #define PFDI_FREE(hfdi, ptr) ((*PFDI_INT(hfdi)->pfnfree) (ptr)) diff --git a/dlls/cabinet/fci.c b/dlls/cabinet/fci.c index 9a97d56e331..08e71f1270b 100644 --- a/dlls/cabinet/fci.c +++ b/dlls/cabinet/fci.c @@ -19,9 +19,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + +There is still some work to be done: + +- currently no support for big-endian machines +- the ERF error structure aren't used on error +- no real compression yet +- unknown behaviour if files>4GB or cabinet >4GB +- incorrect status information +- 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 + +*/ + + + #include "config.h" #include +#include +#include #include "windef.h" #include "winbase.h" @@ -33,12 +51,56 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet); +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 setions*/ + 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; /* minumum 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) * - * Provided with several callbacks, - * returns a handle which can be used to perform operations - * on cabinet files. + * 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 @@ -54,7 +116,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet); * 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 + * 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. @@ -64,8 +126,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet); * 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; ignored in wine - * pccab [I] A pointer to an initialized CCAB structure + * 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. @@ -94,9 +156,13 @@ HFCI __cdecl FCICreate( PCCAB pccab, void *pv) { - HFCI rv; + HFCI hfci; + int err; + PFCI_Int p_fci_internal; - if ((!pfnalloc) || (!pfnfree)) { + if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) || + (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) || + (!pfnfcigtf) || (!pccab)) { perf->erfOper = FCIERR_NONE; perf->erfType = ERROR_BAD_ARGUMENTS; perf->fError = TRUE; @@ -105,7 +171,7 @@ HFCI __cdecl FCICreate( return NULL; } - if (!(rv = (HFCI) (*pfnalloc)(sizeof(FCI_Int)))) { + if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) { perf->erfOper = FCIERR_ALLOC_FAIL; perf->erfType = ERROR_NOT_ENOUGH_MEMORY; perf->fError = TRUE; @@ -114,41 +180,1977 @@ HFCI __cdecl FCICreate( return NULL; } - PFCI_INT(rv)->FCI_Intmagic = FCI_INT_MAGIC; - PFCI_INT(rv)->perf = perf; - PFCI_INT(rv)->pfnfiledest = pfnfiledest; - PFCI_INT(rv)->pfnalloc = pfnalloc; - PFCI_INT(rv)->pfnfree = pfnfree; - PFCI_INT(rv)->pfnopen = pfnopen; - PFCI_INT(rv)->pfnread = pfnread; - PFCI_INT(rv)->pfnwrite = pfnwrite; - PFCI_INT(rv)->pfnclose = pfnclose; - PFCI_INT(rv)->pfnseek = pfnseek; - PFCI_INT(rv)->pfndelete = pfndelete; - PFCI_INT(rv)->pfnfcigtf = pfnfcigtf; - PFCI_INT(rv)->pccab = pccab; - PFCI_INT(rv)->pv = pv; + 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; - /* Still mark as incomplete, because of other missing FCI* APIs */ + memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME); + memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME); - PFCI_INT(rv)->FCI_Intmagic = 0; - PFDI_FREE(rv, rv); - FIXME("(%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p): stub\n", - perf, pfnfiledest, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, - pfnseek, pfndelete, pfnfcigtf, pccab, pv); + /* CFDATA */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + + p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv); + /* TODO check handle */ + /* 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv); + /* TODO check handle */ + /* 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv); + /* TODO check handle */ + /* 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv); + + + /* TODO close and delete new files when return FALSE */ + + /* TODO check handle */ + /* 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) ) { + /* TODO write error */ + 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))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ihandleCFDATA1, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv) != cbReserveCFData ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + 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) { + /* TODO write error */ + 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) { + /* TODO set error code and abort */ + return FALSE; + } + + ++(p_fci_internal->cDataBlocks); + + return TRUE; +} /* end of fci_flush_data_block */ + + + + + +static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed) +{ + cab_ULONG csum; + cab_ULONG ul; + int cUlong; + 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 ) { + /* TODO internal error should never happen */ + 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 splitted 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 */ + /* TODO read error */ + 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 ) { + /* TODO read error */ + 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 remainer */ + /* 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 splitted 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 splitted across */ + /* diffentent cabinets.*/ + } + + /* This should never happen !!! */ + if (pcfdata->cbData==0) { + /* TODO set error */ + return FALSE; + } + + /* 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 ) ); + + /* 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 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData; + + /* 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) { + /* TODO write error */ + 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 remainer 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 ) { + /* TODO internal error */ + return FALSE; + } + + /* set cbData the size of the remainer 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 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err dont 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) { + /* TODO write error */ + 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 */ + /* dont 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) { + /* TODO set error code and abort */ + 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 ) { + /* TODO internal error */ + 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 */ + /* TODO read error */ + 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 ) { + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err dont 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 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err dont 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) { + /* TODO write error */ + 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(+revious ones)*/ + p_fci_internal->statusFolderTotal, /* total folder size */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + 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 remainer 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) ) { + /* TODO write error */ + 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))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ihandleCFFOLDER, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFFolder, /* number of bytes to copy */ + err, p_fci_internal->pv) != cbReserveCFFolder ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + 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 ) { + /* TODO wrong return value */ + } + /* 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 */ + /* TODO read error */ + 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) { + /* TODO read error */ + 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 ) { + /* TODO set error code internal error */ + 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) + != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) { + /* TODO wrong return value */ + } + /* 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 */ + /* TODO set error code */ + return FALSE; + } + if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || + cffile.iFolder==cffileCONTINUED_TO_NEXT ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code */ + 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 */ + /* TODO set error code */ + 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; + } + + /* 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) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFILE2 += sizeof(cffile); + + /* 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 ) { + /* TODO write error */ + 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) ) { + /* TODO write error */ + 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 ) { + /* TODO write error */ + 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)) { + p_fci_internal->perf->erfOper = FCIERR_NONE; + p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; + p_fci_internal->perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab ){ + /* TODO internal error */ + 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 ) { + /* TODO error handling */ + return FALSE; + } + return TRUE; + } + + if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) { + /* TODO error handling */ + return FALSE; + } + + /* FCIFlushFolder has already been called... */ + if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) { + if (p_fci_internal->sizeFileCFFILE2==0) { + /* TODO set error code */ + return FALSE; + } + return TRUE; + } + + /* TODO check what will happen when return FALSE later */ + /* and p_fci_internal->fSplitFolder is set to 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->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) { + /* TODO set error code and abort */ + return FALSE; + } + + /* get a new temp file */ + if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err, + p_fci_internal->pv); + + /* get a new temp file */ + if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) { + /* TODO error handling */ + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + /* safety */ + if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + 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); + + /* 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 */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + 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 catched 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) { + /* TODO internal error */ + 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 ) { + /* TODO wrong return value */ + 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)))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + 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; + int handleCABINET; /* file handle for cabinet */ + char pszFileNameCABINET[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 wasn't 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) { + /* TODO internal error */ + 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) { + /* TODO set error */ + return FALSE; + } + /* get the full name of the cabinet */ + memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath, + CB_MAX_CAB_PATH); + memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), + 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) { + /* TODO set error */ + return FALSE; + } + /* get the full name of the cabinet */ + memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath, + CB_MAX_CAB_PATH); + memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), + p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME); + } + + /* create the cabinet */ + handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET, + 33538, 384, &err, p_fci_internal->pv ); + /* TODO check handle */ + /* TODO error checking of err */ + + 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; + } + } + + 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 setions */ + + 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; + } + + /* 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) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + 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; + } + /* 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) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + } + + /* add optional reserved area */ + if (cbReserveCFHeader!=0) { + if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ipv) != cbReserveCFHeader ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + 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 ) { + /* TODO write error */ + 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 ) { + /* TODO write error */ + 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 ) { + /* TODO write error */ + 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 ) { + /* TODO write error */ + 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 ) { + /* TODO wrong return value */ + } + /* 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*/ + /* TODO read error */ + 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; + } + } + + /* 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) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + /* add optional reserved area */ + + /* This allocation and freeing at each CFFolder block is a bit */ + /* inefficent, 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))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + 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); + /* TODO read error */ + 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); + /* TODO read error */ + 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 ) { + /* TODO wrong return value */ + } + /* 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 */ + 32768, /* 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 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + if (p_fci_internal->fSplitFolder==FALSE) { + p_fci_internal->statusFolderCopied = 0; + p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+ + p_fci_internal->sizeFileCFFILE2; + } + p_fci_internal->statusFolderCopied += read_result; + +/* TODO is this correct */ + /* 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) { + /* TODO set error code and abort */ + 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 ) { + /* TODO wrong return value */ + 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 */ + 32768, /* 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 ) { + /* TODO write error */ + 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) { + /* TODO set error code and abort */ + 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 ) { + /* TODO wrong return value */ + } + /* 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 ) { + /* TODO write error */ + 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* 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)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* 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 */ + if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */ + cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + 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 */ + /* TODO set error code */ + 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 */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched 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 */ + /* TODO set error structures */ + return FALSE; + } + } + + return TRUE; +} /* end of fci_flush_cabinet */ - perf->erfOper = FCIERR_NONE; - perf->erfType = 0; - perf->fError = TRUE; - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; -} /*********************************************************************** * 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, @@ -160,16 +2162,422 @@ BOOL __cdecl FCIAddFile( PFNFCIGETOPENINFO pfnfcigoi, TCOMP typeCompress) { - FIXME("(%p, %p, %p, %d, %p, %p, %p, %hu): stub\n", hfci, pszSourceFile, - pszFileName, fExecute, pfnfcignc, pfnfcis, pfnfcigoi, typeCompress); - - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + 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) { + p_fci_internal->perf->erfOper = FCIERR_NONE; + p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; + p_fci_internal->perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + + /* TODO check if pszSourceFile??? */ + + if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) { + /* TODO internal error */ + return FALSE; + } + + if(p_fci_internal->fNextCab) { + /* TODO internal error */ + 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) { + /* TODO error handling */ + return FALSE; + } + if (p_fci_internal->data_out!=NULL) { + /* TODO error handling */ + return FALSE; + } + if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + if (p_fci_internal->data_out==NULL) { + if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){ + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + } + } + + if (p_fci_internal->data_out==NULL) { + PFCI_FREE(hfci,p_fci_internal->data_in); + /* TODO error handling */ + return FALSE; + } + + /* get information about the file */ + file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time), + &(cffile.attribs), &err, p_fci_internal->pv); + /* TODO check file_handle */ + /* 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 */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab + ) { + /* THIS CAN NEVER HAPPEN */ + /* TODO set error code*/ + 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 */ + /* TODO set error code*/ + return FALSE; + } + + /* read the contents of the file blockwize*/ + while (!FALSE) { + if (p_fci_internal->cdata_in > CAB_BLOCKMAX) { + /* TODO internal error */ + 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 ) { + /* TODO report internal error */ + 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) ) { + /* TODO write error */ + 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 */ + /* TODO set error code */ + return FALSE; + } + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ + pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv) + != strlen(pszFileName)+1 ) { + /* TODO write error */ + 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 */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab + ) { + /* THIS CAN NEVER HAPPEN */ + /* TODO set error code*/ + 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 */ + /* TODO set error code*/ + 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 associateed 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, @@ -177,27 +2585,18 @@ BOOL __cdecl FCIFlushCabinet( PFNFCIGETNEXTCABINET pfnfcignc, PFNFCISTATUS pfnfcis) { - FIXME("(%p, %d, %p, %p): stub\n", hfci, fGetNextCab, pfnfcignc, pfnfcis); + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; - return FALSE; -} + while( p_fci_internal->sizeFileCFFILE1>0 || + p_fci_internal->sizeFileCFFILE2>0 ) { + if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; + } -/*********************************************************************** - * FCIFlushFolder (CABINET.12) - */ -BOOL __cdecl FCIFlushFolder( - HFCI hfci, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis) -{ - FIXME("(%p, %p, %p): stub\n", hfci, pfnfcignc, pfnfcis); + return TRUE; +} /* end of FCIFlushCabinet */ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - - return FALSE; -} /*********************************************************************** * FCIDestroy (CABINET.14) @@ -214,17 +2613,52 @@ BOOL __cdecl FCIFlushFolder( */ BOOL __cdecl FCIDestroy(HFCI hfci) { + int err; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); if (REALLY_IS_FCI(hfci)) { - PFCI_INT(hfci)->FCI_Intmagic = 0; - PFDI_FREE(hfci, hfci); - /*return TRUE; */ + + /* 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; } - /* Still mark as incomplete, because of other missing FCI* APIs */ - FIXME("(%p): stub\n", hfci); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} +} /* end of FCIDestroy */