|
|
#include <windows.h>
#include <lzexpand.h>
#include <fcntl.h>
/************************************************************************\
* * NOTE!!!! * * While the 'Diamond' interfaced functions defined in this file are * multi thread safe, EACH THREAD MUST ONLY HAVE ONE DIAMOND FILE * OPEN AT A TIME! (ie. You can not nest InitDiamond()/TermDiamond() * pairs in one thread of execution.) * \************************************************************************/
//
// diamond headers
//
#include <diamondd.h>
#include "mydiam.h"
HINSTANCE hCabinet; DWORD cCabinetLoad; typedef HFDI (DIAMONDAPI * tFDICreate) (PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf);
typedef BOOL (DIAMONDAPI * tFDIIsCabinet)(HFDI hfdi, INT_PTR hf, PFDICABINETINFO pfdici);
typedef BOOL (DIAMONDAPI * tFDICopy)(HFDI hfdi, char FAR *pszCabinet, char FAR *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void FAR *pvUser);
typedef BOOL (DIAMONDAPI * tFDIDestroy)(HFDI hfdi);
tFDICreate pFDICreate; tFDIIsCabinet pFDIIsCabinet; tFDICopy pFDICopy; tFDIDestroy pFDIDestroy;
// this function is the same as CharNextA, available locally
extern LPSTR WINAPI VerCharNextA(LPCSTR lpCurrentChar);
INT CopyDateTimeStamp(INT_PTR doshFrom, INT_PTR doshTo) { FILETIME lpCreationTime, lpLastAccessTime, lpLastWriteTime;
if (!GetFileTime((HANDLE) doshFrom, &lpCreationTime, &lpLastAccessTime, &lpLastWriteTime)) { return ((INT)LZERROR_BADINHANDLE); } if (!SetFileTime((HANDLE) doshTo, &lpCreationTime, &lpLastAccessTime, &lpLastWriteTime)) { return ((INT)LZERROR_BADINHANDLE); }
return (TRUE); }
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;
} DIAMOND_INFO, *PDIAMOND_INFO;
PSTR StringRevChar( IN PSTR String, IN CHAR Char ) { //
// Although not the most efficient possible algoeithm in each case,
// this algorithm is correct for unicode, sbcs, or dbcs.
//
PCHAR Occurrence,Next;
//
// Check each character in the string and remember
// the most recently encountered occurrence of the desired char.
//
for (Occurrence=NULL,Next=VerCharNextA(String); *String; ) {
if (!memcmp(String,&Char,(int)((PUCHAR)Next-(PUCHAR)String))) { Occurrence = String; }
String = Next; Next = VerCharNextA(Next); }
//
// Return address of final occurrence of the character
// (will be NULL if not found at all).
//
return (Occurrence); }
INT_PTR DIAMONDAPI DiamondNotifyFunction( IN FDINOTIFICATIONTYPE Operation, IN PFDINOTIFICATION Parameters ) { switch (Operation) {
case fdintCABINET_INFO: case fdintNEXT_CABINET: case fdintPARTIAL_FILE: case fdintENUMERATE:
//
// 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 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.
//
lstrcpyA(p,q); }
{ // Check they're not the same file
CHAR Source[MAX_PATH]; CHAR Target[MAX_PATH]; PSTR FileName; DWORD PathLenSource; DWORD PathLenTarget;
PathLenSource = GetFullPathNameA(Info->SourceFileName, MAX_PATH, Source, &FileName); PathLenTarget = GetFullPathNameA(Info->TargetFileName, MAX_PATH, Target, &FileName);
if (PathLenSource == 0 || PathLenSource >= MAX_PATH || PathLenTarget == 0 || PathLenTarget >= MAX_PATH || lstrcmpiA(Source, Target) == 0) { return 0; } }
//
// 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;
CopyDateTimeStamp(Info->SourceFileHandle,Parameters->hf); _lclose((HFILE)Parameters->hf); } return (TRUE);
default:
//
// invalid operation
//
return(-1); } }
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); }
//
// this function is linked in from ntdll
//
extern int sprintf(LPSTR, LPCSTR, ...);
INT ExpandDiamondFile( IN PSTR SourceFileName, // Note ASCII
IN PTSTR TargetFileNameT, IN BOOL RenameTarget, OUT PLZINFO pLZI ) { BOOL b; INT rc; INT_PTR h; DIAMOND_INFO DiamondInfo; CHAR TargetFileName[MAX_PATH];
sprintf(TargetFileName, "%ls", TargetFileNameT);
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.pLZI = pLZI;
b = pFDICopy( 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.
//
DeleteFileA(TargetFileName); }
SpdFdiClose(h);
return (rc); }
BOOL IsDiamondFile( IN PSTR FileName ) { FDICABINETINFO CabinetInfo; BOOL b; INT_PTR h;
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 = pFDIIsCabinet(FdiContext,h,&CabinetInfo);
SpdFdiClose(h);
return (b); }
DWORD InitDiamond( VOID ) { PDIAMOND_CONTEXT pdcx;
if (!GotDmdTlsSlot()) return VIF_OUTOFMEMORY;
if (GotDmdContext()) return VIF_OUTOFMEMORY;
pdcx = LocalAlloc(LPTR, sizeof(DIAMOND_CONTEXT));
if (pdcx == NULL || !TlsSetValue(itlsDiamondContext, pdcx)) { /*
* For some unknown reason, we can't associate * our thread storage with the slot, so free * it and say we never got one. */
if (pdcx) { LocalFree(pdcx); } return VIF_OUTOFMEMORY; }
if (!cCabinetLoad) { hCabinet = LoadLibraryW(L"CABINET.DLL"); if (!hCabinet) { return (VIF_CANNOTLOADCABINET); } pFDICreate = (tFDICreate) GetProcAddress(hCabinet, "FDICreate"); pFDIDestroy = (tFDIDestroy) GetProcAddress(hCabinet, "FDIDestroy"); pFDIIsCabinet = (tFDIIsCabinet) GetProcAddress(hCabinet, "FDIIsCabinet"); pFDICopy = (tFDICopy) GetProcAddress(hCabinet, "FDICopy");
if (!(pFDICreate && pFDIDestroy && pFDIIsCabinet && pFDICopy)) { FreeLibrary(hCabinet); return (VIF_CANNOTLOADCABINET); }
if (InterlockedExchangeAdd(&cCabinetLoad, 1) != 0) { // Multiple threads are attempting to LoadLib
// Free one here.
FreeLibrary(hCabinet); } }
SetFdiContext( pFDICreate( SpdFdiAlloc, SpdFdiFree, SpdFdiOpen, SpdFdiRead, SpdFdiWrite, SpdFdiClose, SpdFdiSeek, cpuUNKNOWN, &FdiError ));
return ((FdiContext == NULL) ? VIF_CANNOTLOADCABINET : 0); }
VOID TermDiamond( VOID ) { if (!GotDmdTlsSlot() || !GotDmdContext()) return;
if (FdiContext) { pFDIDestroy(FdiContext); SetFdiContext( NULL ); }
LocalFree( TlsGetValue(itlsDiamondContext) ); TlsSetValue(itlsDiamondContext, NULL); }
|