www.pudn.com > WinMerge-2.6.12-src.zip > Merge7z311.cpp


/* Merge7z311.cpp: Provide a handy C++ interface to access 7Zip services 
 * Copyright (c) 2003 Jochen Tucht 
 * 
 * License:	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., 675 Mass Ave, Cambridge, MA 02139, USA. 
 * 
 * Remarks:	Based on 7z311 sources. May or may not compile/run with earlier or 
 *			later versions. See Merge7z311.dsp for dependencies. Some less 
 *			version-dependent parts of code reside in Merge7zCommon.cpp. 
 
Please mind 2. a) of the GNU General Public License, and log your changes below. 
 
DATE:		BY:					DESCRIPTION: 
==========	==================	================================================ 
2003/12/09	Jochen Tucht		Created 
2004/03/15	Jochen Tucht		Fix Visual Studio 2003 build issue 
2004/08/19	Laurent Ganier		Compression of folders 
								Through EnumerateDirectory (from code of 7zip) 
2004/10/17	Jochen Tucht		Leave decision whether to recurse into folders 
								to enumerator (Mask.Recurse) 
2005/01/15	Jochen Tucht		Changed as explained in revision.txt 
2005/02/26	Jochen Tucht		Changed as explained in revision.txt 
2005/03/19	Jochen Tucht		Don't show error message on intentional abort 
2006/06/28	Jochen Neubeck		Avoid to occasionally prompt for password twice 
*/ 
 
#include "stdafx.h" 
 
#define INITGUID 
#include  
 
#include "Merge7zCommon.h" 
 
#include "7zip/FileManager/OpenCallback.h" 
#include "7zip/FileManager/ExtractCallback.h" 
#include "7zip/FileManager/UpdateCallback100.h" 
 
#include "7zip/UI/Agent/ArchiveExtractCallback.h" 
#include "7zip/UI/Agent/ArchiveUpdateCallback.h" 
 
/** 
 * @brief Extraction thread 
 */ 
class CThreadExtracting : CThread 
{ 
protected: 
	DWORD Process() 
	{ 
		ExtractCallbackSpec->ProgressDialog.WaitCreating(); 
		result = Archive->Extract(indices, numItems, false, ArchiveExtractCallback); 
		ExtractCallbackSpec->ProgressDialog.MyClose(); 
		return 0; 
	} 
	static DWORD WINAPI Process(void *param) 
	{ 
		return ((CThreadExtracting *)param)->Process(); 
	} 
	CExtractCallbackImp *ExtractCallbackSpec; 
	IInArchive *Archive; 
	IArchiveExtractCallback *ArchiveExtractCallback; 
	const UINT32 *indices; 
	UINT32 numItems; 
public: 
	HRESULT result; 
 
	CThreadExtracting 
	( 
		CExtractCallbackImp *ExtractCallbackSpec, 
		IInArchive *Archive, 
		IArchiveExtractCallback *ArchiveExtractCallback, 
		const CSysString &title, 
		const UINT32 *indices = 0, 
		UINT32 numItems = -1 
	): 
		ExtractCallbackSpec(ExtractCallbackSpec), 
		Archive(Archive), 
		ArchiveExtractCallback(ArchiveExtractCallback), 
		indices(indices), 
		numItems(numItems) 
	{ 
		result = E_FAIL; 
		if COMPLAIN(!Create(Process, this)) 
		{ 
			Complain(GetLastError(), NULL); 
		} 
		ExtractCallbackSpec->StartProgressDialog(GetUnicodeString(title)); 
	} 
}; 
 
/** 
 * @brief Construct Inspector 
 */ 
Format7zDLL::Interface::Inspector::Inspector(Format7zDLL::Interface *format, LPCTSTR path) 
: format(format), archive(0), file(0), callback(0), path(path), ustrDefaultName(GetUnicodeString(path)) 
, passwordIsDefined(false) 
{ 
} 
 
/** 
 * @brief Initialize Inspector 
 */ 
void Format7zDLL::Interface::Inspector::Init(HWND hwndParent) 
{ 
	format->GetDefaultName(hwndParent, ustrDefaultName); 
	COpenArchiveCallback *callbackImpl = new COpenArchiveCallback; 
	(archive = format->GetInArchive()) -> AddRef(); 
	(file = new CInFileStream) -> AddRef(); 
	(callback = callbackImpl) -> AddRef(); 
	callbackImpl->_passwordIsDefined = false; 
	callbackImpl->_parentWindow = hwndParent; 
	if COMPLAIN(!NFile::NFind::FindFile(path, fileInfo)) 
	{ 
		Complain(ERROR_FILE_NOT_FOUND, path); 
	} 
	if COMPLAIN(!file->Open(path)) 
	{ 
		Complain(ERROR_OPEN_FAILED, path); 
	} 
	if COMPLAIN(archive->Open(file, 0, callback) != S_OK) 
	{ 
		Complain(ERROR_CANT_ACCESS_FILE, path); 
	} 
	passwordIsDefined = callbackImpl->_passwordIsDefined; 
	password = callbackImpl->_password; 
} 
 
/** 
 * @brief Extract set of items specified by index 
 */ 
HRESULT Format7zDLL::Interface::Inspector::Extract(HWND hwndParent, LPCTSTR folder, const UINT32 *indices, UINT32 numItems) 
{ 
	CArchiveExtractCallback *extractCallbackSpec = 0; 
	CExtractCallbackImp *extractCallbackSpec2 = 0; 
	HRESULT result = 0; 
	try 
	{ 
		if (*folder) 
		{ 
			if COMPLAIN(!NFile::NDirectory::CreateComplexDirectory(folder)) 
			{ 
				Complain(_T("Can not create output directory")); 
			} 
		} 
 
		(extractCallbackSpec2 = new CExtractCallbackImp) -> AddRef(); 
 
		extractCallbackSpec2->Init 
		( 
			NExtractionMode::NOverwrite::kWithoutPrompt,	// overwriteMode 
			passwordIsDefined,								// passwordIsDefined 
			password										// password 
		); 
 
		extractCallbackSpec2->_parentWindow = hwndParent; 
 
		extractCallbackSpec2->ProgressDialog.MainWindow = 0; 
		(extractCallbackSpec = new CArchiveExtractCallback) -> AddRef(); 
 
		extractCallbackSpec->Init 
		( 
			archive,  
			extractCallbackSpec2, 
			GetUnicodeString(folder), 
			NExtractionMode::NPath::kFullPathnames,  
			NExtractionMode::NOverwrite::kWithoutPrompt, 
			UStringVector(), 
			ustrDefaultName,  
			fileInfo.LastWriteTime, 
			fileInfo.Attributes 
		); 
 
		result = CThreadExtracting 
		( 
			extractCallbackSpec2, 
			archive, 
			extractCallbackSpec, 
			PathFindFileName(path), 
			indices, 
			numItems 
		).result; 
 
		if COMPLAIN(extractCallbackSpec->_numErrors) 
		{ 
			//	There is no canned system message for this one, so it won't 
			//	localize. I can't help it. 
			Complain(_T("%s:\n%I64u error(s)"), path, extractCallbackSpec->_numErrors); 
		} 
		if COMPLAIN(result != S_OK && result != E_ABORT) 
		{ 
			Complain(result, path); 
		} 
	} 
	catch (Complain *complain) 
	{ 
		result = complain->Alert(hwndParent); 
	} 
	Release(static_cast(extractCallbackSpec)); 
	Release(static_cast(extractCallbackSpec2)); 
	return result; 
} 
 
/** 
 * @brief Compression thread 
 */ 
class CThreadUpdateCompress : CThread 
{ 
protected: 
	DWORD Process() 
	{ 
		updateCallback100->ProgressDialog.WaitCreating(); 
		result = outArchive->UpdateItems(file, numItems, updateCallbackSpec); 
		updateCallback100->ProgressDialog.MyClose(); 
		return 0; 
	} 
	static DWORD WINAPI Process(void *param) 
	{ 
		return ((CThreadUpdateCompress *)param)->Process(); 
	} 
	CUpdateCallback100Imp *updateCallback100; 
	IOutArchive *outArchive; 
	CArchiveUpdateCallback *updateCallbackSpec; 
	IOutStream *file; 
public: 
	HRESULT result; 
	UINT32 numItems; 
	CThreadUpdateCompress 
	( 
		CUpdateCallback100Imp *updateCallback100, 
		IOutArchive *outArchive, 
		CArchiveUpdateCallback *updateCallbackSpec, 
		UINT32 numItems, 
		IOutStream *file, 
		const CSysString &title 
	): 
		updateCallback100(updateCallback100), 
		outArchive(outArchive), 
		updateCallbackSpec(updateCallbackSpec), 
		numItems(numItems), 
		file(file) 
	{ 
		result = E_FAIL; 
		if COMPLAIN(!Create(Process, this)) 
		{ 
			Complain(GetLastError(), NULL); 
		} 
		updateCallback100->StartProgressDialog(GetUnicodeString(title)); 
	} 
}; 
 
/** 
 * @brief Construct Updater 
 */ 
Format7zDLL::Interface::Updater::Updater(Format7zDLL::Interface *format, LPCTSTR path) 
: format(format), outArchive(0), file(0), path(path) 
{ 
} 
 
/** 
 * @brief Initialize Updater 
 */ 
void Format7zDLL::Interface::Updater::Init(HWND hwndParent) 
{ 
	(outArchive = format->GetOutArchive()) -> AddRef(); 
	(file = new COutFileStream) -> AddRef(); 
	if COMPLAIN(!file->Open(path)) 
	{ 
		Complain(ERROR_CANNOT_MAKE, path); 
	} 
} 
 
/** 
 * @brief Commit update 
 */ 
HRESULT Format7zDLL::Interface::Updater::Commit(HWND hwndParent) 
{ 
	CArchiveUpdateCallback *updateCallbackSpec = 0; 
	CUpdateCallback100Imp *updateCallback100 = 0; 
	HRESULT result = 0; 
	try 
	{ 
		//	Ref counts are not always accurate with 7-Zip. 
		//	An extra AddRef() ensures that interfaces remain valid until they 
		//	are explicitly released at the end of this function. 
		(updateCallbackSpec = new CArchiveUpdateCallback) -> AddRef(); 
		(updateCallback100 = new CUpdateCallback100Imp) -> AddRef(); 
		updateCallback100->Init 
		( 
			hwndParent, 
			false,											// passwordIsDefined 
			UString()										// password 
		); 
 
		// Build the operationChain. One element per item 
		CObjectVector operationChain; 
		CUpdatePair2 pair2; 
		pair2.IsAnti = false; 
		pair2.ExistInArchive = false; 
		pair2.ExistOnDisk = true; 
		pair2.NewData = pair2.NewProperties = true; 
 
		operationChain.Reserve(dirItems.Size()); 
		int i; 
		for (i = 0 ; i < dirItems.Size() ; i++) 
		{ 
			pair2.DirItemIndex = i; 
			operationChain.Add(pair2); 
		} 
 
		// No items in dest archive. We always recreate the dest archive 
 
		// Now compress... 
		updateCallbackSpec->Init(UString()/*folderPrefix*/, &dirItems, &archiveItems, 
			&operationChain, NULL, updateCallback100); 
 
		result = CThreadUpdateCompress 
		( 
			updateCallback100, 
			outArchive, 
			updateCallbackSpec, 
			operationChain.Size(), 
			file, 
			PathFindFileName(path) 
		).result; 
 
		//result = outArchive->UpdateItems(file, operationChain.Size(), updateCallbackSpec); 
		if COMPLAIN(result != S_OK && result != E_ABORT) 
		{ 
			Complain(result, path); 
		} 
	} 
	catch (Complain *complain) 
	{ 
		result = complain->Alert(hwndParent); 
	} 
	//	Always release interfaces in this order, or else all hell will break 
	//	loose! 
	Release(static_cast(updateCallbackSpec)); 
	Release(static_cast(updateCallback100)); 
	return result; 
}