diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/windows/diamond/chuck/fdi.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/windows/diamond/chuck/fdi.c')
-rw-r--r-- | private/windows/diamond/chuck/fdi.c | 1626 |
1 files changed, 1626 insertions, 0 deletions
diff --git a/private/windows/diamond/chuck/fdi.c b/private/windows/diamond/chuck/fdi.c new file mode 100644 index 000000000..00e828442 --- /dev/null +++ b/private/windows/diamond/chuck/fdi.c @@ -0,0 +1,1626 @@ +/*** 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; +} |