diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2009-06-02 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:15:59 +0300 |
commit | 829409452d85cd6dd9dfc9151f109d6e13a2bb1c (patch) | |
tree | e0acaea47044d167f35fa197584dee1bde41c329 /CPP/7zip/Archive/Udf | |
parent | 8874e4fbc9faabdcff719b9b2ac8ebad4f282bbe (diff) |
9.04 beta
Diffstat (limited to 'CPP/7zip/Archive/Udf')
-rwxr-xr-x | CPP/7zip/Archive/Udf/UdfHandler.cpp | 276 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Udf/UdfHandler.h | 4 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Udf/UdfIn.cpp | 22 |
3 files changed, 214 insertions, 88 deletions
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index 12329147..07b61c51 100755 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -8,12 +8,11 @@ #include "Windows/PropVariant.h" #include "Windows/Time.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Compress/CopyCoder.h" -#include "../Common/DummyOutStream.h" - #include "UdfHandler.h" namespace NArchive { @@ -201,79 +200,129 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -class CUdfInStream: - public ISequentialInStream, +class CBufInStream: + public IInStream, public CMyUnknownImp { + CByteBuffer _data; + UInt64 _pos; + +public: + void Init(const CByteBuffer &data) + { + _data = data; + _pos = 0; + } + MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - UInt64 _rem; + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + + +STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != NULL) + *processedSize = 0; + if (_pos > _data.GetCapacity()) + return E_FAIL; + size_t rem = _data.GetCapacity() - (size_t)_pos; + if (size < rem) + rem = (size_t)size; + memcpy(data, (const Byte *)_data + _pos, rem); + _pos += rem; + if (processedSize != NULL) + *processedSize = (UInt32)rem; + return S_OK; +} + +STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch(seekOrigin) + { + case STREAM_SEEK_SET: _pos = offset; break; + case STREAM_SEEK_CUR: _pos += offset; break; + case STREAM_SEEK_END: _pos = _data.GetCapacity() + offset; break; + default: return STG_E_INVALIDFUNCTION; + } + if (newPosition) + *newPosition = _pos; + return S_OK; +} + +struct CSeekExtent +{ + UInt64 Phy; + UInt64 Virt; +}; + +class CExtentsStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _phyPos; + UInt64 _virtPos; + bool _needStartSeek; + + HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); } + public: - CInArchive *_archive; - CMyComPtr<IInStream> _stream; - CRef2 _ref2; - int _extentIndex; - UInt32 _offsetInExtent; + CMyComPtr<IInStream> Stream; + CRecordVector<CSeekExtent> Extents; - void Init(UInt64 size) + MY_UNKNOWN_IMP1(IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + void ReleaseStream() { Stream.Release(); } + + void Init() { - _extentIndex = 0; - _offsetInExtent = 0; - _rem = size; + _virtPos = 0; + _phyPos = 0; + _needStartSeek = true; } - void ReleaseStream() { _stream.Release(); } + }; -STDMETHODIMP CUdfInStream::Read(void *data, UInt32 size, UInt32 *processedSize) + +STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; - if (size > _rem) - size = (UInt32)_rem; - while (size > 0) + if (size > 0) { - const CLogVol &vol = _archive->LogVols[_ref2.Vol]; - const CRef &ref = vol.FileSets[_ref2.Fs].Refs[_ref2.Ref]; - const CFile &file = _archive->Files[ref.FileIndex]; - const CItem &item = _archive->Items[file.ItemIndex]; - - HRESULT res = S_OK; - if (item.IsInline) + UInt64 totalSize = Extents.Back().Virt; + if (_virtPos >= totalSize) + return (_virtPos == totalSize) ? S_OK : E_FAIL; + int left = 0, right = Extents.Size() - 1; + for (;;) { - size_t rem = item.InlineData.GetCapacity() - _offsetInExtent; - if (rem == 0) - return S_OK; - if (rem > _rem) - rem = (size_t)_rem; - memcpy(data, (const Byte *)item.InlineData + _offsetInExtent, rem); + int mid = (left + right) / 2; + if (mid == left) + break; + if (_virtPos < Extents[mid].Virt) + right = mid; + else + left = mid; } - else + + const CSeekExtent &extent = Extents[left]; + UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); + if (_needStartSeek || _phyPos != phyPos) { - if (_extentIndex >= item.Extents.Size()) - return S_OK; - const CMyExtent &extent = item.Extents[_extentIndex]; - UInt32 rem = extent.GetLen() - _offsetInExtent; - if (rem == 0) - { - _extentIndex++; - _offsetInExtent = 0; - continue; - } - if (size > rem) - size = rem; - - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; - const CPartition &partition = _archive->Partitions[partitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << _archive->SecLogSize) + - (UInt64)logBlockNumber * vol.BlockSize + _offsetInExtent; - - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - res = _stream->Read(data, size, &size); + _needStartSeek = false; + _phyPos = phyPos; + RINOK(SeekToPhys()); } - _offsetInExtent += size; - _rem -= size; + + UInt64 rem = Extents[left + 1].Virt - _virtPos; + if (size > rem) + size = (UInt32)rem; + + HRESULT res = Stream->Read(data, size, &size); + _phyPos += size; + _virtPos += size; if (processedSize) *processedSize = size; return res; @@ -281,6 +330,83 @@ STDMETHODIMP CUdfInStream::Read(void *data, UInt32 size, UInt32 *processedSize) return S_OK; } +STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch(seekOrigin) + { + case STREAM_SEEK_SET: _virtPos = offset; break; + case STREAM_SEEK_CUR: _virtPos += offset; break; + case STREAM_SEEK_END: _virtPos = Extents.Back().Virt + offset; break; + default: return STG_E_INVALIDFUNCTION; + } + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = 0; + + const CRef2 &ref2 = _refs2[index]; + const CLogVol &vol = _archive.LogVols[ref2.Vol]; + const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + UInt64 size = item.Size; + + if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item)) + return E_NOTIMPL; + + if (item.IsInline) + { + CBufInStream *inStreamSpec = new CBufInStream; + CMyComPtr<ISequentialInStream> inStream = inStreamSpec; + inStreamSpec->Init(item.InlineData); + *stream = inStream .Detach(); + return S_OK; + } + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec; + + extentStreamSpec->Stream = _inStream; + + UInt64 virtOffset = 0; + for (int extentIndex = 0; extentIndex < item.Extents.Size(); extentIndex++) + { + const CMyExtent &extent = item.Extents[extentIndex]; + UInt32 len = extent.GetLen(); + if (len == 0) + continue; + if (size < len) + return S_FALSE; + + int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = _archive.Partitions[partitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + + (UInt64)logBlockNumber * vol.BlockSize; + + CSeekExtent se; + se.Phy = offset; + se.Virt = virtOffset; + virtOffset += len; + extentStreamSpec->Extents.Add(se); + + size -= len; + } + if (size != 0) + return S_FALSE; + CSeekExtent se; + se.Phy = 0; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, Int32 _aTestMode, IArchiveExtractCallback *extractCallback) { @@ -307,7 +433,6 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, extractCallback->SetTotal(totalSize); UInt64 currentTotalSize = 0; - UInt64 currentItemSize; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; @@ -316,20 +441,13 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - CUdfInStream *udfInStreamSpec = new CUdfInStream(); - CMyComPtr<ISequentialInStream> udfInStream = udfInStreamSpec; - - udfInStreamSpec->_archive = &_archive; - udfInStreamSpec->_stream = _inStream; - - CDummyOutStream *outStreamSpec = new CDummyOutStream; + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + for (i = 0; i < numItems; i++) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); - currentItemSize = 0; CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NArchive::NExtract::NAskMode::kTest : @@ -349,24 +467,28 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); continue; } - currentItemSize = item.Size; + currentTotalSize += item.Size; - if (!testMode && (!realOutStream)) + if (!testMode && !realOutStream) continue; - RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); outStreamSpec->SetStream(realOutStream); realOutStream.Release(); - outStreamSpec->Init(); - Int32 opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod; - if (item.IsRecAndAlloc() && item.CheckChunkSizes() && _archive.CheckItemExtents(ref2.Vol, item)) + outStreamSpec->Init(item.Size); + Int32 opRes; + CMyComPtr<ISequentialInStream> udfInStream; + HRESULT res = GetStream(index, &udfInStream); + if (res == E_NOTIMPL) + opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod; + else if (res != S_OK) + opRes = NArchive::NExtract::NOperationResult::kDataError; + else { - udfInStreamSpec->_ref2 = ref2; - udfInStreamSpec->Init(item.Size); RINOK(copyCoder->Code(udfInStream, outStream, NULL, NULL, progress)); - opRes = (outStreamSpec->GetSize() == currentItemSize) ? - NArchive::NExtract::NOperationResult::kOK: - NArchive::NExtract::NOperationResult::kDataError; + opRes = outStreamSpec->IsFinishedOK() ? + NArchive::NExtract::NOperationResult::kOK: + NArchive::NExtract::NOperationResult::kDataError; } outStreamSpec->ReleaseStream(); RINOK(extractCallback->SetOperationResult(opRes)); diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index ceab85ae..63f859af 100755 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -20,14 +20,16 @@ struct CRef2 class CHandler: public IInArchive, + public IInArchiveGetStream, public CMyUnknownImp { CMyComPtr<IInStream> _inStream; CInArchive _archive; CRecordVector<CRef2> _refs2; public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; }} diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 75a0c333..d2f9e731 100755 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -2,14 +2,11 @@ #include "StdAfx.h" -#include "UdfIn.h" +#include "../../../../C/CpuArch.h" #include "../../Common/StreamUtils.h" -extern "C" -{ - #include "../../../../C/CpuArch.h" -} +#include "UdfIn.h" #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) @@ -580,11 +577,16 @@ HRESULT CInArchive::Open2() UInt64 fileSize; RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); - const int kSecLogSizeMax = 11; - const int kSecLogSizeMin = 8; + // Some UDFs contain additional 2 KB of zeros, so we also check 12, corrected to 11. + const int kSecLogSizeMax = 12; Byte buf[1 << kSecLogSizeMax]; - for (SecLogSize = kSecLogSizeMax; SecLogSize >= kSecLogSizeMin; SecLogSize -= 3) + Byte kSizesLog[] = { 11, 8, 12 }; + + for (int i = 0;; i++) { + if (i == sizeof(kSizesLog) / sizeof(kSizesLog[0])) + return S_FALSE; + SecLogSize = kSizesLog[i]; Int32 bufSize = 1 << SecLogSize; if (bufSize > fileSize) return S_FALSE; @@ -595,8 +597,8 @@ HRESULT CInArchive::Open2() if (tag.Id == DESC_TYPE_AnchorVolPtr) break; } - if (SecLogSize < kSecLogSizeMin) - return S_FALSE; + if (SecLogSize == 12) + SecLogSize = 11; CExtent extentVDS; extentVDS.Parse(buf + 16); |