openarchive.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 529 行
CPP
529 行
// OpenArchive.cpp#include "StdAfx.h"#include "OpenArchive.h"#include "Common/Wildcard.h"#include "Windows/FileName.h"#include "Windows/FileDir.h"#include "Windows/Defs.h"#include "Windows/PropVariant.h"#include "../../Common/FileStreams.h"#include "../../Common/StreamUtils.h"#include "Common/StringConvert.h"#ifdef FORMAT_7Z#include "../../Archive/7z/7zHandler.h"#endif#ifdef FORMAT_BZIP2#include "../../Archive/BZip2/BZip2Handler.h"#endif#ifdef FORMAT_GZIP#include "../../Archive/GZip/GZipHandler.h"#endif#ifdef FORMAT_SPLIT#include "../../Archive/Split/SplitHandler.h"#endif#ifdef FORMAT_TAR#include "../../Archive/Tar/TarHandler.h"#endif#ifdef FORMAT_ZIP#include "../../Archive/Zip/ZipHandler.h"#endif#ifdef FORMAT_Z#include "../../Archive/Z/ZHandler.h"#endif#ifndef EXCLUDE_COM#include "HandlerLoader.h"#endif#include "DefaultName.h"using namespace NWindows;HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result){ NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidPath, &prop)); if(prop.vt == VT_BSTR) result = prop.bstrVal; else if (prop.vt == VT_EMPTY) result.Empty(); else return E_FAIL; return S_OK;}HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result){ RINOK(GetArchiveItemPath(archive, index, result)); if (result.IsEmpty()) result = defaultName; return S_OK;}HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, const FILETIME &defaultFileTime, FILETIME &fileTime){ NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop)); if (prop.vt == VT_FILETIME) fileTime = prop.filetime; else if (prop.vt == VT_EMPTY) fileTime = defaultFileTime; else return E_FAIL; return S_OK;}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);}// Static-SFX (for Linux) can be bigconst UInt64 kMaxCheckStartPosition = #ifdef _WIN321 << 20;#else1 << 22;#endifHRESULT ReOpenArchive(IInArchive *archive, const UString &fileName){ CInFileStream *inStreamSpec = new CInFileStream(true); CMyComPtr<IInStream> inStream(inStreamSpec); inStreamSpec->Open(fileName); return archive->Open(inStream, &kMaxCheckStartPosition, NULL);}#ifndef _SFXstatic inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size){ for (size_t i = 0; i < size; i++) if (p1[i] != p2[i]) return false; return true;}#endifHRESULT OpenArchive( IInStream *inStream, const UString &fileName, #ifndef EXCLUDE_COM HMODULE *module, #endif IInArchive **archiveResult, CArchiverInfo &archiverInfoResult, UString &defaultItemName, IArchiveOpenCallback *openArchiveCallback){ *archiveResult = NULL; CObjectVector<CArchiverInfo> archiverInfoList; ReadArchiverInfoList(archiverInfoList); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Mid(dotPos + 1); } CIntVector orderIndices; int i; bool finded = false; for(i = 0; i < archiverInfoList.Size(); i++) { if (archiverInfoList[i].FindExtension(extension) >= 0) { orderIndices.Insert(0, i); finded = true; } else orderIndices.Add(i); } #ifndef _SFX if (!finded) { CByteBuffer byteBuffer; const UInt32 kBufferSize = (200 << 10); byteBuffer.SetCapacity(kBufferSize); Byte *buffer = byteBuffer; RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); UInt32 processedSize; RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize)); int numFinded = 0; for (int pos = (int)processedSize; pos >= 0 ; pos--) { for(int i = numFinded; i < orderIndices.Size(); i++) { int index = orderIndices[i]; const CArchiverInfo &ai = archiverInfoList[index]; const CByteBuffer &sig = ai.StartSignature; if (sig.GetCapacity() == 0) continue; if (pos + sig.GetCapacity() > processedSize) continue; if (TestSignature(buffer + pos, sig, sig.GetCapacity())) { orderIndices.Delete(i); orderIndices.Insert(0, index); numFinded++; } } } } #endif HRESULT badResult = S_OK; for(i = 0; i < orderIndices.Size(); i++) { inStream->Seek(0, STREAM_SEEK_SET, NULL); const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]]; #ifndef EXCLUDE_COM CHandlerLoader loader; #endif CMyComPtr<IInArchive> archive; #ifdef FORMAT_7Z if (archiverInfo.Name.CompareNoCase(L"7z") == 0) archive = new NArchive::N7z::CHandler; #endif #ifdef FORMAT_BZIP2 if (archiverInfo.Name.CompareNoCase(L"BZip2") == 0) archive = new NArchive::NBZip2::CHandler; #endif #ifdef FORMAT_GZIP if (archiverInfo.Name.CompareNoCase(L"GZip") == 0) archive = new NArchive::NGZip::CHandler; #endif #ifdef FORMAT_SPLIT if (archiverInfo.Name.CompareNoCase(L"Split") == 0) archive = new NArchive::NSplit::CHandler; #endif #ifdef FORMAT_TAR if (archiverInfo.Name.CompareNoCase(L"Tar") == 0) archive = new NArchive::NTar::CHandler; #endif #ifdef FORMAT_ZIP if (archiverInfo.Name.CompareNoCase(L"Zip") == 0) archive = new NArchive::NZip::CHandler; #endif #ifdef FORMAT_Z if (archiverInfo.Name.CompareNoCase(L"Z") == 0) archive = new NArchive::NZ::CHandler; #endif #ifndef EXCLUDE_COM if (!archive) { HRESULT result = loader.CreateHandler(archiverInfo.FilePath, archiverInfo.ClassID, (void **)&archive, false); if (result != S_OK) continue; } #endif if (!archive) return E_FAIL; HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback); if(result == S_FALSE) continue; if(result != S_OK) { badResult = result; if(result == E_ABORT) break; continue; } *archiveResult = archive.Detach(); #ifndef EXCLUDE_COM *module = loader.Detach(); #endif archiverInfoResult = archiverInfo; int subExtIndex = archiverInfo.FindExtension(extension); if (subExtIndex < 0) subExtIndex = 0; defaultItemName = GetDefaultName2(fileName, archiverInfo.Extensions[subExtIndex].Ext, archiverInfo.Extensions[subExtIndex].AddExt); return S_OK; } if (badResult != S_OK) return badResult; return S_FALSE;}HRESULT OpenArchive(const UString &filePath, #ifndef EXCLUDE_COM HMODULE *module, #endif IInArchive **archiveResult, CArchiverInfo &archiverInfo, UString &defaultItemName, IArchiveOpenCallback *openArchiveCallback){ CInFileStream *inStreamSpec = new CInFileStream(true); CMyComPtr<IInStream> inStream(inStreamSpec); if (!inStreamSpec->Open(filePath)) return GetLastError(); return OpenArchive(inStream, ExtractFileNameFromPath(filePath), #ifndef EXCLUDE_COM module, #endif archiveResult, archiverInfo, defaultItemName, openArchiveCallback);}static void MakeDefaultName(UString &name){ int dotPos = name.ReverseFind(L'.'); if (dotPos < 0) return; UString ext = name.Mid(dotPos + 1); if (ext.IsEmpty()) return; for (int pos = 0; pos < ext.Length(); pos++) if (ext[pos] < L'0' || ext[pos] > L'9') return; name = name.Left(dotPos);}HRESULT OpenArchive(const UString &fileName, #ifndef EXCLUDE_COM HMODULE *module0, HMODULE *module1, #endif IInArchive **archive0, IInArchive **archive1, CArchiverInfo &archiverInfo0, CArchiverInfo &archiverInfo1, UString &defaultItemName0, UString &defaultItemName1, IArchiveOpenCallback *openArchiveCallback){ HRESULT result = OpenArchive(fileName, #ifndef EXCLUDE_COM module0, #endif archive0, archiverInfo0, defaultItemName0, openArchiveCallback); RINOK(result); CMyComPtr<IInArchiveGetStream> getStream; result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream); if (result != S_OK || getStream == 0) return S_OK; CMyComPtr<ISequentialInStream> subSeqStream; result = getStream->GetStream(0, &subSeqStream); if (result != S_OK) return S_OK; CMyComPtr<IInStream> subStream; if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK) return S_OK; if (!subStream) return S_OK; UInt32 numItems; RINOK((*archive0)->GetNumberOfItems(&numItems)); if (numItems < 1) return S_OK; UString subPath; RINOK(GetArchiveItemPath(*archive0, 0, subPath)) if (subPath.IsEmpty()) { MakeDefaultName(defaultItemName0); subPath = defaultItemName0; if (archiverInfo0.Name.CompareNoCase(L"7z") == 0) { if (subPath.Right(3).CompareNoCase(L".7z") != 0) subPath += L".7z"; } } else subPath = ExtractFileNameFromPath(subPath); CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName; openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); if (setSubArchiveName) setSubArchiveName->SetSubArchiveName(subPath); result = OpenArchive(subStream, subPath, #ifndef EXCLUDE_COM module1, #endif archive1, archiverInfo1, defaultItemName1, openArchiveCallback); return S_OK;}HRESULT MyOpenArchive(const UString &archiveName, #ifndef EXCLUDE_COM HMODULE *module, #endif IInArchive **archive, UString &defaultItemName, IOpenCallbackUI *openCallbackUI){ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec; openCallbackSpec->Callback = openCallbackUI; UString fullName; int fileNamePartStartIndex; NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex); openCallbackSpec->Init( fullName.Left(fileNamePartStartIndex), fullName.Mid(fileNamePartStartIndex)); CArchiverInfo archiverInfo; return OpenArchive(archiveName, #ifndef EXCLUDE_COM module, #endif archive, archiverInfo, defaultItemName, openCallback);}HRESULT MyOpenArchive(const UString &archiveName, #ifndef EXCLUDE_COM HMODULE *module0, HMODULE *module1, #endif IInArchive **archive0, IInArchive **archive1, UString &defaultItemName0, UString &defaultItemName1, UStringVector &volumePaths, IOpenCallbackUI *openCallbackUI){ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec; openCallbackSpec->Callback = openCallbackUI; UString fullName; int fileNamePartStartIndex; NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex); UString prefix = fullName.Left(fileNamePartStartIndex); UString name = fullName.Mid(fileNamePartStartIndex); openCallbackSpec->Init(prefix, name); CArchiverInfo archiverInfo0, archiverInfo1; HRESULT result = OpenArchive(archiveName, #ifndef EXCLUDE_COM module0, module1, #endif archive0, archive1, archiverInfo0, archiverInfo1, defaultItemName0, defaultItemName1, openCallback); RINOK(result); volumePaths.Add(prefix + name); for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++) volumePaths.Add(prefix + openCallbackSpec->FileNames[i]); return S_OK;}HRESULT CArchiveLink::Close(){ if (Archive1 != 0) RINOK(Archive1->Close()); if (Archive0 != 0) RINOK(Archive0->Close()); return S_OK;}void CArchiveLink::Release(){ if (Archive1 != 0) Archive1.Release(); if (Archive0 != 0) Archive0.Release(); #ifndef EXCLUDE_COM Library1.Free(); Library0.Free(); #endif}HRESULT OpenArchive(const UString &archiveName, CArchiveLink &archiveLink, IArchiveOpenCallback *openCallback){ return OpenArchive(archiveName, #ifndef EXCLUDE_COM &archiveLink.Library0, &archiveLink.Library1, #endif &archiveLink.Archive0, &archiveLink.Archive1, archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1, archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, openCallback);}HRESULT MyOpenArchive(const UString &archiveName, CArchiveLink &archiveLink, IOpenCallbackUI *openCallbackUI){ return MyOpenArchive(archiveName, #ifndef EXCLUDE_COM &archiveLink.Library0, &archiveLink.Library1, #endif &archiveLink.Archive0, &archiveLink.Archive1, archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, archiveLink.VolumePaths, openCallbackUI);}HRESULT ReOpenArchive(CArchiveLink &archiveLink, const UString &fileName){ if (archiveLink.GetNumLevels() > 1) return E_NOTIMPL; if (archiveLink.GetNumLevels() == 0) return MyOpenArchive(fileName, archiveLink, 0); return ReOpenArchive(archiveLink.GetArchive(), fileName);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?