945 lines
20 KiB
C
945 lines
20 KiB
C
#include <windows.h>
|
|
#include <fcntl.h>
|
|
|
|
//
|
|
// lz headers
|
|
//
|
|
#include "lz_common.h"
|
|
#include "lz_buffers.h"
|
|
#include "lz_header.h"
|
|
|
|
//
|
|
// diamond headers
|
|
//
|
|
#include <diamondd.h>
|
|
#include "mydiam.h"
|
|
|
|
|
|
HFDI FdiContext;
|
|
ERF FdiError;
|
|
|
|
INT DiamondLastIoError;
|
|
|
|
BOOL
|
|
PatternMatch(
|
|
IN PCSTR pszString,
|
|
IN PCSTR pszPattern,
|
|
IN BOOL fImplyDotAtEnd
|
|
);
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
SpdFdiOpen(
|
|
IN PSTR FileName,
|
|
IN int oflag,
|
|
IN int pmode
|
|
);
|
|
|
|
int
|
|
DIAMONDAPI
|
|
SpdFdiClose(
|
|
IN INT_PTR Handle
|
|
);
|
|
|
|
typedef struct _DIAMOND_INFO {
|
|
|
|
//
|
|
// A read handle to the source file.
|
|
//
|
|
INT_PTR SourceFileHandle;
|
|
|
|
//
|
|
// File names.
|
|
//
|
|
PSTR SourceFileName;
|
|
PSTR TargetFileName;
|
|
|
|
//
|
|
// Flag indicating whether to rename the target file.
|
|
//
|
|
BOOL RenameTargetFile;
|
|
|
|
//
|
|
// Pointer to LZ information structure.
|
|
// We'll fill in some of the fields to fool expand.
|
|
//
|
|
PLZINFO pLZI;
|
|
|
|
//
|
|
// Expand callback/notification.
|
|
//
|
|
NOTIFYPROC ExpandNotify;
|
|
|
|
//
|
|
// Selective extraction file spec, ie, "aic*.sys" or NULL
|
|
//
|
|
PSTR SelectiveFilesSpec;
|
|
|
|
} DIAMOND_INFO, *PDIAMOND_INFO;
|
|
|
|
|
|
PTSTR
|
|
StringRevChar(
|
|
IN PTSTR String,
|
|
IN TCHAR Char
|
|
)
|
|
{
|
|
//
|
|
// Although not the most efficient possible algoeithm in each case,
|
|
// this algorithm is correct for unicode, sbcs, or dbcs.
|
|
//
|
|
PTCHAR Occurrence,Next;
|
|
|
|
//
|
|
// Check each character in the string and remember
|
|
// the most recently encountered occurrence of the desired char.
|
|
//
|
|
for(Occurrence=NULL,Next=CharNext(String); *String; ) {
|
|
|
|
if(!memcmp(String,&Char,(int)((PUCHAR)Next-(PUCHAR)String))) {
|
|
Occurrence = String;
|
|
}
|
|
|
|
String = Next;
|
|
Next = CharNext(Next);
|
|
}
|
|
|
|
//
|
|
// Return address of final occurrence of the character
|
|
// (will be NULL if not found at all).
|
|
//
|
|
return(Occurrence);
|
|
}
|
|
|
|
|
|
#define WILDCARD '*' /* zero or more of any character */
|
|
#define WILDCHAR '?' /* one of any character (does not match END) */
|
|
#define END '\0' /* terminal character */
|
|
#define DOT '.' /* may be implied at end ("hosts" matches "*.") */
|
|
|
|
|
|
static int __inline Lower(c)
|
|
{
|
|
if ((c >= 'A') && (c <= 'Z'))
|
|
{
|
|
return(c + ('a' - 'A'));
|
|
}
|
|
else
|
|
{
|
|
return(c);
|
|
}
|
|
}
|
|
|
|
|
|
static int __inline CharacterMatch(char chCharacter, char chPattern)
|
|
{
|
|
if (Lower(chCharacter) == Lower(chPattern))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
PatternMatch(
|
|
PCSTR pszString,
|
|
PCSTR pszPattern,
|
|
IN BOOL fImplyDotAtEnd
|
|
)
|
|
{
|
|
/* RECURSIVE */
|
|
|
|
//
|
|
// This function does not deal with 8.3 conventions which might
|
|
// be expected for filename comparisons. (In an 8.3 environment,
|
|
// "alongfilename.html" would match "alongfil.htm")
|
|
//
|
|
// This code is NOT MBCS-enabled
|
|
//
|
|
|
|
for ( ; ; )
|
|
{
|
|
switch (*pszPattern)
|
|
{
|
|
|
|
case END:
|
|
|
|
//
|
|
// Reached end of pattern, so we're done. Matched if
|
|
// end of string, no match if more string remains.
|
|
//
|
|
|
|
return(*pszString == END);
|
|
|
|
case WILDCHAR:
|
|
|
|
//
|
|
// Next in pattern is a wild character, which matches
|
|
// anything except end of string. If we reach the end
|
|
// of the string, the implied DOT would also match.
|
|
//
|
|
|
|
if (*pszString == END)
|
|
{
|
|
if (fImplyDotAtEnd == TRUE)
|
|
{
|
|
fImplyDotAtEnd = FALSE;
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszString++;
|
|
}
|
|
|
|
pszPattern++;
|
|
|
|
break;
|
|
|
|
case WILDCARD:
|
|
|
|
//
|
|
// Next in pattern is a wildcard, which matches anything.
|
|
// Find the required character that follows the wildcard,
|
|
// and search the string for it. At each occurence of the
|
|
// required character, try to match the remaining pattern.
|
|
//
|
|
// There are numerous equivalent patterns in which multiple
|
|
// WILDCARD and WILDCHAR are adjacent. We deal with these
|
|
// before our search for the required character.
|
|
//
|
|
// Each WILDCHAR burns one non-END from the string. An END
|
|
// means we have a match. Additional WILDCARDs are ignored.
|
|
//
|
|
|
|
for ( ; ; )
|
|
{
|
|
pszPattern++;
|
|
|
|
if (*pszPattern == END)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else if (*pszPattern == WILDCHAR)
|
|
{
|
|
if (*pszString == END)
|
|
{
|
|
if (fImplyDotAtEnd == TRUE)
|
|
{
|
|
fImplyDotAtEnd = FALSE;
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszString++;
|
|
}
|
|
}
|
|
else if (*pszPattern != WILDCARD)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now we have a regular character to search the string for.
|
|
//
|
|
|
|
while (*pszString != END)
|
|
{
|
|
//
|
|
// For each match, use recursion to see if the remainder
|
|
// of the pattern accepts the remainder of the string.
|
|
// If it does not, continue looking for other matches.
|
|
//
|
|
|
|
if (CharacterMatch(*pszString, *pszPattern) == TRUE)
|
|
{
|
|
if (PatternMatch(pszString + 1, pszPattern + 1, fImplyDotAtEnd) == TRUE)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
pszString++;
|
|
}
|
|
|
|
//
|
|
// Reached end of string without finding required character
|
|
// which followed the WILDCARD. If the required character
|
|
// is a DOT, consider matching the implied DOT.
|
|
//
|
|
// Since the remaining string is empty, the only pattern which
|
|
// could match after the DOT would be zero or more WILDCARDs,
|
|
// so don't bother with recursion.
|
|
//
|
|
|
|
if ((*pszPattern == DOT) && (fImplyDotAtEnd == TRUE))
|
|
{
|
|
pszPattern++;
|
|
|
|
while (*pszPattern != END)
|
|
{
|
|
if (*pszPattern != WILDCARD)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pszPattern++;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Reached end of the string without finding required character.
|
|
//
|
|
|
|
return(FALSE);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Nothing special about the pattern character, so it
|
|
// must match source character.
|
|
//
|
|
|
|
if (CharacterMatch(*pszString, *pszPattern) == FALSE)
|
|
{
|
|
if ((*pszPattern == DOT) &&
|
|
(*pszString == END) &&
|
|
(fImplyDotAtEnd == TRUE))
|
|
{
|
|
fImplyDotAtEnd = FALSE;
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if (*pszString != END)
|
|
{
|
|
pszString++;
|
|
}
|
|
|
|
pszPattern++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
DiamondNotifyFunction(
|
|
IN FDINOTIFICATIONTYPE Operation,
|
|
IN PFDINOTIFICATION Parameters
|
|
)
|
|
{
|
|
switch(Operation) {
|
|
|
|
case fdintCABINET_INFO:
|
|
case fdintNEXT_CABINET:
|
|
case fdintPARTIAL_FILE:
|
|
default:
|
|
|
|
//
|
|
// Cabinet management functions which we don't use.
|
|
// Return success.
|
|
//
|
|
return(0);
|
|
|
|
case fdintCOPY_FILE:
|
|
|
|
//
|
|
// Diamond is asking us whether we want to copy the file.
|
|
//
|
|
{
|
|
PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
|
|
HFILE h;
|
|
|
|
//
|
|
// If we were given a filespec, see if the name matches.
|
|
//
|
|
|
|
if (Info->SelectiveFilesSpec != NULL) {
|
|
|
|
//
|
|
// Call PatternMatch(), fAllowImpliedDot TRUE if
|
|
// there is no '.' in the file's base name.
|
|
//
|
|
|
|
BOOL fAllowImpliedDot = TRUE;
|
|
PSTR p;
|
|
|
|
for (p = Parameters->psz1; *p != '\0'; p++) {
|
|
if (*p == '.') {
|
|
fAllowImpliedDot = FALSE;
|
|
} else if (*p == '\\') {
|
|
fAllowImpliedDot = TRUE;
|
|
}
|
|
}
|
|
|
|
if (PatternMatch(
|
|
Parameters->psz1,
|
|
Info->SelectiveFilesSpec,
|
|
fAllowImpliedDot) == FALSE) {
|
|
|
|
return(0); // skip this file
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we need to rename the target file, do that here.
|
|
// The name stored in the cabinet file will be used as
|
|
// the uncompressed name.
|
|
//
|
|
if(Info->RenameTargetFile) {
|
|
|
|
PSTR p,q;
|
|
|
|
//
|
|
// Find the start of the filename part of the target.
|
|
//
|
|
if(p = StringRevChar(Info->TargetFileName,'\\')) {
|
|
p++;
|
|
} else {
|
|
p = Info->TargetFileName;
|
|
}
|
|
|
|
//
|
|
// Find the start of the filename part of the name in the cabinet.
|
|
//
|
|
if(q = StringRevChar(Parameters->psz1,'\\')) {
|
|
q++;
|
|
} else {
|
|
q = Parameters->psz1;
|
|
}
|
|
|
|
//
|
|
// Copy the filename part of the name in the cabinet over
|
|
// the filename part of the name in the target spec.
|
|
//
|
|
lstrcpy(p,q);
|
|
}
|
|
|
|
//
|
|
// Inform the expand callback what we are doing.
|
|
//
|
|
if(!Info->ExpandNotify(Info->SourceFileName,Info->TargetFileName,NOTIFY_START_EXPAND)) {
|
|
return(0); // skip this file.
|
|
}
|
|
|
|
//
|
|
// Remember the uncompressed size and open the file.
|
|
// Returns -1 if an error occurs opening the file.
|
|
//
|
|
Info->pLZI->cblOutSize += Parameters->cb;
|
|
h = _lcreat(Info->TargetFileName,0);
|
|
if(h == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADOUTHANDLE;
|
|
return(-1);
|
|
}
|
|
return(h);
|
|
}
|
|
|
|
case fdintCLOSE_FILE_INFO:
|
|
|
|
//
|
|
// Diamond is done with the target file and wants us to close it.
|
|
// (ie, this is the counterpart to fdint_COPY_FILE).
|
|
//
|
|
{
|
|
PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
|
|
HANDLE TargetFileHandle;
|
|
FILETIME ftLocal, ftUTC;
|
|
|
|
_lclose((HFILE)Parameters->hf);
|
|
|
|
//
|
|
// Set the target file's date/time stamp from the value inside
|
|
// the CAB.
|
|
//
|
|
TargetFileHandle = CreateFile(Info->TargetFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if (TargetFileHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (DosDateTimeToFileTime(Parameters->date, Parameters->time, &ftLocal) &&
|
|
LocalFileTimeToFileTime(&ftLocal, &ftUTC))
|
|
{
|
|
SetFileTime(TargetFileHandle, NULL, NULL, &ftUTC);
|
|
}
|
|
|
|
CloseHandle(TargetFileHandle);
|
|
}
|
|
}
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
DIAMONDAPI
|
|
SpdFdiAlloc(
|
|
IN ULONG NumberOfBytes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to allocate memory.
|
|
|
|
Arguments:
|
|
|
|
NumberOfBytes - supplies desired size of block.
|
|
|
|
Return Value:
|
|
|
|
Returns pointer to a block of memory or NULL
|
|
if memory cannot be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
return((PVOID)LocalAlloc(LMEM_FIXED,NumberOfBytes));
|
|
}
|
|
|
|
|
|
VOID
|
|
DIAMONDAPI
|
|
SpdFdiFree(
|
|
IN PVOID Block
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to free a memory block.
|
|
The block must have been allocated with SpdFdiAlloc().
|
|
|
|
Arguments:
|
|
|
|
Block - supplies pointer to block of memory to be freed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LocalFree((HLOCAL)Block);
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
SpdFdiOpen(
|
|
IN PSTR FileName,
|
|
IN int oflag,
|
|
IN int pmode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to open files.
|
|
|
|
Arguments:
|
|
|
|
FileName - supplies name of file to be opened.
|
|
|
|
oflag - supplies flags for open.
|
|
|
|
pmode - supplies additional flags for open.
|
|
|
|
Return Value:
|
|
|
|
Handle to open file or -1 if error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
HFILE h;
|
|
int OpenMode;
|
|
|
|
if(oflag & _O_WRONLY) {
|
|
OpenMode = OF_WRITE;
|
|
} else {
|
|
if(oflag & _O_RDWR) {
|
|
OpenMode = OF_READWRITE;
|
|
} else {
|
|
OpenMode = OF_READ;
|
|
}
|
|
}
|
|
|
|
h = _lopen(FileName,OpenMode | OF_SHARE_DENY_WRITE);
|
|
|
|
if(h == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADINHANDLE;
|
|
return(-1);
|
|
}
|
|
|
|
return((INT_PTR)h);
|
|
}
|
|
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
SpdFdiRead(
|
|
IN INT_PTR Handle,
|
|
OUT PVOID pv,
|
|
IN UINT ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to read from a file.
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies handle to open file to be read from.
|
|
|
|
pv - supplies pointer to buffer to receive bytes we read.
|
|
|
|
ByteCount - supplies number of bytes to read.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes read (ByteCount) or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT rc;
|
|
|
|
rc = _lread((HFILE)Handle,pv,ByteCount);
|
|
|
|
if(rc == HFILE_ERROR) {
|
|
rc = (UINT)(-1);
|
|
DiamondLastIoError = LZERROR_READ;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
SpdFdiWrite(
|
|
IN INT_PTR Handle,
|
|
IN PVOID pv,
|
|
IN UINT ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to write to a file.
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies handle to open file to be written to.
|
|
|
|
pv - supplies pointer to buffer containing bytes to write.
|
|
|
|
ByteCount - supplies number of bytes to write.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes written (ByteCount) or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT rc;
|
|
|
|
rc = _lwrite((HFILE)Handle,pv,ByteCount);
|
|
|
|
if(rc == HFILE_ERROR) {
|
|
|
|
DiamondLastIoError = (GetLastError() == ERROR_DISK_FULL) ? LZERROR_WRITE : LZERROR_BADOUTHANDLE;
|
|
|
|
} else {
|
|
|
|
if(rc != ByteCount) {
|
|
//
|
|
// let caller interpret return value but record last error just in case
|
|
//
|
|
DiamondLastIoError = LZERROR_WRITE;
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
int
|
|
DIAMONDAPI
|
|
SpdFdiClose(
|
|
IN INT_PTR Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to close files.
|
|
|
|
Arguments:
|
|
|
|
Handle - handle of file to close.
|
|
|
|
Return Value:
|
|
|
|
0 (success).
|
|
|
|
--*/
|
|
|
|
{
|
|
_lclose((HFILE)Handle);
|
|
return(0);
|
|
}
|
|
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
SpdFdiSeek(
|
|
IN INT_PTR Handle,
|
|
IN long Distance,
|
|
IN int SeekType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to seek files.
|
|
|
|
Arguments:
|
|
|
|
Handle - handle of file to close.
|
|
|
|
Distance - supplies distance to seek. Interpretation of this
|
|
parameter depends on the value of SeekType.
|
|
|
|
SeekType - supplies a value indicating how Distance is to be
|
|
interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
|
|
|
|
Return Value:
|
|
|
|
New file offset or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG rc;
|
|
|
|
rc = _llseek((HFILE)Handle,Distance,SeekType);
|
|
|
|
if(rc == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADINHANDLE;
|
|
rc = -1L;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
INT
|
|
ExpandDiamondFile(
|
|
IN NOTIFYPROC ExpandNotify,
|
|
IN PSTR SourceFileName,
|
|
IN PSTR TargetFileName,
|
|
IN BOOL RenameTarget,
|
|
IN PSTR SelectiveFilesSpec,
|
|
OUT PLZINFO pLZI
|
|
)
|
|
{
|
|
BOOL b;
|
|
INT rc;
|
|
INT_PTR h;
|
|
DIAMOND_INFO DiamondInfo;
|
|
|
|
if(!FdiContext) {
|
|
return(LZERROR_BADVALUE);
|
|
}
|
|
|
|
DiamondLastIoError = TRUE;
|
|
|
|
//
|
|
// Get a handle to the source to use to
|
|
// copy the date and time stamp.
|
|
//
|
|
h = SpdFdiOpen(SourceFileName,_O_RDONLY,0);
|
|
if(h == -1) {
|
|
return(LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
pLZI->cblInSize = GetFileSize((HANDLE)h,NULL);
|
|
if(pLZI->cblInSize == -1) {
|
|
SpdFdiClose(h);
|
|
return(LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
DiamondInfo.SourceFileHandle = h;
|
|
DiamondInfo.SourceFileName = SourceFileName;
|
|
DiamondInfo.TargetFileName = TargetFileName;
|
|
DiamondInfo.RenameTargetFile = RenameTarget;
|
|
DiamondInfo.ExpandNotify = ExpandNotify;
|
|
DiamondInfo.SelectiveFilesSpec = SelectiveFilesSpec;
|
|
DiamondInfo.pLZI = pLZI;
|
|
|
|
b = FDICopy(
|
|
FdiContext,
|
|
SourceFileName, // pass the whole path as the name
|
|
"", // don't bother with the path part
|
|
0, // flags
|
|
DiamondNotifyFunction,
|
|
NULL, // no decryption
|
|
&DiamondInfo
|
|
);
|
|
|
|
if(b) {
|
|
|
|
rc = TRUE;
|
|
|
|
} else {
|
|
|
|
switch(FdiError.erfOper) {
|
|
|
|
case FDIERROR_CORRUPT_CABINET:
|
|
case FDIERROR_UNKNOWN_CABINET_VERSION:
|
|
case FDIERROR_BAD_COMPR_TYPE:
|
|
rc = LZERROR_READ; // causes SID_FORMAT_ERROR message
|
|
break;
|
|
|
|
case FDIERROR_ALLOC_FAIL:
|
|
rc = LZERROR_GLOBALLOC;
|
|
break;
|
|
|
|
case FDIERROR_TARGET_FILE:
|
|
case FDIERROR_USER_ABORT:
|
|
rc = DiamondLastIoError;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// The rest of the errors are not handled specially.
|
|
//
|
|
rc = LZERROR_BADVALUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Remove the partial target file.
|
|
//
|
|
DeleteFile(TargetFileName);
|
|
}
|
|
|
|
SpdFdiClose(h);
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDiamondFile(
|
|
IN PSTR FileName,
|
|
OUT PBOOL ContainsMultipleFiles
|
|
)
|
|
{
|
|
FDICABINETINFO CabinetInfo;
|
|
BOOL b;
|
|
INT_PTR h;
|
|
|
|
*ContainsMultipleFiles = FALSE;
|
|
|
|
if(!FdiContext) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Open the file such that the handle is valid for use
|
|
// in the diamond context (ie, seek, read routines above).
|
|
//
|
|
h = SpdFdiOpen(FileName,_O_RDONLY,0);
|
|
if(h == -1) {
|
|
return(FALSE);
|
|
}
|
|
|
|
b = FDIIsCabinet(FdiContext,h,&CabinetInfo);
|
|
|
|
SpdFdiClose(h);
|
|
|
|
if (b && (CabinetInfo.cFiles > 1)) {
|
|
*ContainsMultipleFiles = TRUE;
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitDiamond(
|
|
VOID
|
|
)
|
|
{
|
|
if(FdiContext == NULL) {
|
|
|
|
FdiContext = FDICreate(
|
|
SpdFdiAlloc,
|
|
SpdFdiFree,
|
|
SpdFdiOpen,
|
|
SpdFdiRead,
|
|
SpdFdiWrite,
|
|
SpdFdiClose,
|
|
SpdFdiSeek,
|
|
cpuUNKNOWN,
|
|
&FdiError
|
|
);
|
|
}
|
|
|
|
return(FdiContext != NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
TermDiamond(
|
|
VOID
|
|
)
|
|
{
|
|
if(FdiContext) {
|
|
FDIDestroy(FdiContext);
|
|
FdiContext = NULL;
|
|
}
|
|
}
|
|
|
|
|