extract.cpp

来自「zip的全部算法源代码」· C++ 代码 · 共 413 行

CPP
413
字号
/*************************************************************************
                     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.
***************************************************************************/

// Extract.cpp: implementation of the CExtract class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <imagehlp.h>
#include "zipalot.h"
#include "Extract.h"
#include "PasswordDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CExtract * CExtract::m_pPseudoThis = NULL;
CString CExtract::m_sPassword = "";
tagUnzipInfo CExtract::unzipInfo = {0};
BOOL CExtract::m_bPwdSet = FALSE;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
extern BOOL Pump(HWND hWnd);
extern HANDLE hStop;
extern CStringList g_sListCurZIPfiles;
//extern char curfile[_MAX_PATH];
extern char curzipfile[_MAX_PATH];

CExtract::CExtract(CDialog * pUnzipDlg)
{
	m_pPseudoThis = this;
	m_pUnzipDlg = pUnzipDlg;
	memset(&unzipInfo, 0, sizeof(unzipInfo));
	m_bPwdSet = FALSE;
	m_sPassword = "";
}

CExtract::~CExtract()
{
	FreeDLL();
}

BOOL CExtract::FindDLL()
{
	const CString sUnzipDllVer = "5.4";
	const CString sCompanyName = "Info-ZIP";
	char szFullPath[MAX_PATH];
	char *ptr;

	if (SearchPath(
			NULL,               /* address of search path               */
			m_sDLLName,       /* address of filename                  */
			NULL,               /* address of extension                 */
			_MAX_PATH,           /* size, in characters, of buffer       */
			szFullPath,         /* address of buffer for found filename */
			&ptr                /* address of pointer to file component */
			) == 0) {
		return FALSE;
	}

	/* Now we'll check the unzip dll version information. Note that this is
	not the same information as is returned from a call to UzpVersion()
	*/

	DWORD dwVerHnd;
	DWORD dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);

	if (dwVerInfoSize) {
		BOOL  fRet, fRetName;
		char str[256];
		//LPSTR   lpstrVffInfo; /* Pointer to block to hold info */
		LPSTR lszVer = NULL;
		LPSTR lszVerName = NULL;
		UINT  cchVer = 0;


		LPSTR lpstrVffInfo = new char[dwVerInfoSize];

		/* Get the version information */
		if (GetFileVersionInfo(szFullPath, 0L, dwVerInfoSize, lpstrVffInfo)) {
			fRet = VerQueryValue(lpstrVffInfo, TEXT("\\StringFileInfo\\040904E4\\FileVersion"), (void **)&lszVer, &cchVer);
			fRetName = VerQueryValue(lpstrVffInfo, TEXT("\\StringFileInfo\\040904E4\\CompanyName"), (void **)&lszVerName, &cchVer);
			if (!fRet || !fRetName || (lstrcmpi(lszVer, sUnzipDllVer) != 0) || (lstrcmpi(lszVerName, sCompanyName) != 0)) {
				wsprintf (str, "The dll %s has the wrong version number.\r\nPlease use Version %s", m_sDLLName, sUnzipDllVer);
				delete [] lpstrVffInfo;
				MessageBox(NULL, str, "Error", MB_OK);
				return FALSE;
			}
		}
		delete [] lpstrVffInfo;
	}
	else {
		char str[256];
		wsprintf (str, "Cannot find %s", m_sDLLName);
		MessageBox(NULL, str, "Error", MB_OK);
		return FALSE;
	}
	
	return TRUE;
}

int CExtract::List(LPCTSTR sFileName, LPCTSTR sDestination)
{
	return 0;
}

BOOL CExtract::LoadDLL()
{
	m_sDLLName = GetDLLName();
	m_hDLL = LoadLibrary(m_sDLLName);
	if (m_hDLL == NULL) {
		return FALSE;
	}

	return GetProcAddresses();
}

void CExtract::FreeDLL()
{
	if (m_hDLL != NULL) {
		FreeLibrary(m_hDLL);
	}
}

BOOL CExtract::Init()
{
	if (!LoadDLL()) {
		char str[256];
		wsprintf (str, "Could not load %s", m_sDLLName);
		MessageBox(NULL, str, "Error", MB_OK);
		return FALSE;	
	}

	return DLLInit();
}

BOOL CExtract::DLLInit()
{
	return TRUE;
}

errorCode CExtract::ExtractAll(const LPCTSTR sSource, const LPCTSTR sTarget)
{
	CWaitCursor wait;

	// Update the unzip-info
	unzipInfo.sSource = sSource;
	unzipInfo.sTarget = sTarget;

	// Create the thread
	CWinThread * pThread = AfxBeginThread(ExtractThreadProc, NULL, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
	pThread->m_bAutoDelete = FALSE;
	// Fire it up
	pThread->ResumeThread();

	// Hmm, not sure but here could occur a "deadlock". If the Window gets not messages
	// any more and we call Pump at the wrong time, Pump will wait will a new
	// message arrives. Very unlikely, but possible.
	DWORD dwRet;
	while ((dwRet = WaitForSingleObject(pThread->m_hThread, 100)) != WAIT_OBJECT_0) {
		if (dwRet == WAIT_FAILED) {
			break;
		}
		Pump(m_pPseudoThis->m_pUnzipDlg->m_hWnd);
	}

	DWORD exit;
	// If the thread exited successfully, it returns 0;
	::GetExitCodeThread(pThread->m_hThread, &exit);
	delete pThread;

	return (errorCode)exit;
}

UINT CExtract::ExtractThreadProc(LPVOID lpParam)
{
	CFileFind finder;
	CString sFind = m_pPseudoThis->unzipInfo.sSource;

	m_bPwdSet = FALSE;

	if (sFind.Right(1) != "\\") {
		sFind += '\\';
	}

	// Make sure the filter makes sense
	// If the filter is NULL, we add the normal filter
	if (m_pPseudoThis->unzipInfo.sFilter == NULL || strlen(m_pPseudoThis->unzipInfo.sFilter) < 3) {
		if (m_pPseudoThis->unzipInfo.type == ACE) {
			sFind += "*.ace";
		}
		else if (m_pPseudoThis->unzipInfo.type == RAR) {
			sFind += "*.rar";
		}
		else {
			sFind += "*.zip";
		}
	}
	else {
		sFind += m_pPseudoThis->unzipInfo.sFilter;
		sFind.TrimRight();
	}

	int nFiles = 0;
	int nFileNo = 1;
	BOOL bFound = FALSE;

	if (m_pPseudoThis->m_sDLLName == "UNACEV2.DLL" || m_pPseudoThis->m_sDLLName == "UNRAR.DLL") {
		bFound = finder.FindFile(sFind);
		while(bFound) {
			bFound = finder.FindNextFile();
			nFiles += m_pPseudoThis->CountFiles(finder.GetFilePath());
		}
		finder.Close();
	}
	/*else if(m_pPseudoThis->m_sDLLName == "UNRAR.DLL") {
		CString sFileTitle = sFind.Left(sFind.ReverseFind('.')) + "*";
		bFound = finder.FindFile(sFileTitle);
		while (bFound) {
			nFiles++;
			bFound = finder.FindNextFile();
		}

	}*/
	else {
		// Count the *.zip files in the directory.
		bFound = finder.FindFile(sFind);
		while (bFound) {
			nFiles++;
			bFound = finder.FindNextFile();
		}
		finder.Close();
	}


	if (nFiles == 0) {
		return EX_NO_ARCHIVES;
	}
	strcpy(curzipfile, m_pPseudoThis->unzipInfo.sSource);
	m_pPseudoThis->m_pUnzipDlg->SendMessage(WM_EXTRACT_SETSOURCE, 0, (long)curzipfile);
	strcpy(curzipfile, m_pPseudoThis->unzipInfo.sTarget);
	m_pPseudoThis->m_pUnzipDlg->SendMessage(WM_EXTRACT_SETTARGET, 0, (long)curzipfile);

	if (m_pPseudoThis->m_pUnzipDlg) {
		m_pPseudoThis->m_pUnzipDlg->PostMessage(WM_EXTRACT_RANGE, 0, nFiles);
	}

	finder.Close();

	CString sPath;
	CString sFileName;
	errorCode nRet = EX_NO_FILES;
	
	// Process all files
	bFound = finder.FindFile(sFind);
	while (bFound) {
		// Check for cancel event
		if (WaitForSingleObject(hStop, 0) == WAIT_OBJECT_0) {
			return EX_CANCELLED;
		}
		bFound = finder.FindNextFile();

		// Get the file informations
		sPath = finder.GetFilePath();
		sFileName = finder.GetFileName();

		if (m_pPseudoThis->m_pUnzipDlg) {
			g_sListCurZIPfiles.AddTail(sFileName);
			m_pPseudoThis->m_pUnzipDlg->PostMessage(WM_EXTRACT_CURZIPFILE, 0, 0);
		}

		if (m_pPseudoThis->unzipInfo.type != ZIP) {
			// Clear the password if it's not a ZIP FILE
			m_pPseudoThis->m_sPassword = "";
		}

		CString sNewDir;

		if (unzipInfo.bOwnDir) {
			CString sFName = sFileName;
			sFName = sFName.Mid(sFileName.ReverseFind('\\') + 1);
			sNewDir = m_pPseudoThis->unzipInfo.sTarget;
			sNewDir += "\\";
			sNewDir += sFName.Left(sFName.ReverseFind('.'));
			if (sNewDir.Right(1) != "\\") {
				sNewDir += "\\";
			}
			MakeSureDirectoryPathExists(sNewDir);
		}
		else if (m_pPseudoThis->unzipInfo.sTarget != NULL) {
			sNewDir = m_pPseudoThis->unzipInfo.sTarget;
		}

		nRet = m_pPseudoThis->Extract((LPTSTR)(LPCTSTR)sPath, sNewDir);
		if (nRet != EX_OK) {
			ReportError(nRet);
			// If the disk is full, we don't try processing the other
			// files
			/*if (nRet == EX_DISK) {
				return EX_DISK;
			}*/
		}
		if (m_pPseudoThis->m_pUnzipDlg) {
			m_pPseudoThis->m_pUnzipDlg->SendMessage(WM_EXTRACT_STEPIT, 0, 0);
		}
	}

	return nRet;
}

LPCTSTR CExtract::GetFileName(LPCTSTR sFilePath)
{
	LPCTSTR s = strrchr(sFilePath, '\\');
	if (s == NULL) {
		// No backslash found
		return sFilePath;
	}
	// Skip the backslash
	return ++s;
}

int CExtract::PromptPassword(LPTSTR *lpszPassword, LPCTSTR lpszFileName, LPCTSTR lpszArchive, LPCTSTR lpszMessage, BOOL bForce /* = FALSE */)
{
	if (!bForce && !m_sPassword.IsEmpty()) {
		*lpszPassword = (LPTSTR)(LPCTSTR)m_sPassword;
		return IDOK;
	}
	CPasswordDlg dlg;
	dlg.m_sFileName = lpszFileName;
	dlg.m_sMessage = lpszMessage;
	dlg.m_sZipPath = lpszArchive;
	if (dlg.DoModal() == IDOK) {
		m_sPassword = dlg.m_sPassword;
		*lpszPassword = (LPTSTR)(LPCTSTR)m_sPassword;
		return IDOK;
	}
	else {
		return IDCANCEL;
	}
}

void CExtract::ReportError(errorCode error, LPCTSTR sFile /* = NULL */)
{
	if (sFile) {
		strcpy(curzipfile, sFile);
	}
	m_pPseudoThis->m_pUnzipDlg->PostMessage(WM_EXTRACT_ERROR, (WPARAM)curzipfile, error);
}

int CExtract::RequestFile(LPTSTR lpszFileName)
{
	OPENFILENAME openfilename;
	openfilename.lStructSize = sizeof(OPENFILENAME);
	openfilename.hwndOwner = AfxGetMainWnd()->m_hWnd;
	openfilename.hInstance = AfxGetInstanceHandle();
	openfilename.lpstrFilter = NULL;
	openfilename.lpstrCustomFilter = NULL;
	openfilename.nMaxCustFilter = 0;
	openfilename.nFilterIndex = 0;
	openfilename.lpstrFile = lpszFileName;
	openfilename.nMaxFile = MAX_PATH;
	openfilename.lpstrFileTitle = NULL;
	openfilename.nMaxFileTitle = 0;
	openfilename.lpstrInitialDir = NULL;
	openfilename.lpstrTitle = "Open next archive...";
	openfilename.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
	openfilename.nFileOffset = 0;
	openfilename.nFileExtension = 0;
	openfilename.lpstrDefExt = NULL;
	openfilename.lCustData = 0;
	openfilename.lpfnHook = NULL;
	openfilename.lpTemplateName = NULL;
	return GetOpenFileName(&openfilename);
}

int CExtract::CountFiles(LPCTSTR sFilePath)
{
	int nFiles = 0;
	CString sFile = sFilePath;
	sFile = sFile.Left(sFile.ReverseFind('.')) + "*";
	CFileFind finder;
	BOOL bFound = finder.FindFile(sFile);
	while (bFound) {
		nFiles++;
		bFound = finder.FindNextFile();
	}

	return nFiles;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?