diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2010-11-02 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:04 +0300 |
commit | c65230d8585317f7cd58ae2982067385269fdee9 (patch) | |
tree | 436513094ff5034da4c88def9609f0ea376065c6 /CPP/7zip/Archive | |
parent | 2eb60a059819da595efb8e1de49f04c241f5b981 (diff) |
9.189.18
Diffstat (limited to 'CPP/7zip/Archive')
33 files changed, 3051 insertions, 301 deletions
diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index ec0b5af4..87996bc0 100755 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -193,11 +193,9 @@ HRESULT CEncoder::Encode( // UInt64 outStreamStartPos; // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); - CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = - new CSequentialInStreamSizeCount2; + CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; - CSequentialOutStreamSizeCount *outStreamSizeCountSpec = - new CSequentialOutStreamSizeCount; + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec; inStreamSizeCountSpec->Init(inStream); @@ -226,13 +224,11 @@ HRESULT CEncoder::Encode( _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); if (writeCoderProperties != NULL) { - CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp; + CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); outStreamSpec->Init(); writeCoderProperties->WriteCoderProperties(outStream); - size_t size = outStreamSpec->GetSize(); - encodingInfo.Props.SetCapacity(size); - memmove(encodingInfo.Props, outStreamSpec->GetBuffer(), size); + outStreamSpec->CopyToBuffer(encodingInfo.Props); } } @@ -250,8 +246,7 @@ HRESULT CEncoder::Encode( RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); - ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, - folderItem); + ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); packSizes.Add(outStreamSizeCountSpec->GetSize()); diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 686bb288..0feb81d2 100755 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -280,28 +280,46 @@ void CInByte2::ReadString(UString &s) _pos += rem + 2; } -static inline bool TestSignatureCandidate(const Byte *p) +static inline bool TestSignature(const Byte *p) { for (int i = 0; i < kSignatureSize; i++) if (p[i] != kSignature[i]) return false; - return (p[0x1A] == 0 && p[0x1B] == 0); + return CrcCalc(p + 12, 20) == GetUi32(p + 8); } +#ifdef FORMAT_7Z_RECOVERY +static inline bool TestSignature2(const Byte *p) +{ + int i; + for (i = 0; i < kSignatureSize; i++) + if (p[i] != kSignature[i]) + return false; + if (CrcCalc(p + 12, 20) == GetUi32(p + 8)) + return true; + for (i = 8; i < kHeaderSize; i++) + if (p[i] != 0) + return false; + return (p[6] != 0 || p[7] != 0); +} +#else +#define TestSignature2(p) TestSignature(p) +#endif + HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); - if (TestSignatureCandidate(_header)) + if (TestSignature2(_header)) return S_OK; CByteBuffer byteBuffer; const UInt32 kBufferSize = (1 << 16); byteBuffer.SetCapacity(kBufferSize); Byte *buffer = byteBuffer; - UInt32 numPrevBytes = kHeaderSize - 1; - memcpy(buffer, _header + 1, numPrevBytes); - UInt64 curTestPos = _arhiveBeginStreamPosition + 1; + UInt32 numPrevBytes = kHeaderSize; + memcpy(buffer, _header, kHeaderSize); + UInt64 curTestPos = _arhiveBeginStreamPosition; for (;;) { if (searchHeaderSizeLimit != NULL) @@ -316,14 +334,14 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search if (processedSize == 0) return S_FALSE; } - while (numPrevBytes < kHeaderSize); - UInt32 numTests = numPrevBytes - kHeaderSize + 1; + while (numPrevBytes <= kHeaderSize); + UInt32 numTests = numPrevBytes - kHeaderSize; for (UInt32 pos = 0; pos < numTests; pos++) { for (; buffer[pos] != '7' && pos < numTests; pos++); if (pos == numTests) break; - if (TestSignatureCandidate(buffer + pos)) + if (TestSignature(buffer + pos)) { memcpy(_header, buffer + pos, kHeaderSize); curTestPos += pos; @@ -812,7 +830,7 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( ThrowUnsupported(); data.SetCapacity(unpackSize); - CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->Init(data, unpackSize); @@ -1164,23 +1182,24 @@ HRESULT CInArchive::ReadDatabase2( nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); } + else #endif - - #ifdef FORMAT_7Z_RECOVERY - crcFromArchive = crc; - #endif + { + if (crc != crcFromArchive) + ThrowIncorrect(); + } db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; - if (crc != crcFromArchive) - ThrowIncorrect(); - if (nextHeaderSize == 0) return S_OK; if (nextHeaderSize > (UInt64)0xFFFFFFFF) return S_FALSE; + if ((Int64)nextHeaderOffset < 0) + return S_FALSE; + RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); CByteBuffer buffer2; diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index 71996a63..a5e0dc0b 100755 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../../C/Types.h" + #include "ItemNameUtils.h" namespace NArchive { diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp index cf7dc050..04d11caf 100755 --- a/CPP/7zip/Archive/Common/MultiStream.cpp +++ b/CPP/7zip/Archive/Common/MultiStream.cpp @@ -6,72 +6,61 @@ STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if(processedSize != NULL) + if (processedSize) *processedSize = 0; - while(_streamIndex < Streams.Size() && size > 0) + if (size == 0) + return S_OK; + if (_pos >= _totalLength) + return (_pos == _totalLength) ? S_OK : E_FAIL; + { - CSubStreamInfo &s = Streams[_streamIndex]; - if (_pos == s.Size) + int left = 0, mid = _streamIndex, right = Streams.Size(); + for (;;) { - _streamIndex++; - _pos = 0; - continue; + CSubStreamInfo &m = Streams[mid]; + if (_pos < m.GlobalOffset) + right = mid; + else if (_pos >= m.GlobalOffset + m.Size) + left = mid + 1; + else + { + _streamIndex = mid; + break; + } + mid = (left + right) / 2; } - RINOK(s.Stream->Seek(s.Pos + _pos, STREAM_SEEK_SET, 0)); - UInt32 sizeToRead = UInt32(MyMin((UInt64)size, s.Size - _pos)); - UInt32 realProcessed; - HRESULT result = s.Stream->Read(data, sizeToRead, &realProcessed); - data = (void *)((Byte *)data + realProcessed); - size -= realProcessed; - if(processedSize != NULL) - *processedSize += realProcessed; - _pos += realProcessed; - _seekPos += realProcessed; - RINOK(result); - break; + _streamIndex = mid; } - return S_OK; + + CSubStreamInfo &s = Streams[_streamIndex]; + UInt64 localPos = _pos - s.GlobalOffset; + if (localPos != s.LocalPos) + { + RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos)); + } + UInt64 rem = s.Size - localPos; + if (size > rem) + size = (UInt32)rem; + HRESULT result = s.Stream->Read(data, size, &size); + _pos += size; + s.LocalPos += size; + if (processedSize) + *processedSize = size; + return result; } -STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, - UInt64 *newPosition) +STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - UInt64 newPos; switch(seekOrigin) { - case STREAM_SEEK_SET: - newPos = offset; - break; - case STREAM_SEEK_CUR: - newPos = _seekPos + offset; - break; - case STREAM_SEEK_END: - newPos = _totalLength + offset; - break; - default: - return STG_E_INVALIDFUNCTION; - } - _seekPos = 0; - for (_streamIndex = 0; _streamIndex < Streams.Size(); _streamIndex++) - { - UInt64 size = Streams[_streamIndex].Size; - if (newPos < _seekPos + size) - { - _pos = newPos - _seekPos; - _seekPos += _pos; - if (newPosition != 0) - *newPosition = newPos; - return S_OK; - } - _seekPos += size; + case STREAM_SEEK_SET: _pos = offset; break; + case STREAM_SEEK_CUR: _pos = _pos + offset; break; + case STREAM_SEEK_END: _pos = _totalLength + offset; break; + default: return STG_E_INVALIDFUNCTION; } - if (newPos == _seekPos) - { - if (newPosition != 0) - *newPosition = newPos; - return S_OK; - } - return E_FAIL; + if (newPosition != 0) + *newPosition = _pos; + return S_OK; } diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h index 137c9400..3fceb7cc 100755 --- a/CPP/7zip/Archive/Common/MultiStream.h +++ b/CPP/7zip/Archive/Common/MultiStream.h @@ -1,36 +1,44 @@ // MultiStream.h -#ifndef __MULTISTREAM_H -#define __MULTISTREAM_H +#ifndef __MULTI_STREAM_H +#define __MULTI_STREAM_H #include "../../../Common/MyCom.h" #include "../../../Common/MyVector.h" -#include "../../Archive/IArchive.h" + +#include "../../IStream.h" class CMultiStream: public IInStream, public CMyUnknownImp { - int _streamIndex; UInt64 _pos; - UInt64 _seekPos; UInt64 _totalLength; + int _streamIndex; public: struct CSubStreamInfo { CMyComPtr<IInStream> Stream; - UInt64 Pos; UInt64 Size; + UInt64 GlobalOffset; + UInt64 LocalPos; }; CObjectVector<CSubStreamInfo> Streams; - void Init() + + HRESULT Init() { - _streamIndex = 0; - _pos = 0; - _seekPos = 0; - _totalLength = 0; + UInt64 total = 0; for (int i = 0; i < Streams.Size(); i++) - _totalLength += Streams[i].Size; + { + CSubStreamInfo &s = Streams[i]; + s.GlobalOffset = total; + total += Streams[i].Size; + RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos)); + } + _totalLength = total; + _pos = 0; + _streamIndex = 0; + return S_OK; } MY_UNKNOWN_IMP1(IInStream) diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp new file mode 100755 index 00000000..a55e3743 --- /dev/null +++ b/CPP/7zip/Archive/CramfsHandler.cpp @@ -0,0 +1,644 @@ +// CramfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/Alloc.h" + +#include "Common/ComTry.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" + +namespace NArchive { +namespace NCramfs { + +#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' } + +static const UInt32 kSignatureSize = 16; +static const char kSignature[kSignatureSize] = SIGNATURE; + +static const UInt32 kArcSizeMax = (256 + 16) << 20; +static const UInt32 kNumFilesMax = (1 << 19); +static const unsigned kNumDirLevelsMax = (1 << 8); + +static const UInt32 kHeaderSize = 0x40; +static const unsigned kHeaderNameSize = 16; +static const UInt32 kNodeSize = 12; + +static const UInt32 kFlag_FsVer2 = (1 << 0); + +static const CUInt32PCharPair k_Flags[] = +{ + { 0, "Ver2" }, + { 1, "SortedDirs" }, + { 8, "Holes" }, + { 9, "WrongSignature" }, + { 10, "ShiftedRootOffset" } +}; + +static const unsigned kBlockSizeLog = 12; +static const UInt32 kBlockSize = 1 << kBlockSizeLog; + +/* +struct CNode +{ + UInt16 Mode; + UInt16 Uid; + UInt32 Size; + Byte Gid; + UInt32 NameLen; + UInt32 Offset; + + void Parse(const Byte *p) + { + Mode = GetUi16(p); + Uid = GetUi16(p + 2); + Size = Get32(p + 4) & 0xFFFFFF; + Gid = p[7]; + NameLen = p[8] & 0x3F; + Offset = Get32(p + 8) >> 6; + } +}; +*/ + +#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) + +static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } +static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; } + +static UInt32 GetSize(const Byte *p, bool be) +{ + if (be) + return GetBe32(p + 4) >> 8; + else + return GetUi32(p + 4) & 0xFFFFFF; +} + +static UInt32 GetNameLen(const Byte *p, bool be) +{ + if (be) + return (p[8] & 0xFC); + else + return (p[8] & 0x3F) << 2; +} + +static UInt32 GetOffset(const Byte *p, bool be) +{ + if (be) + return (GetBe32(p + 8) & 0x03FFFFFF) << 2; + else + return GetUi32(p + 8) >> 6 << 2; +} + +struct CItem +{ + UInt32 Offset; + int Parent; +}; + +struct CHeader +{ + bool be; + UInt32 Size; + UInt32 Flags; + // UInt32 Future; + UInt32 Crc; + // UInt32 Edition; + UInt32 NumBlocks; + UInt32 NumFiles; + char Name[kHeaderNameSize]; + + bool Parse(const Byte *p) + { + if (memcmp(p + 16, kSignature, kSignatureSize) != 0) + return false; + switch(GetUi32(p)) + { + case 0x28CD3D45: be = false; break; + case 0x453DCD28: be = true; break; + default: return false; + } + Size = Get32(p + 4); + Flags = Get32(p + 8); + // Future = Get32(p + 0xC); + Crc = Get32(p + 0x20); + // Edition = Get32(p + 0x24); + NumBlocks = Get32(p + 0x28); + NumFiles = Get32(p + 0x2C); + memcpy(Name, p + 0x30, kHeaderNameSize); + return true; + } + + bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CRecordVector<CItem> _items; + CMyComPtr<IInStream> _stream; + Byte *_data; + UInt32 _size; + UInt32 _headersSize; + AString _errorMessage; + CHeader _h; + + // Current file + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr<ICompressCoder> _zlibDecoder; + + CBufInStream *_inStreamSpec; + CMyComPtr<ISequentialInStream> _inStream; + + CBufPtrSeqOutStream *_outStreamSpec; + CMyComPtr<ISequentialOutStream> _outStream; + + UInt32 _curBlocksOffset; + UInt32 _curNumBlocks; + + HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); + HRESULT Open2(IInStream *inStream); + AString GetPath(int index) const; + bool GetPackSize(int index, UInt32 &res) const; + void Free(); +public: + CHandler(): _data(0) {} + ~CHandler() { Free(); } + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +}; + +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI4}, + { NULL, kpidPackSize, VT_UI4}, + { NULL, kpidPosixAttrib, VT_UI4} + // { NULL, kpidOffset, VT_UI4} +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidName, VT_BSTR}, + { NULL, kpidBigEndian, VT_BOOL}, + { NULL, kpidCharacts, VT_BSTR}, + { NULL, kpidPhySize, VT_UI4}, + { NULL, kpidHeadersSize, VT_UI4}, + { NULL, kpidNumSubFiles, VT_UI4}, + { NULL, kpidNumBlocks, VT_UI4} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) +{ + const Byte *p = _data + baseOffset; + bool be = _h.be; + if (!IsDir(p, be)) + return S_OK; + UInt32 offset = GetOffset(p, be); + UInt32 size = GetSize(p, be); + if (offset == 0 && size == 0) + return S_OK; + UInt32 end = offset + size; + if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax) + return S_FALSE; + if (end > _headersSize) + _headersSize = end; + + int startIndex = _items.Size(); + + while (size != 0) + { + if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax) + return S_FALSE; + CItem item; + item.Parent = parent; + item.Offset = offset; + _items.Add(item); + UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be); + if (size < nodeLen) + return S_FALSE; + offset += nodeLen; + size -= nodeLen; + } + + int endIndex = _items.Size(); + for (int i = startIndex; i < endIndex; i++) + { + RINOK(OpenDir(i, _items[i].Offset, level + 1)); + } + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *inStream) +{ + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); + if (!_h.Parse(buf)) + return S_FALSE; + if (_h.IsVer2()) + { + if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax) + return S_FALSE; + } + else + { + UInt64 size; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &size)); + if (size > kArcSizeMax) + return S_FALSE; + _h.Size = (UInt32)size; + RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); + } + _data = (Byte *)MidAlloc(_h.Size); + if (_data == 0) + return E_OUTOFMEMORY; + memcpy(_data, buf, kHeaderSize); + size_t processed = _h.Size - kHeaderSize; + RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)); + if (processed < kNodeSize) + return S_FALSE; + _size = kHeaderSize + (UInt32)processed; + if (_size != _h.Size) + _errorMessage = "Unexpected end of archive"; + else + { + SetUi32(_data + 0x20, 0); + if (_h.IsVer2()) + if (CrcCalc(_data, _h.Size) != _h.Crc) + _errorMessage = "CRC error"; + } + if (_h.IsVer2()) + _items.Reserve(_h.NumFiles - 1); + return OpenDir(-1, kHeaderSize, 0); +} + +AString CHandler::GetPath(int index) const +{ + unsigned len = 0; + int indexMem = index; + do + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + } + while (index >= 0); + len--; + + AString path; + char *dest = path.GetBuffer(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + if (index < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + path.ReleaseBuffer(len); + return path; +} + +bool CHandler::GetPackSize(int index, UInt32 &res) const +{ + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + return false; + UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog; + UInt32 start = offset + numBlocks * 4; + if (start > _size) + return false; + UInt32 end = Get32(_data + start - 4); + if (end < start) + return false; + res = end - start; + return true; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream)); + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +void CHandler::Free() +{ + MidFree(_data); + _data = 0; +} + +STDMETHODIMP CHandler::Close() +{ + _headersSize = 0; + _items.Clear(); + _stream.Release(); + _errorMessage.Empty(); + Free(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidName: + { + char dest[kHeaderNameSize + 4]; + memcpy(dest, _h.Name, kHeaderNameSize); + dest[kHeaderNameSize] = 0; + prop = dest; + break; + } + case kpidBigEndian: prop = _h.be; break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break; + case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break; + case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break; + case kpidHeadersSize: prop = _headersSize; break; + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + bool isDir = IsDir(p, be); + switch(propID) + { + case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; + case kpidIsDir: prop = isDir; break; + // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; + case kpidSize: if (!isDir) prop = GetSize(p, be); break; + case kpidPackSize: + if (!isDir) + { + UInt32 size; + if (GetPackSize(index, size)) + prop = size; + } + break; + case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CCramfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +public: + CHandler *Handler; +}; + +HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } + if (!_inStream) + { + _inStreamSpec = new CBufInStream(); + _inStream = _inStreamSpec; + } + if (!_outStream) + { + _outStreamSpec = new CBufPtrSeqOutStream(); + _outStream = _outStreamSpec; + } + bool be = _h.be; + const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); + UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4)); + UInt32 end = Get32(p); + if (end < start || end > _size) + return S_FALSE; + UInt32 inSize = end - start; + _inStreamSpec->Init(_data + start, inSize); + _outStreamSpec->Init(dest, blockSize); + RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL)); + return (_zlibDecoderSpec->GetInputProcessedSize() == inSize && + _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + bool be = _h.be; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset; + if (!IsDir(p, be)) + totalSize += GetSize(p, be); + } + extractCallback->SetTotal(totalSize); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + const Byte *p = _data + item.Offset; + + if (IsDir(p, be)) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + UInt32 curSize = GetSize(p, be); + totalSize += curSize; + UInt32 packSize; + if (GetPackSize(index, packSize)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + curSize = 0; + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr<ISequentialInStream> inSeqStream; + CMyComPtr<IInStream> inStream; + HRESULT hres = GetStream(index, &inSeqStream); + if (inSeqStream) + inSeqStream.QueryInterface(IID_IInStream, &inStream); + if (hres == E_OUTOFMEMORY) + return E_OUTOFMEMORY; + if (hres == S_FALSE || !inStream) + res = NExtract::NOperationResult::kUnSupportedMethod; + else + { + RINOK(hres); + if (inStream) + { + HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); + if (hres != S_OK && hres != S_FALSE) + { + RINOK(hres); + } + if (copyCoderSpec->TotalSize == curSize && hres == S_OK) + res = NExtract::NOperationResult::kOK; + } + } + } + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + + bool be = _h.be; + if (IsDir(p, be)) + return E_FAIL; + + UInt32 size = GetSize(p, be); + UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog; + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + { + if (offset != 0) + return S_FALSE; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + streamSpec->Init(NULL, 0); + *stream = streamTemp.Detach(); + return S_OK; + } + + if (offset + numBlocks * 4 > _size) + return S_FALSE; + UInt32 prev = offset; + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt32 next = Get32(_data + offset + i * 4); + if (next < prev || next > _size) + return S_FALSE; + prev = next; + } + + CCramfsInStream *streamSpec = new CCramfsInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + _curNumBlocks = numBlocks; + _curBlocksOffset = offset; + streamSpec->Handler = this; + if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog)) + return E_OUTOFMEMORY; + streamSpec->Init(size); + *stream = streamTemp.Detach(); + + return S_OK; + COM_TRY_END +} + +static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; } + +static CArcInfo g_ArcInfo = + { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + +REGISTER_ARC(Cramfs) + +}} diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 6f5a6776..c4ad78e9 100755 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -277,9 +277,9 @@ static const CUInt32PCharPair g_AbiOS[] = static const CUInt32PCharPair g_SegmentFlags[] = { - { 1 << 0, "Execute" }, - { 1 << 1, "Write" }, - { 1 << 2, "Read" } + { 0, "Execute" }, + { 1, "Write" }, + { 2, "Read" } }; static const char *g_Types[] = diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico Binary files differnew file mode 100755 index 00000000..551a7439 --- /dev/null +++ b/CPP/7zip/Archive/Icons/squashfs.ico diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index dc20c240..4bfb7dc6 100755 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -24,7 +24,7 @@ using namespace NTime; namespace NArchive { namespace NIso { -static STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -33,8 +33,17 @@ static STATPROPSTG kProps[] = { NULL, kpidMTime, VT_FILETIME} }; +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidMTime, VT_FILETIME} + // { NULL, kpidPhySize, VT_UI8}, + // { NULL, kpidHeadersSize, VT_UI8} +}; + IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, @@ -66,6 +75,58 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } +static void AddString(AString &s, const char *name, const Byte *p, int size) +{ + int i; + for (i = 0; i < size && p[i]; i++); + for (; i > 0 && p[i - 1] == ' '; i--); + if (i != 0) + { + AString d; + memcpy(d.GetBuffer(i), p, i); + d.ReleaseBuffer(i); + s += '\n'; + s += name; + s += ": "; + s += d; + } +} + +#define ADD_STRING(n, v) AddString(s, n, vol. ## v, sizeof(vol. ## v)) + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex]; + switch(propID) + { + case kpidComment: + { + AString s; + ADD_STRING("System", SystemId); + ADD_STRING("Volume", VolumeId); + ADD_STRING("VolumeSet", VolumeSetId); + ADD_STRING("Publisher", PublisherId); + ADD_STRING("Preparer", DataPreparerId); + ADD_STRING("Application", ApplicationId); + ADD_STRING("Copyright", CopyrightFileId); + ADD_STRING("Abstract", AbstractFileId); + ADD_STRING("Bib", BibFileId); + prop = s; + break; + } + case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } + case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; } + // case kpidPhySize: break; + // case kpidHeadersSize: break; + case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -87,9 +148,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = (const wchar_t *)s; break; } - case kpidIsDir: - prop = false; - break; + case kpidIsDir: prop = false; break; case kpidSize: case kpidPackSize: prop = (UInt64)_archive.GetBootItemSize(index); @@ -121,9 +180,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = (const wchar_t *)NItemName::GetOSName2(s); } break; - case kpidIsDir: - prop = item.IsDir(); - break; + case kpidIsDir: prop = item.IsDir(); break; case kpidSize: case kpidPackSize: if (!item.IsDir()) @@ -131,16 +188,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; case kpidMTime: { - FILETIME utcFileTime; - if (item.DateTime.GetFileTime(utcFileTime)) - prop = utcFileTime; - /* - else - { - utcFileTime.dwLowDateTime = 0; - utcFileTime.dwHighDateTime = 0; - } - */ + FILETIME utc; + if (item.DateTime.GetFileTime(utc)) + prop = utc; break; } } diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 84143348..7ed618d2 100755 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -65,7 +65,7 @@ UInt16 CInArchive::ReadUInt16() for (int i = 0; i < 2; i++) { if (b[i] != b[3 - i]) - throw 1; + IncorrectBigEndian = true; value |= ((UInt16)(b[i]) << (8 * i)); } return (UInt16)value; @@ -440,6 +440,7 @@ HRESULT CInArchive::Open(IInStream *inStream) void CInArchive::Clear() { + IncorrectBigEndian = false; Refs.Clear(); _rootDir.Clear(); VolDescs.Clear(); diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 49687e27..f9c6f640 100755 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -111,6 +111,20 @@ struct CDateTime signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } + + bool GetFileTime(FILETIME &ft) const + { + UInt64 value; + bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); + if (res) + { + value -= (UInt64)((Int64)GmtOffset * 15 * 60); + value *= 10000000; + } + ft.dwLowDateTime = (DWORD)value; + ft.dwHighDateTime = (DWORD)(value >> 32); + return res; + } }; struct CBootRecordDescriptor @@ -268,6 +282,7 @@ public: int MainVolDescIndex; UInt32 BlockSize; CObjectVector<CBootInitialEntry> BootEntries; + bool IncorrectBigEndian; bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index c568ee4c..95efc501 100755 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -266,7 +266,7 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) return (startHeader[0] == 0) ? S_OK: S_FALSE; const Byte *p = header; - memmove(item.Method, p, kMethodIdSize); + memcpy(item.Method, p, kMethodIdSize); if (!item.IsValidMethod()) return S_OK; p += kMethodIdSize; diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index ad4a5afb..a6261f34 100755 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -77,16 +77,16 @@ static const char *g_FileTypes[] = static const CUInt32PCharPair g_Flags[] = { - { (UInt32)1 << 31, "PURE_INSTRUCTIONS" }, - { 1 << 30, "NO_TOC" }, - { 1 << 29, "STRIP_STATIC_SYMS" }, - { 1 << 28, "NO_DEAD_STRIP" }, - { 1 << 27, "LIVE_SUPPORT" }, - { 1 << 26, "SELF_MODIFYING_CODE" }, - { 1 << 25, "DEBUG" }, - { 1 << 10, "SOME_INSTRUCTIONS" }, - { 1 << 9, "EXT_RELOC" }, - { 1 << 8, "LOC_RELOC" } + { 31, "PURE_INSTRUCTIONS" }, + { 30, "NO_TOC" }, + { 29, "STRIP_STATIC_SYMS" }, + { 28, "NO_DEAD_STRIP" }, + { 27, "LIVE_SUPPORT" }, + { 26, "SELF_MODIFYING_CODE" }, + { 25, "DEBUG" }, + { 10, "SOME_INSTRUCTIONS" }, + { 9, "EXT_RELOC" }, + { 8, "LOC_RELOC" } }; static const CUInt32PCharPair g_MachinePairs[] = diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 506e944a..c64067aa 100755 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -300,53 +300,53 @@ void CSection::Parse(const Byte *p) static const CUInt32PCharPair g_HeaderCharacts[] = { - { 1 << 1, "Executable" }, - { 1 << 13, "DLL" }, - { 1 << 8, "32-bit" }, - { 1 << 5, "LargeAddress" }, - { 1 << 0, "NoRelocs" }, - { 1 << 2, "NoLineNums" }, - { 1 << 3, "NoLocalSyms" }, - { 1 << 4, "AggressiveWsTrim" }, - { 1 << 9, "NoDebugInfo" }, - { 1 << 10, "RemovableRun" }, - { 1 << 11, "NetRun" }, - { 1 << 12, "System" }, - { 1 << 14, "UniCPU" }, - { 1 << 7, "Little-Endian" }, - { 1 << 15, "Big-Endian" } + { 1, "Executable" }, + { 13, "DLL" }, + { 8, "32-bit" }, + { 5, "LargeAddress" }, + { 0, "NoRelocs" }, + { 2, "NoLineNums" }, + { 3, "NoLocalSyms" }, + { 4, "AggressiveWsTrim" }, + { 9, "NoDebugInfo" }, + { 10, "RemovableRun" }, + { 11, "NetRun" }, + { 12, "System" }, + { 14, "UniCPU" }, + { 7, "Little-Endian" }, + { 15, "Big-Endian" } }; static const CUInt32PCharPair g_DllCharacts[] = { - { 1 << 6, "Relocated" }, - { 1 << 7, "Integrity" }, - { 1 << 8, "NX-Compatible" }, - { 1 << 9, "NoIsolation" }, - { 1 << 10, "NoSEH" }, - { 1 << 11, "NoBind" }, - { 1 << 13, "WDM" }, - { 1 << 15, "TerminalServerAware" } + { 6, "Relocated" }, + { 7, "Integrity" }, + { 8, "NX-Compatible" }, + { 9, "NoIsolation" }, + { 10, "NoSEH" }, + { 11, "NoBind" }, + { 13, "WDM" }, + { 15, "TerminalServerAware" } }; static const CUInt32PCharPair g_SectFlags[] = { - { 1 << 3, "NoPad" }, - { 1 << 5, "Code" }, - { 1 << 6, "InitializedData" }, - { 1 << 7, "UninitializedData" }, - { 1 << 9, "Comments" }, - { 1 << 11, "Remove" }, - { 1 << 12, "COMDAT" }, - { 1 << 15, "GP" }, - { 1 << 24, "ExtendedRelocations" }, - { 1 << 25, "Discardable" }, - { 1 << 26, "NotCached" }, - { 1 << 27, "NotPaged" }, - { 1 << 28, "Shared" }, - { 1 << 29, "Execute" }, - { 1 << 30, "Read" }, - { (UInt32)1 << 31, "Write" } + { 3, "NoPad" }, + { 5, "Code" }, + { 6, "InitializedData" }, + { 7, "UninitializedData" }, + { 9, "Comments" }, + { 11, "Remove" }, + { 12, "COMDAT" }, + { 15, "GP" }, + { 24, "ExtendedRelocations" }, + { 25, "Discardable" }, + { 26, "NotCached" }, + { 27, "NotPaged" }, + { 28, "Shared" }, + { 29, "Execute" }, + { 30, "Read" }, + { 31, "Write" } }; static const CUInt32PCharPair g_MachinePairs[] = @@ -1723,6 +1723,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) size_t offset = item.Offset - sect.Va; if (!CheckItem(sect, item, offset)) return S_FALSE; + if (item.HeaderSize == 0) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<IInStream> streamTemp2 = streamSpec; + streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this); + *stream = streamTemp2.Detach(); + return S_OK; + } referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size); memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 8906614a..54709f6c 100755 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -46,7 +46,7 @@ static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); static const wchar_t *kUnknownOS = L"Unknown"; -STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -68,7 +68,7 @@ STATPROPSTG kProps[] = { NULL, kpidUnpackVer, VT_UI1} }; -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidSolid, VT_BOOL}, { NULL, kpidNumBlocks, VT_UI4}, @@ -93,7 +93,7 @@ UInt64 CHandler::GetPackSize(int refIndex) const STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { - // COM_TRY_BEGIN + COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; switch(propID) { @@ -112,10 +112,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = (UInt32)numBlocks; break; } + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; } prop.Detach(value); return S_OK; - // COM_TRY_END + COM_TRY_END } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) @@ -396,7 +397,14 @@ HRESULT CHandler::Open2(IInStream *stream, for (;;) { bool decryptionError; - HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError); + AString errorMessageLoc; + HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc); + if (errorMessageLoc) + { + if (!_errorMessage.IsEmpty()) + _errorMessage += '\n'; + _errorMessage += errorMessageLoc; + } if (result == S_FALSE) { if (decryptionError && _items.IsEmpty()) @@ -461,6 +469,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { COM_TRY_BEGIN + _errorMessage.Empty(); _refItems.Clear(); _items.Clear(); _archives.Clear(); diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index 58e3fefc..c8015b2a 100755 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -32,6 +32,7 @@ private: CObjectVector<CItemEx> _items; CObjectVector<CInArchive> _archives; NArchive::NRar::CInArchiveInfo _archiveInfo; + AString _errorMessage; DECL_EXTERNAL_CODECS_VARS diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h index 4df42e62..8bb1da21 100755 --- a/CPP/7zip/Archive/Rar/RarHeader.h +++ b/CPP/7zip/Archive/Rar/RarHeader.h @@ -18,16 +18,16 @@ namespace NBlockType { enum EBlockType { - kMarker = 0x72, - kArchiveHeader = 0x73, - kFileHeader = 0x74, - kCommentHeader = 0x75, - kOldAuthenticity = 0x76, - kSubBlock = 0x77, - kRecoveryRecord = 0x78, - kAuthenticity = 0x79, - - kEndOfArchive = 0x7B // Is not safe + kMarker = 0x72, + kArchiveHeader, + kFileHeader, + kCommentHeader, + kOldAuthenticity, + kOldSubBlock, + kRecoveryRecord, + kAuthenticity, + kSubBlock, + kEndOfArchive }; } diff --git a/CPP/7zip/Archive/Rar/RarIn.cpp b/CPP/7zip/Archive/Rar/RarIn.cpp index c5d30fac..7d64c6fd 100755 --- a/CPP/7zip/Archive/Rar/RarIn.cpp +++ b/CPP/7zip/Archive/Rar/RarIn.cpp @@ -372,14 +372,14 @@ void CInArchive::AddToSeekValue(UInt64 addValue) m_Position += addValue; } -HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError) +HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage) { decryptionError = false; if (m_SeekOnArchiveComment) SkipArchiveComment(); for (;;) { - if(!SeekInArchive(m_Position)) + if (!SeekInArchive(m_Position)) return S_FALSE; if (!m_CryptoMode && (m_ArchiveHeader.Flags & NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) @@ -438,8 +438,11 @@ HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPa } m_FileHeaderData.EnsureCapacity(7); - if(!ReadBytesAndTestSize((Byte *)m_FileHeaderData, 7)) + if (!ReadBytesAndTestSize((Byte *)m_FileHeaderData, 7)) + { + errorMessage = "Unexpected end of archive"; return S_FALSE; + } m_CurData = (Byte *)m_FileHeaderData; m_CurPos = 0; diff --git a/CPP/7zip/Archive/Rar/RarIn.h b/CPP/7zip/Archive/Rar/RarIn.h index 5d9f67a3..75c98cc4 100755 --- a/CPP/7zip/Archive/Rar/RarIn.h +++ b/CPP/7zip/Archive/Rar/RarIn.h @@ -110,7 +110,7 @@ class CInArchive public: HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); void Close(); - HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError); + HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage); void SkipArchiveComment(); diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index f533e78f..1d31d451 100755 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -79,7 +79,7 @@ static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h) char dat[kCSigHeaderSigSize]; char *cur = dat; RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize)); - memmove(h.Magic, cur, 4); + memcpy(h.Magic, cur, 4); cur += 4; cur += 4; h.IndexLen = Get32(cur); @@ -95,7 +95,7 @@ HRESULT OpenArchive(IInStream *inStream) char *cur = leadData; CLead lead; RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize)); - memmove(lead.Magic, cur, 4); + memcpy(lead.Magic, cur, 4); cur += 4; lead.Major = *cur++; lead.Minor = *cur++; @@ -103,7 +103,7 @@ HRESULT OpenArchive(IInStream *inStream) cur += 2; lead.ArchNum = Get16(cur); cur += 2; - memmove(lead.Name, cur, sizeof(lead.Name)); + memcpy(lead.Name, cur, sizeof(lead.Name)); cur += sizeof(lead.Name); lead.OSNum = Get16(cur); cur += 2; diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index e3129c6a..5d84de4e 100755 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -347,7 +347,6 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { CMultiStream::CSubStreamInfo subStreamInfo; subStreamInfo.Stream = _streams[i]; - subStreamInfo.Pos = 0; subStreamInfo.Size = _sizes[i]; streamSpec->Streams.Add(subStreamInfo); } diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp new file mode 100755 index 00000000..e09c09de --- /dev/null +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -0,0 +1,1959 @@ +// SquashfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "Common/ComTry.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariantUtils.h" +#include "Windows/Time.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" +#include "../Compress/LzmaDecoder.h" + +namespace NArchive { +namespace NSquashfs { + +static const UInt32 kNumFilesMax = (1 << 28); +static const unsigned kNumDirLevelsMax = (1 << 10); + +// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs + +/* +#define Get16(p) (be ? GetBe16(p) : GetUi16(p)) +#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) +#define Get64(p) (be ? GetBe64(p) : GetUi64(p)) +*/ + +UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } +UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); } +UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } + +#define Get16(p) Get16b(p, be) +#define Get32(p) Get32b(p, be) +#define Get64(p) Get64b(p, be) + +#define LE_16(offs, dest) dest = GetUi16(p + (offs)); +#define LE_32(offs, dest) dest = GetUi32(p + (offs)); +#define LE_64(offs, dest) dest = GetUi64(p + (offs)); + +#define GET_16(offs, dest) dest = Get16(p + (offs)); +#define GET_32(offs, dest) dest = Get32(p + (offs)); +#define GET_64(offs, dest) dest = Get64(p + (offs)); + +static const UInt32 kSignatureSize = 4; +#define SIGNATURE { 'h', 's', 'q', 's' } +static const UInt32 kSignature32_LE = 0x73717368; +static const UInt32 kSignature32_BE = 0x68737173; +static const UInt32 kSignature32_LZ = 0x71736873; + +#define kMethod_ZLIB 1 +#define kMethod_LZMA 2 +#define kMethod_LZO 3 + +static const char *k_Methods[] = +{ + "Unknown", + "ZLIB", + "LZMA", + "LZO" +}; + +static const UInt32 kMetadataBlockSizeLog = 13; +static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); + +#define MY_S_IFIFO 0x1000 +#define MY_S_IFCHR 0x2000 +#define MY_S_IFDIR 0x4000 +#define MY_S_IFBLK 0x6000 +#define MY_S_IFREG 0x8000 +#define MY_S_IFLNK 0xA000 +#define MY_S_IFSOCK 0xC000 + +enum +{ + kType_IPC, + kType_DIR, + kType_FILE, + kType_LNK, + kType_BLK, + kType_CHR, + kType_FIFO, + kType_SOCK +}; + +static const UInt32 k_TypeToMode[] = +{ + 0, + MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK, + MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK +}; + + +enum +{ + kFlag_UNC_INODES, + kFlag_UNC_DATA, + kFlag_CHECK, + kFlag_UNC_FRAGS, + kFlag_NO_FRAGS, + kFlag_ALWAYS_FRAG, + kFlag_DUPLICATE, + kFlag_EXPORT +}; + +static const CUInt32PCharPair k_Flags[] = +{ + { kFlag_UNC_INODES, "UNCOMPRESSED_INODES" }, + { kFlag_UNC_DATA, "UNCOMPRESSED_DATA" }, + { kFlag_CHECK, "CHECK" }, + { kFlag_UNC_FRAGS, "UNCOMPRESSED_FRAGMENTS" }, + { kFlag_NO_FRAGS, "NO_FRAGMENTS" }, + { kFlag_ALWAYS_FRAG, "ALWAYS_FRAGMENTS" }, + { kFlag_DUPLICATE, "DUPLICATES_REMOVED" }, + { kFlag_EXPORT, "EXPORTABLE" } +}; + +static const UInt32 kNotCompressedBit16 = (1 << 15); +static const UInt32 kNotCompressedBit32 = (1 << 24); + +#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32) +#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0) + +static const UInt32 kHeaderSize1 = 0x33; +static const UInt32 kHeaderSize2 = 0x3F; +static const UInt32 kHeaderSize3 = 0x77; +static const UInt32 kHeaderSize4 = 0x60; + +struct CHeader +{ + bool be; + bool SeveralMethods; + Byte NumUids; + Byte NumGids; + + UInt32 NumInodes; + UInt32 CTime; + UInt32 BlockSize; + UInt32 NumFrags; + UInt16 Method; + UInt16 BlockSizeLog; + UInt16 Flags; + UInt16 NumIDs; + UInt16 Major; + UInt16 Minor; + UInt64 RootInode; + UInt64 Size; + UInt64 UidTable; + UInt64 GidTable; + UInt64 XattrIdTable; + UInt64 InodeTable; + UInt64 DirTable; + UInt64 FragTable; + UInt64 LookupTable; + + void Parse3(const Byte *p) + { + Method = kMethod_ZLIB; + GET_32 (0x08, Size); + GET_32 (0x0C, UidTable); + GET_32 (0x10, GidTable); + GET_32 (0x14, InodeTable); + GET_32 (0x18, DirTable); + GET_16 (0x20, BlockSize); + GET_16 (0x22, BlockSizeLog); + Flags = p[0x24]; + NumUids = p[0x25]; + NumGids = p[0x26]; + GET_32 (0x27, CTime); + GET_64 (0x2B, RootInode); + NumFrags = 0; + FragTable = UidTable; + + if (Major >= 2) + { + GET_32 (0x33, BlockSize); + GET_32 (0x37, NumFrags); + GET_32 (0x3B, FragTable); + if (Major == 3) + { + GET_64 (0x3F, Size); + GET_64 (0x47, UidTable); + GET_64 (0x4F, GidTable); + GET_64 (0x57, InodeTable); + GET_64 (0x5F, DirTable); + GET_64 (0x67, FragTable); + GET_64 (0x6F, LookupTable); + } + } + } + + void Parse4(const Byte *p) + { + LE_32 (0x08, CTime); + LE_32 (0x0C, BlockSize); + LE_32 (0x10, NumFrags); + LE_16 (0x14, Method); + LE_16 (0x16, BlockSizeLog); + LE_16 (0x18, Flags); + LE_16 (0x1A, NumIDs); + LE_64 (0x20, RootInode); + LE_64 (0x28, Size); + LE_64 (0x30, UidTable); + LE_64 (0x38, XattrIdTable); + LE_64 (0x40, InodeTable); + LE_64 (0x48, DirTable); + LE_64 (0x50, FragTable); + LE_64 (0x58, LookupTable); + GidTable = 0; + } + + bool Parse(const Byte *p) + { + be = false; + SeveralMethods = false; + switch (GetUi32(p)) + { + case kSignature32_LE: break; + case kSignature32_BE: be = true; break; + case kSignature32_LZ: SeveralMethods = true; break; + default: return false; + } + GET_32 (4, NumInodes); + GET_16 (0x1C, Major); + GET_16 (0x1E, Minor); + if (Major <= 3) + Parse3(p); + else + { + if (be) + return false; + Parse4(p); + } + return + InodeTable < DirTable && + DirTable <= FragTable && + FragTable <= Size && + UidTable <= Size && + BlockSizeLog >= 12 && + BlockSizeLog < 31 && + BlockSize == ((UInt32)1 << BlockSizeLog); + } + + bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; } + bool IsOldVersion() const { return Major < 4; } + bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; } + unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); } + unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); } + unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; } +}; + +static const UInt32 kFrag_Empty = (UInt32)(Int32)-1; +// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1; + +struct CNode +{ + UInt16 Type; + UInt16 Mode; + UInt16 Uid; + UInt16 Gid; + UInt32 Frag; + UInt32 Offset; + // UInt32 MTime; + // UInt32 Number; + // UInt32 NumLinks; + // UInt32 RDev; + // UInt32 Xattr; + // UInt32 Parent; + + UInt64 FileSize; + UInt64 StartBlock; + // UInt64 Sparse; + + UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h); + + bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); } + bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); } + UInt64 GetSize() const { return IsDir() ? 0 : FileSize; } + + bool ThereAreFrags() const { return Frag != kFrag_Empty; } + UInt64 GetNumBlocks(const CHeader &_h) const + { + return (FileSize >> _h.BlockSizeLog) + + (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0); + } +}; + +UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) +{ + bool be = _h.be; + if (size < 4) + return 0; + UInt16 t = Get16(p); + if (be) + { + Type = t >> 12; + Mode = t & 0xFFF; + Uid = p[2] >> 4; + Gid = p[2] & 0xF; + } + else + { + Type = t & 0xF; + Mode = t >> 4; + Uid = p[2] & 0xF; + Gid = p[2] >> 4; + } + + // Xattr = kXattr_Empty; + // MTime = 0; + FileSize = 0; + StartBlock = 0; + Frag = kFrag_Empty; + + if (Type == 0) + { + Byte t = p[3]; + if (be) + { + Type = t >> 4; + Offset = t & 0xF; + } + else + { + Type = t & 0xF; + Offset = t >> 4; + } + return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0; + } + + Type--; + Uid += (Type / 5) * 16; + Type = (Type % 5) + 1; + + if (Type == kType_FILE) + { + if (size < 15) + return 0; + // GET_32 (3, MTime); + GET_32 (7, StartBlock); + UInt32 t; + GET_32 (11, t); + FileSize = t; + UInt32 numBlocks = t >> _h.BlockSizeLog; + if ((t & (_h.BlockSize - 1)) != 0) + numBlocks++; + UInt32 pos = numBlocks * 2 + 15; + return (pos <= size) ? pos : 0; + } + + if (Type == kType_DIR) + { + if (size < 14) + return 0; + UInt32 t = Get32(p + 3); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + // GET_32 (7, MTime); + GET_32 (10, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + return 14; + } + + if (size < 5) + return 0; + + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (3, len); + FileSize = len; + len += 5; + return (len <= size) ? len : 0; + } + + // GET_32 (3, RDev); + return 5; +} + +UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) +{ + bool be = _h.be; + if (size < 4) + return 0; + UInt16 t = Get16(p); + if (be) + { + Type = t >> 12; + Mode = t & 0xFFF; + } + else + { + Type = t & 0xF; + Mode = t >> 4; + } + Uid = p[2]; + Gid = p[3]; + + // Xattr = kXattr_Empty; + + if (Type == kType_FILE) + { + if (size < 24) + return 0; + // GET_32 (4, MTime); + GET_32 (8, StartBlock); + GET_32 (12, Frag); + GET_32 (16, Offset); + UInt32 t; + GET_32 (20, t); + FileSize = t; + UInt32 numBlocks = t >> _h.BlockSizeLog; + if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0) + numBlocks++; + UInt32 pos = numBlocks * 4 + 24; + return (pos <= size) ? (UInt32)pos : 0; + } + + FileSize = 0; + // MTime = 0; + StartBlock = 0; + Frag = kFrag_Empty; + + if (Type == kType_DIR) + { + if (size < 15) + return 0; + UInt32 t = Get32(p + 4); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + // GET_32 (8, MTime); + GET_32 (11, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + return 15; + } + + if (Type == kType_DIR + 7) + { + if (size < 18) + return 0; + UInt32 t = Get32(p + 4); + UInt32 t2 = Get16(p + 7); + if (be) + { + FileSize = t >> 5; + Offset = t2 & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFFFF; + Offset = t2 >> 3; + } + // GET_32 (9, MTime); + GET_32 (12, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + UInt32 iCount; + GET_16 (16, iCount); + UInt32 pos = 18; + for (UInt32 i = 0; i < iCount; i++) + { + // 27 bits: index + // 29 bits: startBlock + if (pos + 8 > size) + return 0; + pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize + if (pos > size) + return 0; + } + return pos; + } + + if (Type == kType_FIFO || Type == kType_SOCK) + return 4; + + if (size < 6) + return 0; + + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (4, len); + FileSize = len; + len += 6; + return (len <= size) ? len : 0; + } + + if (Type == kType_BLK || Type == kType_CHR) + { + // GET_16 (4, RDev); + return 6; + } + + return 0; +} + +UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) +{ + bool be = _h.be; + if (size < 12) + return 0; + UInt16 t = Get16(p); + if (be) + { + Type = t >> 12; + Mode = t & 0xFFF; + } + else + { + Type = t & 0xF; + Mode = t >> 4; + } + Uid = p[2]; + Gid = p[3]; + // GET_32 (4, MTime); + // GET_32 (8, Number); + // Xattr = kXattr_Empty; + FileSize = 0; + StartBlock = 0; + + if (Type == kType_FILE || Type == kType_FILE + 7) + { + UInt32 offset; + if (Type == kType_FILE) + { + if (size < 32) + return 0; + GET_64 (12, StartBlock); + GET_32 (20, Frag); + GET_32 (24, Offset); + GET_32 (28, FileSize); + offset = 32; + } + else + { + if (size < 40) + return 0; + // GET_32 (12, NumLinks); + GET_64 (16, StartBlock); + GET_32 (24, Frag); + GET_32 (28, Offset); + GET_64 (32, FileSize); + offset = 40; + } + UInt64 pos = GetNumBlocks(_h) * 4 + offset; + return (pos <= size) ? (UInt32)pos : 0; + } + + if (size < 16) + return 0; + // GET_32 (12, NumLinks); + + if (Type == kType_DIR) + { + if (size < 28) + return 0; + UInt32 t = Get32(p + 16); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + GET_32 (20, StartBlock); + // GET_32 (24, Parent); + return 28; + } + + if (Type == kType_DIR + 7) + { + if (size < 31) + return 0; + UInt32 t = Get32(p + 16); + UInt32 t2 = Get16(p + 19); + if (be) + { + FileSize = t >> 5; + Offset = t2 & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFFFF; + Offset = t2 >> 3; + } + GET_32 (21, StartBlock); + UInt32 iCount; + GET_16 (25, iCount); + // GET_32 (27, Parent); + UInt32 pos = 31; + for (UInt32 i = 0; i < iCount; i++) + { + // UInt32 index + // UInt32 startBlock + if (pos + 9 > size) + return 0; + pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize + if (pos > size) + return 0; + } + return pos; + } + + if (Type == kType_FIFO || Type == kType_SOCK) + return 16; + + if (size < 18) + return 0; + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (16, len); + FileSize = len; + len += 18; + return (len <= size) ? len : 0; + } + + if (Type == kType_BLK || Type == kType_CHR) + { + // GET_16 (16, RDev); + return 18; + } + + return 0; +} + +UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h) +{ + if (size < 20) + return 0; + LE_16 (0, Type); + LE_16 (2, Mode); + LE_16 (4, Uid); + LE_16 (6, Gid); + // LE_32 (8, MTime); + // LE_32 (12, Number); + + // Xattr = kXattr_Empty; + FileSize = 0; + StartBlock = 0; + + if (Type == kType_FILE || Type == kType_FILE + 7) + { + UInt32 offset; + if (Type == kType_FILE) + { + if (size < 32) + return 0; + LE_32 (16, StartBlock); + LE_32 (20, Frag); + LE_32 (24, Offset); + LE_32 (28, FileSize); + offset = 32; + } + else + { + if (size < 56) + return 0; + LE_64 (16, StartBlock); + LE_64 (24, FileSize); + // LE_64 (32, Sparse); + // LE_32 (40, NumLinks); + LE_32 (44, Frag); + LE_32 (48, Offset); + // LE_32 (52, Xattr); + offset = 56; + } + UInt64 pos = GetNumBlocks(_h) * 4 + offset; + return (pos <= size) ? (UInt32)pos : 0; + } + + if (Type == kType_DIR) + { + if (size < 32) + return 0; + LE_32 (16, StartBlock); + // LE_32 (20, NumLinks); + LE_16 (24, FileSize); + LE_16 (26, Offset); + // LE_32 (28, Parent); + return 32; + } + + // LE_32 (16, NumLinks); + + if (Type == kType_DIR + 7) + { + if (size < 40) + return 0; + LE_32 (20, FileSize); + LE_32 (24, StartBlock); + // LE_32 (28, Parent); + UInt32 iCount; + LE_16 (32, iCount); + LE_16 (34, Offset); + // LE_32 (36, Xattr); + + UInt32 pos = 40; + for (UInt32 i = 0; i < iCount; i++) + { + // UInt32 index + // UInt32 startBlock + if (pos + 12 > size) + return 0; + UInt32 nameLen = GetUi32(p + pos + 8); + pos += 12 + nameLen + 1; + if (pos > size || nameLen > (1 << 10)) + return 0; + } + return pos; + } + + unsigned offset = 20; + switch(Type) + { + case kType_FIFO: case kType_FIFO + 7: + case kType_SOCK: case kType_SOCK + 7: + break; + case kType_LNK: case kType_LNK + 7: + { + if (size < 24) + return 0; + UInt32 len; + LE_32 (20, len); + FileSize = len; + offset = len + 24; + if (size < offset || len > (1 << 30)) + return 0; + break; + } + case kType_BLK: case kType_BLK + 7: + case kType_CHR: case kType_CHR + 7: + if (size < 24) + return 0; + // LE_32 (20, RDev); + offset = 24; + break; + default: + return 0; + } + + if (Type >= 8) + { + if (size < offset + 4) + return 0; + // LE_32 (offset, Xattr); + offset += 4; + } + return offset; +} + +struct CItem +{ + int Node; + int Parent; + UInt32 Ptr; +}; + +struct CData +{ + CByteBuffer Data; + CRecordVector<UInt32> PackPos; + CRecordVector<UInt32> UnpackPos; // additional item at the end contains TotalUnpackSize + + UInt32 GetNumBlocks() const { return PackPos.Size(); } + void Clear() + { + Data.Free(); + PackPos.Clear(); + UnpackPos.Clear(); + } +}; + +struct CFrag +{ + UInt64 StartBlock; + UInt32 Size; +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CRecordVector<CItem> _items; + CRecordVector<CNode> _nodes; + CRecordVector<UInt32> _nodesPos; + CRecordVector<UInt32> _blockToNode; + CData _inodesData; + CData _dirs; + CRecordVector<CFrag> _frags; + // CByteBuffer _uids; + // CByteBuffer _gids; + CHeader _h; + + CMyComPtr<IInStream> _stream; + UInt64 _sizeCalculated; + + IArchiveOpenCallback *_openCallback; + + int _nodeIndex; + CRecordVector<bool> _blockCompressed; + CRecordVector<UInt64> _blockOffsets; + + CByteBuffer _cachedBlock; + UInt64 _cachedBlockStartPos; + UInt32 _cachedPackBlockSize; + UInt32 _cachedUnpackBlockSize; + + CLimitedSequentialInStream *_limitedInStreamSpec; + CMyComPtr<ISequentialInStream> _limitedInStream; + + CBufPtrSeqOutStream *_outStreamSpec; + CMyComPtr<ISequentialOutStream> _outStream; + + NCompress::NLzma::CDecoder *_lzmaDecoderSpec; + CMyComPtr<ICompressCoder> _lzmaDecoder; + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr<ICompressCoder> _zlibDecoder; + + CDynBufSeqOutStream *_dynOutStreamSpec; + CMyComPtr<ISequentialOutStream> _dynOutStream; + + void ClearCache() + { + _cachedBlockStartPos = 0; + _cachedPackBlockSize = 0; + _cachedUnpackBlockSize = 0; + } + + HRESULT Decompress(ISequentialOutStream *outStream, UInt32 inSize, UInt32 outSizeMax); + HRESULT ReadMetadataBlock(UInt32 &packSize); + HRESULT ReadData(CData &data, UInt64 start, UInt64 end); + + HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); + HRESULT ScanInodes(UInt64 ptr); + // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); + HRESULT Open2(IInStream *inStream); + AString GetPath(int index) const; + bool GetPackSize(int index, UInt64 &res, bool fillOffsets); + +public: + CHandler(); + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +}; + +CHandler::CHandler() +{ + _limitedInStreamSpec = new CLimitedSequentialInStream; + _limitedInStream = _limitedInStreamSpec; + + _outStreamSpec = new CBufPtrSeqOutStream(); + _outStream = _outStreamSpec; + + _dynOutStreamSpec = new CDynBufSeqOutStream; + _dynOutStream = _dynOutStreamSpec; +} + +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, kpidLinks, VT_UI4}, + // { NULL, kpidOffset, VT_UI4} +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidFileSystem, VT_BSTR}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidBlock, VT_UI4}, + { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidHeadersSize, VT_UI8}, + { NULL, kpidBigEndian, VT_BOOL}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidCharacts, VT_BSTR} + // { NULL, kpidNumBlocks, VT_UI4} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +HRESULT CHandler::Decompress(ISequentialOutStream *outStream, UInt32 inSize, UInt32 outSizeMax) +{ + UInt32 method = _h.Method; + if (_h.SeveralMethods) + { + Byte props[1]; + RINOK(ReadStream_FALSE(_stream, props, 1)); + method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB); + RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); + } + + if (method == kMethod_LZMA) + { + if (!_lzmaDecoder) + { + _lzmaDecoderSpec = new NCompress::NLzma::CDecoder(); + _lzmaDecoder = _lzmaDecoderSpec; + } + const UInt32 kPropsSize = 5 + 8; + Byte props[kPropsSize]; + ReadStream_FALSE(_limitedInStream, props, kPropsSize); + RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5)); + UInt64 outSize = GetUi64(props + 5); + if (outSize > outSizeMax) + return S_FALSE; + RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL)); + if (inSize != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize()) + return S_FALSE; + } + else + { + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } + RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); + if (inSize != _zlibDecoderSpec->GetInputProcessedSize()) + return S_FALSE; + } + return S_OK; +} + +HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) +{ + Byte temp[3]; + unsigned offset = _h.NeedCheckData() ? 3 : 2; + if (offset > packSize) + return S_FALSE; + RINOK(ReadStream_FALSE(_stream, temp, offset)); + // if (NeedCheckData && Major < 4) checkByte must be = 0xFF + bool be = _h.be; + UInt32 size = Get16(temp); + bool isCompressed = ((size & kNotCompressedBit16) == 0); + if (size != kNotCompressedBit16) + size &= ~kNotCompressedBit16; + + if (size > kMetadataBlockSize || offset + size > packSize) + return S_FALSE; + packSize = offset + size; + if (isCompressed) + { + _limitedInStreamSpec->Init(size); + RINOK(Decompress(_dynOutStream, size, kMetadataBlockSize)); + } + else + { + // size != 0 here + Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size); + if (!buf) + return E_OUTOFMEMORY; + RINOK(ReadStream_FALSE(_stream, buf, size)); + _dynOutStreamSpec->UpdateSize(size); + } + return S_OK; +} + +HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) +{ + if (end < start || end - start >= ((UInt64)1 << 32)) + return S_FALSE; + UInt32 size = (UInt32)(end - start); + RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + _dynOutStreamSpec->Init(); + UInt32 packPos = 0; + while (packPos != size) + { + data.PackPos.Add(packPos); + data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); + if (packPos > size) + return S_FALSE; + UInt32 packSize = size - packPos; + RINOK(ReadMetadataBlock(packSize)); + if (_dynOutStreamSpec->GetSize() >= ((UInt64)1 << 32)) + return S_FALSE; + packPos += packSize; + } + data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize()); + _dynOutStreamSpec->CopyToBuffer(data.Data); + return S_OK; +} + +struct CTempItem +{ + UInt32 StartBlock; + // UInt32 iNodeNumber1; + UInt32 Offset; + // UInt16 iNodeNumber2; + UInt16 Type; +}; + +HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex) +{ + if (level > kNumDirLevelsMax) + return S_FALSE; + + int blockIndex = _inodesData.PackPos.FindInSorted(startBlock); + if (blockIndex < 0) + return S_FALSE; + UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset; + if (unpackPos < offset) + return S_FALSE; + + nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]); + // nodeIndex = _nodesPos.FindInSorted(unpackPos); + if (nodeIndex < 0) + return S_FALSE; + + const CNode &n = _nodes[nodeIndex]; + if (!n.IsDir()) + return S_OK; + blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock); + if (blockIndex < 0) + return S_FALSE; + unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; + if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity()) + return S_FALSE; + + UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos; + const Byte *p = _dirs.Data + unpackPos; + UInt32 fileSize = (UInt32)n.FileSize; + + if (fileSize > rem) + return S_FALSE; + rem = fileSize; + if (_h.Major >= 3) + { + if (rem < 3) + return S_FALSE; + rem -= 3; + } + + CRecordVector<CTempItem> tempItems; + while (rem != 0) + { + bool be = _h.be; + UInt32 count; + CTempItem tempItem; + if (_h.Major <= 2) + { + if (rem < 4) + return S_FALSE; + count = p[0]; + tempItem.StartBlock = Get32(p); + if (be) + tempItem.StartBlock &= 0xFFFFFF; + else + tempItem.StartBlock >>= 8; + p += 4; + rem -= 4; + } + else + { + if (_h.Major == 3) + { + if (rem < 9) + return S_FALSE; + count = p[0]; + p += 1; + rem -= 1; + } + else + { + if (rem < 12) + return S_FALSE; + count = GetUi32(p); + p += 4; + rem -= 4; + } + GET_32 (0, tempItem.StartBlock); + // GET_32 (4, tempItem.iNodeNumber1); + p += 8; + rem -= 8; + } + count++; + + for (UInt32 i = 0; i < count; i++) + { + if (rem == 0) + return S_FALSE; + + UInt32 nameOffset = _h.GetFileNameOffset(); + if (rem < nameOffset) + return S_FALSE; + + if ((UInt32)_items.Size() >= kNumFilesMax) + return S_FALSE; + if (_openCallback) + { + UInt64 numFiles = _items.Size(); + if ((numFiles & 0xFFFF) == 0) + { + RINOK(_openCallback->SetCompleted(&numFiles, NULL)); + } + } + + CItem item; + item.Ptr = (UInt32)(p - _dirs.Data); + + UInt32 size; + if (_h.IsOldVersion()) + { + UInt32 t = Get16(p); + if (be) + { + tempItem.Offset = t >> 3; + tempItem.Type = (UInt16)(t & 0x7); + } + else + { + tempItem.Offset = t & 0x1FFF; + tempItem.Type = (UInt16)(t >> 13); + } + size = (UInt32)p[2]; + /* + if (_h.Major > 2) + tempItem.iNodeNumber2 = Get16(p + 3); + */ + } + else + { + GET_16 (0, tempItem.Offset); + // GET_16 (2, tempItem.iNodeNumber2); + GET_16 (4, tempItem.Type); + GET_16 (6, size); + } + p += nameOffset; + rem -= nameOffset; + size++; + if (rem < size) + return S_FALSE; + p += size; + rem -= size; + item.Parent = parent; + _items.Add(item); + tempItems.Add(tempItem); + } + } + + int startItemIndex = _items.Size() - tempItems.Size(); + for (int i = 0; i < tempItems.Size(); i++) + { + const CTempItem &tempItem = tempItems[i]; + int index = startItemIndex + i; + CItem &item = _items[index]; + RINOK(OpenDir(index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node)); + } + + return S_OK; +} + +/* +HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) +{ + size_t size = num * 4; + ids.SetCapacity(size); + RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(_stream, ids, size); +} +*/ + +HRESULT CHandler::Open2(IInStream *inStream) +{ + { + Byte buf[kHeaderSize3]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3)); + if (!_h.Parse(buf)) + return S_FALSE; + if (!_h.IsSupported()) + return E_NOTIMPL; + + switch (_h.Method) + { + case kMethod_ZLIB: + case kMethod_LZMA: + break; + default: + return E_NOTIMPL; + } + } + + _stream = inStream; + + if (_h.NumFrags != 0) + { + if (_h.NumFrags > kNumFilesMax) + return S_FALSE; + _frags.Reserve(_h.NumFrags); + CByteBuffer data; + unsigned bigFrag = (_h.Major > 2); + + unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); + UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; + size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); + data.SetCapacity(numBlocksBytes); + RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); + bool be = _h.be; + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + _dynOutStreamSpec->Init(); + UInt32 packSize = kMetadataBlockSize + 3; + RINOK(ReadMetadataBlock(packSize)); + UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize(); + if (unpackSize != kMetadataBlockSize) + if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) + return S_FALSE; + const Byte *buf = _dynOutStreamSpec->GetBuffer(); + for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) + { + CFrag frag; + if (bigFrag) + { + frag.StartBlock = Get64(buf + j); + frag.Size = Get32(buf + j + 8); + // some archives contain nonzero in unused (buf + j + 12) + j += 16; + } + else + { + frag.StartBlock = Get32(buf + j); + frag.Size = Get32(buf + j + 4); + j += 8; + } + _frags.Add(frag); + } + } + if ((UInt32)_frags.Size() != _h.NumFrags) + return S_FALSE; + } + + // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL)); + + RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); + RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); + + UInt64 absOffset = _h.RootInode >> 16; + if (absOffset >= ((UInt64)1 << 32)) + return S_FALSE; + { + UInt32 pos = 0; + UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity(); + _nodesPos.Reserve(_h.NumInodes); + _nodes.Reserve(_h.NumInodes); + // we use _blockToNode for binary search seed optimizations + _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1); + int curBlock = 0; + for (UInt32 i = 0; i < _h.NumInodes; i++) + { + CNode n; + const Byte *p = _inodesData.Data + pos; + UInt32 size = totalSize - pos; + + switch(_h.Major) + { + case 1: size = n.Parse1(p, size, _h); break; + case 2: size = n.Parse2(p, size, _h); break; + case 3: size = n.Parse3(p, size, _h); break; + default: size = n.Parse4(p, size, _h); break; + } + if (size == 0) + return S_FALSE; + while (pos >= _inodesData.UnpackPos[curBlock]) + { + _blockToNode.Add(_nodesPos.Size()); + curBlock++; + } + _nodesPos.Add(pos); + _nodes.Add(n); + pos += size; + } + _blockToNode.Add(_nodesPos.Size()); + if (pos != totalSize) + return S_FALSE; + } + int rootNodeIndex; + RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)); + + /* + if (_h.Major < 4) + { + RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)); + RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids)); + } + else + { + UInt32 size = _h.NumIDs * 4; + _uids.SetCapacity(size); + + UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; + UInt32 numBlocksBytes = numBlocks << 3; + CByteBuffer data; + data.SetCapacity(numBlocksBytes); + RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt64 offset = GetUi64(data + i * 8); + UInt32 unpackSize, packSize; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); + if (unpackSize != kMetadataBlockSize) + if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) + return S_FALSE; + } + } + */ + + { + const UInt32 alignSize = 1 << 12; + Byte buf[alignSize]; + RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); + UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); + _sizeCalculated = _h.Size; + if (rem != 0) + { + if (ReadStream_FALSE(_stream, buf, rem) == S_OK) + { + size_t i; + for (i = 0; i < rem && buf[i] == 0; i++); + if (i == rem) + _sizeCalculated = _h.Size + rem; + } + } + } + return S_OK; +} + +AString CHandler::GetPath(int index) const +{ + unsigned len = 0; + int indexMem = index; + bool be = _h.be; + do + { + const CItem &item = _items[index]; + index = item.Parent; + const Byte *p = _dirs.Data + item.Ptr; + unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + } + while (index >= 0); + len--; + + AString path; + char *dest = path.GetBuffer(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + index = item.Parent; + + const Byte *p = _dirs.Data + item.Ptr; + unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + if (index < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + path.ReleaseBuffer(len); + return path; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + Close(); + _limitedInStreamSpec->SetStream(stream); + HRESULT res; + try + { + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + _openCallback = callback; + res = Open2(stream); + } + catch(...) + { + Close(); + throw; + } + if (res != S_OK) + { + Close(); + return res; + } + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _limitedInStreamSpec->ReleaseStream(); + _stream.Release(); + + _items.Clear(); + _nodes.Clear(); + _nodesPos.Clear(); + _blockToNode.Clear(); + _frags.Clear(); + _inodesData.Clear(); + _dirs.Clear(); + + // _uids.Free(); + // _gids.Free();; + + _cachedBlock.Free(); + ClearCache(); + + return S_OK; +} + +bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets) +{ + totalPack = 0; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + UInt32 ptr = _nodesPos[item.Node]; + const Byte *p = _inodesData.Data + ptr; + bool be = _h.be; + + UInt32 type = node.Type; + UInt32 offset; + if (node.IsLink() || node.FileSize == 0) + { + totalPack = node.FileSize; + return true; + } + + UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h); + + if (fillOffsets) + { + _blockOffsets.Clear(); + _blockCompressed.Clear(); + _blockOffsets.Add(totalPack); + } + + if (_h.Major <= 1) + { + offset = 15; + p += offset; + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt32 t = Get16(p + i * 2); + if (fillOffsets) + _blockCompressed.Add((t & kNotCompressedBit16) == 0); + if (t != kNotCompressedBit16) + t &= ~kNotCompressedBit16; + totalPack += t; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + } + else + { + if (_h.Major <= 2) + offset = 24; + else if (type == kType_FILE) + offset = 32; + else if (type == kType_FILE + 7) + offset = (_h.Major <= 3 ? 40 : 56); + else + return false; + + p += offset; + + for (UInt64 i = 0; i < numBlocks; i++) + { + UInt32 t = Get32(p + i * 4); + if (fillOffsets) + _blockCompressed.Add(IS_COMPRESSED_BLOCK(t)); + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t); + if (size > _h.BlockSize) + return false; + totalPack += size; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + + if (node.ThereAreFrags()) + { + if (node.Frag >= (UInt32)_frags.Size()) + return false; + const CFrag &frag = _frags[node.Frag]; + if (node.Offset == 0) + { + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + if (size > _h.BlockSize) + return false; + totalPack += size; + } + } + } + return true; +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidMethod: + { + const char *s; + if (_h.SeveralMethods) + s = "LZMA ZLIB"; + else + { + s = k_Methods[0]; + if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0])) + s = k_Methods[_h.Method]; + } + prop = s; + break; + } + case kpidFileSystem: + { + AString res = "SquashFS"; + if (_h.SeveralMethods) + res += "-LZMA"; + res += ' '; + char s[16]; + ConvertUInt32ToString(_h.Major, s); + res += s; + res += '.'; + ConvertUInt32ToString(_h.Minor, s); + res += s; + prop = res; + break; + } + case kpidBlock: prop = _h.BlockSize; break; + case kpidBigEndian: prop = _h.be; break; + case kpidCTime: + if (_h.CTime != 0) + { + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft); + prop = ft; + } + break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + // case kpidNumBlocks: prop = _h.NumFrags; break; + case kpidPhySize: prop = _sizeCalculated; break; + case kpidHeadersSize: + if (_sizeCalculated >= _h.InodeTable) + prop = _sizeCalculated - _h.InodeTable; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + bool isDir = node.IsDir(); + bool be = _h.be; + + switch(propID) + { + case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; + case kpidIsDir: prop = isDir; break; + // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break; + case kpidSize: if (!isDir) prop = node.GetSize(); break; + case kpidPackSize: + if (!isDir) + { + UInt64 size; + if (GetPackSize(index, size, false)) + prop = size; + } + break; + case kpidMTime: + { + UInt32 offset = 0; + switch(_h.Major) + { + case 1: + if (node.Type == kType_FILE) + offset = 3; + else if (node.Type == kType_DIR) + offset = 7; + break; + case 2: + if (node.Type == kType_FILE) + offset = 4; + else if (node.Type == kType_DIR) + offset = 8; + else if (node.Type == kType_DIR + 7) + offset = 9; + break; + case 3: offset = 4; break; + case 4: offset = 8; break; + } + if (offset != 0) + { + const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; + FILETIME ft; + NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); + prop = ft; + } + break; + } + case kpidPosixAttrib: + { + if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0])) + prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; + break; + } + /* + case kpidUser: + { + UInt32 offset = node.Uid * 4; + if (offset < _uids.GetCapacity()) + prop = (UInt32)Get32(_uids + offset); + break; + } + case kpidGroup: + { + if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) + { + UInt32 offset = node.Uid * 4; + if (offset < _uids.GetCapacity()) + prop = (UInt32)Get32(_uids + offset); + } + else + { + UInt32 offset = node.Gid * 4; + if (offset < _gids.GetCapacity()) + prop = (UInt32)Get32(_gids + offset); + } + break; + } + */ + /* + case kpidLinks: + if (_h.Major >= 3 && node.Type != kType_FILE) + prop = node.NumLinks; + break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CSquashfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +public: + CHandler *Handler; +}; + +HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + const CNode &node = _nodes[_nodeIndex]; + UInt64 blockOffset; + UInt32 packBlockSize; + UInt32 offsetInBlock = 0; + bool compressed; + if (blockIndex < _blockCompressed.Size()) + { + compressed = _blockCompressed[(int)blockIndex]; + blockOffset = _blockOffsets[(int)blockIndex]; + packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset); + blockOffset += node.StartBlock; + } + else + { + if (!node.ThereAreFrags()) + return S_FALSE; + const CFrag &frag = _frags[node.Frag]; + offsetInBlock = node.Offset; + blockOffset = frag.StartBlock; + packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + compressed = IS_COMPRESSED_BLOCK(frag.Size); + } + + if (packBlockSize == 0) + { + // sparse file ??? + memset(dest, 0, blockSize); + return S_OK; + } + + if (blockOffset != _cachedBlockStartPos || + packBlockSize != _cachedPackBlockSize) + { + ClearCache(); + RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); + _limitedInStreamSpec->Init(packBlockSize); + + if (compressed) + { + _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize); + HRESULT res = Decompress(_outStream, packBlockSize, _h.BlockSize); + _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos(); + RINOK(res); + } + else + { + RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize)); + _cachedUnpackBlockSize = packBlockSize; + } + _cachedBlockStartPos = blockOffset; + _cachedPackBlockSize = packBlockSize; + } + if (offsetInBlock + blockSize > _cachedUnpackBlockSize) + return S_FALSE; + memcpy(dest, _cachedBlock + offsetInBlock, blockSize); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + const CNode &node = _nodes[item.Node]; + totalSize += node.GetSize(); + } + extractCallback->SetTotal(totalSize); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + // const Byte *p = _data + item.Offset; + + if (node.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + UInt64 unpackSize = node.GetSize(); + totalSize += unpackSize; + UInt64 packSize; + if (GetPackSize(index, packSize, false)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr<ISequentialInStream> inSeqStream; + CMyComPtr<IInStream> inStream; + HRESULT hres = GetStream(index, &inSeqStream); + if (inSeqStream) + inSeqStream.QueryInterface(IID_IInStream, &inStream); + if (hres == S_FALSE || !inStream) + { + if (hres == E_OUTOFMEMORY) + return hres; + res = NExtract::NOperationResult::kUnSupportedMethod; + } + else + { + RINOK(hres); + if (inStream) + { + HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); + if (hres != S_OK && hres != S_FALSE) + { + RINOK(hres); + } + if (copyCoderSpec->TotalSize == unpackSize && hres == S_OK) + res = NExtract::NOperationResult::kOK; + else + { + res = res; + } + } + } + } + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + + if (node.IsDir()) + return E_FAIL; + + const Byte *p = _inodesData.Data + _nodesPos[item.Node]; + + if (node.FileSize == 0 || node.IsLink()) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + if (node.IsLink()) + streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize); + else + streamSpec->Init(NULL, 0); + *stream = streamTemp.Detach(); + return S_OK; + } + + UInt64 packSize; + if (!GetPackSize(index, packSize, true)) + return S_FALSE; + + _nodeIndex = item.Node; + + size_t cacheSize = _h.BlockSize; + if (_cachedBlock.GetCapacity() != cacheSize) + { + ClearCache(); + _cachedBlock.SetCapacity(cacheSize); + } + + CSquashfsInStream *streamSpec = new CSquashfsInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + streamSpec->Handler = this; + unsigned cacheSizeLog = 22; + if (cacheSizeLog <= _h.BlockSizeLog) + cacheSizeLog = _h.BlockSizeLog + 1; + if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog)) + return E_OUTOFMEMORY; + streamSpec->Init(node.FileSize); + *stream = streamTemp.Detach(); + + return S_OK; + + COM_TRY_END +} + +static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; } + +static CArcInfo g_ArcInfo = + { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + +REGISTER_ARC(Cramfs) + +}} diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index e25463de..4db0cae8 100755 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -10,6 +10,8 @@ #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" #include "../Common/ItemNameUtils.h" @@ -21,7 +23,9 @@ using namespace NWindows; namespace NArchive { namespace NTar { -static STATPROPSTG kProps[] = +static const char *kUnexpectedEnd = "Unexpected end of archive"; + +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -34,8 +38,14 @@ static STATPROPSTG kProps[] = { NULL, kpidLink, VT_BSTR} }; +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidHeadersSize, VT_UI8} +}; + IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { @@ -43,11 +53,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 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; @@ -56,26 +77,29 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); } - _isGood = true; - UInt64 pos = 0; + _phySizeDefined = true; for (;;) { CItemEx item; bool filled; - item.HeaderPosition = pos; - RINOK(ReadItem(stream, filled, item)); + RINOK(ReadItem2(stream, filled, item)); if (!filled) break; _items.Add(item); - RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos)); - if (pos > endPos) - return S_FALSE; - if (pos == endPos) + RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize)); + if (_phySize > endPos) + { + _errorMessage = kUnexpectedEnd; + break; + } + /* + if (_phySize == endPos) { - _isGood = false; + _errorMessage = "There are no trailing zero-filled records"; break; } + */ if (callback != NULL) { if (_items.Size() == 1) @@ -85,7 +109,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) if (_items.Size() % 100 == 0) { UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &pos)); + RINOK(callback->SetCompleted(&numFiles, &_phySize)); } } } @@ -132,7 +156,10 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) STDMETHODIMP CHandler::Close() { + _errorMessage.Empty(); _phySizeDefined = false; + _phySize = 0; + _headersSize = 0; _curIndex = 0; _latestIsRead = false; _items.Clear(); @@ -161,16 +188,24 @@ HRESULT CHandler::SkipTo(UInt32 index) { 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; - // item.HeaderPosition = pos; - RINOK(ReadItem(_seqStream, filled, _latestItem)); + RINOK(ReadItem2(_seqStream, filled, _latestItem)); if (!filled) + { + _phySizeDefined = true; return E_INVALIDARG; + } _latestIsRead = true; } } @@ -203,10 +238,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val switch(propID) { - case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break; - case kpidIsDir: prop = item->IsDir(); break; - case kpidSize: prop = item->Size; break; - case kpidPackSize: prop = item->GetPackSize(); break; + 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) { @@ -216,9 +251,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } 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; + 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; @@ -242,7 +277,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; + totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize(); extractCallback->SetTotal(totalSize); UInt64 totalPackSize; @@ -282,7 +317,8 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, item = &_items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - totalSize += item->Size; + UInt64 unpackSize = item->GetUnpackSize(); + totalSize += unpackSize; totalPackSize += item->GetPackSize(); if (item->IsDir()) { @@ -302,14 +338,21 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStreamSpec->SetStream(realOutStream); realOutStream.Release(); - outStreamSpec->Init(skipMode ? 0 : item->Size, true); + outStreamSpec->Init(skipMode ? 0 : unpackSize, true); - if (!seqMode) + if (item->IsLink()) + { + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length())); + } + else { - RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + if (!seqMode) + { + RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + } + streamSpec->Init(item->GetPackSize()); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); } - streamSpec->Init(item->GetPackSize()); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); if (seqMode) { _latestIsRead = false; @@ -328,6 +371,14 @@ 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 } diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index d2def9a1..b1967061 100755 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -23,18 +23,20 @@ class CHandler: CObjectVector<CItemEx> _items; CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; - bool _isGood; UInt32 _curIndex; bool _latestIsRead; CItemEx _latestItem; UInt64 _phySize; + UInt64 _headersSize; bool _phySizeDefined; + AString _errorMessage; NCompress::CCopyCoder *copyCoderSpec; CMyComPtr<ICompressCoder> copyCoder; + HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); HRESULT SkipTo(UInt32 index); diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index a999f838..ffdf2b13 100755 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt IArchiveUpdateCallback *callback) { COM_TRY_BEGIN - if ((_stream && !_isGood) || _seqStream) + if ((_stream && !_errorMessage.IsEmpty()) || _seqStream) return E_NOTIMPL; CObjectVector<CUpdateItem> updateItems; for (UInt32 i = 0; i < numItems; i++) diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index c9c3c422..5ceaa509 100755 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -63,29 +63,40 @@ static void ReadString(const char *s, int size, AString &result) result = temp; } -static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, size_t &processedSize) +static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error) { - item.LongLinkSize = 0; char buf[NFileHeader::kRecordSize]; char *p = buf; + error.Empty(); filled = false; bool thereAreEmptyRecords = false; for (;;) { - processedSize = NFileHeader::kRecordSize; + size_t processedSize = NFileHeader::kRecordSize; RINOK(ReadStream(stream, buf, &processedSize)); if (processedSize == 0) + { + if (!thereAreEmptyRecords ) + error = "There are no trailing zero-filled records"; return S_OK; + } if (processedSize != NFileHeader::kRecordSize) - return S_FALSE; + { + error = "There is no correct record at the end of archive"; + return S_OK; + } + item.HeaderSize += NFileHeader::kRecordSize; if (!IsRecordLast(buf)) break; thereAreEmptyRecords = true; } if (thereAreEmptyRecords) - return S_FALSE; + { + error = "There are data after end of archive"; + return S_OK; + } ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; @@ -143,59 +154,54 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE return S_OK; } -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item) +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error) { - size_t processedSize; - RINOK(GetNextItemReal(stream, filled, item, processedSize)); - if (!filled) - return S_OK; - // GNUtar extension - if (item.LinkFlag == 'L' || // NEXT file has a long name - item.LinkFlag == 'K') // NEXT file has a long linkname + item.HeaderSize = 0; + bool flagL = false; + bool flagK = false; + AString nameL; + AString nameK; + for (;;) { - if (item.Name.Compare(NFileHeader::kLongLink) != 0) - if (item.Name.Compare(NFileHeader::kLongLink2) != 0) + RINOK(GetNextItemReal(stream, filled, item, error)); + if (!filled) + return S_OK; + if (item.LinkFlag == 'L' || // NEXT file has a long name + item.LinkFlag == 'K') // NEXT file has a long linkname + { + AString *name; + if (item.LinkFlag == 'L') + { if (flagL) return S_FALSE; flagL = true; name = &nameL; } + else + { if (flagK) return S_FALSE; flagK = true; name = &nameK; } + + if (item.Name.Compare(NFileHeader::kLongLink) != 0 && + item.Name.Compare(NFileHeader::kLongLink2) != 0) return S_FALSE; - - AString fullName; - if (item.Size > (1 << 15)) - return S_FALSE; - int packSize = (int)item.GetPackSize(); - char *buffer = fullName.GetBuffer(packSize + 1); - - RINOK(ReadStream_FALSE(stream, buffer, packSize)); - processedSize += packSize; - buffer[item.Size] = '\0'; - fullName.ReleaseBuffer(); - - UInt64 headerPosition = item.HeaderPosition; - if (item.LinkFlag == 'L') + if (item.Size > (1 << 14)) + return S_FALSE; + int packSize = (int)item.GetPackSize(); + char *buf = name->GetBuffer(packSize); + RINOK(ReadStream_FALSE(stream, buf, packSize)); + item.HeaderSize += packSize; + buf[(size_t)item.Size] = '\0'; + name->ReleaseBuffer(); + continue; + } + if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X') { - size_t processedSize2; - RINOK(GetNextItemReal(stream, filled, item, processedSize2)); - item.LongLinkSize = (unsigned)processedSize; + // pax Extended Header } - else + else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir) { - item.LongLinkSize = (unsigned)processedSize - NFileHeader::kRecordSize; - item.Size = 0; + // GNU Extensions to the Archive Format } - item.Name = fullName; - item.HeaderPosition = headerPosition; - } - else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X') - { - // pax Extended Header - return S_OK; - } - else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir) - { - // GNU Extensions to the Archive Format + else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) + return S_FALSE; + if (flagL) item.Name = nameL; + if (flagK) item.LinkName = nameK; return S_OK; } - else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) - return S_FALSE; - return S_OK; } }} diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h index cc6e3f5b..a5491ebe 100755 --- a/CPP/7zip/Archive/Tar/TarIn.h +++ b/CPP/7zip/Archive/Tar/TarIn.h @@ -1,9 +1,8 @@ -// Archive/TarIn.h +// TarIn.h #ifndef __ARCHIVE_TAR_IN_H #define __ARCHIVE_TAR_IN_H -#include "Common/MyCom.h" #include "../../IStream.h" #include "TarItem.h" @@ -11,7 +10,7 @@ namespace NArchive { namespace NTar { -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error); }} diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index afe8997d..859e66dd 100755 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -31,6 +31,9 @@ struct CItem bool DeviceMajorDefined; bool DeviceMinorDefined; + bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); } + UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; } + bool IsDir() const { switch(LinkFlag) @@ -58,10 +61,10 @@ struct CItem struct CItemEx: public CItem { - UInt64 HeaderPosition; - unsigned LongLinkSize; - UInt64 GetDataPosition() const { return HeaderPosition + LongLinkSize + NFileHeader::kRecordSize; } - UInt64 GetFullSize() const { return LongLinkSize + NFileHeader::kRecordSize + Size; } + UInt64 HeaderPos; + unsigned HeaderSize; + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } + UInt64 GetFullSize() const { return HeaderSize + Size; } }; }} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index 0577848f..c1633218 100755 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -111,25 +111,25 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, } else { - const CItemEx &existItemInfo = inputItems[ui.IndexInArchive]; + const CItemEx &existItem = inputItems[ui.IndexInArchive]; UInt64 size; if (ui.NewProps) { RINOK(outArchive.WriteHeader(item)); - RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL)); - size = existItemInfo.Size; + RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); + size = existItem.Size; } else { - RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL)); - size = existItemInfo.GetFullSize(); + RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); + size = existItem.GetFullSize(); } streamSpec->Init(size); RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; - RINOK(outArchive.FillDataResidual(existItemInfo.Size)); + RINOK(outArchive.FillDataResidual(existItem.Size)); complexity += size; } } diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index c7eb9980..50b879e7 100755 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -323,25 +323,13 @@ static void AddTagUInt64(AString &s, const char *name, UInt64 value) AddTag(s, name, temp); } -static void ConvertUInt32ToHex(UInt32 value, char *s) -{ - for (int i = 0; i < 8; i++) - { - int t = value & 0xF; - value >>= 4; - s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - s[8] = '\0'; -} - - static AString TimeToXml(FILETIME &ft) { AString res; char temp[16] = { '0', 'x' }; - ConvertUInt32ToHex(ft.dwHighDateTime, temp + 2); + ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2); AddTag(res, "HIGHPART", temp); - ConvertUInt32ToHex(ft.dwLowDateTime, temp + 2); + ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2); AddTag(res, "LOWPART", temp); return res; } diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 5edfacc5..c210804d 100755 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -240,7 +240,7 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l buf.Free(); buf.SetCapacity(size); - CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2(); + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream(); CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->Init((Byte *)buf, size); diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 56570230..e7d88b6c 100755 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -268,7 +268,7 @@ HRESULT CHandler::Open2(IInStream *stream) inStreamLimSpec->SetStream(stream); inStreamLimSpec->Init(packSize); - CSequentialOutStreamImp2 *outStreamLimSpec = new CSequentialOutStreamImp2; + CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec); outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize); diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index ae75a1a2..4c5fd38d 100755 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -53,18 +53,17 @@ HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIAN EncoderSpec = new NCompress::NLzma::CEncoder; Encoder = EncoderSpec; } - CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp; + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - outStreamSpec->Init(); + outStreamSpec->Init(Header + 4, kLzmaPropsSize); RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps)); RINOK(EncoderSpec->WriteCoderProperties(outStream)); - if (outStreamSpec->GetSize() != kLzmaPropsSize) + if (outStreamSpec->GetPos() != kLzmaPropsSize) return E_FAIL; Header[0] = MY_VER_MAJOR; Header[1] = MY_VER_MINOR; Header[2] = kLzmaPropsSize; Header[3] = 0; - memcpy(Header + 4, outStreamSpec->GetBuffer(), kLzmaPropsSize); return S_OK; } |