mirror of
https://github.com/reactos/wine.git
synced 2024-11-26 21:20:25 +00:00
2865 lines
101 KiB
C
2865 lines
101 KiB
C
/*
|
|
* 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 */
|
|
/* inefficient, but it's harder to forget about freeing the buffer :-). */
|
|
/* Reserved areas are used seldom besides that... */
|
|
if (cbReserveCFData!=0) {
|
|
if(!(reserved = 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 = 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 */
|
|
p_fci_internal->oldCCAB = *p_fci_internal->pccab;
|
|
/* 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 = 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 = 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 */
|
|
if (p_fci_internal->data_out) 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 */
|
|
if (p_fci_internal->data_out) 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 */
|
|
p_fci_internal->oldCCAB = *p_fci_internal->pccab;
|
|
/* 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 = 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 */
|
|
p_fci_internal->oldCCAB = *p_fci_internal->pccab;
|
|
/* 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 */
|
|
p_fci_internal->oldCCAB = *p_fci_internal->pccab;
|
|
/* 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 */
|