#include "pch.h" #include #include #include #include #include #include #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 ); }