📄 fdi.c
字号:
PFDI_INT(rv)->FDI_Intmagic = FDI_INT_MAGIC;
PFDI_INT(rv)->pfnalloc = pfnalloc;
PFDI_INT(rv)->pfnfree = pfnfree;
PFDI_INT(rv)->pfnopen = pfnopen;
PFDI_INT(rv)->pfnread = pfnread;
PFDI_INT(rv)->pfnwrite = pfnwrite;
PFDI_INT(rv)->pfnclose = pfnclose;
PFDI_INT(rv)->pfnseek = pfnseek;
/* no-brainer: we ignore the cpu type; this is only used
for the 16-bit versions in Windows anyhow... */
PFDI_INT(rv)->perf = perf;
return rv;
}
/*******************************************************************
* FDI_getoffset (internal)
*
* returns the file pointer position of a file handle.
*/
static long FDI_getoffset(HFDI hfdi, INT_PTR hf)
{
return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR);
}
/**********************************************************************
* FDI_realloc (internal)
*
* we can't use _msize; the user might not be using malloc, so we require
* an explicit specification of the previous size. inefficient.
*/
static void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
{
void *rslt = NULL;
char *irslt, *imem;
size_t copysize = (prevsize < newsize) ? prevsize : newsize;
if (prevsize == newsize) return mem;
rslt = PFDI_ALLOC(hfdi, newsize);
if (rslt)
for (irslt = (char *)rslt, imem = (char *)mem; (copysize); copysize--)
*irslt++ = *imem++;
PFDI_FREE(hfdi, mem);
return rslt;
}
/**********************************************************************
* FDI_read_string (internal)
*
* allocate and read an arbitrarily long string from the cabinet
*/
static char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
{
size_t len=256,
oldlen = 0,
base = FDI_getoffset(hfdi, hf),
maxlen = cabsize - base;
BOOL ok = FALSE;
unsigned int i;
cab_UBYTE *buf = NULL;
TRACE("(hfdi == ^%p, hf == %d)\n", hfdi, hf);
do {
if (len > maxlen) len = maxlen;
if (!(buf = FDI_realloc(hfdi, buf, oldlen, len))) break;
oldlen = len;
if (!PFDI_READ(hfdi, hf, buf, len)) break;
/* search for a null terminator in what we've just read */
for (i=0; i < len; i++) {
if (!buf[i]) {ok=TRUE; break;}
}
if (!ok) {
if (len == maxlen) {
ERR("cabinet is truncated\n");
break;
}
len += 256;
PFDI_SEEK(hfdi, hf, base, SEEK_SET);
}
} while (!ok);
if (!ok) {
if (buf)
PFDI_FREE(hfdi, buf);
else
ERR("out of memory!\n");
return NULL;
}
/* otherwise, set the stream to just after the string and return */
PFDI_SEEK(hfdi, hf, base + ((cab_off_t) strlen((char *) buf)) + 1, SEEK_SET);
return (char *) buf;
}
/******************************************************************
* FDI_read_entries (internal)
*
* process the cabinet header in the style of FDIIsCabinet, but
* without the sanity checks (and bug)
*/
static BOOL FDI_read_entries(
HFDI hfdi,
INT_PTR hf,
PFDICABINETINFO pfdici,
PMORE_ISCAB_INFO pmii)
{
int num_folders, num_files, header_resv, folder_resv = 0;
LONG base_offset, cabsize;
USHORT setid, cabidx, flags;
cab_UBYTE buf[64], block_resv;
char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL;
TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici);
/*
* FIXME: I just noticed that I am memorizing the initial file pointer
* offset and restoring it before reading in the rest of the header
* information in the cabinet. Perhaps that's correct -- that is, perhaps
* this API is supposed to support "streaming" cabinets which are embedded
* in other files, or cabinets which begin at file offsets other than zero.
* Otherwise, I should instead go to the absolute beginning of the file.
* (Either way, the semantics of wine's FDICopy require me to leave the
* file pointer where it is afterwards -- If Windows does not do so, we
* ought to duplicate the native behavior in the FDIIsCabinet API, not here.
*
* So, the answer lies in Windows; will native cabinet.dll recognize a
* cabinet "file" embedded in another file? Note that cabextract.c does
* support this, which implies that Microsoft's might. I haven't tried it
* yet so I don't know. ATM, most of wine's FDI cabinet routines (except
* this one) would not work in this way. To fix it, we could just make the
* various references to absolute file positions in the code relative to an
* initial "beginning" offset. Because the FDICopy API doesn't take a
* file-handle like this one, we would therein need to search through the
* file for the beginning of the cabinet (as we also do in cabextract.c).
* Note that this limits us to a maximum of one cabinet per. file: the first.
*
* So, in summary: either the code below is wrong, or the rest of fdi.c is
* wrong... I cannot imagine that both are correct ;) One of these flaws
* should be fixed after determining the behavior on Windows. We ought
* to check both FDIIsCabinet and FDICopy for the right behavior.
*
* -gmt
*/
/* get basic offset & size info */
base_offset = FDI_getoffset(hfdi, hf);
if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) {
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
cabsize = FDI_getoffset(hfdi, hf);
if ((cabsize == -1) || (base_offset == -1) ||
( PFDI_SEEK(hfdi, hf, base_offset, SEEK_SET) == -1 )) {
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* read in the CFHEADER */
if (PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) {
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* check basic MSCF signature */
if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) {
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* get the number of folders */
num_folders = EndGetI16(buf+cfhead_NumFolders);
if (num_folders == 0) {
/* PONDERME: is this really invalid? */
WARN("weird cabinet detect failure: no folders in cabinet\n");
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* get the number of files */
num_files = EndGetI16(buf+cfhead_NumFiles);
if (num_files == 0) {
/* PONDERME: is this really invalid? */
WARN("weird cabinet detect failure: no files in cabinet\n");
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0;
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* setid */
setid = EndGetI16(buf+cfhead_SetID);
/* cabinet (set) index */
cabidx = EndGetI16(buf+cfhead_CabinetIndex);
/* check the header revision */
if ((buf[cfhead_MajorVersion] > 1) ||
(buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
{
WARN("cabinet format version > 1.3\n");
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION;
PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
/* pull the flags out */
flags = EndGetI16(buf+cfhead_Flags);
/* read the reserved-sizes part of header, if present */
if (flags & cfheadRESERVE_PRESENT) {
if (PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) {
ERR("bunk reserve-sizes?\n");
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
header_resv = EndGetI16(buf+cfheadext_HeaderReserved);
if (pmii) pmii->header_resv = header_resv;
folder_resv = buf[cfheadext_FolderReserved];
if (pmii) pmii->folder_resv = folder_resv;
block_resv = buf[cfheadext_DataReserved];
if (pmii) pmii->block_resv = block_resv;
if (header_resv > 60000) {
WARN("WARNING; header reserved space > 60000\n");
}
/* skip the reserved header */
if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1)) {
ERR("seek failure: header_resv\n");
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
}
}
if (flags & cfheadPREV_CABINET) {
prevname = FDI_read_string(hfdi, hf, cabsize);
if (!prevname) {
if (pmii) {
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
PFDI_INT(hfdi)->perf->fError = TRUE;
}
return FALSE;
} else
if (pmii)
pmii->prevname = prevname;
else
PFDI_FREE(hfdi, prevname);
previnfo = FDI_read_string(hfdi, hf, cabsize);
if (previnfo) {
if (pmii)
pmii->previnfo = previnfo;
else
PFDI_FREE(hfdi, previnfo);
}
}
if (flags & cfheadNEXT_CABINET) {
if (pmii)
pmii->hasnext = TRUE;
nextname = FDI_read_string(hfdi, hf, cabsize);
if (!nextname) {
if ((flags & cfheadPREV_CABINET) && pmii) {
if (pmii->prevname) PFDI_FREE(hfdi, prevname);
if (pmii->previnfo) PFDI_FREE(hfdi, previnfo);
}
PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET;
PFDI_INT(hfdi)->perf->erfType = 0; /* ? */
PFDI_INT(hfdi)->perf->fError = TRUE;
return FALSE;
} else
if (pmii)
pmii->nextname = nextname;
else
PFDI_FREE(hfdi, nextname);
nextinfo = FDI_read_string(hfdi, hf, cabsize);
if (nextinfo) {
if (pmii)
pmii->nextinfo = nextinfo;
else
PFDI_FREE(hfdi, nextinfo);
}
}
/* we could process the whole cabinet searching for problems;
instead lets stop here. Now let's fill out the paperwork */
pfdici->cbCabinet = cabsize;
pfdici->cFolders = num_folders;
pfdici->cFiles = num_files;
pfdici->setID = setid;
pfdici->iCabinet = cabidx;
pfdici->fReserve = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE;
pfdici->hasprev = (flags & cfheadPREV_CABINET) ? TRUE : FALSE;
pfdici->hasnext = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE;
return TRUE;
}
/***********************************************************************
* FDIIsCabinet (CABINET.21)
*
* Informs the caller as to whether or not the provided file handle is
* really a cabinet or not, filling out the provided PFDICABINETINFO
* structure with information about the cabinet. Brief explanations of
* the elements of this structure are available as comments accompanying
* its definition in wine's include/fdi.h.
*
* PARAMS
* hfdi [I] An HFDI from FDICreate
* hf [I] The file handle about which the caller inquires
* pfdici [IO] Pointer to a PFDICABINETINFO structure which will
* be filled out with information about the cabinet
* file indicated by hf if, indeed, it is determined
* to be a cabinet.
*
* RETURNS
* TRUE if the file is a cabinet. The info pointed to by pfdici will
* be provided.
* FALSE if the file is not a cabinet, or if an error was encountered
* while processing the cabinet. The PERF structure provided to
* FDICreate can be queried for more error information.
*
* INCLUDES
* fdi.c
*/
BOOL __cdecl FDIIsCabinet(
HFDI hfdi,
INT_PTR hf,
PFDICABINETINFO pfdici)
{
BOOL rv;
TRACE("(hfdi == ^%p, hf == ^%d, pfdici == ^%p)\n", hfdi, hf, pfdici);
if (!REALLY_IS_FDI(hfdi)) {
ERR("REALLY_IS_FDI failed on ^%p\n", hfdi);
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!hf) {
ERR("(!hf)!\n");
/* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND;
PFDI_INT(hfdi)->perf->erfType = ERROR_INVALID_HANDLE;
PFDI_INT(hfdi)->perf->fError = TRUE; */
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -