diff options
Diffstat (limited to 'src/libs/3rdparty/7zip/win/CPP/7zip/Archive/SplitHandler.cpp')
-rw-r--r-- | src/libs/3rdparty/7zip/win/CPP/7zip/Archive/SplitHandler.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/libs/3rdparty/7zip/win/CPP/7zip/Archive/SplitHandler.cpp b/src/libs/3rdparty/7zip/win/CPP/7zip/Archive/SplitHandler.cpp new file mode 100644 index 000000000..db9f49aa0 --- /dev/null +++ b/src/libs/3rdparty/7zip/win/CPP/7zip/Archive/SplitHandler.cpp @@ -0,0 +1,369 @@ +// SplitHandler.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/MultiStream.h" + +using namespace NWindows; + +namespace NArchive { +namespace NSplit { + +static const Byte kProps[] = +{ + kpidPath, + kpidSize +}; + +static const Byte kArcProps[] = +{ + kpidNumVolumes, + kpidTotalPhySize +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector<CMyComPtr<IInStream> > _streams; + CRecordVector<UInt64> _sizes; + UString _subName; + UInt64 _totalSize; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; + case kpidTotalPhySize: prop = _totalSize; break; + case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; + } + prop.Detach(value); + return S_OK; +} + +struct CSeqName +{ + UString _unchangedPart; + UString _changedPart; + bool _splitStyle; + + UString GetNextName() + { + UString newName; + if (_splitStyle) + { + int i; + int numLetters = _changedPart.Len(); + for (i = numLetters - 1; i >= 0; i--) + { + wchar_t c = _changedPart[i]; + if (c == 'z') + { + newName.InsertAtFront('a'); + continue; + } + else if (c == 'Z') + { + newName.InsertAtFront('A'); + continue; + } + c++; + if ((c == 'z' || c == 'Z') && i == 0) + { + _unchangedPart += c; + wchar_t newChar = (c == 'z') ? L'a' : L'A'; + newName.Empty(); + numLetters++; + for (int k = 0; k < numLetters; k++) + newName += newChar; + break; + } + newName.InsertAtFront(c); + i--; + for (; i >= 0; i--) + newName.InsertAtFront(_changedPart[i]); + break; + } + } + else + { + int i; + int numLetters = _changedPart.Len(); + for (i = numLetters - 1; i >= 0; i--) + { + wchar_t c = _changedPart[i]; + if (c == '9') + { + newName.InsertAtFront('0'); + if (i == 0) + newName.InsertAtFront('1'); + continue; + } + c++; + newName.InsertAtFront(c); + i--; + for (; i >= 0; i--) + newName.InsertAtFront(_changedPart[i]); + break; + } + } + _changedPart = newName; + return _unchangedPart + _changedPart; + } +}; + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + Close(); + if (!callback) + return S_FALSE; + + CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); + if (!volumeCallback) + return S_FALSE; + + UString name; + { + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidName, &prop)); + if (prop.vt != VT_BSTR) + return S_FALSE; + name = prop.bstrVal; + } + + int dotPos = name.ReverseFind('.'); + const UString prefix = name.Left(dotPos + 1); + const UString ext = name.Ptr(dotPos + 1); + UString ext2 = ext; + ext2.MakeLower_Ascii(); + + CSeqName seqName; + + unsigned numLetters = 2; + bool splitStyle = false; + + if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) + { + splitStyle = true; + while (numLetters < ext2.Len()) + { + if (ext2[ext2.Len() - numLetters - 1] != 'a') + break; + numLetters++; + } + } + else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) + { + while (numLetters < ext2.Len()) + { + if (ext2[ext2.Len() - numLetters - 1] != '0') + break; + numLetters++; + } + if (numLetters != ext.Len()) + return S_FALSE; + } + else + return S_FALSE; + + seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); + seqName._changedPart = ext.RightPtr(numLetters); + seqName._splitStyle = splitStyle; + + if (prefix.Len() < 1) + _subName = L"file"; + else + _subName.SetFrom(prefix, prefix.Len() - 1); + + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + + _totalSize += size; + _sizes.Add(size); + _streams.Add(stream); + + { + UInt64 numFiles = _streams.Size(); + RINOK(callback->SetCompleted(&numFiles, NULL)); + } + + for (;;) + { + const UString fullName = seqName.GetNextName(); + CMyComPtr<IInStream> nextStream; + HRESULT result = volumeCallback->GetStream(fullName, &nextStream); + if (result == S_FALSE) + break; + if (result != S_OK) + return result; + if (!stream) + break; + { + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + _totalSize += size; + _sizes.Add(size); + _streams.Add(nextStream); + { + UInt64 numFiles = _streams.Size(); + RINOK(callback->SetCompleted(&numFiles, NULL)); + } + } + + if (_streams.Size() == 1) + { + if (splitStyle) + return S_FALSE; + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + HRESULT res = Open2(stream, callback); + if (res != S_OK) + Close(); + return res; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + _subName.Empty(); + _streams.Clear(); + _sizes.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _streams.IsEmpty() ? 0 : 1; + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: prop = _subName; break; + case kpidSize: + case kpidPackSize: + prop = _totalSize; + break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + UInt64 currentTotalSize = 0; + RINOK(extractCallback->SetTotal(_totalSize)); + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &outStream, askMode)); + if (!testMode && !outStream) + return S_OK; + RINOK(extractCallback->PrepareOperation(askMode)); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + FOR_VECTOR (i, _streams) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + IInStream *inStream = _streams[i]; + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + currentTotalSize += copyCoderSpec->TotalSize; + } + outStream.Release(); + return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + if (index != 0) + return E_INVALIDARG; + *stream = 0; + CMultiStream *streamSpec = new CMultiStream; + CMyComPtr<ISequentialInStream> streamTemp = streamSpec; + FOR_VECTOR (i, _streams) + { + CMultiStream::CSubStreamInfo subStreamInfo; + subStreamInfo.Stream = _streams[i]; + subStreamInfo.Size = _sizes[i]; + streamSpec->Streams.Add(subStreamInfo); + } + streamSpec->Init(); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "Split", "001", 0, 0xEA, + 0, { 0 }, + 0, + 0, + CreateArc }; + +REGISTER_ARC(Split) + +}} |