www.pudn.com > cab文件压缩、解压程序源代码.rar > Cabinet.hpp
//--------------------------------------------------------------------------- // Copyright (C) 1998, Interscope Ltd. All rights reserved. // Reproduction or distribution of this program, or any portion of it, // is permitted only if this header is kept as it is. // For more information, contact: // // Interscope Ltd., 5 Culturii St., 5th floor, 4800 Baia Mare, Romania // Phone/Fax: +40-62-215023 // E-mail: office@interscope.ro // // $Author: Levente Farkas $ // $Date: 5/13/98 12:02a $ // $Modtime: 4/27/98 6:50a $ // $Revision: 51 $ // $Archive: /Interscope/Thebe/InstallMaster/Cabinet.hpp $ // $Workfile: Cabinet.hpp $ //----------------------------------------------------------------------- #ifndef __Cabinet_Hpp__ #define __Cabinet_Hpp__ // Define the following symbol if compiling using precompiled headers through // header file StdAfx.H // #define __STDAFX__ // // Define the following symbol if used in a MFC project // #define __MFC__ #ifdef __MFC__ #undef __STDAFX__ #define __STDAFX__ #endif // If you want 2 trace the progress of compression/decompression, define the // symbols below // #define __TRACE_CAB_MEMORY__ // #define __TRACE_CAB_COMPRESSION__ // #define __TRACE_CAB_EXTRACTION__ // Define one of the following symbols 2 include only the code you need // in your project // #define __CAB_BUILD__ // #define __CAB_EXTRACT__ #if !defined(__CAB_BUILD__) && !defined(__CAB_EXTRACT__) #error You did not specified what cabinet functionality to include #endif #include#include "Portable.H" #include "StringHelper.Hpp" #include "Path.Hpp" #ifdef __CAB_BUILD__ #include "FCI.H" // File Compression Interface #endif #ifdef __CAB_EXTRACT__ #include "FDI.H" // File Decompression Interface #endif using namespace std; //--- Cabinet handler base ----------------------------------------------- // These classes implement cabinet file (.CAB) file handlig. They require the // code of the Microsoft Cabinet API and the headers and sources that implement // C wrappers for the API. These reside in the files CABINET.DLL (the API code) and // in the files FCI.H, FDI.H, FCIDLL.C and FDIDLL.C. These files are part of the // Microsoft Cabinet SDK which can be obtained from Microsft SiteBuilder website // at http://www.microsoft.com/sbnmember/download/download.asp // // Warning: These classes are not thread safe. So, do not mess with the same instance // of either CCabinetBuilder or CCabinetExtractor from withing different threads // However, since each instance of these classes keeps its own compression/decompression // context, you can use multiple instances and you even can instantiate separate instances // in separate threads class CCabinetBase { // Data members protected: ERF m_CabinetError; BOOL m_bStatus; // TRUE when everything is OK public: CPath m_CabinetPath; string m_strCabinetName; // Implementation public: CCabinetBase(): m_bStatus(FALSE) { ZeroMemory(&m_CabinetError,sizeof(m_CabinetError)); } BOOL GetStatus() const { return m_bStatus && !m_CabinetError.fError; } int GetErrorCode() const { return m_CabinetError.erfOper; } int GetErrorCodeEx() const { return m_CabinetError.erfType; } // Callbacks protected: static void HUGE * FAR DIAMONDAPI MemAlloc(ULONG cbSize); static void FAR DIAMONDAPI MemFree(void HUGE *ptrMemory); static int FAR DIAMONDAPI FileOpen(char FAR *pszFile, int oFlag, int pMode, int FAR *ptrErr, void FAR *pv); static UINT FAR DIAMONDAPI FileRead (int hFile, void FAR *ptrBuffer, UINT cbRead, int FAR *ptrErr, void FAR *pv); static UINT FAR DIAMONDAPI FileWrite(int hFile, void FAR *ptrBuffer, UINT cbWrite, int FAR *ptrErr, void FAR *pv); static long FAR DIAMONDAPI FileSeek (int hFile, long offset, int seekType, int FAR *ptrErr, void FAR *pv); static int FAR DIAMONDAPI FileClose(int hFile, int FAR *ptrErr, void FAR *pv); }; //--- Class 4 cabinet creation ------------------------------------------- #ifdef __CAB_BUILD__ // Warning: File paths are not stored in the .CAB file(s), so that you will // have 2 remember or know where 2 extract them later class CCabinetBuilder: public CCabinetBase { // Data members protected: HFCI m_hContext; CCAB m_CabinetInfo; int m_nLastStartDisk; string m_strLastCabinet; public: string m_strDiskName; ULONG m_cbFirstCabSize; // Size 4 the first .CAB file ULONG m_cbCabSize; // Size 4 the rest of the .CAB files ULONG m_cbTreshold; // Flush 2 cabinet after each block of this size USHORT m_nID; // Unique ID UINT m_cbReserveCFHeader; // Space to reserve in CFHEADER UINT m_cbReserveCFFolder; // Space to reserve in CFFOLDER UINT m_cbReserveCFData; // Space to reserve in CFDATA // Construction and destruction public: CCabinetBuilder(USHORT nID, ULONG cbFirstCabSize, ULONG cbCabSize, ULONG cbTreshold); BOOL InitCabinet(LPCTSTR lpcszCabPath, LPCTSTR lpcszCabName, LPCTSTR lpcszDiskName, BOOL bCreatePath =TRUE); void ReserveHeader(UINT reserve) { m_cbReserveCFHeader =reserve; } void ReserveFolder(UINT reserve) { m_cbReserveCFFolder =reserve; } void ReserveData(UINT reserve) { m_cbReserveCFData =reserve; } BOOL AddFile(LPTSTR lpszFileName, LPTSTR lpszStoreAs =NULL, BOOL bCompress =TRUE, BOOL bExecuteOnExtract =FALSE); BOOL FlushFolder(); BOOL FlushCabinet(); void WaitUntilDone() { FlushCabinet(); } virtual ~CCabinetBuilder(); // Callbacks protected: static int FAR DIAMONDAPI FileDelete(char FAR *pszFile, int FAR *ptrErr, void FAR *pv); static BOOL FAR DIAMONDAPI GetTempFile(char *pszTempName, int cbTempName, void FAR *pv); static int FAR DIAMONDAPI GetFileInfo(char *pszName, USHORT *pdate, USHORT *ptime, USHORT *pattribs, int FAR *ptrErr, void FAR *pv); static BOOL FAR DIAMONDAPI GetNextCabinet(PCCAB pccab, ULONG cbPrevCab, void FAR *pv); static int FAR DIAMONDAPI NotifyFilePlaced(PCCAB pccab, char *pszFile, long cbFile, BOOL bContinuation, void FAR *pv); static long FAR DIAMONDAPI NotifyProgress(UINT typeStatus, ULONG cb1, ULONG cb2, void FAR *pv); // Callback helpers protected: virtual PFNFCIALLOC MemAllocProc() const { return CCabinetBase::MemAlloc; } virtual PFNFCIFREE MemFreeProc() const { return CCabinetBase::MemFree; } virtual PFNFCIOPEN FileOpenProc() const { return CCabinetBase::FileOpen; } virtual PFNFCIREAD FileReadProc() const { return CCabinetBase::FileRead; } virtual PFNFCIWRITE FileWriteProc() const { return CCabinetBase::FileWrite; } virtual PFNFCISEEK FileSeekProc() const { return CCabinetBase::FileSeek; } virtual PFNFCICLOSE FileCloseProc() const { return CCabinetBase::FileClose; } virtual PFNFCIDELETE FileDeleteProc() const { return CCabinetBuilder::FileDelete; } virtual PFNFCIGETTEMPFILE GetTempFileProc() const { return CCabinetBuilder::GetTempFile; } virtual PFNFCIGETOPENINFO GetFileInfoProc() const { return CCabinetBuilder::GetFileInfo; } virtual PFNFCIGETNEXTCABINET GetNextCabinetProc() const { return CCabinetBuilder::GetNextCabinet; } virtual PFNFCISTATUS NotifyProgressProc() const { return CCabinetBuilder::NotifyProgress; } virtual PFNFCIFILEPLACED NotifyFilePlacedProc() const { return CCabinetBuilder::NotifyFilePlaced; } // Miscellaneous helpers public: virtual void ManufactureDiskName(PCCAB cabinfo); virtual void ManufactureCabinetName(PCCAB cabinfo); protected: virtual BOOL NotifyPlaced(char *pszFile, long cbFile, BOOL bContinuation, int nDisk, char *pszCabinet); virtual BOOL NotifyCompress(ULONG cbOriginal, ULONG cbCompressed); virtual BOOL NotifyFolderFlush(ULONG cbSize, ULONG cbWritten); virtual ULONG NotifyCabinetFlush(ULONG cbEstimatedSize, ULONG cbActualSize); }; #endif //--- Compression errors --------------------------------------------------- // Clients can retrieve the error code of the last cabinet operation using the // GetErrorCode and GetErrorCodeEx (additional error info) members // Possible values returned by GetErrorCode are: // FCIERR_NONE No error // FCIERR_OPEN_SRC Failure opening file to be stored in cabinet // Use GetErrorCodeEx 2 get C run-time *errno* value // FCIERR_READ_SRC Failure reading file to be stored in cabinet // Use GetErrorCodeEx 2 get C run-time *errno* value // FCIERR_ALLOC_FAIL Out of memory // FCIERR_TEMP_FILE Could not create a temporary file // Use GetErrorCodeEx 2 get C run-time *errno* value // FCIERR_BAD_COMPR_TYPE Unknown compression type // FCIERR_CAB_FILE Could not create cabinet file // Use GetErrorCodeEx 2 get C run-time *errno* value // FCIERR_USER_ABORT Client requested abort // FCIERR_MCI_FAIL Failure compressing data //--- Structure 2 hold information about a cabinet file -------------------- #ifdef __CAB_EXTRACT__ struct CABINETINFO { long m_cbSize; // Total length of cabinet file USHORT m_nFolders; // Count of folders in cabinet USHORT m_nFiles; // Count of files in cabinet USHORT m_nID; // Cabinet set ID USHORT m_nIndex; // Cabinet number in set (0 based) BOOL m_bHasReservedSpace; // TRUE if there are reserved areas present in cabinet BOOL m_bChainedPrev; // TRUE if cabinet is chained prev BOOL m_bChainedNext; // TRUE if cabinet is chained next }; #endif #define MAX_CABINETS_IN_SET 50 //--- Class 4 cabinet extraction ------------------------------------------ #ifdef __CAB_EXTRACT__ class CCabinetExtractor: public CCabinetBase { // Data members private: CPath m_NextCabinet; string m_strNextDisk; int m_nNextIndex; CPath m_ContinueCabinet; string m_strContinueDisk; int m_nContinueIndex; BOOL m_bLastFileSkipped; BOOL m_bNextCabinetReady; protected: HFDI m_hContext; int m_nLastFileStartCabinetIndex; int m_nLastFileEndCabinetIndex; BOOL m_bCabinetSetFinished; public: CPath m_DefaultExtractPath; CPath m_LastExtracted; // Last extracted file (real path, where file was extracted) // Construction and destruction public: CCabinetExtractor(); BOOL GetCabinetInfo(LPCTSTR lpcszCabFile, CABINETINFO *lpInfo =NULL); void SetDefaultExtractPath(LPCTSTR lpcszDefExtractPath); BOOL ExtractFiles(LPCTSTR lpcszCabFile, BOOL bContinuous =TRUE); virtual ~CCabinetExtractor(); // Callbacks protected: static int FAR DIAMONDAPI FileOpen(char FAR *pszFile, int oFlag, int pMode); static UINT FAR DIAMONDAPI FileRead(int hFile, void FAR *ptrBuffer, UINT cbRead); static UINT FAR DIAMONDAPI FileWrite(int hFile, void FAR *ptrBuffer, UINT cbWrite); static int FAR DIAMONDAPI FileClose(int hFile); static long FAR DIAMONDAPI FileSeek(int hFile, long offset, int seekType); static int FAR DIAMONDAPI NotifyProgress(FDINOTIFICATIONTYPE notifyType, PFDINOTIFICATION notifyInfo); // Callback helpers protected: virtual PFNALLOC MemAllocProc() const { return CCabinetBase::MemAlloc; } virtual PFNFREE MemFreeProc() const { return CCabinetBase::MemFree; } virtual PFNOPEN FileOpenProc() const { return CCabinetExtractor::FileOpen; } virtual PFNREAD FileReadProc() const { return CCabinetExtractor::FileRead; } virtual PFNWRITE FileWriteProc() const { return CCabinetExtractor::FileWrite; } virtual PFNSEEK FileSeekProc() const { return CCabinetExtractor::FileSeek; } virtual PFNCLOSE FileCloseProc() const { return CCabinetExtractor::FileClose; } virtual PFNFDINOTIFY NotifyProgressProc() const { return CCabinetExtractor::NotifyProgress; } // Miscellaneous helpers protected: virtual BOOL NotifyCabinetInfo(USHORT nID, LPCTSTR lpcszCabPath, LPCTSTR lpcszCabName, LPCTSTR lpcszDiskName, USHORT nCabIndex); virtual BOOL NotifyPartialFile(LPCTSTR lpcszFileName, LPCTSTR lpcszFirstCab, LPCTSTR lpcszFirstDisk); virtual BOOL NotifyFileCopy(LPCTSTR lpcszFileName, ULONG cbSize, string &strExtractTo, BOOL &bSkipFile); virtual BOOL NotifyFileCopied(LPCTSTR lpcszFileName, USHORT &nDate, USHORT &nTime, USHORT &nAttribs); virtual BOOL NotifyFileCopiedAndClosed(LPCTSTR lpcszFileName); virtual BOOL NotifyEnumerate(USHORT nID, long &nCurrentPosition, USHORT &nFilesRemaining); virtual BOOL NotifyNextCabinet(LPCTSTR lpcszNextCab, LPCTSTR lpcszNextDisk, string &strNextCabPath, int nErrorCode); }; #endif //--- Decompression errors ------------------------------------------------------- // Clients can retrieve the error code of the last cabinet operation using the // GetErrorCode and GetErrorCodeEx (additional error info) members // Possible values returned by GetErrorCode are: // FDIERROR_NONE No error // FDIERROR_CABINET_NOT_FOUND Cabinet not found // Bad file name or path passed to FDICopy(), or returned // to fdintNEXT_CABINET // FDIERROR_NOT_A_CABINET Cabinet file does not have the correct format // File passed to to FDICopy(), or returned to // fdintNEXT_CABINET, is too small to be a cabinet file, // or does not have the cabinet signature in its first 4 bytes // FDIERROR_UNKNOWN_CABINET_VERSION Cabinet file has an unknown version number // File passed to to FDICopy(), or returned to // fdintNEXT_CABINET, has what looks like a cabinet file // header, but the version of the cabinet file format // is not one understood by this version of FDI. The // erf.erfType field is filled in with the version number // found in the cabinet file // FDIERROR_CORRUPT_CABINET Cabinet file is corrupt // FDI returns this error any time it finds a problem // with the logical format of a cabinet file, and any // time one of the passed-in file I/O calls fails when // operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD, // or PFNCLOSE). The client can distinguish these two // cases based upon whether the last file I/O call // failed or not // Assuming this is not a real corruption problem in // a cabinet file, the file I/O functions could attempt // to do retries on failure (for example, if there is a // temporary network connection problem). If this does // not work, and the file I/O call has to fail, then the // FDI client will have to clean up and call the // FDICopy() function again. // FDIERROR_ALLOC_FAIL Could not allocate enough memory // FDI tried to allocate memory with the PFNALLOC // function, but it failed // If possible, PFNALLOC should take whatever steps // are possible to allocate the memory requested. If // memory is not immediately available, it might post a // dialog asking the user to free memory, for example. // Note that the bulk of FDI's memory allocations are // made at FDICreate() time and when the first cabinet // file is opened during FDICopy() // FDIERROR_BAD_COMPR_TYPE Unknown compression type in a cabinet folder [Should never happen] // A folder in a cabinet has an unknown compression type. // This is probably caused by a mismatch between the version of FCI.LIB // used to create the cabinet and the FDI.LIB used to read the cabinet // FDIERROR_MDI_FAIL Failure decompressing data from a cabinet file // The decompressor found an error in the data coming // from the file cabinet. The cabinet file was corrupted. // [When checksuming is turned on, this error should never occur] // FDIERROR_TARGET_FILE Failure writing to target file // FDI returns this error any time it gets an error back // from one of the passed-in file I/O calls fails when // writing to a file being extracted from a cabinet // To avoid or minimize this error, the file I/O functions // could attempt to avoid failing. A common cause might // be disk full. In this case, the PFNWRITE function // could have a check for free space, and put up a dialog // asking the user to free some disk space. // FDIERROR_RESERVE_MISMATCH Cabinets in a set do not have the same RESERVE sizes [Should never happen] // FDI requires that the sizes of the per-cabinet, per-folder, // and per-data block RESERVE sections be consistent across all the // cabinets in a set // FDIERROR_WRONG_CABINET Cabinet returned on fdintNEXT_CABINET is incorrect // Note: This error is NEVER returned by FDICopy() // Rather, FDICopy() keeps calling the fdintNEXT_CABINET // callback until either the correct cabinet is specified, // or you return ABORT. // When FDICopy() is extracting a file that crosses a // cabinet boundary, it calls fdintNEXT_CABINET to ask // for the path to the next cabinet. Not being very // trusting, FDI then checks to make sure that the // correct continuation cabinet was supplied. It does // this by checking the "setID" and "iCabinet" fields // in the cabinet. FDI makes sure that the 16-bit // setID of the continuation cabinet matches the // cabinet file just processed, then checks that // the cabinet number (iCabinet) is one more than the // cabinet number for the cabinet just processed // FDIERROR_USER_ABORT Client requested abort #endif