www.pudn.com > WinMerge-2.6.12-src.zip > Merge7zCommon.cpp
/* Merge7zCommon.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: This file contains the presumably version-independent parts of * Merge7z code. Version specific code resides in Merge7zXXX.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 2003/12/16 Jochen Tucht GuessFormat() now checks for directory 2004/03/18 Jochen Tucht Experimental DllGetVersion() based on rcsid. 2004/10/10 Jochen Tucht DllGetVersion() based on new REVISION.TXT 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 Changed as explained in revision.txt 2005/06/22 Jochen Tucht Treat .ear and .war like .zip 2005/07/05 Jochen Tucht Add missing .tbz2 2005/08/20 Jochen Tucht Option to guess archive format by signature. EnumerateDirectory() in EnumDirItems.cpp has somewhat changed so I can no longer use it. 2005/10/02 Jochen Tucht Add CHM format 2005/11/19 Jochen Tucht Minor changes to build against 7z430 beta 2006/06/28 Jochen Neubeck Add ISO format (introduced with 7z436 beta) Add NSIS format (introduced with 7z440 beta) */ #include "stdafx.h" #include "Merge7zCommon.h" #include "7zip/FileManager/LangUtils.h" //#include "7zip/UI/Common/EnumDirItems.cpp" // defines static void EnumerateDirectory() using namespace NWindows; using namespace NFile; using namespace NName; void AddDirFileInfo( const UString &prefix, const UString &fullPathName, NFind::CFileInfoW &fileInfo, CObjectVector&dirItems) { CDirItem item; item.Attributes = fileInfo.Attributes; item.Size = fileInfo.Size; item.CreationTime = fileInfo.CreationTime; item.LastAccessTime = fileInfo.LastAccessTime; item.LastWriteTime = fileInfo.LastWriteTime; item.Name = prefix + fileInfo.Name; item.FullPath = fullPathName; dirItems.Add(item); } static void EnumerateDirectory( const UString &baseFolderPrefix, const UString &directory, const UString &prefix, CObjectVector &dirItems) { NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard)); NFind::CFileInfoW fileInfo; while (enumerator.Next(fileInfo)) { AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems); if (fileInfo.IsDirectory()) { EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter), prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems); } } } HINSTANCE g_hInstance; #ifndef _UNICODE bool g_IsNT = false; static bool IsItWindowsNT() { OSVERSIONINFO versionInfo; versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); if (!::GetVersionEx(&versionInfo)) return false; return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); } #endif DWORD g_dwFlags; CHAR g_cPath7z[MAX_PATH]; /** * @brief Dll entry point */ BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) { if (dwReason == DLL_PROCESS_ATTACH) { g_hInstance = hInstance; # ifndef _UNICODE g_IsNT = IsItWindowsNT(); # endif } return TRUE; } /** * @brief Load a dll and import a number of functions. */ static HMODULE DllProxyHelper(LPCSTR *proxy, ...) { HMODULE handle = NULL; if (LPCSTR name = *proxy) { if (proxy[1] && proxy[1] != name) { char path[MAX_PATH]; FormatMessageA ( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, name, 0, 0, path, sizeof path, (va_list *)(&proxy + 1) ); handle = LoadLibraryA(path); if (handle) { LPCSTR *export = proxy; *proxy = NULL; while ((name = *++export) != NULL) { *export = (LPCSTR)GetProcAddress(handle, name); if (*export == NULL) { *proxy = proxy[1] = name; export = proxy + 2; break; } } *export = (LPCSTR)handle; } } if ((name = *proxy) != NULL) { DWORD dwError = ERROR_MOD_NOT_FOUND; HMODULE hContext = NULL; if (proxy[1] == name) { dwError = ERROR_PROC_NOT_FOUND; hContext = (HMODULE)proxy[2]; } Complain(dwError, GetSystemString(name), hContext); } } return handle; } /** * @brief Access archiver dll functions through proxy. */ struct Format7zDLL *Format7zDLL::Proxy::operator->() { DllProxyHelper(Format7zDLL, g_cPath7z); return (struct Format7zDLL *)Format7zDLL; } /** * @brief Ask archiver dll for an interface of given class. */ HRESULT Format7zDLL::Interface::CreateObject(const GUID *interfaceID, void **outObject) { PROPVARIANT value; HRESULT result = proxy->GetHandlerProperty(NArchive::kClassID, &value); if SUCCEEDED(result) { if (value.vt != VT_BSTR || SysStringByteLen(value.bstrVal) != sizeof(GUID)) { result = DISP_E_TYPEMISMATCH; } else { result = proxy->CreateObject((const CLSID *)value.bstrVal, interfaceID, outObject); } VariantClear((VARIANT *)&value); } return result; } /** * @brief Ask archiver dll for an instance of IInArchive. */ IInArchive *Format7zDLL::Interface::GetInArchive() { void *pv; if COMPLAIN(CreateObject(&IID_IInArchive, &pv) != S_OK) { Complain(RPC_S_INTERFACE_NOT_FOUND, _T("IInArchive"), proxy.handle); } return static_cast (pv); } /** * @brief Ask archiver dll for an instance of IOutArchive. */ IOutArchive *Format7zDLL::Interface::GetOutArchive() { void *pv; if COMPLAIN(CreateObject(&IID_IOutArchive, &pv) != S_OK) { Complain(RPC_S_INTERFACE_NOT_FOUND, _T("IOutArchive"), proxy.handle); } return static_cast (pv); } /** * @brief Extraction method accessible from outside */ HRESULT Format7zDLL::Interface::DeCompressArchive(HWND hwndParent, LPCTSTR path, LPCTSTR folder) { HRESULT result = E_FAIL; if (Merge7z::Format::Inspector *inspector = Open(hwndParent, path)) { if (CMyComBSTR(GetHandlerAddExtension(hwndParent)).Length()) { //Most handlers seem to be happy with missing index array, but rpm //handler doesn't know how to "extract all" and needs index array //even for the one and only file inside (which is .cpio.gz). static const UINT32 indices[1] = {0}; result = inspector->Extract(hwndParent, folder, indices, 1); } else { result = inspector->Extract(hwndParent, folder); } inspector->Free(); } return result; } /** * @brief Open archive for inspection. */ Merge7z::Format::Inspector *Format7zDLL::Interface::Open(HWND hwndParent, LPCTSTR path) { Inspector *inspector = new Inspector(this, path); try { inspector->Init(hwndParent); } catch (Complain *complain) { complain->Alert(hwndParent); inspector->Free(); inspector = 0; } return inspector; } /** * @brief Prepare inspection interface for iteration. */ UINT32 Format7zDLL::Interface::Inspector::Open() { UINT32 numItems = 0; archive->GetNumberOfItems(&numItems); return numItems; } /** * @brief free inspection interface. */ void Format7zDLL::Interface::Inspector::Free() { Release(archive); Release(static_cast (file)); Release(callback); delete this; } HRESULT Format7zDLL::Interface::Inspector::GetProperty(UINT32 index, PROPID propID, PROPVARIANT *value, VARTYPE vt) { VariantInit((VARIANT *)value); HRESULT result = archive->GetProperty(index, propID, value); if (SUCCEEDED(result) && value->vt != vt) { VariantClear((VARIANT *)value); result = DISP_E_TYPEMISMATCH; } return result; } BSTR Format7zDLL::Interface::Inspector::GetPath(UINT32 index) { PROPVARIANT value; return SUCCEEDED(GetProperty(index, kpidPath, &value, VT_BSTR)) ? value.bstrVal : 0; } BSTR Format7zDLL::Interface::Inspector::GetName(UINT32 index) { PROPVARIANT value; return SUCCEEDED(GetProperty(index, kpidName, &value, VT_BSTR)) ? value.bstrVal : 0; } BSTR Format7zDLL::Interface::Inspector::GetExtension(UINT32 index) { PROPVARIANT value; return SUCCEEDED(GetProperty(index, kpidExtension, &value, VT_BSTR)) ? value.bstrVal : 0; } VARIANT_BOOL Format7zDLL::Interface::Inspector::IsFolder(UINT32 index) { PROPVARIANT value; return SUCCEEDED(GetProperty(index, kpidIsFolder, &value, VT_BOOL)) ? value.boolVal : 0; } FILETIME Format7zDLL::Interface::Inspector::LastWriteTime(UINT32 index) { static const FILETIME invalid = { 0, 0 }; PROPVARIANT value; return SUCCEEDED(GetProperty(index, kpidLastWriteTime, &value, VT_FILETIME)) ? value.filetime : invalid; } void Format7zDLL::Interface::GetDefaultName(HWND hwndParent, UString &ustrDefaultName) { int dot = ustrDefaultName.ReverseFind('.'); int slash = ustrDefaultName.ReverseFind('\\'); if (dot > slash) { LPCWSTR pchExtension = ustrDefaultName; pchExtension += dot + 1; static const OLECHAR wBlank[] = L" "; CMyComBSTR bstrHandlerExtension = GetHandlerExtension(hwndParent); CMyComBSTR bstrHandlerAddExtension = GetHandlerAddExtension(hwndParent); LPWSTR pchHandlerExtension = bstrHandlerExtension.m_str; LPWSTR pchHandlerAddExtension = bstrHandlerAddExtension.m_str; while (int cchHandlerAddExtension = StrCSpnW(pchHandlerAddExtension += StrSpnW(pchHandlerAddExtension, wBlank), wBlank)) { int cchHandlerExtension = StrCSpnW(pchHandlerExtension += StrSpnW(pchHandlerExtension, wBlank), wBlank); if (StrIsIntlEqualW(FALSE, pchExtension, pchHandlerExtension, cchHandlerExtension) && pchExtension[cchHandlerExtension] == 0) { pchHandlerAddExtension[cchHandlerAddExtension] = '\0'; // will also stop iteration ustrDefaultName.ReleaseBuffer(dot); if (*pchHandlerAddExtension == '.') // consider != '*' { ustrDefaultName += pchHandlerAddExtension; dot += cchHandlerAddExtension; // make ReleaseBuffer(dot) below a NOP } } pchHandlerExtension += cchHandlerExtension; pchHandlerAddExtension += cchHandlerAddExtension; } ustrDefaultName.ReleaseBuffer(dot); ustrDefaultName.Delete(0, slash + 1); } else { ustrDefaultName = L"noname"; } } BSTR Format7zDLL::Interface::GetDefaultName(HWND hwndParent, LPCTSTR path) { UString ustrDefaultName = GetUnicodeString(path); GetDefaultName(hwndParent, ustrDefaultName); return SysAllocString(ustrDefaultName); } BSTR Format7zDLL::Interface::Inspector::GetDefaultName() { //UString ustrDefaultName = GetUnicodeString(path); return SysAllocString(ustrDefaultName); } /** * @brief Open archive for update. */ Merge7z::Format::Updater *Format7zDLL::Interface::Update(HWND hwndParent, LPCTSTR path) { Updater *updater = new Updater(this, path); try { updater->Init(hwndParent); } catch (Complain *complain) { complain->Alert(hwndParent); updater->Free(); updater = 0; } return updater; } /** * @brief Add item to updater */ UINT32 Format7zDLL::Interface::Updater::Add(Merge7z::DirItemEnumerator::Item &etorItem) { // fill in the default values from the enumerator CDirItem item; if (etorItem.Mask.Item & etorItem.Mask.Name) item.Name = GetUnicodeString(etorItem.Name); if (etorItem.Mask.Item & etorItem.Mask.FullPath) item.FullPath = GetUnicodeString(etorItem.FullPath); if (etorItem.Mask.Item & etorItem.Mask.Attributes) item.Attributes = etorItem.Attributes; if (etorItem.Mask.Item & etorItem.Mask.Size) item.Size = etorItem.Size; if (etorItem.Mask.Item & etorItem.Mask.CreationTime) item.CreationTime = etorItem.CreationTime; if (etorItem.Mask.Item & etorItem.Mask.LastAccessTime) item.LastAccessTime = etorItem.LastAccessTime; if (etorItem.Mask.Item & etorItem.Mask.LastWriteTime) item.LastWriteTime = etorItem.LastWriteTime; if (etorItem.Mask.Item && (etorItem.Mask.Item & (etorItem.Mask.NeedFindFile|etorItem.Mask.CheckIfPresent)) != etorItem.Mask.NeedFindFile) { // Check the info from the disk NFile::NFind::CFileInfoW fileInfo; if (NFile::NFind::FindFile(item.FullPath, fileInfo)) { if (!(etorItem.Mask.Item & etorItem.Mask.Name)) item.Name = fileInfo.Name; if (!(etorItem.Mask.Item & etorItem.Mask.Attributes)) item.Attributes = fileInfo.Attributes; if (!(etorItem.Mask.Item & etorItem.Mask.Size)) item.Size = fileInfo.Size; if (!(etorItem.Mask.Item & etorItem.Mask.CreationTime)) item.CreationTime = fileInfo.CreationTime; if (!(etorItem.Mask.Item & etorItem.Mask.LastAccessTime)) item.LastAccessTime = fileInfo.LastAccessTime; if (!(etorItem.Mask.Item & etorItem.Mask.LastWriteTime)) item.LastWriteTime = fileInfo.LastWriteTime; } else { // file not valid, forget it etorItem.Mask.Item = 0; } } if (etorItem.Mask.Item) { // No check from disk, simply use info from enumerators (risky) // Why risky? This is not at all obvious. dirItems.Add(item); // Recurse into directories (call a function of 7zip) if ((etorItem.Mask.Item & etorItem.Mask.Recurse) && (item.Attributes & FILE_ATTRIBUTE_DIRECTORY)) { EnumerateDirectory(UString(), item.FullPath + L'\\', item.Name + L'\\', dirItems); } } return etorItem.Mask.Item; } /** * @brief free updater interface. */ void Format7zDLL::Interface::Updater::Free() { Release(outArchive); Release(static_cast (file)); delete this; } /** * @brief Compression method accessible from outside * * @note See CAgent::DoOperation (in 7zip source) for model */ HRESULT Format7zDLL::Interface::CompressArchive(HWND hwndParent, LPCTSTR path, Merge7z::DirItemEnumerator *etor) { HRESULT result = E_FAIL; if (Merge7z::Format::Updater *updater = Update(hwndParent, path)) { UINT count = etor->Open(); while (count--) { Merge7z::DirItemEnumerator::Item etorItem; etorItem.Mask.Item = 0; Merge7z::Envelope *envelope = etor->Enum(etorItem); updater->Add(etorItem); if (envelope) { envelope->Free(); } } result = updater->Commit(hwndParent); updater->Free(); } return result; } /** * @brief get handler property identified by given propID */ HRESULT Format7zDLL::Interface::GetHandlerProperty(HWND hwndParent, PROPID propID, PROPVARIANT *value, VARTYPE vt) { VariantInit((VARIANT *)value); HRESULT result = DISP_E_EXCEPTION; try { result = proxy->GetHandlerProperty(propID, value); if (SUCCEEDED(result) && value->vt != vt) { VariantClear((VARIANT *)value); result = DISP_E_TYPEMISMATCH; } } catch (Complain *complain) { complain->Alert(hwndParent); } return result; } /** * @brief get Name handler property */ BSTR Format7zDLL::Interface::GetHandlerName(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kName, &value, VT_BSTR)) ? value.bstrVal : 0; } /** * @brief get ClassID handler property */ BSTR Format7zDLL::Interface::GetHandlerClassID(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kClassID, &value, VT_BSTR)) ? value.bstrVal : 0; } /** * @brief get Extension handler property */ BSTR Format7zDLL::Interface::GetHandlerExtension(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kExtension, &value, VT_BSTR)) ? value.bstrVal : 0; } /** * @brief get AddExtension handler property */ BSTR Format7zDLL::Interface::GetHandlerAddExtension(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kAddExtension, &value, VT_BSTR)) ? value.bstrVal : 0; } /** * @brief get Update handler property */ VARIANT_BOOL Format7zDLL::Interface::GetHandlerUpdate(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kUpdate, &value, VT_BOOL)) ? value.boolVal : 0; } /** * @brief get KeepName handler property */ VARIANT_BOOL Format7zDLL::Interface::GetHandlerKeepName(HWND hwndParent) { PROPVARIANT value; return SUCCEEDED(GetHandlerProperty(hwndParent, NArchive::kKeepName, &value, VT_BOOL)) ? value.boolVal : 0; } /** * @brief Initialize the library. */ int Merge7z::Initialize(DWORD dwFlags) { g_dwFlags = dwFlags; if (dwFlags & Initialize::Local7z) { GetModuleFileNameA(g_hInstance, g_cPath7z, sizeof g_cPath7z); PathRemoveFileSpecA(g_cPath7z); } else { DWORD type = 0; DWORD size = sizeof g_cPath7z; SHGetValueA(HKEY_LOCAL_MACHINE, "Software\\7-Zip", "Path", &type, g_cPath7z, &size); } PathAddBackslashA(g_cPath7z); if (WORD wLangID = HIWORD(dwFlags)) { LoadLang(MAKEINTATOM(wLangID)); } return 0; } static const char aCreateObject[] = "CreateObject"; static const char aGetHandlerProperty[] = "GetHandlerProperty"; Format7zDLL::Interface *Format7zDLL::Interface::head = NULL; #define DEFINE_FORMAT(name, dll, extension, signature) \ Format7zDLL::Proxy PROXY_##name = \ { \ "%1Formats\\" dll, \ aCreateObject, \ aGetHandlerProperty, \ (HMODULE)0, \ signature extension + sizeof signature extension - sizeof extension, \ sizeof signature extension - sizeof extension \ }; \ Format7zDLL::Interface name = PROXY_##name; DEFINE_FORMAT(CFormat7z, "7Z.DLL", "7z", "@7z\xBC\xAF\x27\x1C"); DEFINE_FORMAT(CArjHandler, "ARJ.DLL", "arj", "@\x60\xEA"); DEFINE_FORMAT(CBZip2Handler, "BZ2.DLL", "bz2 tbz2", "@BZh"); DEFINE_FORMAT(CCabHandler, "CAB.DLL", "cab", "@MSCF"); DEFINE_FORMAT(CCpioHandler, "CPIO.DLL", "cpio", ""); DEFINE_FORMAT(CDebHandler, "DEB.DLL", "deb", "@! \n"); DEFINE_FORMAT(CLzhHandler, "LZH.DLL", "lzh lha", "@@@-l@@-");//"@-l" doesn't work because signature starts at offset 2 DEFINE_FORMAT(CGZipHandler, "GZ.DLL", "gz tgz", "@\x1F\x8B"); DEFINE_FORMAT(CRarHandler, "RAR.DLL", "rar", "@Rar!\x1a\x07\x00"); DEFINE_FORMAT(CRpmHandler, "RPM.DLL", "rpm", ""); DEFINE_FORMAT(CSplitHandler, "SPLIT.DLL", "001", ""); DEFINE_FORMAT(CTarHandler, "TAR.DLL", "tar", ""); DEFINE_FORMAT(CZHandler, "Z.DLL", "z", "@\x1F\x9D"); DEFINE_FORMAT(CZipHandler, "ZIP.DLL", "zip jar war ear xpi", "@PK\x03\x04"); DEFINE_FORMAT(CChmHandler, "CHM.DLL", "chm chi chq chw hxs hxi hxr hxq hxw lit", "@ITSF"); DEFINE_FORMAT(CIsoHandler, "ISO.DLL", "iso", ""); DEFINE_FORMAT(CNsisHandler, "NSIS.DLL", "exe", "@@@@@\xEF\xBE\xAD\xDENullsoftInst"); /** * @brief Construct Merge7z interface. */ Merge7z::Merge7z(): Format7z(CFormat7z), ZipHandler(CZipHandler), RarHandler(CRarHandler), BZip2Handler(CBZip2Handler), TarHandler(CTarHandler) { } /** * @brief Figure out which archiver dll to use for a given archive. */ Merge7z::Format *Merge7z::GuessFormat(LPCTSTR path) { if (g_dwFlags & Initialize::GuessFormatBySignature) return GuessFormatBySignature(path, g_dwFlags & Initialize::GuessFormatByExtension ? path : 0); return GuessFormatByExtension(path); } /** * @brief Figure out which archiver dll to use for a given archive. */ Merge7z::Format *Merge7z::GuessFormatByExtension(LPCTSTR path) { SZ_EXTENSION ext; if (PathIsDirectory(path)) return 0; return GuessFormatEx(GetExtension(path, ext), 0, 0); } /** * @brief Figure out which archiver dll to use for a given archive. */ Merge7z::Format *Merge7z::GuessFormatBySignature(LPCTSTR path, LPCTSTR extension) { SZ_EXTENSION ext; CH_SIGNATURE sig; if (PathIsDirectory(path)) return 0; return GuessFormatEx(GetExtension(extension, ext), sig, GetSignature(path, sig)); } /** * @brief Figure out which archiver dll to use for a given archive. */ Merge7z::Format *Merge7z::GuessFormatEx(LPCSTR ext, LPCH sig, int cchSig) { Format7zDLL::Interface *pFormat = Format7zDLL::Interface::head; Format7zDLL::Interface *pFormatByExtension = 0; while (pFormat) { static const char aBlank[] = " "; LPCSTR pchExtension = pFormat->proxy.extension; int cchExtension = pFormat->proxy.signature; if (cchSig > 0 && cchExtension) { LPCSTR pchSignature = pchExtension - cchExtension; char joker = *pchSignature++; --cchExtension; if (cchSig >= cchExtension) { while (cchExtension--) { char expected = pchSignature[cchExtension]; if (expected != joker && sig[cchExtension] != expected) break; } if (cchExtension == -1) return pFormat; } } else while ( ext && pFormatByExtension == 0 && (cchExtension = StrCSpnA(pchExtension += StrSpnA(pchExtension, aBlank), aBlank)) != 0 ) { if (StrIsIntlEqualA(FALSE, pchExtension, ext, cchExtension) && ext[cchExtension] == '\0') { pFormatByExtension = pFormat; } pchExtension += cchExtension; } pFormat = pFormat->next; } return pFormat ? pFormat : pFormatByExtension; } /** * @brief Get filename extension as ANSI characters. */ LPCSTR Merge7z::GetExtension(LPCTSTR path, SZ_EXTENSION ext) { if (path == NULL) return NULL; path = PathFindExtension(path); #ifdef UNICODE return WideCharToMultiByte(CP_ACP, 0, path, -1, ext, sizeof(SZ_EXTENSION), 0, 0) > 1 ? ext + 1 : 0; #else ext[sizeof(SZ_EXTENSION) - 2] = '\0'; lstrcpynA(ext, path, sizeof(SZ_EXTENSION)); return ext[0] != '\0' && ext[sizeof(SZ_EXTENSION) - 2] == '\0' ? ext + 1 : 0; #endif } /** * @brief Read start signature from given file. */ DWORD Merge7z::GetSignature(LPCTSTR path, CH_SIGNATURE sig) { if (sig == NULL) return sizeof(CH_SIGNATURE); DWORD cchSig = 0; HANDLE h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (h != INVALID_HANDLE_VALUE) { ReadFile(h, sig, sizeof(CH_SIGNATURE), &cchSig, 0); if (cchSig >= 64 && MAKEWORD(sig[0],sig[1]) == IMAGE_DOS_SIGNATURE) { DWORD offset = ( LPDWORD(sig)[5] //DOS CS:IP ? 512UL * (LPWORD(sig)[1] ? LPWORD(sig)[2] - 1 : LPWORD(sig)[2]) + LPWORD(sig)[1] : LPDWORD(sig)[15] ); if (SetFilePointer(h, offset, 0, FILE_BEGIN) == offset) { ReadFile(h, sig, sizeof(CH_SIGNATURE), &cchSig, 0); if (cchSig >= 4 + sizeof(IMAGE_FILE_HEADER) && MAKELONG(MAKEWORD(sig[0],sig[1]), MAKEWORD(sig[2],sig[3])) == MAKELONG(MAKEWORD('P','E'), 0)) { cchSig = 0; IMAGE_FILE_HEADER *pImageFileHeader = (IMAGE_FILE_HEADER *) (sig + 4); offset += 4 + sizeof(IMAGE_FILE_HEADER) + pImageFileHeader->SizeOfOptionalHeader; if (SetFilePointer(h, offset, 0, FILE_BEGIN) == offset) { int iSection = pImageFileHeader->NumberOfSections; while (iSection--) { IMAGE_SECTION_HEADER ImageSectionHeader; DWORD cbImageSectionHeader = 0; ReadFile(h, &ImageSectionHeader, sizeof ImageSectionHeader, &cbImageSectionHeader, 0); if (cbImageSectionHeader != sizeof ImageSectionHeader) break; if (memcmp(ImageSectionHeader.Name, "_winzip_", 8) == 0) { // looks like WinZip Self-Extractor memcpy(sig, "PK\x03\x04", cchSig = 4); break; } DWORD ahead = ImageSectionHeader.PointerToRawData + ImageSectionHeader.SizeOfRawData; if (offset < ahead) offset = ahead; } if (iSection == -1 && SetFilePointer(h, offset, 0, FILE_BEGIN) == offset) { ReadFile(h, sig, sizeof(CH_SIGNATURE), &cchSig, 0); } } } } } CloseHandle(h); } return cchSig; } /** * @brief Load language file for 7-Zip UIs. */ static CSysString g_LangPath; LPCTSTR Merge7z::LoadLang(LPCTSTR langFile) { TCHAR langFileGuess[8]; if (HIWORD(langFile) == 0) { langFileGuess[0] = '\0'; if (int cchLng = GetLocaleInfo(LCID(langFile), LOCALE_SISO639LANGNAME, langFileGuess, 4)) { langFileGuess[cchLng - 1] = '-'; GetLocaleInfo(LCID(langFile), LOCALE_SISO3166CTRYNAME, langFileGuess + cchLng, 4); langFile = langFileGuess; } } g_LangPath = GetSystemString(g_cPath7z); g_LangPath += TEXT("Lang\\"); g_LangPath += langFile; int slash = g_LangPath.ReverseFind('\\'); int minus = g_LangPath.ReverseFind('-'); int dot = g_LangPath.ReverseFind('.'); if (dot <= slash) { dot = g_LangPath.Length(); g_LangPath += TEXT(".txt"); } if (minus > slash && !PathFileExists(g_LangPath)) { // 2nd chance: filename == language code CSysString Region = g_LangPath.Mid(minus, dot - minus); Region.Replace('-', '\\'); g_LangPath.Delete(minus, dot - minus); if (!PathFileExists(g_LangPath)) { // 3rd chance: filename == region code (Norwegian) g_LangPath.Delete(slash, minus - slash); g_LangPath.Insert(slash, Region); } } ReloadLang(); return g_LangPath; } /** * @brief Override ReadRegLang to return path set by Merge7z::LoadLang(). * This is global 7-Zip function otherwise defined in RegistryUtils.cpp. * Exclude RegistryUtils.cpp from build to avoid link-time collision. */ void ReadRegLang(CSysString &langFile) { langFile = g_LangPath; } /** * @brief 7-Zip 4.26: ReloadLangSmart() wants this #ifdef _UNICODE. * We certainly don't want to write 7-Zip's registry so we make it a NOP. */ void SaveRegLang(const CSysString &langFile) { } #ifndef _UNICODE void ReadRegLang(UString &langFile) { langFile = GetUnicodeString(g_LangPath); } void SaveRegLang(const UString &langFile) { } #endif /** * @brief 7-Zip 4.15+: IsArchiveItemFolder(), needed by CArchiveExtractCallback, * used to reside in OpenArchive.cpp, which has been removed from Merge7z in an * attempt to reduce dependencies (actually got rid of four cpp files). */ static HRESULT IsArchiveItemProp(IInArchive *archive, UINT32 index, PROPID propID, bool &result) { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, propID, &prop)); if(prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt == VT_EMPTY) result = false; else return E_FAIL; return S_OK; } HRESULT IsArchiveItemFolder(IInArchive *archive, UINT32 index, bool &result) { return IsArchiveItemProp(archive, index, kpidIsFolder, result); } HRESULT IsArchiveItemAnti(IInArchive *archive, UINT32 index, bool &result) { return IsArchiveItemProp(archive, index, kpidIsAnti, result); } /** * @brief Export instance of Merge7z interface. */ EXTERN_C { __declspec(dllexport) Merge7z Merge7z; } EXTERN_C HRESULT CALLBACK DllGetVersion(DLLVERSIONINFO *pdvi) { // Compute dwBuild from revision.txt static const DWORD dwBuild = ( sizeof"" # define VERSION(MAJOR,MINOR) # include "revision.txt" # undef VERSION ); C_ASSERT(dwBuild == DllBuild_Merge7z); // Compute dwVersion from revision.txt static const DWORD dwVersion = ( 0*sizeof"" # define VERSION(MAJOR,MINOR) , MAKELONG(MINOR,MAJOR) + 0*sizeof"" # include "revision.txt" # undef VERSION ); static const DLLVERSIONINFO dvi = { sizeof dvi, HIWORD(dwVersion), LOWORD(dwVersion), dwBuild, DLLVER_PLATFORM_WINDOWS }; CopyMemory(pdvi, &dvi, pdvi->cbSize < dvi.cbSize ? pdvi->cbSize : dvi.cbSize); return S_OK; }