//////////////////////////////////////////////////////////////////////////////////////////////////////概述://基于系统函数的文件压缩解压缩包实现类////日期://2008 年 1 月 12 日////作者://王志科////内容:// CEncryptImpl 对数据进行加密// CDecryptImpl 对数据进行解密////<1> CPackageImpl 文件打包实现类//<2> CExtractImpl 文件解包实现类//<3> CExpressImpl 内存解包实现类//<4> CStorageImpl 资源解包实现类////<5> CFilePackage 文件打包包装类//<6> CFileExtract 文件解包包装类//<7> CFileExpress 内存解包包装类//<8> CFileStorage 资源解包包装类////备注://<1> 由于 FCI 需要的都是 ANSI 格式的参数,所以使用了大量 ANSI API,一些调用时需要转换参数//<2> 对加解密的支持采用策略的方式提供,可以参考系统的 CryptGraphics 服务提供的函数////////////////////////////////////////////////////////////////////////////////////////////////////#pragmaonce#include#include#include#include#include#include#include#pragmawarning( push )#pragmacomment( lib , "Cabinet" )//==================================================================================================#defineFOLDER_THRESHOLD 900000//==================================================================================================#ifndef CHK_EXP_RET#defineCHK_EXP_RET( exp , ret ) if( exp ) { return ret ; }#endif//==================================================================================================namespaceCabinet
{//==============================================================================================templateclassCEncryptImpl
{public:
BOOL SetEncryptKey(LPVOID lpKey, DWORD dwSize)
{returnTRUE;
}
BOOL EncryptData(LPVOID lpData, DWORD dwData)
{returnTRUE;
}
};
templateclassCDecryptImpl
{public:
BOOL SetDecryptKey(LPVOID lpKey, DWORD dwSize)
{returnTRUE;
}
BOOL DecryptData(LPVOID lpData, DWORD dwData)
{returnTRUE;
}
};//==============================================================================================template>classCPackageImpl :publicEncryptT
{public:
CPackageImpl()
{
Initialize();
}~CPackageImpl()
{
DestroyContext();
}public:
BOOL CreateContext(LPCSTR lpszPathFile, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{//校验输入参数CHK_EXP_RET(lpszPathFile==NULL, FALSE );
CHK_EXP_RET( strlen(lpszPathFile)<6, FALSE );
CHK_EXP_RET( IsBadReadPtr(lpszPathFile,6), FALSE );//准备参数CHAR szPathFile[MAX_PATH]={""};
strncpy(szPathFile, lpszPathFile, MAX_PATH);
LPCSTR lpszFile=PathFindFileNameA(szPathFile);
CHK_EXP_RET(lpszFile==szPathFile, ERROR_PATH_NOT_FOUND);//处理数据并调用函数szPathFile[lpszFile-szPathFile-1]=0;returnCreateContext(szPathFile, lpszFile, nSplitSize, wCabinetID);
}
BOOL CreateContext(LPCSTR lpszPath, LPCSTR lpszFile, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{//校验输入参数CHK_EXP_RET(lpszPath==NULL, FALSE );
CHK_EXP_RET(lpszFile==NULL, FALSE );
CHK_EXP_RET( strlen(lpszPath)<2, FALSE );
CHK_EXP_RET( strlen(lpszFile)<2, FALSE );
CHK_EXP_RET( IsBadReadPtr(lpszPath,2), FALSE );
CHK_EXP_RET( IsBadReadPtr(lpszFile,2), FALSE );
m_bAutoFlush=TRUE;
m_bOperAbort=FALSE;
T*pT=static_cast(this);
CHK_EXP_RET(!pT->OnPrepareCreate(m_xPackage,lpszPath,lpszFile,nSplitSize,wCabinetID) , FALSE );
m_hContext=FCICreate(&m_xError, FCI_FilePlaced, FCI_Alloc, FCI_Free, FCI_Open, FCI_Read, FCI_Write,
FCI_Close, FCI_Seek, FCI_Delete, FCI_GetTempFile,&m_xPackage,this);return(m_hContext!=NULL);
}
BOOL DestroyContext()
{
CHK_EXP_RET( m_hContext==NULL , TRUE );
CHK_EXP_RET(m_bAutoFlush&&!FlushCabinet(FALSE) , FALSE );
CHK_EXP_RET(!FCIDestroy(m_hContext) , FALSE );
m_hContext=NULL;returnTRUE;
}
VOID AbortPackage()
{
m_bOperAbort=TRUE;
}
BOOL FlushFolder()
{
ATLASSERT( m_hContext!=NULL );
CHK_EXP_RET( m_hContext==NULL , FALSE );returnFCIFlushFolder(m_hContext, FCI_GetNextCabinet, FCI_UpdateStatus);
}
BOOL FlushCabinet(BOOL bCreateNewCabinetFile=FALSE)
{
ATLASSERT( m_hContext!=NULL );
CHK_EXP_RET( m_hContext==NULL , FALSE );returnFCIFlushCabinet(m_hContext,bCreateNewCabinetFile,FCI_GetNextCabinet,FCI_UpdateStatus);
}
BOOL AddFile(LPSTR szFileToAdd, LPSTR szNameInCab=NULL)
{
ATLASSERT(m_hContext!=NULL);
CHK_EXP_RET( m_hContext==NULL , FALSE );
m_bAutoFlush=TRUE;//必须刷新才行szNameInCab=szNameInCab?szNameInCab : PathFindFileNameA(szFileToAdd);returnFCIAddFile(m_hContext,szFileToAdd,szNameInCab,FALSE,FCI_GetNextCabinet,FCI_UpdateStatus,FCI_GetOpenInfo,tcompTYPE_MSZIP);
}//nFolder 是压缩目录的根目录长度用来产生目录结构,外面调用不要设置该参数BOOL AddFolder(LPCSTR szFolder, LPCSTR szFilter=NULL, UINT nFolder=0)
{
ATLASSERT(m_hContext!=NULL);
CHK_EXP_RET( m_hContext==NULL , FALSE );
CHAR szPath[MAX_PATH]={""};
strncpy(szPath, szFolder, MAX_PATH);
PathAddBackslashA(szPath);//计算根目录的长度并设置搜索路径UINT nSearch=strlen(szPath);
nFolder=nFolder?nFolder : nSearch;
szFilter=szFilter?szFilter :"*.*";
strcat(szPath, szFilter);
WIN32_FIND_DATAA datFinder;
HANDLE hFinder=FindFirstFileA(szPath,&datFinder);
CHK_EXP_RET(hFinder==INVALID_HANDLE_VALUE, FALSE);
BOOL bFindFile=(hFinder!=INVALID_HANDLE_VALUE);while(bFindFile)
{if(datFinder.cFileName[0]=='.')
{
bFindFile=FindNextFileA(hFinder,&datFinder);continue;
}
strcpy(szPath+nSearch, datFinder.cFileName);if(datFinder.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
{if(!AddFolder(szPath, szFilter, nFolder) )
{
FindClose(hFinder);returnFALSE;
}
}else{if(!AddFile(szPath, szPath+nFolder) )
{
FindClose(hFinder);returnFALSE;
}
}//搜索下一个文件bFindFile=FindNextFileA(hFinder,&datFinder);
}
FindClose(hFinder);returnTRUE;
}
BOOL SetTempDirectory(LPCSTR szTempDir)
{
ATLASSERT(szTempDir!=NULL);
INT nLength=strlen(szTempDir);
CHK_EXP_RET(3
CHK_EXP_RET( nLength>MAX_PATH , FALSE );
strncpy(m_szTempDir, szTempDir, MAX_PATH);
PathAddBackslashA(m_szTempDir);returnTRUE;
}public://使用下面的函数可以直接对一个目录下的特定文件或者一个文件进行打包BOOL PackageFolder(LPSTR szCabinet,LPSTR szFolder, LPSTR szFilter=NULL, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
CHK_EXP_RET(!CreateContext(szCabinet,nSplitSize,wCabinetID) , FALSE );
CHK_EXP_RET(!AddFolder(szFolder, szFilter),(DestroyContext(), FALSE));returnDestroyContext();
}
BOOL PackageFile(LPSTR szCabinet,LPSTR szFile, LPSTR szName=NULL, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
CHK_EXP_RET(!CreateContext(szCabinet,nSplitSize,wCabinetID) , FALSE );
CHK_EXP_RET(!AddFile(szFile, szName),(DestroyContext(), FALSE));returnDestroyContext();
}public://下面这些函数是为了在 UNICODE 版本中方便使用而做的参数类型转换BOOL CreateContext(LPCWSTR lpszPathFile, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
USES_CONVERSION_EX; ATLASSERT(lpszPathFile!=NULL);returnCreateContext(W2A_EX(lpszPathFile,0),nSplitSize,wCabinetID);
}
BOOL CreateContext(LPCWSTR lpszPath, LPCWSTR lpszFile, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
USES_CONVERSION_EX; ATLASSERT(lpszPath!=NULL); ATLASSERT(lpszFile!=NULL);returnCreateContext(W2A_EX(lpszPath,0),W2A_EX(lpszFile,0),nSplitSize,wCabinetID);
}
BOOL AddFile(LPWSTR szFileToAdd, LPWSTR szNameInCab=NULL)
{
USES_CONVERSION_EX; ATLASSERT(szFileToAdd!=NULL);returnAddFile(W2A_EX(szFileToAdd,0), szNameInCab?W2A_EX(szNameInCab,0) : NULL);
}
BOOL AddFolder(LPCWSTR szFolder, LPCWSTR szFilter=NULL)
{
USES_CONVERSION_EX; ATLASSERT(szFolder!=NULL);returnAddFolder(W2A_EX(szFolder,0), szFilter?W2A_EX(szFilter,0) : NULL);
}
BOOL SetTempDirectory(LPCWSTR szTempDir)
{
USES_CONVERSION_EX; ATLASSERT(szTempDir!=NULL)returnSetTempDirectory(W2A_EX(szTempDir,0));
}
BOOL PackageFolder(LPCWSTR szCabinet,LPCWSTR szFolder, LPCWSTR szFilter=NULL, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
USES_CONVERSION_EX;returnPackageFolder(W2A_EX(szCabinet,0),W2A_EX(szFolder,0), szFilter?W2A_EX(szFilter,0) : NULL, nSplitSize, wCabinetID);
}
BOOL PackageFile(LPCWSTR szCabinet,LPCWSTR szFile, LPCWSTR szName=NULL, UINT nSplitSize=INT_MAX, WORD wCabinetID=0)
{
USES_CONVERSION_EX;returnPackageFile(W2A_EX(szCabinet,0),W2A_EX(szFile,0), szName?W2A_EX(szName,0) : NULL, nSplitSize, wCabinetID);
}public:
BOOL OnPrepareCreate(CCAB&rCab, LPCSTR lpszPath, LPCSTR lpszFile, UINT nSplitSize, WORD wCabinetID)
{//设置产生ZeroMemory(&rCab,sizeof(CCAB));
strcpy(rCab.szCabPath,lpszPath);
PathAddBackslashA(rCab.szCabPath);//FCI 内部处理是有符号的rCab.cb=nSplitSize&INT_MAX ;
rCab.cbFolderThresh=FOLDER_THRESHOLD;
rCab.iCab=rCab.iDisk=1;
rCab.setID=wCabinetID;//不需要任何的扩展空间rCab.cbReserveCFHeader=0;
rCab.cbReserveCFFolder=0;
rCab.cbReserveCFData=0;//格式化一个文件名称出来strcpy(m_szCabFileFormat,lpszFile);
FCI_GetNextCabinet(&rCab,0,this);returnTRUE;
}public://在新的类中重新定义这两个静态函数可以使用不同的内存策略staticLPVOID Alloc(ULONG nSize){returnmalloc(nSize); }staticvoidFree(LPVOID lpMemory){ free(lpMemory); }public://下面的函数可以重新实现以实现不同的文件管理INT FilePlaced(PCCAB lpCabinet, LPSTR pszFile, LONG nFile, BOOL fContinuation, LPVOID pData=NULL)
{returnERROR_SUCCESS;
}
INT_PTR Open(LPSTR pszFile, INT nOpenFlag, INT nMode, LPINT pError, LPVOID pData=NULL)
{
INT_PTR xResult=_open(pszFile, nOpenFlag, nMode);if(xResult==-1)*pError=errno;returnxResult;
}
UINT Read(INT_PTR hFile, LPVOID lpMemory, UINT nSize, LPINT pError, LPVOID pData=NULL)
{
UINT result=(UINT) _read(hFile, lpMemory, nSize);if(result!=nSize)*pError=errno;returnresult;
}
UINT Write(INT_PTR hFile, LPVOID lpMemory, UINT nSize, LPINT pError, LPVOID pData=NULL)
{
UINT result=(UINT) _write(hFile, lpMemory, nSize);if(result!=nSize)*pError=errno;returnresult;
}
INT Close(INT_PTR hFile, LPINT pError, LPVOID pData=NULL)
{
INT result=_close(hFile);if(result!=0)*pError=errno;returnresult;
}
LONG Seek(INT_PTR hFile, LONG nDistance, INT nSeekType, LPINT pError, LPVOID pData=NULL)
{
LONG result=_lseek(hFile, nDistance, nSeekType);if(result==-1)*pError=errno;returnresult;
}
INT Delete(LPSTR pszFile, LPINT pError, LPVOID pData=NULL)
{
INT result=remove(pszFile);if(result!=0)*pError=errno;returnresult;
}
BOOL GetTempFile(LPSTR pszTempName, INT nTempName, LPVOID pData=NULL)
{while(true)
{
wsprintfA(pszTempName,"%sCab%05u",m_szTempDir,m_nTempCounter++);
CHK_EXP_RET( GetFileAttributesA(pszTempName)==INVALID_FILE_ATTRIBUTES , TRUE );
}returnFALSE;
}public:
BOOL GetNextCabinet(PCCAB pCab, ULONG nPrevCab, LPVOID pData=NULL)
{
wsprintfA(pCab->szCab, m_szCabFileFormat, pCab->iCab);
wsprintfA(pCab->szDisk,"Disk %d", pCab->iDisk++);//如果需要修改其他产数//pCab->cbFolderThresh = xyz;//pCab->setID = xyz;//pCab->cb = xyz;returnTRUE;
}
INT_PTR GetOpenInfo(LPSTR pszName, USHORT*pDate, USHORT*pTime, USHORT*pAttribs, LPINT pError, LPVOID pData=NULL)
{
BY_HANDLE_FILE_INFORMATION xFileInfo;
FILETIME xFileTime;
DWORD dwFileAttrib=FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN;
HANDLE handle=CreateFileA(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, dwFileAttrib, NULL);if(handle==INVALID_HANDLE_VALUE)
{*pError=GetLastError();returnUINT_MAX;
}if(!GetFileInformationByHandle(handle,&xFileInfo))
{*pError=GetLastError();
CloseHandle(handle);returnUINT_MAX;
}
FileTimeToLocalFileTime(&xFileInfo.ftLastWriteTime,&xFileTime);
FileTimeToDosDateTime (&xFileTime, pDate, pTime);
DWORD dwAttribs=GetFileAttributesA(pszName);if(dwAttribs==ULONG_MAX)*pAttribs=0;//失败了不要打断工作,设置空属性else*pAttribs=(INT)(dwAttribs&(_A_RDONLY|_A_SYSTEM|_A_HIDDEN|_A_ARCH));
CloseHandle(handle);//返回一个 _open 打开的文件句柄return_open(pszName, _O_RDONLY|_O_BINARY);
}
LONG UpdateStatus(UINT nTypes, ULONG nParam1, ULONG nParam2, LPVOID pData=NULL)
{//可以使用 ParseStatus 函数分析状态后直接使用结果returnERROR_SUCCESS;
}protected://下面的这些保护函数实现系统 FCI 回调staticLPVOID DIAMONDAPI FCI_Alloc(ULONG nSize)
{returnT::Alloc(nSize);
}staticvoidDIAMONDAPI FCI_Free(LPVOID lpMemory)
{returnT::Free(lpMemory);
}staticintDIAMONDAPI FCI_FilePlaced(PCCAB lpCabinet, LPSTR pszFile, LONG nFile, BOOL fContinuation, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->FilePlaced(lpCabinet,pszFile,nFile,fContinuation);
}staticINT_PTR DIAMONDAPI FCI_Open(LPSTR pszFile, INT nOpenFlag, INT nMode, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Open(pszFile,nOpenFlag,nMode,pError);
}staticUINT DIAMONDAPI FCI_Read(INT_PTR hFile, LPVOID lpMemory, UINT nSize, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Read(hFile,lpMemory,nSize,pError);
}staticUINT DIAMONDAPI FCI_Write(INT_PTR hFile, LPVOID lpMemory, UINT nSize, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Write(hFile,lpMemory,nSize,pError);
}staticINT DIAMONDAPI FCI_Close(INT_PTR hFile, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Close(hFile,pError);
}staticlongDIAMONDAPI FCI_Seek(INT_PTR hFile, LONG nDistance, INT nSeekType, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Seek(hFile,nDistance,nSeekType,pError);
}staticintDIAMONDAPI FCI_Delete(LPSTR pszFile, LPINT pError, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->Delete(pszFile, pError);
}staticBOOL DIAMONDAPI FCI_GetTempFile(LPSTR pszTempName, INT nTempName, LPVOID pData)
{returnstatic_cast((CPackageImpl*)pData)->GetTempFile(pszTempName,nTempName);
}staticBOOL DIAMONDAPI FCI_GetNextCabinet(PCCAB pCab, ULONG nPrevCab, LPVOID pData)
{
CPackageImpl*pThis=(CPackageImpl*)(pData);
CHK_EXP_RET( pThis->m_bOperAbort , (TRUE==FALSE) );returnstatic_cast(pThis)->GetNextCabinet(pCab, nPrevCab);
}staticINT_PTR DIAMONDAPI FCI_GetOpenInfo(LPSTR pszName,USHORT*pDate, USHORT*pTime, USHORT*pAttribs, LPINT pError, LPVOID pData)
{
CPackageImpl*pThis=(CPackageImpl*)(pData);
CHK_EXP_RET( pThis->m_bOperAbort , (INT_PTR)(UINT_MAX) );returnstatic_cast(pThis)->GetOpenInfo(pszName,pDate,pTime,pAttribs,pError);
}staticLONG DIAMONDAPI FCI_UpdateStatus(UINT nTypes, ULONG nParam1, ULONG nParam2, LPVOID pData)
{
CPackageImpl*pThis=(CPackageImpl*)(pData);
CHK_EXP_RET( pThis->m_bOperAbort , (LONG)(ULONG_MAX) );returnstatic_cast(pThis)->UpdateStatus(nTypes,nParam1,nParam2);
}protected:
VOID ParseStatus(UINT nTypes, ULONG nParam1, ULONG nParam2)
{
m_nParam1=nParam1;
m_nParam2=nParam2;
m_nFolderPercent=0;if(statusFile==nTypes)
{
m_nTotalCompressSize+=nParam1;
m_nTotalUncompressSize+=nParam2;
}elseif(statusFolder==nTypes)
{
DOUBLE nPercent=100.0*nParam1/nParam2 ;
m_nFolderPercent=(ULONG)(nPercent);
}
}protected:
BOOL Initialize()
{
m_hContext=0;
m_xError.fError=FALSE;
GetTempPathA(MAX_PATH, m_szTempDir);
m_nTotalUncompressSize=0;
m_nTotalCompressSize=0;
m_nTempCounter=1;returnTRUE;
}protected:
HFCI m_hContext;
CCAB m_xPackage;
ERF m_xError;
BOOL m_bAutoFlush;
BOOL m_bOperAbort;
LONG m_nTempCounter;
CHAR m_szTempDir[MAX_PATH];
CHAR m_szCabFileFormat[CB_MAX_CABINET_NAME];//下面是状态信息,可以用来处理用户界面ULONG m_nTotalUncompressSize;
ULONG m_nTotalCompressSize;
ULONG m_nParam1,m_nParam2;
ULONG m_nFolderPercent;
};//==============================================================================================//文件打包类,附加消息通知功能classCFilePackage :publicCPackageImpl{public:
CFilePackage(HWND hWnd=NULL, UINT uMsg=WM_NULL) : m_hWnd(hWnd), m_uMsg(uMsg)
{
}public:structS_GetNextCabinet
{
PCCAB pCab;
ULONG nPrevCab;
LPVOID pData;
};structS_GetOpenInfo
{
LPSTR pszName;
USHORT*pDate;
USHORT*pTime;
USHORT*pAttribs;
LPINT pError;
LPVOID pData;
};structS_UpdateStatus
{
ULONG nTypes,nParam1,nParam2;
ULONG nTotalUncompressSize;
ULONG nTotalCompressSize;
ULONG nFolderPercent;
};enumE_MessageNotify
{
EM_GET_NEXT_CAIBNET=1,
EM_GET_OPEN_INFO=2,
EM_UPDATE_STATUS=3,
};public://重载回调函数,提供消息通知功能BOOL GetNextCabinet(PCCAB pCab, ULONG nPrevCab, LPVOID pData=NULL)
{
S_GetNextCabinet xParam={ pCab, nPrevCab, pData };
SendMessage(m_hWnd, m_uMsg, EM_GET_NEXT_CAIBNET, reinterpret_cast(&xParam));returnCPackageImpl::GetNextCabinet(pCab,nPrevCab,pData);
}
INT_PTR GetOpenInfo(LPSTR pszName, USHORT*pDate, USHORT*pTime, USHORT*pAttribs, LPINT pError, LPVOID pData=NULL)
{
S_GetOpenInfo xParam={ pszName, pDate, pTime, pAttribs, pError, pData };
SendMessage(m_hWnd, m_uMsg, EM_GET_OPEN_INFO, reinterpret_cast(&xParam));returnCPackageImpl::GetOpenInfo(pszName,pDate,pTime,pAttribs,pError,pData);
}
LONG UpdateStatus(UINT nTypes, ULONG nParam1, ULONG nParam2, LPVOID pData=NULL)
{
ParseStatus(nTypes, nParam1, nParam2);
S_UpdateStatus xParam={ nTypes, nParam1, nParam2, m_nTotalUncompressSize, m_nTotalCompressSize, m_nFolderPercent };
SendMessage(m_hWnd, m_uMsg, EM_UPDATE_STATUS, reinterpret_cast(&xParam));returnCPackageImpl::UpdateStatus(nTypes, nParam1, nParam2);
}protected:
HWND m_hWnd;
UINT m_uMsg;
};//==============================================================================================template>classCExtractImpl :publicDecryptT
{public:
CExtractImpl()
{
Initialize();
}~CExtractImpl()
{
DestroyContext();
}public:
BOOL CreateContext(INT nCpuType=cpu80386)
{
CHK_EXP_RET(m_hContext!=NULL , FALSE );
m_hContext=FDICreate( FDI_Alloc, FDI_Free, FDI_Open, FDI_Read, FDI_Write, FDI_Close, FDI_Seek,-1,&m_xError);return(m_hContext!=NULL);
}
BOOL DestroyContext()
{
CHK_EXP_RET(m_hContext==NULL , TRUE );
CHK_EXP_RET(!FDIDestroy(m_hContext) , FALSE );
m_hContext=NULL;returnTRUE;
}voidAbortExtract()
{
m_bOperAbort=TRUE;
}
BOOL Extract(LPCSTR lpszCabinet, LPCSTR lpszTarget=NULL)
{//检查参数ATLASSERT(m_hContext!=NULL);
CHK_EXP_RET(m_hContext==NULL , FALSE);
CHK_EXP_RET(strlen(lpszCabinet)>MAX_PATH, FALSE);
CHK_EXP_RET(!T::IsCabinetFileName(lpszCabinet), FALSE);//分析路径CHAR szPath[MAX_PATH]={""};
strncpy(szPath, lpszCabinet, MAX_PATH);
LPSTR lpszName=PathFindFileNameA(szPath);//复制文件名CHAR szName[MAX_PATH]={""};
strncpy(szName, lpszName, MAX_PATH);//截取路径,注意保留结束的‘\’if(lpszName!=szPath) lpszName[0]=0;//缓存目标路径ZeroMemory(m_szTargetDir, MAX_PATH);if(!IsBadReadPtr(lpszTarget ,3) )
{
strcpy(m_szTargetDir,lpszTarget);
PathAddBackslashA(m_szTargetDir);
}else{
PSTR szFileName=PathFindFileNameA(lpszCabinet);
strncpy(m_szTargetDir,lpszCabinet,szFileName-lpszCabinet);
PathAddBackslashA(m_szTargetDir);
}
m_bOperAbort=FALSE;returnFDICopy(m_hContext,szName,szPath,0,FDI_Callback,NULL,this);
}
BOOL IsCabinet(INT hFile, PFDICABINETINFO lpCabInfo=NULL)
{
CHK_EXP_RET(m_hContext==NULL , FALSE );
FDICABINETINFO xCabinetInfo;
lpCabInfo=lpCabInfo?lpCabInfo :&xCabinetInfo;returnFDIIsCabinet(m_hContext, hFile, lpCabInfo);
}
BOOL IsCabinet(LPSTR szFileName, PFDICABINETINFO lpCabInfo=NULL)
{
INT nAttr=_O_BINARY|_O_RDONLY|_O_SEQUENTIAL;
INT hCabinetFile=FDI_Open(szFileName, nAttr,0);
CHK_EXP_RET( hCabinetFile==-1, FALSE);
BOOL bCabinet=IsCabinet(hCabinetFile, lpCabInfo);
FDI_Close(hCabinetFile);returnbCabinet;
}
BOOL ExtractFile(LPCSTR szCabinet, LPCSTR szTarget=NULL)
{
CHK_EXP_RET(!CreateContext(cpu80386), FALSE );
BOOL bExtract=Extract(szCabinet, szTarget);returnDestroyContext()&&bExtract;
}public://下面的函数是为了 UNICODE 使用而做的类型转换BOOL Extract(LPCWSTR lpszCabinet, LPCWSTR lpszTarget=NULL)
{
USES_CONVERSION_EX; ATLASSERT(lpszCabinet!=NULL);returnExtract(W2A_EX(lpszCabinet,0), lpszTarget?W2A_EX(lpszTarget,0) : NULL);
}
BOOL IsCabinet(LPCWSTR szFileName, PFDICABINETINFO lpCabInfo=NULL)
{
USES_CONVERSION_EX; ATLASSERT(szFileName!=NULL);returnIsCabinet(W2A_EX(szFileName,0), lpCabInfo);
}
BOOL ExtractFile(LPCWSTR szCabinet, LPCWSTR szTarget=NULL)
{
USES_CONVERSION_EX; ATLASSERT(szCabinet!=NULL);returnExtractFile(W2A_EX(szCabinet,0),szTarget?W2A_EX(szTarget,0) : NULL );
}public://下面四个函数用来处理解压缩时的回调信息INT_PTR OnCabinetInfo(PFDINOTIFICATION pNotify, LPVOID lpData=NULL)
{//pNotify->psz1 : szNextCabinet//pNotify->psz2 : szNextDisk//pNotify->psz3 : szCabPathreturnERROR_SUCCESS;
}
INT_PTR OnNextCabinet(PFDINOTIFICATION pNotify, LPVOID lpData=NULL)
{//pNotify->psz1 : szNextCabinet//pNotify->psz2 : szNextDisk//pNotify->psz3 : szCabPathreturnERROR_SUCCESS;
}
INT_PTR OnCopyFile(PFDINOTIFICATION pNotify, LPVOID lpData=NULL)
{charszPath[MAX_PATH]={""};
strncpy(szPath, m_szTargetDir, MAX_PATH);
strncat(szPath, pNotify->psz1, MAX_PATH);//确保目录存在LPSTR lpszPath=strchr(szPath,'\\');while(lpszPath!=NULL)
{//构筑目录名称INT nLength=lpszPath-szPath;
CHAR szFolder[MAX_PATH]={""};
strncpy(szFolder, szPath, nLength);
szFolder[nLength]=0;//创建目录,并搜索下一个目录CreateDirectoryA(szFolder, NULL);
lpszPath=strchr(lpszPath+1,'\\');
}
WORD wAttr=_O_BINARY|_O_CREAT|_O_WRONLY|_O_SEQUENTIAL;returnFDI_Open(szPath, wAttr, _S_IREAD|_S_IWRITE);
}
INT_PTR OnFileCopyComplete(PFDINOTIFICATION pNotify, LPVOID lpData=NULL)
{
FDI_Close(pNotify->hf);
CHAR szPath[MAX_PATH]={""};
strncpy(szPath, m_szTargetDir, MAX_PATH);
strncat(szPath, pNotify->psz1, MAX_PATH);
SetFileAttrDate(szPath, pNotify->date, pNotify->time, pNotify->attribs);returnTRUE;//返回该值让系统继续处理,否则系统停止处理下一个}public:staticBOOL IsCabinetFileName(LPCSTR szCabinetFile)
{returnPathFileExistsA(szCabinetFile);
}public:staticLPVOID Alloc(ULONG nSize)
{returnmalloc(nSize);
}staticvoidFree(LPVOID lpMemory)
{returnfree(lpMemory);
}public:staticINT_PTR Open(LPSTR pszFile, INT nOpenFlag, INT nMode)
{return_open(pszFile, nOpenFlag, nMode);
}staticUINT Read(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{return_read(hFile, lpMemory, nSize);
}staticUINT Write(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{return_write(hFile, lpMemory, nSize);
}staticLONG Seek(INT_PTR hFile, LONG nDistance, INT nSeekType)
{return_lseek(hFile, nDistance, nSeekType);
}staticINT Close(INT_PTR hFile)
{return_close(hFile);
}protected://下面的这些保护函数实现系统 FDI 回调staticLPVOID DIAMONDAPI FDI_Alloc(ULONG nSize)
{returnT::Alloc(nSize);
}staticvoidDIAMONDAPI FDI_Free(LPVOID lpMemory)
{returnT::Free(lpMemory);
}protected:staticINT_PTR DIAMONDAPI FDI_Open(LPSTR pszFile, INT nOpenFlag, INT nMode)
{returnT::Open(pszFile,nOpenFlag,nMode);
}staticUINT DIAMONDAPI FDI_Read(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{returnT::Read(hFile,lpMemory,nSize);
}staticUINT DIAMONDAPI FDI_Write(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{returnT::Write(hFile,lpMemory,nSize);
}staticlongDIAMONDAPI FDI_Seek(INT_PTR hFile, LONG nDistance, INT nSeekType)
{returnT::Seek(hFile,nDistance,nSeekType);
}staticINT DIAMONDAPI FDI_Close(INT_PTR hFile)
{returnT::Close(hFile);
}protected:staticINT_PTR FDI_Callback(FDINOTIFICATIONTYPE eNotifyType, PFDINOTIFICATION pNotify)
{
CExtractImpl*pThis=(CExtractImpl*)(pNotify->pv);
CHK_EXP_RET(pThis->m_bOperAbort , (INT_PTR)(UINT_MAX));
T*pT=static_cast(pThis);
CHK_EXP_RET( eNotifyType==fdintCOPY_FILE , pT->OnCopyFile (pNotify));
CHK_EXP_RET( eNotifyType==fdintCABINET_INFO , pT->OnCabinetInfo (pNotify));
CHK_EXP_RET( eNotifyType==fdintNEXT_CABINET , pT->OnNextCabinet (pNotify));
CHK_EXP_RET( eNotifyType==fdintCLOSE_FILE_INFO , pT->OnFileCopyComplete (pNotify));returnERROR_SUCCESS;//允许不支持的通知继续进行}staticBOOL SetFileAttrDate(LPCSTR lpszFileName, WORD wDate, WORD wTime, WORD wAttribs)
{
SetFileAttributesA(lpszFileName, wAttribs&(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE));
HANDLE hFile=CreateFileA(lpszFileName,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
CHK_EXP_RET(hFile==INVALID_HANDLE_VALUE, FALSE);
FILETIME ftFile={0,0}, ftLocal={0,0};
CHK_EXP_RET(!DosDateTimeToFileTime(wDate, wTime,&ftFile),(CloseHandle(hFile) , FALSE));
CHK_EXP_RET(!LocalFileTimeToFileTime(&ftFile,&ftLocal),(CloseHandle(hFile) , FALSE));
SetFileTime(hFile,&ftLocal, NULL,&ftLocal);
CloseHandle(hFile);returnTRUE;
}protected:
VOID Initialize()
{
m_hContext=NULL;
m_xError.fError=FALSE;
}protected:
HFDI m_hContext;
ERF m_xError;
BOOL m_bOperAbort;
CHAR m_szTargetDir[MAX_PATH];//临时存储解压缩的目标目录};//==============================================================================================//直接从 CAB 文件进行解压缩classCFileExtract :publicCExtractImpl{
};//==============================================================================================//从内存缓冲中解压缩 CAB 文件templateclassCExpressImpl :publicCExtractImpl{public:
BOOL ExtractMemory(LPCTSTR szTargetDir, LPVOID lpMemory, DWORD dwLength)
{
TCHAR szMemory[MAX_PATH]={ TEXT("") };
CHK_EXP_RET(!MakeMemoryName(szMemory, MAX_PATH, lpMemory, dwLength) , FALSE);returnExtractFile(szMemory, szTargetDir);
}public://重载该函数实现不同的资源访问staticLPCTSTR GetIdentifier()
{returnTEXT("MEM://");
}staticBOOL MakeCabinetName(LPTSTR szCabinet, DWORD dwLength, LPCTSTR szInput)
{//检查输入的参数CHK_EXP_RET(szInput==NULL, FALSE);
CHK_EXP_RET(dwLength==NULL, FALSE);
CHK_EXP_RET(szCabinet==NULL, FALSE);//检查缓冲区大小SIZE_T dwInput=lstrlen(szInput);
LPCTSTR szIdentifier=T::GetIdentifier();
SIZE_T dwIdentifier=lstrlen(szIdentifier);
CHK_EXP_RET(dwIdentifier+dwInput>=dwLength , FALSE);//构筑压缩包的名称lstrcpy(szCabinet, szIdentifier);
lstrcpy(szCabinet+dwIdentifier, szInput);returnTRUE;
}//使用该函数构筑一个存储于内存中的压缩包的名称staticBOOL MakeMemoryName(LPTSTR szCabinet, DWORD dwLength, LPVOID lpData, SIZE_T dwSize)
{
CHK_EXP_RET(dwSize==0, FALSE);
CHK_EXP_RET(lpData==NULL, FALSE);
CONST TCHAR szFormat[]={ TEXT("%p/%IX") };
TCHAR szMemory[MAX_PATH]={ TEXT("") };//Addr/Sizewsprintf(szMemory, szFormat, lpData, dwSize);returnMakeCabinetName(szCabinet, dwLength, szMemory);
}staticBOOL IsCabinetFileName(LPCSTR szFileName)
{
USES_CONVERSION_EX;
LPCSTR szIdentifier=T2A_EX(T::GetIdentifier(),0);
SIZE_T dwIdentifier=strlen(szIdentifier);returnStrCmpNIA(szIdentifier, szFileName, dwIdentifier)==0;
}staticBOOL IsCabinetFileName(LPCWSTR szFileName)
{
USES_CONVERSION_EX;
LPWSTR szIdentifier=T2W_EX(T::GetIdentifier(),0);
SIZE_T dwIdentifier=lstrlenW(szIdentifier);returnStrCmpNIW(szIdentifier, szFileName, dwIdentifier)==0;
}public:structMemoryInfo
{
LPBYTE lpBuffer;
SIZE_T dwBuffer;
SIZE_T dwOffset;
SIZE_T dwSymbol;
};staticINT_PTR InterOpenMemory(LPVOID lpBuffer, SIZE_T dwBuffer, SIZE_T dwSymbol=ULONG_MAX)
{
MemoryInfo*lpInfo=newMemoryInfo;
CHK_EXP_RET(lpInfo==NULL ,-1);
lpInfo->lpBuffer=(LPBYTE)lpBuffer;
lpInfo->dwBuffer=(SIZE_T)dwBuffer;
lpInfo->dwSymbol=(SIZE_T)dwSymbol;
lpInfo->dwOffset=(SIZE_T)NO_ERROR;return(INT_PTR)(lpInfo);
}public://下面这四个函数都是访问内存 CAB 文件数据的实现函数staticINT_PTR InterOpen(LPSTR pszFile, INT nOpenFlag, INT nMode)
{
USES_CONVERSION_EX;
LPCSTR szIdentifier=T2A_EX(T::GetIdentifier(),0);
SIZE_T dwIdentifier=strlen(szIdentifier);
LPSTR szAddress=pszFile+dwIdentifier;
CONST CHAR szFormat[]={"%p/%IX"};
LPVOID lpAddr=NULL; SIZE_T dwSize=0;
sscanf(szAddress, szFormat,&lpAddr,&dwSize);
CHK_EXP_RET( IsBadReadPtr(lpAddr, dwSize) , (INT_PTR)-1);
CHK_EXP_RET( dwSize<=FALSE , (INT_PTR)-1);returnInterOpenMemory(lpAddr, dwSize);
}staticUINT InterRead(INT_PTR hFile, LPVOID lpMemory, UINT nLength)
{
MemoryInfo*lpInfo=(MemoryInfo*)(hFile);
SIZE_T nMemory=lpInfo->dwBuffer-lpInfo->dwOffset;
SIZE_T dwCopy=nMemory
LPBYTE lpCopy=lpInfo->lpBuffer+lpInfo->dwOffset;
CopyMemory(lpMemory, lpCopy, dwCopy);
lpInfo->dwOffset+=dwCopy;returndwCopy;
}staticUINT InterWrite(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{returnUINT_MAX;//errno = ENOSPC;}staticLONG InterSeek(INT_PTR hFile, LONG nDistance, INT nSeekType)
{
MemoryInfo*lpMemInfo=(MemoryInfo*)(hFile);
LONG_PTR dwOffset=(LONG_PTR)lpMemInfo->dwOffset;
LONG_PTR dwBuffer=(LONG_PTR)lpMemInfo->dwBuffer;if(nSeekType==SEEK_END) dwOffset=dwBuffer+nDistance;elseif(nSeekType==SEEK_CUR) dwOffset+=nDistance;elseif(nSeekType==SEEK_SET) dwOffset=nDistance;
CHK_EXP_RET(dwOffset>dwBuffer ,(errno=EBADF,-1));
CHK_EXP_RET(dwOffset<0,(errno=EBADF,-1));
lpMemInfo->dwOffset=(SIZE_T)dwOffset;returndwOffset ;
}staticINT InterClose(INT_PTR hFile)
{
MemoryInfo*lpMemInfo=(MemoryInfo*)(hFile);
delete lpMemInfo;return0;
}public://因为只存储 CABINET 文件指针,所以使用简单数组方式的映射//映射的键是文件指针,值可以由继承类自己决定如何使用typedef ATL::CSimpleMapCMapFilePtr;staticBOOL IsCabinetFilePtr(INT_PTR hFile)
{
CMapFilePtr&rMapper=GetFileMapper();returnrMapper.FindKey(hFile)!=-1;
}staticCMapFilePtr&GetFileMapper()
{staticCMapFilePtr sxMapFilePtr;returnsxMapFilePtr;
}public:staticINT_PTR Open(LPSTR pszFile, INT nOpenFlag, INT nMode)
{if( IsCabinetFileName(pszFile) )
{
INT_PTR hFile=T::InterOpen(pszFile, nOpenFlag, nMode);
GetFileMapper().Add(hFile,0);returnhFile;
}returnCExtractImpl::Open(pszFile, nOpenFlag, nMode);
}staticUINT Read(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{
CHK_EXP_RET( IsCabinetFilePtr(hFile) , T::InterRead(hFile, lpMemory, nSize) );returnCExtractImpl::Read(hFile, lpMemory, nSize);
}staticUINT Write(INT_PTR hFile, LPVOID lpMemory, UINT nSize)
{
CHK_EXP_RET( IsCabinetFilePtr(hFile) , T::InterWrite(hFile, lpMemory, nSize) );returnCExtractImpl::Write(hFile, lpMemory, nSize);
}staticLONG Seek(INT_PTR hFile, LONG nDistance, INT nSeekType)
{
CHK_EXP_RET( IsCabinetFilePtr(hFile) , T::InterSeek(hFile, nDistance, nSeekType) );returnCExtractImpl::Seek(hFile, nDistance, nSeekType);
}staticINT Close(INT_PTR hFile)
{if( IsCabinetFilePtr(hFile) )
{
INT nClose=T::InterClose(hFile);
GetFileMapper().Remove(hFile);returnnClose;
}returnCExtractImpl::Close(hFile);
}
};//==============================================================================================//从资源中解压缩 CAB 文件templateclassCStorageImpl :publicCExpressImpl{public:
BOOL ExtractResource(LPCTSTR szTargetDir, LPCTSTR szResName, LPCTSTR szResType=RT_RCDATA, LPCTSTR szModule=NULL)
{
TCHAR szResource[MAX_PATH]={ TEXT("") };
CHK_EXP_RET(!MakeResourceName(szResource,MAX_PATH,szResName,szResType,szModule) , FALSE);returnExtractFile(szResource, szTargetDir);
}
BOOL ExtractResource(LPCTSTR szTargetDir, UINT nResID=1, LPCTSTR szResType=RT_RCDATA, LPCTSTR szModule=NULL)
{returnExtractResource(szTargetDir, MAKEINTRESOURCE(nResID), szResType, szModule);
}public:staticLPCTSTR GetIdentifier()
{returnTEXT("RES://");
}//使用该函数构筑一个存储于资源中的压缩包的名称staticBOOL MakeResourceName(LPTSTR szCabinet, DWORD dwLength, LPCTSTR lpszResName, LPCTSTR lpszResType=RT_RCDATA, LPCTSTR lpszModule=NULL)
{
TCHAR szResource[MAX_PATH]={ TEXT("") };//HRES:\\Type\Name\ModuleLPTSTR lpStr=szResource;if( IS_INTRESOURCE(lpszResType) )
{
wsprintf(lpStr, TEXT("#%d/"), PtrToInt(lpszResType));
}else{
lstrcpy(lpStr, lpszResType);
lstrcat(lpStr, TEXT("/"));
}
lpStr=lpStr+lstrlen(lpStr);if( IS_INTRESOURCE(lpszResName) )
{
wsprintf(lpStr, TEXT("#%d"), PtrToInt(lpszResName));
}else{
lstrcpy(lpStr, lpszResName);
}
lpStr=lpStr+lstrlen(lpStr);if( lpszModule!=NULL )
{
lstrcpy(lpStr, TEXT("/"));
lstrcat(lpStr, lpszModule);
}returnMakeCabinetName(szCabinet, dwLength, szResource);
}public:staticINT_PTR InterOpenResource(LPCSTR szName, LPCSTR szType, LPCSTR szModule=NULL)
{
HMODULE hModule=GetModuleHandleA(szModule);
HRSRC hResource=FindResourceA(hModule, szName, szType);
CHK_EXP_RET( hResource==NULL , (INT_PTR)-1);
HGLOBAL hGlobal=LoadResource(hModule, hResource);
CHK_EXP_RET( hGlobal==NULL , (INT_PTR)-1);
LPVOID lpBuffer=LockResource(hGlobal);
SIZE_T dwBuffer=SizeofResource(hModule, hResource);returnInterOpenMemory(lpBuffer, dwBuffer, ULONG_MAX);
}public:staticINT_PTR InterOpen(LPSTR pszFile, INT nOpenFlag, INT nMode)
{
USES_CONVERSION_EX;
LPCSTR szIdentifier=T2A_EX(T::GetIdentifier(),0);
SIZE_T dwIdentifier=strlen(szIdentifier);
CHAR szFile[MAX_PATH]={""};
strcpy(szFile, pszFile+dwIdentifier);
LPSTR szType=szFile;
LPSTR szName=strchr(szType,'/');
CHK_EXP_RET(szName==NULL,-1);
szName[0]=0; szName++;
LPSTR szModule=strchr(szName,'/');if(szModule!=NULL){*szModule=0; szModule++; }returnInterOpenResource(szName, szType, szModule);
}
};//==============================================================================================classCFileExpress :publicCExpressImpl{public://从内存中进行解压缩BOOL ExtractFromMemory(LPCTSTR szTarget, LPVOID lpBuffer, SIZE_T dwBuffer)
{
TCHAR szCabinet[MAX_PATH]={ TEXT("") };
MakeMemoryName(szCabinet, MAX_PATH, lpBuffer, dwBuffer);returnExtractFile(szCabinet, szTarget);
}
};//==============================================================================================classCFileStorage :publicCStorageImpl{public://从资源中进行解压缩BOOL ExtractFromResource(LPCTSTR szTarget, LPCTSTR szResName, LPCTSTR szResType=RT_RCDATA, LPCTSTR szModule=NULL)
{
TCHAR szCabinet[MAX_PATH]={ TEXT("") };
MakeResourceName(szCabinet, MAX_PATH, szResName, szResType, szModule);returnExtractFile(szCabinet, szTarget);
}
};
}