diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp | 303 |
1 files changed, 271 insertions, 32 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp index fd2807ac149..4e5f1f56041 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -6,14 +6,54 @@ #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" +#include "../../../Windows/System.h" -#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" #include "ArchiveOpenCallback.h" +// #define DEBUG_VOLUMES + +#ifdef DEBUG_VOLUMES +#include <stdio.h> +#endif + + +#ifdef DEBUG_VOLUMES + #define PRF(x) x +#else + #define PRF(x) +#endif + using namespace NWindows; -STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes) +HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName) +{ + Volumes.Init(); + FileNames.Clear(); + FileNames_WasUsed.Clear(); + FileSizes.Clear(); + _subArchiveMode = false; + // TotalSize = 0; + PasswordWasAsked = false; + _folderPrefix = folderPrefix; + if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName)) + { + // throw 20121118; + return GetLastError_noZero_HRESULT(); + } + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name)) +{ + _subArchiveMode = true; + _subArchiveName = name; + // TotalSize = 0; + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)) { COM_TRY_BEGIN if (ReOpenCallback) @@ -24,7 +64,7 @@ STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes COM_TRY_END } -STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes) +Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)) { COM_TRY_BEGIN if (ReOpenCallback) @@ -34,8 +74,9 @@ STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *b return Callback->Open_SetCompleted(files, bytes); COM_TRY_END } - -STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) + + +Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)) { COM_TRY_BEGIN NCOM::CPropVariant prop; @@ -48,37 +89,194 @@ STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) else switch (propID) { - case kpidName: prop = _fileInfo.Name; break; + case kpidName: prop = fs2us(_fileInfo.Name); break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; - case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; - case kpidCTime: prop = _fileInfo.CTime; break; - case kpidATime: prop = _fileInfo.ATime; break; - case kpidMTime: prop = _fileInfo.MTime; break; + case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break; } prop.Detach(value); return S_OK; COM_TRY_END } -struct CInFileStreamVol: public CInFileStream -{ - int FileNameIndex; + +// ---------- CInFileStreamVol ---------- + +Z7_CLASS_IMP_COM_2( + CInFileStreamVol + , IInStream + , IStreamGetSize +) + Z7_IFACE_COM7_IMP(ISequentialInStream) +public: + unsigned FileIndex; COpenCallbackImp *OpenCallbackImp; CMyComPtr<IArchiveOpenCallback> OpenCallbackRef; - + + HRESULT EnsureOpen() + { + return OpenCallbackImp->Volumes.EnsureOpen(FileIndex); + } + ~CInFileStreamVol() { if (OpenCallbackRef) - OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false; + OpenCallbackImp->AtCloseFile(FileIndex); } }; +void CMultiStreams::InsertToList(unsigned index) +{ + { + CSubStream &s = Streams[index]; + s.Next = Head; + s.Prev = -1; + } + if (Head != -1) + Streams[(unsigned)Head].Prev = (int)index; + else + { + // if (Tail != -1) throw 1; + Tail = (int)index; + } + Head = (int)index; + NumListItems++; +} + +// s must bee in List +void CMultiStreams::RemoveFromList(CSubStream &s) +{ + if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev; + if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next; + s.Next = -1; // optional + s.Prev = -1; // optional + NumListItems--; +} + +void CMultiStreams::CloseFile(unsigned index) +{ + CSubStream &s = Streams[index]; + if (s.Stream) + { + s.Stream.Release(); + RemoveFromList(s); + // s.InFile->Close(); + // s.IsOpen = false; + #ifdef DEBUG_VOLUMES + static int numClosing = 0; + numClosing++; + printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems); + #endif + } +} + +void CMultiStreams::Init() +{ + Head = -1; + Tail = -1; + NumListItems = 0; + Streams.Clear(); +} + +CMultiStreams::CMultiStreams(): + Head(-1), + Tail(-1), + NumListItems(0) +{ + NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); + PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax)); +} + + +HRESULT CMultiStreams::PrepareToOpenNew() +{ + if (NumListItems < NumOpenFiles_AllowedMax) + return S_OK; + if (Tail == -1) + return E_FAIL; + CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail]; + RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos)) + CloseFile((unsigned)Tail); + return S_OK; +} + + +HRESULT CMultiStreams::EnsureOpen(unsigned index) +{ + CMultiStreams::CSubStream &s = Streams[index]; + if (s.Stream) + { + if ((int)index != Head) + { + RemoveFromList(s); + InsertToList(index); + } + } + else + { + RINOK(PrepareToOpenNew()) + { + CInFileStream *inFile = new CInFileStream; + CMyComPtr<IInStream> inStreamTemp = inFile; + if (!inFile->Open(s.Path)) + return GetLastError_noZero_HRESULT(); + s.FileSpec = inFile; + s.Stream = s.FileSpec; + InsertToList(index); + } + // s.IsOpen = true; + if (s.LocalPos != 0) + { + RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos)) + } + #ifdef DEBUG_VOLUMES + static int numOpens = 0; + numOpens++; + printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems); + #endif + } + return S_OK; +} + + +Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + PRF(printf("\n== %u, Read =%u \n", FileIndex, size)); + return s.Stream->Read(data, size, processedSize); +} + +Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + // if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset)); + return s.Stream->Seek(offset, seekOrigin, newPosition); +} + +Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size)) +{ + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + return s.FileSpec->GetSize(size); +} + + // from ArchiveExtractCallback.cpp bool IsSafePath(const UString &path); -STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream) +Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)) { COM_TRY_BEGIN *inStream = NULL; @@ -87,13 +285,13 @@ STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStre return S_FALSE; if (Callback) { - RINOK(Callback->Open_CheckBreak()); + RINOK(Callback->Open_CheckBreak()) } UString name2 = name; - #ifndef _SFX + #ifndef Z7_SFX #ifdef _WIN32 name2.Replace(L'/', WCHAR_PATH_SEPARATOR); @@ -102,30 +300,58 @@ STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStre // if (!allowAbsVolPaths) if (!IsSafePath(name2)) return S_FALSE; - + + #ifdef _WIN32 + /* WIN32 allows wildcards in Find() function + and doesn't allow wildcard in File.Open() + so we can work without the following wildcard check here */ + if (name2.Find(L'*') >= 0) + return S_FALSE; + { + unsigned startPos = 0; + if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\")) + startPos = 3; + if (name2.Find(L'?', startPos) >= 0) + return S_FALSE; + } + #endif + #endif FString fullPath; if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath)) return S_FALSE; - if (!_fileInfo.Find(fullPath)) + if (!_fileInfo.Find_FollowLink(fullPath)) return S_FALSE; if (_fileInfo.IsDir()) return S_FALSE; - CInFileStreamVol *inFile = new CInFileStreamVol; - CMyComPtr<IInStream> inStreamTemp = inFile; - if (!inFile->Open(fullPath)) + + CMultiStreams::CSubStream s; + { - DWORD lastError = ::GetLastError(); - if (lastError == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(lastError); + CInFileStream *inFile = new CInFileStream; + CMyComPtr<IInStream> inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return GetLastError_noZero_HRESULT(); + RINOK(Volumes.PrepareToOpenNew()) + s.FileSpec = inFile; + s.Stream = s.FileSpec; + s.Path = fullPath; + // s.Size = _fileInfo.Size; + // s.IsOpen = true; } + const unsigned fileIndex = Volumes.Streams.Add(s); + Volumes.InsertToList(fileIndex); + FileSizes.Add(_fileInfo.Size); FileNames.Add(name2); - inFile->FileNameIndex = FileNames_WasUsed.Add(true); + FileNames_WasUsed.Add(true); + + CInFileStreamVol *inFile = new CInFileStreamVol; + CMyComPtr<IInStream> inStreamTemp = inFile; + inFile->FileIndex = fileIndex; inFile->OpenCallbackImp = this; inFile->OpenCallbackRef = this; // TotalSize += _fileInfo.Size; @@ -134,14 +360,16 @@ STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStre COM_TRY_END } -#ifndef _NO_CRYPTO -STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) + +#ifndef Z7_NO_CRYPTO +Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password)) { COM_TRY_BEGIN if (ReOpenCallback) { - CMyComPtr<ICryptoGetTextPassword> getTextPassword; - ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoGetTextPassword, + getTextPassword, ReOpenCallback) if (getTextPassword) return getTextPassword->CryptoGetTextPassword(password); } @@ -152,3 +380,14 @@ STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) COM_TRY_END } #endif + +// IProgress +Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */)) +{ + return S_OK; +} |