diff options
author | kh1 <karsten.heimrich@nokia.com> | 2012-03-15 14:53:47 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@nokia.com> | 2012-03-19 16:14:04 +0100 |
commit | be3b47d0d504a3409ce66bd77bb8c0acff87c4f5 (patch) | |
tree | 09dfb02d484a4f395991972b828da71400fb761a /src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp | |
parent | 9fd62353cf7f973d78cd2093328ac15b5c4980b6 (diff) |
Reorganize the tree, have better ifw.pri. Shadow build support.
Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb
Reviewed-by: Tim Jenssen <tim.jenssen@nokia.com>
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp')
-rw-r--r-- | src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp new file mode 100644 index 000000000..4db0cae82 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -0,0 +1,386 @@ +// TarHandler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../Common/ItemNameUtils.h" + +#include "TarHandler.h" +#include "TarIn.h" + +using namespace NWindows; + +namespace NArchive { +namespace NTar { + +static const char *kUnexpectedEnd = "Unexpected end of archive"; + +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidPosixAttrib, VT_UI4}, + { NULL, kpidUser, VT_BSTR}, + { NULL, kpidGroup, VT_BSTR}, + { NULL, kpidLink, VT_BSTR} +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidHeadersSize, VT_UI8} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch(propID) + { + case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; + case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + } + prop.Detach(value); + return S_OK; +} + +HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) +{ + item.HeaderPos = _phySize; + RINOK(ReadItem(stream, filled, item, _errorMessage)); + _phySize += item.HeaderSize; + _headersSize += item.HeaderSize; + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + UInt64 endPos = 0; + { + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + + _phySizeDefined = true; + for (;;) + { + CItemEx item; + bool filled; + RINOK(ReadItem2(stream, filled, item)); + if (!filled) + break; + _items.Add(item); + + RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize)); + if (_phySize > endPos) + { + _errorMessage = kUnexpectedEnd; + break; + } + /* + if (_phySize == endPos) + { + _errorMessage = "There are no trailing zero-filled records"; + break; + } + */ + if (callback != NULL) + { + if (_items.Size() == 1) + { + RINOK(callback->SetTotal(NULL, &endPos)); + } + if (_items.Size() % 100 == 0) + { + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &_phySize)); + } + } + } + + if (_items.Size() == 0) + { + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + if (!callback) + return S_FALSE; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + if (!openVolumeCallback) + return S_FALSE; + NCOM::CPropVariant prop; + if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) + return S_FALSE; + if (prop.vt != VT_BSTR) + return S_FALSE; + UString baseName = prop.bstrVal; + baseName = baseName.Right(4); + if (baseName.CompareNoCase(L".tar") != 0) + return S_FALSE; + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream, openArchiveCallback)); + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _errorMessage.Empty(); + _phySizeDefined = false; + _phySize = 0; + _headersSize = 0; + _curIndex = 0; + _latestIsRead = false; + _items.Clear(); + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1); + return S_OK; +} + +CHandler::CHandler() +{ + copyCoderSpec = new NCompress::CCopyCoder(); + copyCoder = copyCoderSpec; +} + +HRESULT CHandler::SkipTo(UInt32 index) +{ + while (_curIndex < index || !_latestIsRead) + { + if (_latestIsRead) + { + UInt64 packSize = _latestItem.GetPackSize(); + RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); + _phySize += copyCoderSpec->TotalSize; + if (copyCoderSpec->TotalSize != packSize) + { + _errorMessage = kUnexpectedEnd; + return S_FALSE; + } + _latestIsRead = false; + _curIndex++; + } + else + { + bool filled; + RINOK(ReadItem2(_seqStream, filled, _latestItem)); + if (!filled) + { + _phySizeDefined = true; + return E_INVALIDARG; + } + _latestIsRead = true; + } + } + return S_OK; +} + +static UString TarStringToUnicode(const AString &s) +{ + return MultiByteToUnicodeString(s, CP_OEMCP); +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + + const CItemEx *item; + if (_stream) + item = &_items[index]; + else + { + if (index < _curIndex) + return E_INVALIDARG; + else + { + RINOK(SkipTo(index)); + item = &_latestItem; + } + } + + switch(propID) + { + case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break; + case kpidIsDir: prop = item->IsDir(); break; + case kpidSize: prop = item->GetUnpackSize(); break; + case kpidPackSize: prop = item->GetPackSize(); break; + case kpidMTime: + if (item->MTime != 0) + { + FILETIME ft; + NTime::UnixTimeToFileTime(item->MTime, ft); + prop = ft; + } + break; + case kpidPosixAttrib: prop = item->Mode; break; + case kpidUser: prop = TarStringToUnicode(item->User); break; + case kpidGroup: prop = TarStringToUnicode(item->Group); break; + case kpidLink: prop = TarStringToUnicode(item->LinkName); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + ISequentialInStream *stream = _seqStream; + bool seqMode = (_stream == NULL); + if (!seqMode) + stream = _stream; + + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (_stream && numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize(); + extractCallback->SetTotal(totalSize); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(stream); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + + for (i = 0; i < numItems || seqMode; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItemEx *item; + if (seqMode) + { + HRESULT res = SkipTo(index); + if (res == E_INVALIDARG) + break; + RINOK(res); + item = &_latestItem; + } + else + item = &_items[index]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + UInt64 unpackSize = item->GetUnpackSize(); + totalSize += unpackSize; + totalPackSize += item->GetPackSize(); + if (item->IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + bool skipMode = false; + if (!testMode && !realOutStream) + { + if (!seqMode) + continue; + skipMode = true; + askMode = NExtract::NAskMode::kSkip; + } + RINOK(extractCallback->PrepareOperation(askMode)); + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(skipMode ? 0 : unpackSize, true); + + if (item->IsLink()) + { + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length())); + } + else + { + if (!seqMode) + { + RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + } + streamSpec->Init(item->GetPackSize()); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + } + if (seqMode) + { + _latestIsRead = false; + _curIndex++; + } + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(outStreamSpec->GetRem() == 0 ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItemEx &item = _items[index]; + if (item.IsLink()) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); + COM_TRY_END +} + +}} |