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.
596 lines
11 KiB
596 lines
11 KiB
#include "pch.h"
|
|
#include <fdi.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <sys\stat.h>
|
|
#include <malloc.h>
|
|
#include <lzexpand.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
BOOL
|
|
UncompressFile(
|
|
IN LPCSTR CompressedFileName,
|
|
IN LPCSTR UncompressedFileName
|
|
);
|
|
|
|
DWORD
|
|
UncompressLZFile(
|
|
IN LPCSTR CompressedFileName,
|
|
IN LPCSTR UncompressedFileName
|
|
);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
typedef struct
|
|
{
|
|
LPCSTR TargetFileName; // pathname of file to create
|
|
LPCSTR SymbolFileName; // name of file to uncompress
|
|
DWORD FileSize; // expected file size
|
|
DWORD LastError; // completion code
|
|
} OPCONTEXT;
|
|
|
|
|
|
DWORD
|
|
ExtractSingleFileFromCabinet(
|
|
IN LPCSTR CabinetFileName,
|
|
IN LPCSTR TargetFileName,
|
|
IN LPCSTR FileNameInCabinet
|
|
);
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
FdiNotification(
|
|
FDINOTIFICATIONTYPE fdint,
|
|
PFDINOTIFICATION pfdin
|
|
);
|
|
|
|
void HUGE *
|
|
FAR DIAMONDAPI
|
|
FdiAlloc(
|
|
ULONG cb
|
|
);
|
|
|
|
void
|
|
FAR DIAMONDAPI
|
|
FdiFree(
|
|
void HUGE *pv
|
|
);
|
|
|
|
INT_PTR
|
|
FAR DIAMONDAPI
|
|
FdiOpen(
|
|
char FAR *pszFile,
|
|
int oflag,
|
|
int pmode
|
|
);
|
|
|
|
UINT
|
|
FAR DIAMONDAPI
|
|
FdiRead(
|
|
INT_PTR hf,
|
|
void FAR *pv,
|
|
UINT cb
|
|
);
|
|
|
|
UINT
|
|
FAR DIAMONDAPI
|
|
FdiWrite(
|
|
INT_PTR hf,
|
|
void FAR *pv,
|
|
UINT cb
|
|
);
|
|
|
|
long
|
|
FAR DIAMONDAPI
|
|
FdiSeek(
|
|
INT_PTR hf,
|
|
long dist,
|
|
int seektype
|
|
);
|
|
|
|
int
|
|
FAR DIAMONDAPI
|
|
FdiClose(
|
|
INT_PTR hf
|
|
);
|
|
|
|
DWORD
|
|
GetLastErrorWithDefault(
|
|
DWORD DefaultError
|
|
);
|
|
|
|
#ifdef STANDALONE
|
|
|
|
int __cdecl main( int argc, char * argv[] )
|
|
{
|
|
BOOL rc;
|
|
|
|
printf( "UncompressFile( \"%s\", \"%s\" )\n", argv[ 1 ], argv[ 2 ] );
|
|
|
|
rc = UncompressFile( argv[1], argv[2] );
|
|
|
|
if ( rc == TRUE )
|
|
{
|
|
printf( "Expanded \"%s\" to \"%s\"\n", argv[1], argv[2] );
|
|
}
|
|
else
|
|
{
|
|
printf( "Failed to expand, GLE=%u\n", GetLastError());
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
UncompressFile(
|
|
IN LPCSTR CompressedFileName,
|
|
IN LPCSTR UncompressedFileName
|
|
)
|
|
{
|
|
DWORD rc;
|
|
LPCSTR FileNameInCabinet;
|
|
|
|
// Assume the name to be extracted from the
|
|
// compressed file is the same as the base
|
|
// name of the specified target file.
|
|
|
|
FileNameInCabinet = strrchr( UncompressedFileName, '\\' );
|
|
if ( FileNameInCabinet == NULL )
|
|
{
|
|
FileNameInCabinet = UncompressedFileName;
|
|
}
|
|
else
|
|
{
|
|
FileNameInCabinet++;
|
|
}
|
|
|
|
__try
|
|
{
|
|
rc = ExtractSingleFileFromCabinet(
|
|
CompressedFileName,
|
|
UncompressedFileName,
|
|
FileNameInCabinet
|
|
);
|
|
|
|
//
|
|
// If the file is not a cabinet, it might be an LZExpand file
|
|
//
|
|
|
|
if ( rc == ERROR_FILE_CORRUPT )
|
|
{
|
|
rc = UncompressLZFile(
|
|
CompressedFileName,
|
|
UncompressedFileName
|
|
);
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
rc = GetExceptionCode();
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
{
|
|
rc = E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( rc );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
DWORD
|
|
ExtractSingleFileFromCabinet(
|
|
IN LPCSTR CabinetFileName,
|
|
IN LPCSTR TargetFileName,
|
|
IN LPCSTR FileNameInCabinet
|
|
)
|
|
{
|
|
HFDI hFDI;
|
|
OPCONTEXT Context;
|
|
ERF Erf;
|
|
DWORD rc;
|
|
|
|
memset( &Context, 0, sizeof( Context ));
|
|
Context.TargetFileName = TargetFileName;
|
|
Context.SymbolFileName = FileNameInCabinet;
|
|
Context.LastError = ERROR_FILE_NOT_FOUND;
|
|
|
|
memset( &Erf, 0, sizeof( Erf ));
|
|
|
|
hFDI = FDICreate(
|
|
FdiAlloc,
|
|
FdiFree,
|
|
FdiOpen,
|
|
FdiRead,
|
|
FdiWrite,
|
|
FdiClose,
|
|
FdiSeek,
|
|
cpuUNKNOWN,
|
|
&Erf
|
|
);
|
|
|
|
if ( hFDI == NULL )
|
|
{
|
|
Context.LastError = GetLastErrorWithDefault( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else
|
|
{
|
|
rc = FDICopy(
|
|
hFDI,
|
|
"",
|
|
(char *) CabinetFileName,
|
|
0,
|
|
FdiNotification,
|
|
NULL,
|
|
&Context
|
|
);
|
|
|
|
FDIDestroy( hFDI );
|
|
|
|
if (( rc == FALSE ) &&
|
|
( Context.LastError == ERROR_FILE_NOT_FOUND ))
|
|
{
|
|
switch ( Erf.erfOper )
|
|
{
|
|
case FDIERROR_NOT_A_CABINET:
|
|
case FDIERROR_UNKNOWN_CABINET_VERSION:
|
|
case FDIERROR_CORRUPT_CABINET:
|
|
case FDIERROR_BAD_COMPR_TYPE:
|
|
case FDIERROR_MDI_FAIL:
|
|
|
|
Context.LastError = ERROR_FILE_CORRUPT;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( Context.LastError );
|
|
}
|
|
|
|
|
|
DWORD
|
|
UncompressLZFile(
|
|
IN LPCSTR CompressedFileName,
|
|
IN LPCSTR UncompressedFileName
|
|
)
|
|
{
|
|
INT_PTR hSource;
|
|
int hSrc, hDst;
|
|
OFSTRUCT ofSrc, ofDst;
|
|
long l;
|
|
static unsigned char Signature[] = { 'S', 'Z', 'D', 'D', 0x88, 0xF0, 0x27, 0x33 };
|
|
unsigned char SignatureBuffer[ sizeof( Signature ) ];
|
|
|
|
//
|
|
// Make sure it really is an LZExpand file
|
|
//
|
|
|
|
memset( SignatureBuffer, 0xFF, sizeof( Signature ));
|
|
|
|
hSource = FdiOpen(
|
|
(char *) CompressedFileName,
|
|
_O_BINARY,
|
|
0
|
|
);
|
|
|
|
if ( hSource != -1 )
|
|
{
|
|
FdiRead( hSource, SignatureBuffer, sizeof( Signature ));
|
|
FdiClose( hSource );
|
|
}
|
|
|
|
if ( memcmp( Signature, SignatureBuffer, sizeof( Signature )))
|
|
{
|
|
return ERROR_FILE_CORRUPT;
|
|
}
|
|
|
|
//
|
|
// Use LZ32.DLL functions to decompress
|
|
//
|
|
|
|
hSrc = LZOpenFile(
|
|
(char *) CompressedFileName,
|
|
&ofSrc,
|
|
OF_READ | OF_SHARE_DENY_WRITE
|
|
);
|
|
|
|
if ( hSrc >= 0 )
|
|
{
|
|
hDst = LZOpenFile(
|
|
(char *) UncompressedFileName,
|
|
&ofDst,
|
|
OF_CREATE | OF_WRITE | OF_SHARE_EXCLUSIVE
|
|
);
|
|
|
|
if ( hDst >= 0 )
|
|
{
|
|
l = LZCopy( hSrc, hDst );
|
|
|
|
if ( l >= 0 )
|
|
{
|
|
l = 0;
|
|
}
|
|
|
|
LZClose( hDst );
|
|
}
|
|
else
|
|
{
|
|
l = hDst;
|
|
}
|
|
|
|
LZClose( hSrc );
|
|
}
|
|
else
|
|
{
|
|
l = hSrc;
|
|
}
|
|
|
|
switch( l )
|
|
{
|
|
case NO_ERROR:
|
|
return( NO_ERROR );
|
|
|
|
case LZERROR_BADINHANDLE:
|
|
case LZERROR_READ:
|
|
return( ERROR_READ_FAULT );
|
|
|
|
case LZERROR_BADOUTHANDLE:
|
|
case LZERROR_WRITE:
|
|
return( ERROR_WRITE_FAULT );
|
|
|
|
case LZERROR_GLOBALLOC:
|
|
case LZERROR_GLOBLOCK:
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
case LZERROR_BADVALUE:
|
|
case LZERROR_UNKNOWNALG:
|
|
return( ERROR_INVALID_DATA );
|
|
|
|
default:
|
|
return( ERROR_INVALID_FUNCTION );
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetLastErrorWithDefault(
|
|
DWORD DefaultError
|
|
)
|
|
{
|
|
DWORD LastError;
|
|
|
|
LastError = GetLastError();
|
|
|
|
if ( LastError == ERROR_SUCCESS )
|
|
{
|
|
LastError = DefaultError;
|
|
}
|
|
|
|
return( LastError );
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
FdiNotification(
|
|
FDINOTIFICATIONTYPE fdint,
|
|
PFDINOTIFICATION pfdin
|
|
)
|
|
{
|
|
OPCONTEXT * Context = (OPCONTEXT *) pfdin->pv;
|
|
FILETIME LocalTime;
|
|
FILETIME FileTime;
|
|
INT_PTR hFile;
|
|
|
|
switch ( fdint )
|
|
{
|
|
case fdintCOPY_FILE:
|
|
|
|
hFile = 0;
|
|
|
|
if ( _stricmp( pfdin->psz1, Context->SymbolFileName ) == 0 )
|
|
{
|
|
Context->FileSize = pfdin->cb;
|
|
|
|
hFile = FdiOpen(
|
|
(char *) Context->TargetFileName,
|
|
_O_CREAT,
|
|
0
|
|
);
|
|
|
|
if ( hFile == -1 )
|
|
{
|
|
Context->LastError = GetLastErrorWithDefault( ERROR_CANNOT_MAKE );
|
|
}
|
|
}
|
|
|
|
return( hFile ); // 0 = skip, -1 = abort, other = handle
|
|
|
|
case fdintCLOSE_FILE_INFO:
|
|
|
|
if ( DosDateTimeToFileTime( pfdin->date, pfdin->time, &LocalTime ) &&
|
|
LocalFileTimeToFileTime( &LocalTime, &FileTime ))
|
|
{
|
|
SetFileTime(
|
|
(HANDLE) pfdin->hf,
|
|
NULL,
|
|
NULL,
|
|
&FileTime // last-modified date/time
|
|
);
|
|
}
|
|
|
|
if ( GetFileSize( (HANDLE) pfdin->hf, NULL ) == Context->FileSize )
|
|
{
|
|
Context->LastError = ERROR_SUCCESS;
|
|
}
|
|
|
|
FdiClose( pfdin->hf );
|
|
|
|
return 0;
|
|
|
|
case fdintNEXT_CABINET:
|
|
|
|
return -1; // multi-part cabinets not supported
|
|
|
|
default:
|
|
|
|
return 0; // disregard any other messages
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// FDI I/O callback functions
|
|
//
|
|
|
|
void HUGE *
|
|
FAR DIAMONDAPI
|
|
FdiAlloc(
|
|
ULONG cb
|
|
)
|
|
{
|
|
void HUGE * pv;
|
|
|
|
pv = LocalAlloc(LPTR, cb);
|
|
|
|
return( pv );
|
|
}
|
|
|
|
|
|
void
|
|
FAR DIAMONDAPI
|
|
FdiFree(
|
|
void HUGE *pv
|
|
)
|
|
{
|
|
LocalFree( pv );
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
FAR DIAMONDAPI
|
|
FdiOpen(
|
|
char FAR *pszFile,
|
|
int oflag,
|
|
int pmode
|
|
)
|
|
{
|
|
HANDLE Handle;
|
|
BOOL Create = ( oflag & _O_CREAT );
|
|
|
|
Handle = CreateFile(
|
|
pszFile,
|
|
Create ? GENERIC_WRITE : GENERIC_READ,
|
|
Create ? 0 : FILE_SHARE_READ,
|
|
NULL,
|
|
Create ? CREATE_ALWAYS : OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if ( Handle == INVALID_HANDLE_VALUE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
return( (INT_PTR) Handle );
|
|
}
|
|
|
|
|
|
UINT
|
|
FAR DIAMONDAPI
|
|
FdiRead(
|
|
INT_PTR hf,
|
|
void FAR *pv,
|
|
UINT cb
|
|
)
|
|
{
|
|
BOOL rc;
|
|
DWORD cbActual;
|
|
|
|
rc = ReadFile((HANDLE)hf,
|
|
pv,
|
|
cb,
|
|
&cbActual,
|
|
NULL);
|
|
|
|
return rc ? cbActual : 0;
|
|
}
|
|
|
|
|
|
UINT
|
|
FAR DIAMONDAPI
|
|
FdiWrite(
|
|
INT_PTR hf,
|
|
void FAR *pv,
|
|
UINT cb
|
|
)
|
|
{
|
|
DWORD cbActual = 0;
|
|
|
|
WriteFile((HANDLE)hf,
|
|
pv,
|
|
cb,
|
|
&cbActual,
|
|
NULL);
|
|
|
|
return cbActual;
|
|
}
|
|
|
|
|
|
long
|
|
FAR DIAMONDAPI
|
|
FdiSeek(
|
|
INT_PTR hf,
|
|
long dist,
|
|
int seektype
|
|
)
|
|
{
|
|
long result;
|
|
DWORD NewPosition;
|
|
|
|
NewPosition = SetFilePointer(
|
|
(HANDLE) hf,
|
|
dist,
|
|
NULL,
|
|
(DWORD) seektype
|
|
);
|
|
|
|
if ( NewPosition == INVALID_SET_FILE_POINTER )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
return( (long) NewPosition );
|
|
}
|
|
|
|
|
|
int
|
|
FAR DIAMONDAPI
|
|
FdiClose(
|
|
INT_PTR hf
|
|
)
|
|
{
|
|
if ( ! CloseHandle( (HANDLE) hf ))
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|