Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2009-06-02 04:00:00 +0400
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:15:59 +0300
commit829409452d85cd6dd9dfc9151f109d6e13a2bb1c (patch)
treee0acaea47044d167f35fa197584dee1bde41c329 /CPP/7zip/Archive/Udf
parent8874e4fbc9faabdcff719b9b2ac8ebad4f282bbe (diff)
9.04 beta
Diffstat (limited to 'CPP/7zip/Archive/Udf')
-rwxr-xr-xCPP/7zip/Archive/Udf/UdfHandler.cpp276
-rwxr-xr-xCPP/7zip/Archive/Udf/UdfHandler.h4
-rwxr-xr-xCPP/7zip/Archive/Udf/UdfIn.cpp22
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);