📄 fci.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 setions*/
cab_UWORD setID; /* identification number of all cabinets in a set*/
cab_UWORD iCabinet; /* number of the cabinet in a set */
/* additional area if "flags" were set*/
} CFHEADER; /* minimum 36 bytes */
typedef struct {
cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
cab_UWORD cCFData; /* number of this folder's CFDATA sections */
cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
/* additional area if reserve flag was set */
} CFFOLDER; /* minumum 8 bytes */
typedef struct {
cab_ULONG cbFile; /* size of the uncompressed file in bytes */
cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
cab_UWORD iFolder; /* number of folder in the cabinet 0=first */
/* for special values see below this structure*/
cab_UWORD date; /* last modification date*/
cab_UWORD time; /* last modification time*/
cab_UWORD attribs; /* DOS fat attributes and UTF indicator */
/* ... and a C string with the name of the file */
} CFFILE; /* 16 bytes + name of file */
typedef struct {
cab_ULONG csum; /* checksum of this entry*/
cab_UWORD cbData; /* number of compressed bytes */
cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */
/* optional reserved area */
/* compressed data */
} CFDATA;
/***********************************************************************
* FCICreate (CABINET.10)
*
* 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) || (!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 = ((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;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -