Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1626 lines
56 KiB

/*** fdi.c - Diamond File Decompression Interface
*
* Microsoft Confidential
* Copyright (C) Microsoft Corporation 1993-1994
* All Rights Reserved.
*
* Author:
* Chuck Strouss
*
* History:
* 24-jan-1994 chuckst Initial version
* 16-Mar-1994 bens Add RESERVE support
* 17-Mar-1994 bens Fix bug in CFDATA splitting introduced by RESERVE
* 21-Mar-1994 bens Use spruced up fci_int.h definitions
* 25-Mar-1994 bens Add fdintCABINET_INFO notification; reduce stack
* 07-Apr-1994 bens Add Decryption interfaces
* 02-Jun-1994 bens Added Quantum compression support
* 19-Aug-1994 bens Add cpuType parameter to FDICreate().
* 31-Jan-1994 msliger Make CreateDecompress alloc buffers before MDI/QDI
* 3-Apr-1995 jeffwe Added chaining info to FDICABINETINFO
*
* Overview:
* The File Decompression Interface is used to simplify the reading of
* Diamond cabinet files. A setup program will proceed in a manner very
* similar to the pseudo code below. An FDI context is created, the
* setup program calls FDICopy() for each cabinet to be processed. For
* each file in the cabinet, FDICopy() calls a notification callback
* routine, asking the setup program if the file should be copied.
* This call-back approach is great because it allows the cabinet file
* to be read and decompressed in an optimal manner.
*/
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#include <string.h>
#include "types.h"
#include "asrt.h"
#include "fdi_int.h"
#include "cabinet.h"
#include "erf.h"
#include "..\mszip\mdi.h"
#include "..\quantum\qdi.h"
#include "checksum.h"
typedef struct {
// place (long) stuff first
#ifdef ASSERT
SIGNATURE sig; // structure signature sigFDI
#endif
PERF perf;
PFNFREE pfnfree; // FDI client callback functions
PFNALLOC pfnalloc;
PFNOPEN pfnopen;
PFNREAD pfnread;
PFNWRITE pfnwrite;
PFNCLOSE pfnclose;
PFNSEEK pfnseek;
int cpuType; // CPU type (see cpuXXX in fdi_int.h)
PFNFDINOTIFY pfnfdin; // passed in on FDICopy call
PFNFDIDECRYPT pfnfdid; // passed in on FDICopy call
COFF coffFolders; // Offset of CFFOLDER start
UOFF uoffFolder; // Uncompressed offset of current CFDATA
// in current folder;
MDI_CONTEXT_HANDLE mdh; // decompress context handle
void *pvUser; // User's callback context
char *pchCompr; // pointer to compressed data buffer
char *pchUncompr; // pointer to uncompressed data buffer
CFFOLDER *pcffolder; // Dynamic due to variable RESERVE size
CFDATA *pcfdata; // Dynamic due to variable RESERVE size
void *pbCFHeaderReserve; // Reserved data for CFHEADER
// Next comes the nested structures.
CFHEADER cfheader;
CFFILE cffile;
// Now the ints
int hfCabData; // file handle of cabinet for Data reads
int hfCabFiles; // file handle of cabinet for File reads
int hfNew; // file handle we're writing to
UINT iFolder; // current folder we're operating on
UINT cbMaxUncompr; // maximum uncompressed block size
UINT cbMaxCompr; // maximum compressed block size
int fInContin; // In continuation cabinet flag
UINT cbCFHeaderReserve; // Size of CFHEADER RESERVE
UINT cbCFFolderPlusReserve; // Size of CFFOLDER + folder RESERVE
UINT cbCFDataPlusReserve; // Size of CFDATA + data RESERVE
// Now the shorts
USHORT cFilesRemain; // count of CFFILE entries remaining
USHORT cFilesSkipped; // count of CONTD_FORWARD files skipped
USHORT cCFDataRemain; // Number of CFDATA blocks left in folder
TCOMP typeCompress; // selected compression type
// Now the piggy buffers
char achName [CB_MAX_FILENAME +1];
char achCabinetFirst[CB_MAX_CABINET_NAME+1];
char achDiskFirst [CB_MAX_DISK_NAME +1];
char achCabinetNext [CB_MAX_CABINET_NAME+1];
char achDiskNext [CB_MAX_DISK_NAME +1];
char szCabPath [CB_MAX_CAB_PATH +1];
//NOTE: The following items could have been on the stack, but
// some FDI clients (NT setup, for example), are very tight on
// stack space, so we use our FDI context instead!
char szCabName [CB_MAX_CAB_PATH +1];
FDINOTIFICATION fdin; // Notifcation structure
FDIDECRYPT fdid; // Decryption structure
} FDI; /* fdi */
typedef FDI *PFDI; /* pfdi */
#define PFDIfromHFDI(hfdi) ((PFDI)(hfdi))
#define HFDIfromPFDI(pfdi) ((HFDI)(pfdi))
#ifdef ASSERT
#define sigFDI MAKESIG('F','D','I','X') // FDI signature
#define AssertFDI(pfdi) AssertStructure(pfdi,sigFDI);
#else // !ASSERT
#define AssertFDI(pfdi)
#endif // !ASSERT
//** Internal function prototypes
BOOL doCabinetInfoNotify(PFDI pfdi);
BOOL InitFolder(PFDI pfdi, UINT iFolder);
BOOL FDIReadCFFILEEntry(PFDI pfdi);
BOOL FDIReadCFDATAEntry(PFDI pfdi, UINT cbPartial);
BOOL FDIReadPSZ(char *pb, int cb, PFDI pfdi);
BOOL FDIGetFile(PFDI pfdi);
BOOL FDIGetDataBlock(PFDI pfdi);
BOOL SwitchToNewCab(PFDI pfdi);
BOOL LoginCabinet(PFDI pfdi, char *pszCabinet, USHORT setID, USHORT iCabinet);
BOOL SeekFolder(PFDI pfdi,UINT iFolder);
BOOL SetDecompressionType(TCOMP typeCompress,PFDI pfdi);
BOOL MDIDestroyDecompressionGlobal(PFDI pfdi);
BOOL MDICreateDecompressionGlobal(PFDI pfdi);
BOOL MDIResetDecompressionGlobal(PFDI pfdi);
BOOL MDIDecompressGlobal(PFDI pfdi, USHORT *pcbData);
/*** FDICreate - Create an FDI context
*
* NOTE: See fdi_int.h for entry/exit conditions.
*/
HFDI FAR DIAMONDAPI FDICreate(PFNALLOC pfnalloc,
PFNFREE pfnfree,
PFNOPEN pfnopen,
PFNREAD pfnread,
PFNWRITE pfnwrite,
PFNCLOSE pfnclose,
PFNSEEK pfnseek,
int cpuType,
PERF perf)
{
PFDI pfdi;
pfdi = (PFDI)pfnalloc(sizeof (FDI));
if (pfdi == NULL) {
ErfSetCodes(perf,FDIERROR_ALLOC_FAIL,0);
return NULL;
}
SetAssertSignature(pfdi,sigFDI);
AssertFDI(pfdi); // Make sure we've really set sig
pfdi->pfnfree = pfnfree; // Save free function in our context
pfdi->pfnalloc = pfnalloc; // and all other passed in functions
pfdi->pfnopen = pfnopen;
pfdi->pfnread = pfnread;
pfdi->pfnwrite = pfnwrite;
pfdi->pfnclose = pfnclose;
pfdi->pfnseek = pfnseek;
pfdi->cpuType = cpuType;
pfdi->perf = perf; // and error reporting structure
pfdi->typeCompress = tcompBAD; // no decompressor initialized
//** Don't know how big reserved sections are yet, so we cannot allocate
// the buffers. Set bad sizes to help catch errors. LoginCabinet
// will get the sizes from the CFHEADER/CFRESERVE structures in the
// cabinet file and will allocate the buffers.
pfdi->pcfdata = NULL;
pfdi->pcffolder = NULL;
pfdi->pbCFHeaderReserve = NULL;
pfdi->cbCFHeaderReserve = cbCF_HEADER_BAD; // Bad value
pfdi->cbCFDataPlusReserve = 0xFFFF; // Bad value
pfdi->cbCFFolderPlusReserve = 0xFFFF; // Bad value
//** Remember that cabinet file handles are closed
pfdi->hfCabFiles = -1;
pfdi->hfCabData = -1;
//** Success
return HFDIfromPFDI(pfdi);
}
/*** FDIDestroy - Destroy an FDI context
*
* NOTE: See fdi_int.h for entry/exit conditions.
*/
BOOL FAR DIAMONDAPI FDIDestroy(HFDI hfdi)
{
PFDI pfdi;
pfdi = PFDIfromHFDI (hfdi);
AssertFDI (pfdi);
SetDecompressionType(tcompBAD,pfdi); // free the decompressor
//** Free cabinet structure buffers d
if (pfdi->pbCFHeaderReserve) {
(*pfdi->pfnfree)(pfdi->pbCFHeaderReserve);
}
if (pfdi->pcffolder) {
(*pfdi->pfnfree)(pfdi->pcffolder);
}
if (pfdi->pcfdata) {
(*pfdi->pfnfree)(pfdi->pcfdata);
}
//** Make sure any open file handles are closed
if (pfdi->hfCabFiles != -1) {
pfdi->pfnclose(pfdi->hfCabFiles); // close File Cab File
}
if (pfdi->hfCabData != -1) {
pfdi->pfnclose(pfdi->hfCabData); // close Data Cab File
}
ClearAssertSignature(pfdi);
pfdi->pfnfree(pfdi); // free our data
return TRUE;
}
/*** FDIIsCabinet - Determines if file is a cabinet, returns info if it is
*
* NOTE: See fdi_int.h for entry/exit conditions.
*/
BOOL FAR DIAMONDAPI FDIIsCabinet(HFDI hfdi,
int hf,
PFDICABINETINFO pfdici)
{
CFHEADER cfheader;
PFDI pfdi;
pfdi = PFDIfromHFDI (hfdi);
AssertFDI(pfdi);
//** Read the CFHEADER structure
if (sizeof(CFHEADER) != pfdi->pfnread(hf,
&cfheader,
sizeof(CFHEADER))) {
return FALSE; // Too small or error on I/O
}
//** Make sure this is a cabinet file
if (cfheader.sig != sigCFHEADER) {
return FALSE; // Signature does not match
}
//** Make sure we know this version number
if (cfheader.version != verCF) {
//** Set the error in this case, so client knows version is wrong
ErfSetCodes(pfdi->perf,FDIERROR_UNKNOWN_CABINET_VERSION,
cfheader.version); // return version found
return FALSE;
}
//** Return cabinet info to caller
pfdici->cbCabinet = cfheader.cbCabinet;
pfdici->cFolders = cfheader.cFolders;
pfdici->cFiles = cfheader.cFiles;
pfdici->setID = cfheader.setID;
pfdici->iCabinet = cfheader.iCabinet;
pfdici->fReserve = (cfheader.flags & cfhdrRESERVE_PRESENT) != 0;
pfdici->hasprev = (cfheader.flags & cfhdrPREV_CABINET);
pfdici->hasnext = (cfheader.flags & cfhdrNEXT_CABINET);
return TRUE;
} /* FDIIsCabinet() */
/*** FDICopy - extracts files from a cabinet
*
* NOTE: See fdi_int.h for entry/exit conditions.
*/
BOOL FAR DIAMONDAPI FDICopy(HFDI hfdi,
char *pszCabinet,
char *pszCabPath,
int flags,
PFNFDINOTIFY pfnfdin,
PFNFDIDECRYPT pfnfdid,
void *pvUser)
{
PFDINOTIFICATION pfdin;
PFDI pfdi;
BOOL rc=FALSE; // Assume error
pfdi = PFDIfromHFDI (hfdi);
AssertFDI(pfdi);
pfdin = &pfdi->fdin;
//** Save call back info for use by other functions
pfdi->pvUser = pvUser;
pfdi->pfnfdin = pfnfdin;
pfdi->pfnfdid = pfnfdid;
pfdi->cFilesSkipped = 0; // we haven't skipped any CONTD_FOR files yet
strcpy(pfdi->szCabPath,pszCabPath); // make a local copy of cabinet path
//** Get cabinet; skip setID/iCabinet check
if (!LoginCabinet(pfdi,pszCabinet,0,iCABINET_BAD)) { // Get cabinet
goto error; // error already filled in
}
pfdi->fInContin = 0; // Not in continuation
pfdi->iFolder = 0xFFFF; // No folder being used yet
strcpy(pfdi->szCabPath,pszCabPath); // save path to cabinet
while (pfdi->cFilesRemain--) {
if (!FDIReadCFFILEEntry(pfdi)) {
goto error; // error already filled in
}
//** Now copy stuff that is needed on a notification callback
pfdin->psz1 = pfdi->achName; // pass name of the file
pfdin->cb = pfdi->cffile.cbFile; // pass size of file
pfdin->psz2 = pfdi->achCabinetFirst; // name of First Cab (if app.)
pfdin->psz3 = pfdi->achDiskFirst; // name of First Disk (if app.)
pfdin->date = pfdi->cffile.date; // pass date
pfdin->time = pfdi->cffile.time; // pass time
pfdin->attribs = pfdi->cffile.attribs; // pass attributes
pfdin->pv = pfdi->pvUser;
if (IS_CONTD_BACK(pfdi->cffile.iFolder)) { // continued back?
if (pfdi->fInContin) { // in a continuation cab?
//** We're in a continuation cabinet, and have a continued-
// back candidate. Ask the caller if he wants it, and copy
// it if so.
pfdi->hfNew = pfnfdin(fdintCOPY_FILE,pfdin);
if (pfdi->hfNew == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
goto error;
}
if (pfdi->hfNew) {
if (!FDIGetFile(pfdi)) { // Get the file written into hfNew
goto error; // error already filled in
}
}
else { // caller elected to skip this file
if (IS_CONTD_FORWARD(pfdi->cffile.iFolder)) {
pfdi->cFilesSkipped++; // count forward files skipped
}
}
}
else {
//** If a file is continued-back, but we're not in a
// continuation cabinet, the proper behavior is just to
// notify the caller that we're skipping the file.
if (-1 == pfnfdin(fdintPARTIAL_FILE,pfdin)) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
goto error;
}
}
}
else { // not continued-back
if (!pfdi->fInContin) { // in original cab?
//** This is a normal (not continued-back) file in the
// non-continued cabinet, so ask the user if he wants it,
// and copy it if so.
pfdi->hfNew = pfnfdin(fdintCOPY_FILE,pfdin);
if (pfdi->hfNew == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
goto error;
}
if (pfdi->hfNew) {
if (!FDIGetFile(pfdi)) { // Get the file written into hfNew
goto error; // error already filled in
}
}
else { // caller elected to skip this file
if (IS_CONTD_FORWARD(pfdi->cffile.iFolder)) {
pfdi->cFilesSkipped++; // count forward files skipped
}
}
} // ignore non-continued-back files in continuation cabs
}
} // end while cFilesRemain
//** Success
rc = TRUE;
error:
//** Ignore errors closing cabinet files. There is potential that this
// error may occur if a network goes down, etc., and there is no harm
// done.
if (pfdi->hfCabFiles != -1) {
pfdi->pfnclose(pfdi->hfCabFiles); // close File Cab File
}
if (pfdi->hfCabData != -1) {
pfdi->pfnclose(pfdi->hfCabData); // close Data Cab File
}
//** Remember that cabinet file handles are closed
pfdi->hfCabFiles = -1;
pfdi->hfCabData = -1;
return rc;
}
/*** LoginCabinet - Make a cabinet current
*
* Entry:
* pfdi - pointer to FDI context
* pszCabinet - pointer to cabinet path/name
* setID - required setID (only if iCabinet == iCABINET_BAD)
* iCabinet - required iCabinet; check that setID/iCabinet match
* cabinet; Set iCabinet == iCABINET_BAD to skip this check.
*
* Exit-Success:
* returns TRUE
* pfdi->cfheader is filled in
* pfdi->hfCabFiles points to first CFFILE entry
* pfdi->cFilesRemain initialized from CFHEADER
*
* Exit-Failure:
* returns FALSE, cabinet was not requested setID/iCabinet, or other
* errors -- perr filled in.
*/
BOOL LoginCabinet(PFDI pfdi, char *pszCabinet, USHORT setID, USHORT iCabinet)
{
CFHEADER cfheader;
CFRESERVE cfreserve;
UINT cbCFFolderPlusReserve;
UINT cbCFDataPlusReserve;
AssertFDI(pfdi);
strcpy(pfdi->szCabName,pfdi->szCabPath); // build path to cabinet
strcat(pfdi->szCabName,pszCabinet);
Assert(pfdi->hfCabFiles == -1);
Assert(pfdi->hfCabData == -1);
/** NOTE: It is very important to avoid changing any globals (besides
* the cabinet file handles) until we have verified this cabinet
* is the requested one!
*/
if ((-1 == (pfdi->hfCabFiles=pfdi->pfnopen(pfdi->szCabName,
_O_BINARY | _O_RDONLY,
_S_IREAD | _S_IWRITE )))
// Yes, Virginia, we're going to open the same file again, so that
// we can read the CFFILE and CFDATA streams separately, and so we
// can switch to a different cabinet for the remaining data streams
// We could probably use dup() instead, but that would require our
// caller to support it as a callback, so we'll just do another open.
|| (-1 == (pfdi->hfCabData=pfdi->pfnopen(pfdi->szCabName,
_O_BINARY | _O_RDONLY,
_S_IREAD | _S_IWRITE )))) {
//** We don't have a specfic error code from the caller's function
ErfSetCodes(pfdi->perf,FDIERROR_CABINET_NOT_FOUND,0);
return FALSE;
}
//** Read the CFHEADER structure
if (sizeof(CFHEADER) != pfdi->pfnread(pfdi->hfCabFiles,
&cfheader,
sizeof(CFHEADER))) {
//** We don't have a specfic error code from the caller's function
ErfSetCodes(pfdi->perf,FDIERROR_NOT_A_CABINET,0);
return FALSE;
}
//** Make sure this is a cabinet file
if (cfheader.sig != sigCFHEADER) {
//** We don't have a specfic error code from the caller's function
ErfSetCodes(pfdi->perf,FDIERROR_NOT_A_CABINET,0);
return FALSE;
}
//** Make sure we know this version number
if (cfheader.version != verCF) {
ErfSetCodes(pfdi->perf,FDIERROR_UNKNOWN_CABINET_VERSION,
cfheader.version); // return version found
return FALSE;
}
//** Check setID/iCabinet, if we are asked to
if ((iCabinet != iCABINET_BAD) && // Need to to check setID/iCabinet
((setID != cfheader.setID) || // SetIDs don't match
(iCabinet != cfheader.iCabinet))) { // or cabinet numbers don't match
//** Not the cabinet that was requested
ErfSetCodes(pfdi->perf,FDIERROR_WRONG_CABINET,0);
return FALSE;
}
/** OK, this cabinet looks like the one we want.
* Store the cfheader in our state structure.
*/
pfdi->cfheader = cfheader;
//** Assume there is no CFRESERVE section
cfreserve.cbCFHeader = 0;
cfreserve.cbCFFolder = 0;
cfreserve.cbCFData = 0;
//** Now read in the CFRESERVE section (if present)
if (pfdi->cfheader.flags & cfhdrRESERVE_PRESENT) {
//** Read the CFRESERVE first
if (sizeof(CFRESERVE) != pfdi->pfnread(pfdi->hfCabFiles,
&cfreserve,
sizeof(CFRESERVE))) {
//** We don't have a specfic error code from the caller's function
ErfSetCodes(pfdi->perf,FDIERROR_NOT_A_CABINET,0);
return FALSE;
}
//** Make sure CFRESERVE fields seem valid
Assert(cfreserve.cbCFHeader <= cbRESERVE_HEADER_MAX);
Assert(cfreserve.cbCFFolder <= cbRESERVE_FOLDER_MAX);
Assert(cfreserve.cbCFData <= cbRESERVE_DATA_MAX);
//** Allocate buffer for reserved portion of CF header, if necessary
if (pfdi->cbCFHeaderReserve == cbCF_HEADER_BAD) {
//** First header we are reading
pfdi->cbCFHeaderReserve = cfreserve.cbCFHeader; // Remember size
if (pfdi->cbCFHeaderReserve > 0) { // Need to allocate buffer
if (!(pfdi->pbCFHeaderReserve =
(*pfdi->pfnalloc)(pfdi->cbCFHeaderReserve))) {
ErfSetCodes(pfdi->perf,FDIERROR_ALLOC_FAIL,0);
return FALSE;
}
}
}
//** Read RESERVE data area for CFHEADER, if present
if (pfdi->cbCFHeaderReserve > 0) { // Need to read reserved data
if (pfdi->cbCFHeaderReserve != pfdi->pfnread(pfdi->hfCabFiles,
pfdi->pbCFHeaderReserve,
pfdi->cbCFHeaderReserve)) {
//** No specfic error code from the caller's function
ErfSetCodes(pfdi->perf,FDIERROR_NOT_A_CABINET,0);
return FALSE;
}
}
}
//** Compute size of CFFOLDER buffer and allocate it if necessary
cbCFFolderPlusReserve = cfreserve.cbCFFolder + sizeof(CFFOLDER);
if (!pfdi->pcffolder) { // First time, need to allocate buffer
pfdi->cbCFFolderPlusReserve = cbCFFolderPlusReserve; // Full size
if (!(pfdi->pcffolder = (*pfdi->pfnalloc)(pfdi->cbCFFolderPlusReserve))) {
ErfSetCodes(pfdi->perf,FDIERROR_ALLOC_FAIL,0);
return FALSE;
}
}
else {
//** Make sure this folder has same reserve size as last folder!
if (cbCFFolderPlusReserve != pfdi->cbCFFolderPlusReserve) {
ErfSetCodes(pfdi->perf,FDIERROR_RESERVE_MISMATCH,0);
return FALSE;
}
}
//** Compute size of CFDATA buffer and allocate it if necessary
// NOTE: It is important not to touch the CFDATA block if already
// allocated, because our caller depends upon the old data
// staying there across cabinet boundaries in order to handle
// CFDATA blocks that are split across cabinet boundaries!
//
cbCFDataPlusReserve = cfreserve.cbCFData + sizeof(CFDATA);
if (!pfdi->pcfdata) { // First time, need to allocate buffer
pfdi->cbCFDataPlusReserve = cbCFDataPlusReserve; // Full size
if (!(pfdi->pcfdata = (*pfdi->pfnalloc)(pfdi->cbCFDataPlusReserve))) {
ErfSetCodes(pfdi->perf,FDIERROR_ALLOC_FAIL,0);
return FALSE;
}
}
else {
//** Make sure this Data has same reserve size as last Data!
if (cbCFDataPlusReserve != pfdi->cbCFDataPlusReserve) {
ErfSetCodes(pfdi->perf,FDIERROR_RESERVE_MISMATCH,0);
return FALSE;
}
}
//** Now read in the back/forward continuation fields, if present
if (pfdi->cfheader.flags & cfhdrPREV_CABINET) {
if (!FDIReadPSZ(pfdi->achCabinetFirst,CB_MAX_CABINET_NAME,pfdi)
|| !FDIReadPSZ(pfdi->achDiskFirst,CB_MAX_DISK_NAME,pfdi)) {
return FALSE; // Error already filled in
}
}
else {
//** No previous disk/cabinet
pfdi->achCabinetFirst[0] = '\0';
pfdi->achDiskFirst[0] = '\0';
}
if (pfdi->cfheader.flags & cfhdrNEXT_CABINET) {
if (!FDIReadPSZ(pfdi->achCabinetNext,CB_MAX_CABINET_NAME,pfdi)
|| !FDIReadPSZ(pfdi->achDiskNext,CB_MAX_DISK_NAME,pfdi)) {
return FALSE; // Error already filled in
}
}
else {
//** No next disk/cabinet
pfdi->achCabinetNext[0] = '\0';
pfdi->achDiskNext[0] = '\0';
}
//** Remember base of folder entries
pfdi->coffFolders = pfdi->pfnseek(pfdi->hfCabFiles,0L,SEEK_CUR);
if (-1L == pfdi->coffFolders) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
//** Seek to first CFFILE entry
if (-1L == pfdi->pfnseek(pfdi->hfCabFiles,
pfdi->cfheader.coffFiles,
SEEK_SET)) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
pfdi->cFilesRemain = pfdi->cfheader.cFiles;
//** Tell client what the *next* cabinet is
if (!doCabinetInfoNotify(pfdi)) {
return FALSE;
}
//** Success
return TRUE;
}
/*** FDIGetFile - Extract one individual file from cabinet.
*
* Entry:
* pfdi - pointer to FDI context
* pfdi->hfNew - open file handle to write to
* pfdi->cffile - filled in
*
* Exit-Success:
* returns TRUE, output file closed
*
* Exit-Failure:
* returns FALSE, output file closed, error structure filled in
*/
BOOL FDIGetFile(PFDI pfdi)
{
UOFF uoffFile;
UOFF cbFileRemain;
UINT cbWriteBase;
UINT cbWrite;
PFDINOTIFICATION pfdin;
int rcClose;
//** First, we must make sure we have selected the correct folder
AssertFDI(pfdi);
if (!InitFolder(pfdi,pfdi->cffile.iFolder)) {
goto error; // error code already filled in
}
uoffFile = pfdi->cffile.uoffFolderStart; // init file pointer
cbFileRemain = pfdi->cffile.cbFile; // init file counter
//jeffwe: Only bypass if there is something to bypass
if (cbFileRemain) {
//** Now bypass any unwanted data blocks
while (uoffFile >= (pfdi->uoffFolder + pfdi->pcfdata->cbUncomp)) {
if (!FDIGetDataBlock(pfdi)) { // get next data block
goto error; // error code already filled in
}
}
}
//** Okay, now we have the first block. Write it, and any that
// remain, into our target file
while (cbFileRemain) {
cbWriteBase = (UINT)(uoffFile - pfdi->uoffFolder);
cbWrite = pfdi->pcfdata->cbUncomp - cbWriteBase; // size left in block
if ((ULONG)cbWrite > cbFileRemain) {
cbWrite = (UINT)cbFileRemain;
}
if (cbWrite != pfdi->pfnwrite(pfdi->hfNew,
&pfdi->pchUncompr[cbWriteBase],
cbWrite)) {
ErfSetCodes(pfdi->perf,FDIERROR_TARGET_FILE,0);
goto error; // couldn't write
}
uoffFile += cbWrite;
cbFileRemain -= cbWrite;
//** Get another block?
if (cbFileRemain && !FDIGetDataBlock(pfdi)) {
goto error; // error code already filled in
}
}
pfdin = &pfdi->fdin;
pfdin->psz1 = pfdi->achName; // pass name of file
pfdin->hf = pfdi->hfNew; // pass file handle
pfdin->date = pfdi->cffile.date; // pass date
pfdin->time = pfdi->cffile.time; // pass time
pfdin->attribs = pfdi->cffile.attribs; // pass attributes
pfdin->pv = pfdi->pvUser; // pass callback context
pfdin->cb = 0; // Default as don't run after ext.
if (pfdin->attribs & RUNATTRIB) {
pfdin->cb = 1; // Run This after extraction
pfdin->attribs &= ~RUNATTRIB; // Clear the flag
}
//** Let client close file and set file date/time/attributes
rcClose = pfdi->pfnfdin(fdintCLOSE_FILE_INFO,pfdin);
if (rcClose == -1) {
//** NOTE: We assume that the client *did* close the file!
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
goto error;
}
pfdi->hfNew = -1; // Remember that file is closed
if (!rcClose) {
ErfSetCodes(pfdi->perf,FDIERROR_TARGET_FILE,0);
return FALSE;
}
return TRUE;
error:
//** Make sure output file is closed
if (pfdi->hfNew != -1) {
pfdi->pfnclose(pfdi->hfNew); // Close it
pfdi->hfNew = -1; // Remember that file is closed
}
return FALSE;
}
/*** FDIGetDataBlock -- read next CFDATA entry, decompress
*
* Entry:
* pfdi -- FDI context
*
* Exit-success:
* returns TRUE;
* pfdi->uoffFolder has *previous* block added to it
* new data block ready in pfdi->pchUncompr
*
* Exit-failure:
* returns FALSE, error code filled in
*/
BOOL FDIGetDataBlock(PFDI pfdi)
{
USHORT cbResult;
AssertFDI(pfdi);
pfdi->uoffFolder += pfdi->pcfdata->cbUncomp; // update uncompr base ptr
if (pfdi->cCFDataRemain == 0) {
if (!SwitchToNewCab(pfdi)) {
return FALSE; // error already filled in
}
}
pfdi->cCFDataRemain--;
if (!FDIReadCFDATAEntry(pfdi,0)) {
return FALSE; // error already filled in
}
//** Is this a continued-forward block?
if (pfdi->pcfdata->cbUncomp == 0) {
//** Switch to new cabinet and read second piece of data block
if ((!SwitchToNewCab(pfdi))
|| (!FDIReadCFDATAEntry(pfdi,pfdi->pcfdata->cbData))) {
return FALSE; // error already filled in
}
}
cbResult = pfdi->pcfdata->cbUncomp; // Expected uncompressed size
if (!MDIDecompressGlobal(pfdi,&cbResult)) {
return FALSE; // error already filled in
}
if (cbResult != pfdi->pcfdata->cbUncomp) {
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE; // wrong length after decompress
}
return TRUE;
}
/*** SwitchToNewCab -- move on to the continuation cabinet
*
* Entry:
* pfdi -- FDI context pointer
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE, error filled in
*/
BOOL SwitchToNewCab(PFDI pfdi)
{
BOOL fWrongCabinet;
USHORT iCabinet;
PFDINOTIFICATION pfdin;
USHORT setID;
AssertFDI(pfdi);
Assert(pfdi->hfCabData != -1);
Assert(pfdi->hfCabFiles != -1);
//** Remember cabinet info so we can make sure we get the correct
// continuation cabinet
setID = pfdi->cfheader.setID;
iCabinet = pfdi->cfheader.iCabinet + 1;
pfdin = &pfdi->fdin;
pfdin->psz1 = pfdi->achCabinetNext; // pass name of next cab
pfdin->psz2 = pfdi->achDiskNext; // pass name of next disk
pfdin->psz3 = pfdi->szCabPath; // allow cabinet path to change
pfdin->pv = pfdi->pvUser; // pass callback context
pfdin->setID = setID; // required setID
pfdin->iCabinet = iCabinet; // required iCabinet
pfdin->fdie = FDIERROR_NONE; // No error
//** Get continuation cabinet
do {
fWrongCabinet = FALSE; // Assume we will get the right cabinet
//** Make sure cabinet file handles are closed
if (((pfdi->hfCabData != -1) && pfdi->pfnclose(pfdi->hfCabData)) ||
((pfdi->hfCabFiles != -1) && pfdi->pfnclose(pfdi->hfCabFiles))) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE; // couldn't close old cabinet
}
//** Remember they are closed
pfdi->hfCabFiles = -1;
pfdi->hfCabData = -1;
//** Ask client for next cabinet
if (pfdi->pfnfdin(fdintNEXT_CABINET,pfdin) == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
return FALSE; // Client aborted
}
//** Open next cabinet
if ((!LoginCabinet(pfdi,pfdi->achCabinetNext,setID,iCabinet))
|| (!SeekFolder(pfdi,0))) { // select following folder
//** Don't bail unless explicitly told to
if (pfdi->perf->erfOper == FDIERROR_USER_ABORT) {
return FALSE; // error already filled in
}
//** Have to call fdintNEXT_CABINET again
fWrongCabinet = TRUE;
}
//** Pass error code to fdintNEXT_CABINET (if we call again)
pfdin->fdie = pfdi->perf->erfOper;
}
while (fWrongCabinet); // Keep going until we get right one
//** Skip over CFFILE entries that are dups from previous cabinet
pfdi->cFilesSkipped++; // skip file we're doing right now, too
while (pfdi->cFilesSkipped) {
pfdi->cFilesRemain--;
pfdi->cFilesSkipped--;
if (!FDIReadCFFILEEntry(pfdi)) {
return FALSE; // error code already filled in
}
}
pfdi->fInContin = TRUE;
return TRUE;
}
/*** doCabinetInfoNotify - pass back info on next cabinet to client
*
* Entry:
* pfdi - FDI context pointer
*
* Exit-Success:
* returns TRUE
*
* Exit-Failure:
* returns FALSE, error filled in
*/
BOOL doCabinetInfoNotify(PFDI pfdi)
{
PFDIDECRYPT pfdid;
PFDINOTIFICATION pfdin;
//** Set info for next cabinet and pass back to client
AssertFDI(pfdi);
pfdin = &pfdi->fdin;
pfdid = &pfdi->fdid;
//** Notify extract code
pfdin->psz1 = pfdi->achCabinetNext; // pass name of next cab
pfdin->psz2 = pfdi->achDiskNext; // pass name of next disk
pfdin->psz3 = pfdi->szCabPath; // cabinet filespec
pfdin->pv = pfdi->pvUser; // pass callback context
pfdin->setID = pfdi->cfheader.setID;
pfdin->iCabinet = pfdi->cfheader.iCabinet;
if (pfdi->pfnfdin(fdintCABINET_INFO,pfdin) == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
return FALSE; // user aborted
}
//** Notify decrypt code, if callback was supplied
if (pfdi->pfnfdid != NULL) {
pfdid->fdidt = fdidtNEW_CABINET;
pfdid->pvUser = pfdi->pvUser;
pfdid->cabinet.pHeaderReserve = pfdi->pbCFHeaderReserve;
pfdid->cabinet.cbHeaderReserve = pfdi->cbCFHeaderReserve;
pfdid->cabinet.setID = pfdi->cfheader.setID;
pfdid->cabinet.iCabinet = pfdi->cfheader.iCabinet;
if (pfdi->pfnfdid(pfdid) == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
return FALSE; // user aborted
}
}
return TRUE;
} /* doCabinetInfoNotify() */
/*** InitFolder - make sure desired folder is ready to read
*
* Entry:
* pfdi -> general context pointer
* iFolder = iFolder field from CFFILE entry
* if iFolder == -1, then this is a continuation of prev. folder
*
* Exit-Success:
* Returns TRUE
*
* Exit-Failure:
* Returns FALSE, error code filled in
*
* Note:
* If we're in a continuation cabinet, this function will just
* set iFolder=0 and return. All folder initialization of future
* folders (in continuation cabinets) requires slightly different
* logic and is done elsewhere.
*/
BOOL InitFolder(PFDI pfdi,UINT iFolder)
{
if (pfdi->fInContin) {
iFolder = 0;
return TRUE;
}
if (IS_CONTD_FORWARD(iFolder)) {
iFolder = pfdi->cfheader.cFolders-1;
}
if (pfdi->iFolder != iFolder) {
if ((!MDIResetDecompressionGlobal(pfdi))
|| (!SeekFolder(pfdi,iFolder))) {
return FALSE; // error already filled in
}
if (!FDIGetDataBlock(pfdi)) { // get the first data block into buffer
return FALSE; // bail if error
}
//** Start at offset zero in uncompressed space
pfdi->uoffFolder = 0;
}
return TRUE;
}
/*** SeekFolder - Seek open cabinet to iFolder, prepare to read data
*
* Entry:
* pfdi - FDI context
* iFolder - Folder number to open
*
* Exit-success:
* return TRUE; pfdi->pcffolder filled in; file position updated
*
* Exit-failure:
* return FALSE, error code filled in
*/
BOOL SeekFolder(PFDI pfdi,UINT iFolder)
{
PFDIDECRYPT pfdid;
AssertFDI(pfdi);
pfdid = &pfdi->fdid;
pfdi->iFolder = iFolder;
//** Read folder and position file pointer to first CFFOLDER block
if ((-1L == pfdi->pfnseek(pfdi->hfCabData,
pfdi->coffFolders +
iFolder*pfdi->cbCFFolderPlusReserve,
SEEK_SET)) // seek to CFFOLDER entry
//** Read CFFOLDER + reserved area
|| (pfdi->cbCFFolderPlusReserve !=
(UINT)pfdi->pfnread(pfdi->hfCabData,
pfdi->pcffolder,
pfdi->cbCFFolderPlusReserve))
//** Seek to first CFDATA of this folder
|| (-1L == pfdi->pfnseek(pfdi->hfCabData,
pfdi->pcffolder->coffCabStart,
SEEK_SET))) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE; // problem accessing cabinet file
}
pfdi->cCFDataRemain = pfdi->pcffolder->cCFData;
#ifdef BIT16
//** 09-Jun-1994 bens Turned on Quantum library!
// #define NO_QUANTUM_16 1
#endif
if (!SetDecompressionType(pfdi->pcffolder->typeCompress,pfdi)) {
return FALSE; // error already filled in
}
//** Notify decrypt code, if callback was supplied
if (pfdi->pfnfdid != NULL) {
pfdid->fdidt = fdidtNEW_FOLDER;
pfdid->pvUser = pfdi->pvUser;
//** Point to per folder reserved area
Assert(pfdi->cbCFFolderPlusReserve >= sizeof(CFFOLDER));
pfdid->folder.cbFolderReserve = pfdi->cbCFFolderPlusReserve
- sizeof(CFFOLDER);
if (pfdid->folder.cbFolderReserve > 0) {
pfdid->folder.pFolderReserve = ((BYTE *)pfdi->pcffolder)
+ sizeof(CFFOLDER);
}
else {
pfdid->folder.pFolderReserve = NULL; // No reserved data
}
pfdid->folder.iFolder = iFolder;
if (pfdi->pfnfdid(pfdid) == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
return FALSE; // user aborted
}
}
return TRUE;
}
/*** FDIReadCFFILEEntry -- Read in a complete CFFILE entry
*
* Entry:
* pfdi -- pointer to FDI context
*
* Exit success:
* pfdi->cffile structure filled in
* returns TRUE
*
* Exit failure:
* returns FALSE if couldn't read a CFFILE entry, perf filled in
*
* Note:
* unlike in this routine's counterpart in FCI, it is a fatal
* error if we hit an eof, because at this point, we never call
* this routine unless we know it can expect a valid entry
*/
BOOL FDIReadCFFILEEntry(PFDI pfdi)
{
if ((sizeof(CFFILE) != (unsigned) pfdi->pfnread(pfdi->hfCabFiles,
&pfdi->cffile,
sizeof (CFFILE)))
|| !FDIReadPSZ(pfdi->achName,
CB_MAX_FILENAME,
pfdi))
{
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE; // couldn't get a full valid CFFILE record
}
return TRUE;
}
/*** FDIReadCFDATAEntry - Read in a complete CFDATA entry
*
* Entry:
* pfdi - Pointer to FDI context (for file i/o)
* cbPartial - Amount of data already present in our local data
* buffer (pfdi->pchCompr). 0 means we haven't
* read any data yet for this block; greater than
* 0 means we've read the first portion of a split
* block, and we're reading the second piece now.
*
* Exit-Success:
* cfdata structure filled in
* return code TRUE
*
* Exit-Failure:
* return code FALSE, error structure filled in
*
* Notes:
* Unlike this routine's counterpart in the FCI stuff, it is a fatal
* error here if we get an EOF. That is because FDI knows for sure
* how many entries there should be and never tries to read too much.
*/
int FDIReadCFDATAEntry(PFDI pfdi, UINT cbPartial)
{
BOOL fSplit; // TRUE if this is read of the first
// or second piece of a split block!
PFDIDECRYPT pfdid;
CHECKSUM calcsum;
AssertFDI(pfdi);
pfdid = &pfdi->fdid;
//** Read CFDATA plus reserved section
if ((pfdi->cbCFDataPlusReserve != pfdi->pfnread(pfdi->hfCabData,
pfdi->pcfdata,
pfdi->cbCFDataPlusReserve))
//** Make sure amount read is not larger than compressed data buffer
|| ((pfdi->pcfdata->cbData + cbPartial) > pfdi->cbMaxCompr)
//** Read actual data itself
|| ((pfdi->pcfdata->cbData != pfdi->pfnread(pfdi->hfCabData,
&pfdi->pchCompr[cbPartial],
pfdi->pcfdata->cbData)))) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE; // no valid record available
}
//** JEFFWE - Check CRC if it is set
if (pfdi->pcfdata->csum != 0) {
calcsum = CSUMCompute(&(pfdi->pcfdata->cbData),
pfdi->cbCFDataPlusReserve - sizeof(CHECKSUM),
CSUMCompute(&(pfdi->pchCompr[cbPartial]),
pfdi->pcfdata->cbData,
0
)
);
if (calcsum != pfdi->pcfdata->csum) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
}
pfdi->pcfdata->cbData += cbPartial; // make it look like one whole block
//** Determine if this is a split data block
fSplit = (cbPartial > 0) // Second piece of split block
|| (pfdi->pcfdata->cbUncomp == 0); // First piece of split block
//** Notify decrypt code, if callback was supplied
if (pfdi->pfnfdid != NULL) {
pfdid->fdidt = fdidtDECRYPT;
pfdid->pvUser = pfdi->pvUser;
//** Point to per data block reserved area
Assert(pfdi->cbCFDataPlusReserve >= sizeof(CFDATA));
pfdid->decrypt.cbDataReserve = pfdi->cbCFDataPlusReserve
- sizeof(CFDATA);
if (pfdid->decrypt.cbDataReserve > 0) {
pfdid->decrypt.pDataReserve = ((BYTE *)pfdi->pcfdata)
+ sizeof(CFDATA);
}
else {
pfdid->decrypt.pDataReserve = NULL; // No reserved data
}
pfdid->decrypt.pbData = &pfdi->pchCompr[cbPartial];
pfdid->decrypt.cbData = pfdi->pcfdata->cbData;
pfdid->decrypt.fSplit = fSplit;
pfdid->decrypt.cbPartial = cbPartial;
if (pfdi->pfnfdid(pfdid) == -1) {
ErfSetCodes(pfdi->perf,FDIERROR_USER_ABORT,0);
return FALSE; // user aborted
}
}
return TRUE;
} /* FDIReadCFDATAEntry() */
/*** FDIReadPSZ -- Read in a psz name
*
* Entry:
* pb - buffer to load name into
* cb - maximum legal length for name
* pfdi - pointer to FDI context (for file i/o functions)
*
* Exit-Success:
* Returns TRUE, name filled in
*
* Exit-Failure:
* Returns FALSE (file read error, or string too long)
*/
BOOL FDIReadPSZ(char *pb, int cb, PFDI pfdi)
{
char chLast;
int cbValue;
int cbRead;
long pos;
//** Save current position
pos = (*pfdi->pfnseek)(pfdi->hfCabFiles,0,SEEK_CUR);
//** Read in enough to get longest possible value
cbRead = (*pfdi->pfnread)(pfdi->hfCabFiles,pb,cb);
if (cbRead <= 0) { // At EOF, or an error occured
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
//** Pick out just ASCIIZ string and adjust file position
chLast = pb[cb-1]; // Save last character
pb[cb-1] = '\0'; // Ensure terminated
cbValue = strlen(pb); // Get string length
if ( ((cbValue+1) >= cb) && (chLast != '\0')) {
//** String filled up buffer and was not null terminated in
// file, so something must be wrong.
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
//** Position to just past string
if (-1L == (*pfdi->pfnseek)(pfdi->hfCabFiles,pos+cbValue+1,SEEK_SET)) {
ErfSetCodes(pfdi->perf,FDIERROR_CORRUPT_CABINET,0);
return FALSE;
}
return TRUE;
}
/*** SetDecompressionType -- initializes a new decompressor
*
* Entry:
* typeCompress -- new compression type (tcompBAD to term w/ no new)
* pfdi -- FDI context structure
*
* Exit-success:
* returns TRUE;
*
* Exit-failure:
* returns FALSE, error code filled in
*/
BOOL SetDecompressionType(TCOMP typeCompress,PFDI pfdi)
{
//** Don't do anything if type is unchanged
if (typeCompress == pfdi->typeCompress) {
return TRUE;
}
//** Destroy existing decompression context (if any)
if (!MDIDestroyDecompressionGlobal(pfdi)) {
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE;
}
//** Create new decompression context
pfdi->typeCompress = typeCompress;
if (!MDICreateDecompressionGlobal(pfdi))
{
return FALSE;
}
return TRUE;
}
/*** MDIDestroyDecompressionGlobal -- Destroy the currently selected decompressor
*
* Entry:
* pfdi - pointer to FDI context
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE, error code filled in
*/
BOOL MDIDestroyDecompressionGlobal(PFDI pfdi)
{
switch(CompressionTypeFromTCOMP(pfdi->typeCompress)) {
case tcompBAD: // no existing compression
return TRUE; // nothing to do if there wasn't any compressor
case tcompTYPE_NONE:
break; //no action needed for null compressor
case tcompTYPE_MSZIP:
if (MDI_ERROR_NO_ERROR != MDIDestroyDecompression(pfdi->mdh)) {
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE; // no valid compressor initialized
}
break;
#if !defined(BIT16) || !defined(NO_QUANTUM_16)
case tcompTYPE_QUANTUM:
if (MDI_ERROR_NO_ERROR != QDIDestroyDecompression(pfdi->mdh)) {
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE; // no valid compressor initialized
}
break;
#endif
default:
ErfSetCodes(pfdi->perf,FDIERROR_BAD_COMPR_TYPE,0);
return FALSE;
} // end switch
//** Now free the buffers
pfdi->pfnfree (pfdi->pchCompr);
pfdi->pfnfree (pfdi->pchUncompr);
return TRUE;
}
/*** MDICreateDecompressionGlobal -- Create the currently selected decompressor
*
* Entry:
* pfdi -- pointer to FDI context
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE, error code filled in
*
*/
BOOL MDICreateDecompressionGlobal(PFDI pfdi)
{
QUANTUMDECOMPRESS qdec;
FDIERROR fdierror = FDIERROR_NONE;
int mdierror;
pfdi->cbMaxUncompr = CB_MAX_CHUNK;
/* first pass to establish buffer sizes */
switch(CompressionTypeFromTCOMP(pfdi->typeCompress)) {
case tcompBAD: // no new compressor
return TRUE; // all done if no compressor enabled
case tcompTYPE_NONE:
pfdi->cbMaxCompr = pfdi->cbMaxUncompr; // for null compr., bufs are same
break;
case tcompTYPE_MSZIP:
if (MDI_ERROR_NO_ERROR != MDICreateDecompression(&pfdi->cbMaxUncompr,
NULL,
NULL,
&pfdi->cbMaxCompr,
NULL))
{
fdierror = FDIERROR_MDI_FAIL;
}
break;
#if !defined(BIT16) || !defined(NO_QUANTUM_16)
case tcompTYPE_QUANTUM:
qdec.WindowBits = CompressionMemoryFromTCOMP(pfdi->typeCompress);
//** Set CPU type, make sure FDI & QDI definitions match
Assert(QDI_CPU_UNKNOWN == cpuUNKNOWN);
Assert(QDI_CPU_80286 == cpu80286);
Assert(QDI_CPU_80386 == cpu80386);
qdec.fCPUtype = pfdi->cpuType;
if (MDI_ERROR_NO_ERROR != QDICreateDecompression(&pfdi->cbMaxUncompr,
&qdec,
NULL,
NULL,
&pfdi->cbMaxCompr,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL))
{
fdierror = FDIERROR_MDI_FAIL;
}
break;
#endif
default:
fdierror = FDIERROR_BAD_COMPR_TYPE;
}
if (fdierror != FDIERROR_NONE)
{
ErfSetCodes(pfdi->perf,fdierror,0);
pfdi->typeCompress = tcompBAD; // No compression context
return FALSE;
}
//** Now allocate whatever buffers the selected compressor requested
if (NULL == (pfdi->pchCompr = (char *) pfdi->pfnalloc (pfdi->cbMaxCompr)))
{
ErfSetCodes(pfdi->perf,FDIERROR_ALLOC_FAIL,0);
pfdi->typeCompress = tcompBAD; // No compression context
return FALSE;
}
if (NULL == (pfdi->pchUncompr = (char *) pfdi->pfnalloc (pfdi->cbMaxUncompr)))
{
pfdi->pfnfree(pfdi->pchCompr);
ErfSetCodes(pfdi->perf,FDIERROR_ALLOC_FAIL,0);
pfdi->typeCompress = tcompBAD; // No compression context
return FALSE;
}
/* second pass to really setup a decompressor */
switch(CompressionTypeFromTCOMP(pfdi->typeCompress)) {
case tcompTYPE_MSZIP:
mdierror = MDICreateDecompression(&pfdi->cbMaxUncompr,
pfdi->pfnalloc,
pfdi->pfnfree,
&pfdi->cbMaxCompr,
&pfdi->mdh);
if (mdierror != MDI_ERROR_NO_ERROR)
{
if (mdierror == MDI_ERROR_NOT_ENOUGH_MEMORY)
{
fdierror = FDIERROR_ALLOC_FAIL;
}
else
{
fdierror = FDIERROR_MDI_FAIL;
}
}
break;
#if !defined(BIT16) || !defined(NO_QUANTUM_16)
case tcompTYPE_QUANTUM:
mdierror = QDICreateDecompression(&pfdi->cbMaxUncompr,
&qdec,
pfdi->pfnalloc,
pfdi->pfnfree,
&pfdi->cbMaxCompr,
&pfdi->mdh,
pfdi->pfnopen,
pfdi->pfnread,
pfdi->pfnwrite,
pfdi->pfnclose,
pfdi->pfnseek);
if (mdierror != MDI_ERROR_NO_ERROR)
{
if (mdierror == MDI_ERROR_NOT_ENOUGH_MEMORY)
{
fdierror = FDIERROR_ALLOC_FAIL;
}
else
{
fdierror = FDIERROR_MDI_FAIL;
}
}
break;
#endif
}
if (fdierror != FDIERROR_NONE)
{
pfdi->pfnfree(pfdi->pchCompr);
pfdi->pfnfree(pfdi->pchUncompr);
ErfSetCodes(pfdi->perf,fdierror,0);
pfdi->typeCompress = tcompBAD; // No compression context
return FALSE;
}
// NOTE: At this point, we leave the compression type set in pfdi,
// so that SetDecompressionType() will clean up the handle
// to the compression context.
return TRUE;
}
/*** MDIResetDecompressionGlobal -- reset the currently selected decompressor
*
* Entry:
* pfdi -- pointer to folder context
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE, error code filled in
*/
BOOL MDIResetDecompressionGlobal(PFDI pfdi)
{
switch(CompressionTypeFromTCOMP(pfdi->typeCompress)) {
case tcompBAD:
break; // no compression selected
case tcompTYPE_NONE:
break; // no action for null compressor
case tcompTYPE_MSZIP:
if (MDI_ERROR_NO_ERROR != MDIResetDecompression(pfdi->mdh))
{
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE; // no valid compressor initialized
}
break;
#if !defined(BIT16) || !defined(NO_QUANTUM_16)
case tcompTYPE_QUANTUM:
if (MDI_ERROR_NO_ERROR != QDIResetDecompression(pfdi->mdh))
{
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE; // no valid compressor initialized
}
break;
#endif
default:
ErfSetCodes(pfdi->perf,FDIERROR_BAD_COMPR_TYPE,0);
return FALSE; // unknown compression type
}
return TRUE;
}
/*** MDIDecompressGlobal - Decompress using currently selected decompressor
*
* Entry:
* pfdi - Pointer to FDI context
* pcbData - Location to return the compressed size;
* NOTE: For Quantum, must contain the EXACT EXPECTED
* UNCOMPRESSED data size!
*
* Exit-Success:
* Returns TRUE
*
* Exit-Failure:
* Returns FALSE, error structure filled in
*/
BOOL MDIDecompressGlobal(PFDI pfdi, USHORT *pcbData)
{
UINT cbData;
switch(CompressionTypeFromTCOMP(pfdi->typeCompress)) {
case tcompTYPE_NONE:
memcpy(pfdi->pchUncompr,
pfdi->pchCompr,
*pcbData=pfdi->pcfdata->cbData);
break; // done for null compressor
case tcompTYPE_MSZIP:
cbData = pfdi->cbMaxUncompr; // Size of destination buffer
if (MDI_ERROR_NO_ERROR !=
MDIDecompress(pfdi->mdh, // MDI context
pfdi->pchCompr, // Compressed data
pfdi->pcfdata->cbData, // source buffer size
pfdi->pchUncompr, // Destination buffer
&cbData)) { // resulting data size
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE;
}
//** Narrow result (16-bit case)
*pcbData = (USHORT)cbData;
break;
#if !defined(BIT16) || !defined(NO_QUANTUM_16)
case tcompTYPE_QUANTUM:
cbData = (UINT)*pcbData; // Size of *uncompressed* data!
if (MDI_ERROR_NO_ERROR !=
QDIDecompress(pfdi->mdh, // QDI context
pfdi->pchCompr, // Compressed data
pfdi->pcfdata->cbData, // source buffer size
pfdi->pchUncompr, // Destination buffer
&cbData)) { // resulting data size
ErfSetCodes(pfdi->perf,FDIERROR_MDI_FAIL,0);
return FALSE;
}
//** Narrow result (16-bit case)
*pcbData = (USHORT)cbData;
break;
#endif
default:
ErfSetCodes(pfdi->perf,FDIERROR_BAD_COMPR_TYPE,0);
return FALSE; // no valid compressor initialized
}
return TRUE;
}