/*++ Module Name: diamond.c Abstract: Diamond compression interface. This module contains functions to compress a file using the mszip compression library. Author: Ted Miller Environment: Windows --*/ #include #include #include //#include "main.h" //#include //#include "mydiam.h" #include "pch.h" CHAR MakeCompressedName( LPSTR ); typedef struct _DIAMOND_INFO { DWORD SourceFileSize; DWORD CompressedSize; FILETIME SourceFileCreationTime; FILETIME SourceFileModifiedTime; FILETIME SourceFileAccessedTime; } DIAMOND_INFO, *PDIAMOND_INFO; // // Callback functions to perform memory allocation, io, etc. // We pass addresses of these functions to diamond. // int DIAMONDAPI fciFilePlacedCB( OUT PCCAB Cabinet, IN LPSTR FileName, IN LONG FileSize, IN BOOL Continuation, IN PVOID Context ) /*++ Routine Description: Callback used by diamond to indicate that a file has been comitted to a cabinet. No action is taken and success is returned. Arguments: Cabinet - cabinet structure to fill in. FileName - name of file in cabinet FileSize - size of file in cabinet Continuation - TRUE if this is a partial file, continuation of compression begun in a different cabinet. Context - supplies context information. Return Value: 0 (success). --*/ { UNREFERENCED_PARAMETER(Cabinet); UNREFERENCED_PARAMETER(FileName); UNREFERENCED_PARAMETER(FileSize); UNREFERENCED_PARAMETER(Continuation); UNREFERENCED_PARAMETER(Context); return(0); } PVOID DIAMONDAPI fciAllocCB( IN ULONG NumberOfBytes ) /*++ Routine Description: Callback used by diamond 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 fciFreeCB( IN PVOID Block ) /*++ Routine Description: Callback used by diamond to free a memory block. The block must have been allocated with fciAlloc(). Arguments: Block - supplies pointer to block of memory to be freed. Return Value: None. --*/ { LocalFree((HLOCAL)Block); } FNFCIGETTEMPFILE(fciTempFileCB) { CHAR TempPath[MAX_PATH]; DWORD cchTemp; cchTemp = GetTempPathA(sizeof(TempPath),TempPath); if ((cchTemp == 0) || (cchTemp >= sizeof(TempPath))) { TempPath[0] = '.'; TempPath[1] = '\0'; } if(GetTempFileNameA(TempPath,"dc",0,pszTempName)) { DeleteFileA(pszTempName); } return(TRUE); } BOOL DIAMONDAPI fciNextCabinetCB( OUT PCCAB Cabinet, IN DWORD CabinetSizeEstimate, IN PVOID Context ) /*++ Routine Description: Callback used by diamond to request a new cabinet file. This functionality is not used in our implementation as we deal only with single-file cabinets. Arguments: Cabinet - cabinet structure to be filled in. CabinetSizeEstimate - estimated size of cabinet. Context - supplies context information. Return Value: FALSE (failure). --*/ { UNREFERENCED_PARAMETER(Cabinet); UNREFERENCED_PARAMETER(CabinetSizeEstimate); UNREFERENCED_PARAMETER(Context); return(FALSE); } BOOL DIAMONDAPI fciStatusCB( IN UINT StatusType, IN DWORD Count1, IN DWORD Count2, IN PVOID Context ) /*++ Routine Description: Callback used by diamond to give status on file compression and cabinet operations, etc. Arguments: Status Type - supplies status type. 0 = statusFile - compressing block into a folder. Count1 = compressed size Count2 = uncompressed size 1 = statusFolder - performing AddFilder. Count1 = bytes done Count2 = total bytes Context - supplies context info. Return Value: TRUE (success). --*/ { PDIAMOND_INFO context; UNREFERENCED_PARAMETER(Count2); context = (PDIAMOND_INFO)Context; if(StatusType == statusFile) { // // Track compressed size. // context->CompressedSize += Count1; } return(TRUE); } FNFCIGETOPENINFO(fciOpenInfoCB) { int h; WIN32_FIND_DATAA FindData; HANDLE FindHandle; PDIAMOND_INFO context; FILETIME ftLocal; context = pv; FindHandle = FindFirstFileA(pszName,&FindData); if(FindHandle == INVALID_HANDLE_VALUE) { return(-1); } FindClose(FindHandle); context->SourceFileSize = FindData.nFileSizeLow; context->SourceFileCreationTime = FindData.ftCreationTime; context->SourceFileModifiedTime = FindData.ftLastWriteTime; context->SourceFileAccessedTime = FindData.ftLastAccessTime; FileTimeToLocalFileTime(&FindData.ftLastWriteTime, &ftLocal); FileTimeToDosDateTime(&ftLocal, pdate, ptime); *pattribs = (WORD)(FindData.dwFileAttributes & ( FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE )); h = _open(pszName,_O_RDONLY | _O_BINARY); if(h == -1) { return(-1); } return(h); } FNFCIOPEN(fciOpen) { int result; result = _open(pszFile, oflag, pmode); if (result == -1) { *err = errno; } return(result); } FNFCIREAD(fciRead) { UINT result; result = (UINT) _read((HFILE)hf, memory, cb); if (result != cb) { *err = errno; } return(result); } FNFCIWRITE(fciWrite) { UINT result; result = (UINT) _write((HFILE)hf, memory, cb); if (result != cb) { *err = errno; } return(result); } FNFCICLOSE(fciClose) { int result; result = _close((HFILE)hf); if (result == -1) { *err = errno; } return(result); } FNFCISEEK(fciSeek) { long result; result = _lseek((HFILE)hf, dist, seektype); if (result == -1) { *err = errno; } return(result); } FNFCIDELETE(fciDelete) { int result; result = _unlink(pszFile); if (result == -1) { *err = errno; } return(result); } INT DiamondCompressFile( IN NOTIFYPROC CompressNotify, IN LPSTR SourceFile, IN LPSTR TargetFile, IN BOOL Rename, OUT PLZINFO pLZI ) { BOOL b; LPSTR SourceFilenamePart,p; HFCI FciContext; ERF FciError; CCAB ccab; CHAR targetFile[MAX_PATH]; WCHAR wszSourceFile[MAX_PATH] = NULL_STRING; WCHAR wszTargetFile[MAX_PATH] = NULL_STRING; DIAMOND_INFO Context; INT Status; __try { // // Isolate the filename part of the source file. // if(SourceFilenamePart = strrchr(SourceFile, '\\')) { SourceFilenamePart++; } else { SourceFilenamePart = SourceFile; } // // Form the actual name of the target file. // strcpy(targetFile,TargetFile); if(Rename) { MakeCompressedName(targetFile); } // // Fill in the cabinet structure. // ZeroMemory(&ccab,sizeof(ccab)); lstrcpyA(ccab.szCabPath, targetFile); if(p=strrchr(ccab.szCabPath,'\\')) { lstrcpyA(ccab.szCab,++p); *p = 0; } else { lstrcpyA(ccab.szCab,targetFile); ccab.szCabPath[0] = 0; } // // Call the notification function to see whether we are really // supposed to compress this file. // MultiByteToWideChar( CP_THREAD_ACP, 0, SourceFile, strlen(SourceFile), wszSourceFile, MAX_PATH ); MultiByteToWideChar( CP_THREAD_ACP, 0, targetFile, strlen(targetFile), wszTargetFile, MAX_PATH ); if(!CompressNotify(wszSourceFile,wszTargetFile,NOTIFY_START_COMPRESS)) { Status = BLANK_ERROR; __leave; } ZeroMemory(&Context,sizeof(Context)); // // Compress the file. // FciContext = FCICreate( &FciError, fciFilePlacedCB, fciAllocCB, fciFreeCB, fciOpen, fciRead, fciWrite, fciClose, fciSeek, fciDelete, fciTempFileCB, &ccab, &Context ); if(FciContext) { b = FCIAddFile( FciContext, SourceFile, // file to add to cabinet. SourceFilenamePart, // filename part, name to store in cabinet. FALSE, fciNextCabinetCB, // routine for next cabinet (always fails) fciStatusCB, fciOpenInfoCB, DiamondCompressionType ); if(b) { b = FCIFlushCabinet( FciContext, FALSE, fciNextCabinetCB, fciStatusCB ); if(b) { HANDLE FindHandle; WIN32_FIND_DATA FindData; // // Context.CompressedSize does not include headers // and any other file overhead. // FindHandle = FindFirstFile((LPCWSTR)targetFile,&FindData); if(FindHandle == INVALID_HANDLE_VALUE) { pLZI->cblOutSize = (LONG)Context.CompressedSize; } else { pLZI->cblOutSize = (LONG)FindData.nFileSizeLow; FindClose(FindHandle); } pLZI->cblInSize = (LONG)Context.SourceFileSize; FindHandle = CreateFile((LPWSTR)targetFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (FindHandle != INVALID_HANDLE_VALUE) { SetFileTime(FindHandle, &Context.SourceFileCreationTime, &Context.SourceFileAccessedTime, &Context.SourceFileModifiedTime); CloseHandle(FindHandle); } } } if(b) { Status = TRUE; } else { switch(FciError.erfOper) { case FCIERR_OPEN_SRC: Status = LZERROR_BADINHANDLE; break; case FCIERR_READ_SRC: Status = LZERROR_READ; break; case FCIERR_CAB_FILE: Status = LZERROR_WRITE; break; case FCIERR_ALLOC_FAIL: Status = LZERROR_GLOBALLOC; break; case FCIERR_TEMP_FILE: case FCIERR_BAD_COMPR_TYPE: case FCIERR_USER_ABORT: case FCIERR_MCI_FAIL: default: Status = FALSE; } } FCIDestroy(FciContext); } else { Status = LZERROR_GLOBALLOC; } } __except(EXCEPTION_EXECUTE_HANDLER) { Status = GetLastError(); } return(Status); } CHAR MakeCompressedName(CHAR ARG_PTR *pszFileName) { CHAR chReplaced = '\0'; ULONG NameLength = strlen( pszFileName ); ULONG DotIndex = NameLength; while (( DotIndex > 0 ) && ( pszFileName[ --DotIndex ] != '.' )) { if (( pszFileName[ DotIndex ] == '\\' ) || ( pszFileName[ DotIndex ] == ':' )) { // end of filename part of path DotIndex = 0; // name has no extension break; } } if ( DotIndex > 0 ) { // name has an extension if (( NameLength - DotIndex ) <= 3 ) { // extension less than 3 chars pszFileName[ NameLength++ ] = '_'; // append '_' to extension pszFileName[ NameLength ] = 0; // terminate } else { // extension more than 3 chars chReplaced = pszFileName[ NameLength - 1 ]; // return original pszFileName[ NameLength - 1 ] = '_'; // replace last char with '_' } } else { // name has no extension pszFileName[ NameLength++ ] = '.'; // append '.' pszFileName[ NameLength++ ] = '_'; // append '_' pszFileName[ NameLength ] = 0; // terminate } return(chReplaced); }