unrar.cpp
来自「zip的全部算法源代码」· C++ 代码 · 共 455 行
CPP
455 行
/*************************************************************************
ZipALot
**************************************************************************
Copyright (C) December, 2000 Jean-Pierre Bergamin, james@ractive.ch
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
***************************************************************************/
// Unrar.cpp: implementation of the CUnrar class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipalot.h"
#include "Unrar.h"
#include "RegExp.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
extern CStringList g_sListCurfiles;
extern CStringList g_sListCurZIPfiles;
extern char curzipfile[_MAX_PATH];
extern HANDLE hStop;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CUnrar::CUnrar(CDialog * pUnzipDlg) : CExtract(pUnzipDlg)
{
}
CUnrar::~CUnrar()
{
}
CString CUnrar::GetDLLName(void)
{
return "UNRAR.DLL";
}
BOOL CUnrar::GetProcAddresses()
{
if (m_hDLL) {
RAROpenArchive = (HANDLE (__stdcall *)(struct RAROpenArchiveData *ArchiveData))GetProcAddress(m_hDLL, "RAROpenArchive");
RARCloseArchive = (int (__stdcall *)(HANDLE hArcData))GetProcAddress(m_hDLL, "RARCloseArchive");
RARReadHeader = (int (__stdcall *)(HANDLE hArcData, struct RARHeaderData *HeaderData))GetProcAddress(m_hDLL, "RARReadHeader");
RARProcessFile = (int (__stdcall *)(HANDLE hArcData, int Operation, char *DestPath, char *DestName))GetProcAddress(m_hDLL, "RARProcessFile");
RARSetChangeVolProc = (void (__stdcall *)(HANDLE hArcData, int (*ChangeVolProc)(char *ArcName,int Mode)))GetProcAddress(m_hDLL, "RARSetChangeVolProc");
RARSetProcessDataProc = (void (__stdcall *)(HANDLE hArcData, int (*ProcessDataProc)(unsigned char *Addr,int Size)))GetProcAddress(m_hDLL, "RARSetProcessDataProc");
RARSetPassword = (void (__stdcall *)(HANDLE hArcData, char *Password))GetProcAddress(m_hDLL, "RARSetPassword");
}
return RAROpenArchive && RARCloseArchive && RARReadHeader && RARProcessFile && RARSetChangeVolProc && RARSetProcessDataProc && RARSetPassword;
}
int CUnrar::ChangeVolProc(char *ArcName, int Mode)
{
if (Mode == RAR_VOL_ASK) {
int bRet = RequestFile(ArcName);
if (bRet != IDOK) {
return 0;
}
}
else {
g_sListCurZIPfiles.AddTail(GetFileName(ArcName));
m_pPseudoThis->m_pUnzipDlg->SendMessage(WM_EXTRACT_CURZIPFILE, 0, 0);
m_pPseudoThis->m_pUnzipDlg->SendMessage(WM_EXTRACT_STEPIT, 0, 0);
}
return 1;
}
int CUnrar::ProcessDataProc(unsigned char *Addr, int Size)
{
return 1;
}
errorCode CUnrar::Test(LPCTSTR sFilePath)
{
RAROpenArchiveData ArchiveData = {0};
RARHeaderData HeaderData;
ArchiveData.ArcName = (LPTSTR)sFilePath;
ArchiveData.OpenMode = RAR_OM_EXTRACT;
ArchiveData.CmtBufSize = COMMENTBUFSIZE;
ArchiveData.CmtBuf = m_sCommentBuf;
HANDLE hRARFile = RAROpenArchive(&ArchiveData);
if (!hRARFile) {
return EX_OPEN;
}
if (ArchiveData.OpenResult != 0) {
return EX_OPEN;
}
RARSetChangeVolProc(hRARFile, ChangeVolProc);
RARSetProcessDataProc(hRARFile,ProcessDataProc);
HeaderData.CmtBuf=NULL;
int RHCode, PFCode;
char * sOEMStr = new char[_MAX_PATH];
CharToOem("C:\\", (LPSTR)sOEMStr);
while ((RHCode=RARReadHeader(hRARFile, &HeaderData))==0) {
if (HeaderData.Flags & 0x04) {
// The file is password protected
LPTSTR lpszPwd;
int nRet = PromptPassword(&lpszPwd, HeaderData.FileName, HeaderData.ArcName, "The file is password protected");
if (nRet == IDOK && strlen(lpszPwd) > 0) {
RARSetPassword(hRARFile, (LPTSTR)lpszPwd);
m_bPwdSet = TRUE;
}
else if (nRet == IDCANCEL) {
delete [] sOEMStr;
return EX_CANCELLED;
}
}
PFCode=RARProcessFile(hRARFile, RAR_TEST, sOEMStr, NULL);
if (PFCode != 0) {
LPCTSTR sFile;
switch(PFCode) {
case ERAR_END_ARCHIVE:
case ERAR_BAD_ARCHIVE:
sFile = GetFileName(HeaderData.ArcName);
break;
case ERAR_EOPEN:
case ERAR_ECREATE:
case ERAR_ECLOSE:
case ERAR_EREAD:
case ERAR_EWRITE:
sFile = GetFileName(HeaderData.FileName);
break;
case ERAR_NO_MEMORY:
case ERAR_BAD_DATA:
case ERAR_UNKNOWN_FORMAT:
case ERAR_SMALL_BUF:
default:
sFile = NULL;
break;
}
ReportError(PFCode, sFile);
if (PFCode == ERAR_EOPEN) {
delete [] sOEMStr;
return EX_OPEN;
}
}
}
delete [] sOEMStr;
if (RHCode==ERAR_BAD_DATA) {
ReportError(RHCode);
}
RARCloseArchive(hRARFile);
return EX_OK;
}
BOOL CUnrar::IsArchive(LPCTSTR sFilePath)
{
RAROpenArchiveData ArchiveData = {0};
ArchiveData.ArcName = (LPTSTR)sFilePath;
ArchiveData.OpenMode = RAR_OM_EXTRACT;
ArchiveData.CmtBufSize = COMMENTBUFSIZE;
ArchiveData.CmtBuf = m_sCommentBuf;
HANDLE hRARFile = RAROpenArchive(&ArchiveData);
if (!hRARFile) {
return FALSE;
}
RARCloseArchive(hRARFile);
return TRUE;
}
errorCode CUnrar::Extract(const LPCTSTR sFileName, const LPCTSTR sDestination)
{
CString sD = sDestination;
if (sD.Right(1) != "\\") {
sD += "\\";
}
RAROpenArchiveData ArchiveData = {0};
RARHeaderData HeaderData;
ArchiveData.ArcName = (LPTSTR)sFileName;
ArchiveData.OpenMode = RAR_OM_EXTRACT;
ArchiveData.CmtBufSize = COMMENTBUFSIZE;
ArchiveData.CmtBuf = m_sCommentBuf;
HANDLE hRARFile = RAROpenArchive(&ArchiveData);
if (!hRARFile) {
return EX_OPEN;
}
if (ArchiveData.OpenResult != 0) {
return EX_OPEN;
}
RARSetChangeVolProc(hRARFile, ChangeVolProc);
RARSetProcessDataProc(hRARFile,ProcessDataProc);
HeaderData.CmtBuf=NULL;
int RHCode, PFCode;
while ((RHCode=RARReadHeader(hRARFile, &HeaderData))==0) {
if (WaitForSingleObject(hStop, 0) == WAIT_OBJECT_0) {
RARCloseArchive(hRARFile);
return EX_CANCELLED;
}
if (CheckForPassword(hRARFile, &HeaderData) == EX_CANCELLED) {
RARCloseArchive(hRARFile);
return EX_CANCELLED;
}
// We assume that everything is extracted
BOOL bExtract = TRUE;
BOOL bIsDir = HeaderData.Flags & 0x38;
CString sFinalDest = sD;
GetDestName(sFinalDest, HeaderData.FileName);
bExtract = CanOverwrite(sFinalDest, &HeaderData);
if (bExtract && unzipInfo.sExFilter != NULL) {
bExtract = FALSE;
TCHAR seps[] = "/";
TCHAR * token = strtok((LPTSTR)unzipInfo.sExFilter, seps);
while( token != NULL )
{
CRegExp regExp;
CString sExpr = token;
sExpr.Replace(".", "\\.");
sExpr.Replace("*", ".*");
sExpr.Replace("?", ".?");
if (regExp.RegComp(sExpr) != NULL) {
if (regExp.RegFind(HeaderData.FileName) != -1) {
// This filter matches -> Extract the file
// Don't process the other filters
bExtract = TRUE;
break;
}
}
// Get next filter
token = strtok( NULL, seps );
}
if (unzipInfo.sDontExFilter != NULL) {
token = strtok((LPTSTR)unzipInfo.sDontExFilter, seps);
while( token != NULL )
{
CRegExp regExp;
if (regExp.RegComp(token) != NULL) {
if (regExp.RegFind(HeaderData.FileName) == -1) {
// This filter matches -> DON'T extract the file
// Don't process the other filters
bExtract = FALSE;
break;
}
}
// Get next filter
token = strtok( NULL, seps );
}
}
}
int nOp = 0;
if (bExtract) {
nOp = RAR_EXTRACT;
if (!bIsDir) {
g_sListCurfiles.AddTail(GetFileName(HeaderData.FileName));
m_pPseudoThis->m_pUnzipDlg->PostMessage(WM_EXTRACT_CURFILE, 0, 0);
}
else {
nOp = unzipInfo.bRecreateDir ? RAR_EXTRACT : RAR_SKIP;
}
}
else {
nOp = RAR_SKIP;
}
PFCode=RARProcessFile(hRARFile, nOp, NULL, (LPTSTR)(LPCTSTR)sFinalDest);
if (bExtract && PFCode != 0) {
LPCTSTR sFile;
switch(PFCode) {
case ERAR_END_ARCHIVE:
case ERAR_BAD_ARCHIVE:
sFile = GetFileName(HeaderData.ArcName);
break;
case ERAR_EOPEN:
case ERAR_ECREATE:
case ERAR_ECLOSE:
case ERAR_EREAD:
case ERAR_EWRITE:
sFile = GetFileName(HeaderData.FileName);
break;
case ERAR_NO_MEMORY:
case ERAR_BAD_DATA:
case ERAR_UNKNOWN_FORMAT:
case ERAR_SMALL_BUF:
default:
sFile = NULL;
break;
}
ReportError(PFCode, sFile);
if (PFCode == ERAR_EOPEN) {
return EX_OPEN;
}
}
}
if (RHCode==ERAR_BAD_DATA) {
ReportError(RHCode);
}
RARCloseArchive(hRARFile);
return EX_OK;
}
void CUnrar::ReportError(int nError, LPCTSTR sFile /* = NULL */)
{
errorCode error;
switch(nError) {
case ERAR_END_ARCHIVE:
error = EX_EOF;
break;
case ERAR_NO_MEMORY:
error = EX_MEM;
break;
case ERAR_BAD_DATA: {
if (m_bPwdSet) {
error = EX_BADPWD;
}
else {
error = EX_CRC;
}
break;
}
case ERAR_BAD_ARCHIVE:
error = EX_ARCHIVE;
break;
case ERAR_UNKNOWN_FORMAT:
error = EX_UNSUP;
break;
case ERAR_EOPEN:
error = EX_OPEN;
break;
case ERAR_ECREATE:
error = EX_CREATE;
break;
case ERAR_ECLOSE:
error = EX_CLOSE;
break;
case ERAR_EREAD:
error = EX_READ;
break;
case ERAR_EWRITE:
error = EX_WRITE;
break;
case ERAR_SMALL_BUF:
error = EX_BUF;
break;
default:
error = EX_UNKNOWN;
}
CExtract::ReportError(error, sFile);
}
int CUnrar::CheckForPassword(HANDLE hRARFile, RARHeaderData *HeaderData)
{
if (HeaderData->Flags & 0x04) {
// The file is password protected
LPTSTR lpszPwd;
int nRet = PromptPassword(&lpszPwd, HeaderData->FileName, HeaderData->ArcName, "The file is password protected");
if (nRet == IDOK && strlen(lpszPwd) > 0) {
RARSetPassword(hRARFile, (LPTSTR)lpszPwd);
m_bPwdSet = TRUE;
}
else if (nRet == IDCANCEL) {
return EX_CANCELLED;
}
}
return EX_OK;
}
BOOL CUnrar::CanOverwrite(const CString &sDest, RARHeaderData * HeaderData)
{
CFileFind finder;
if (finder.FindFile(sDest)) {
if (!unzipInfo.bOverwrite) {
// No overwriting allowed
return FALSE;
}
if (unzipInfo.bOnlyNewer) {
finder.FindNextFile();
FILETIME existingFTime, localExistingFTime;
finder.GetLastWriteTime(&existingFTime);
FileTimeToLocalFileTime(&existingFTime, &localExistingFTime);
WORD existingDate, existingTime;
FileTimeToDosDateTime(&localExistingFTime, &existingDate, &existingTime);
//UINT hD = HIWORD(HeaderData->FileTime);
//UINT lD = LOWORD(HeaderData->FileTime);
if (existingDate > HIWORD(HeaderData->FileTime)) {
return FALSE;
}
if (existingDate == HIWORD(HeaderData->FileTime) && existingTime >= LOWORD(HeaderData->FileTime)) {
return FALSE;
}
}
}
return TRUE;
}
void CUnrar::GetDestName(CString &sDest, LPCTSTR sFileName)
{
if (unzipInfo.bRecreateDir) {
sDest += sFileName;
}
else {
CString sName = sFileName;
sName = sName.Right(sName.GetLength() - sName.ReverseFind('\\') - 1);
sDest += sName;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?