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 | |
parent | 2eb60a059819da595efb8e1de49f04c241f5b981 (diff) |
9.189.18
Diffstat (limited to 'CPP/7zip')
64 files changed, 3465 insertions, 436 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; } diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile index e9e30d6f..02ee7af1 100755 --- a/CPP/7zip/Bundles/Fm/makefile +++ b/CPP/7zip/Bundles/Fm/makefile @@ -160,6 +160,7 @@ AR_OBJS = \ $O\ArjHandler.obj \ $O\Bz2Handler.obj \ $O\CpioHandler.obj \ + $O\CramfsHandler.obj \ $O\DebHandler.obj \ $O\DeflateProps.obj \ $O\DmgHandler.obj \ @@ -178,6 +179,7 @@ AR_OBJS = \ $O\PpmdHandler.obj \ $O\RpmHandler.obj \ $O\SplitHandler.obj \ + $O\SquashfsHandler.obj \ $O\SwfHandler.obj \ $O\VhdHandler.obj \ $O\XarHandler.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index 52edc93f..b13ea42a 100755 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gr /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /FAcs /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gr /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "NO_REGISTRY" /D "EXTERNAL_CODECS" /D "_7ZIP_LARGE_PAGES" /FAs /Yu"StdAfx.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x419 /d "NDEBUG" @@ -164,6 +164,10 @@ SOURCE=..\..\Archive\Icons\split.ico # End Source File # Begin Source File +SOURCE=..\..\Archive\Icons\squashfs.ico +# End Source File +# Begin Source File + SOURCE=..\..\Archive\Icons\tar.ico # End Source File # Begin Source File @@ -2330,6 +2334,10 @@ SOURCE=..\..\Archive\CpioHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\CramfsHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\DebHandler.cpp # End Source File # Begin Source File @@ -2420,6 +2428,10 @@ SOURCE=..\..\Archive\SplitHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\SquashfsHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\SwfHandler.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile index 8199dd79..11c74872 100755 --- a/CPP/7zip/Bundles/Format7zF/makefile +++ b/CPP/7zip/Bundles/Format7zF/makefile @@ -58,6 +58,7 @@ AR_OBJS = \ $O\ArjHandler.obj \ $O\Bz2Handler.obj \ $O\CpioHandler.obj \ + $O\CramfsHandler.obj \ $O\DebHandler.obj \ $O\DeflateProps.obj \ $O\DmgHandler.obj \ @@ -77,6 +78,7 @@ AR_OBJS = \ $O\RpmHandler.obj \ $O\SplitHandler.obj \ $O\SwfHandler.obj \ + $O\SquashfsHandler.obj \ $O\VhdHandler.obj \ $O\XarHandler.obj \ $O\XzHandler.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc index c6edfecc..df492020 100755 --- a/CPP/7zip/Bundles/Format7zF/resource.rc +++ b/CPP/7zip/Bundles/Format7zF/resource.rc @@ -27,10 +27,11 @@ MY_VERSION_INFO_DLL("7z Standalone Plugin", "7za") 21 ICON "../../Archive/Icons/fat.ico" 22 ICON "../../Archive/Icons/ntfs.ico" 23 ICON "../../Archive/Icons/xz.ico" +24 ICON "../../Archive/Icons/squashfs.ico" STRINGTABLE BEGIN - 100 "7z:0 zip:1 bz2:2 bzip2:2 tbz2:2 tbz:2 rar:3 arj:4 z:5 taz:5 lzh:6 lha:6 cab:7 iso:8 001:9 rpm:10 deb:11 cpio:12 tar:13 gz:14 gzip:14 tgz:14 tpz:14 wim:15 swm:15 lzma:16 dmg:17 hfs:18 xar:19 vhd:20 fat:21 ntfs:22 xz:23 txz:23" + 100 "7z:0 zip:1 bz2:2 bzip2:2 tbz2:2 tbz:2 rar:3 arj:4 z:5 taz:5 lzh:6 lha:6 cab:7 iso:8 001:9 rpm:10 deb:11 cpio:12 tar:13 gz:14 gzip:14 tgz:14 tpz:14 wim:15 swm:15 lzma:16 dmg:17 hfs:18 xar:19 vhd:20 fat:21 ntfs:22 xz:23 txz:23 squashfs:24" END diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h index f6900d51..2cbe18e4 100755 --- a/CPP/7zip/Common/LimitedStreams.h +++ b/CPP/7zip/Common/LimitedStreams.h @@ -17,6 +17,7 @@ class CLimitedSequentialInStream: bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } void Init(UInt64 streamSize) { _size = streamSize; diff --git a/CPP/7zip/Common/StreamObjects.cpp b/CPP/7zip/Common/StreamObjects.cpp index 2237b930..3c86c3ae 100755 --- a/CPP/7zip/Common/StreamObjects.cpp +++ b/CPP/7zip/Common/StreamObjects.cpp @@ -2,20 +2,24 @@ #include "StdAfx.h" +#include "../../../C/Alloc.h" + #include "StreamObjects.h" STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != NULL) + if (processedSize) *processedSize = 0; + if (size == 0) + return S_OK; if (_pos > _size) return E_FAIL; size_t rem = _size - (size_t)_pos; - if (size < rem) + if (rem > size) rem = (size_t)size; memcpy(data, _data + (size_t)_pos, rem); _pos += rem; - if (processedSize != NULL) + if (processedSize) *processedSize = (UInt32)rem; return S_OK; } @@ -34,51 +38,184 @@ STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosi return S_OK; } +void CByteDynBuffer::Free() +{ + free(_buf); + _buf = 0; + _capacity = 0; +} + +bool CByteDynBuffer::EnsureCapacity(size_t cap) +{ + if (cap <= _capacity) + return true; + size_t delta; + if (_capacity > 64) + delta = _capacity / 4; + else if (_capacity > 8) + delta = 16; + else + delta = 4; + cap = MyMax(_capacity + delta, cap); + Byte *buf = (Byte *)realloc(_buf, cap); + if (!buf) + return false; + _buf = buf; + _capacity = cap; + return true; +} + +Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) +{ + addSize += _size; + if (addSize < _size) + return NULL; + if (!_buffer.EnsureCapacity(addSize)) + return NULL; + return (Byte *)_buffer + _size; +} -void CWriteBuffer::Write(const void *data, size_t size) +void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const { - size_t newCapacity = _size + size; - _buffer.EnsureCapacity(newCapacity); - memcpy(_buffer + _size, data, size); - _size += size; + dest.SetCapacity(_size); + memcpy(dest, _buffer, _size); } -STDMETHODIMP CSequentialOutStreamImp::Write(const void *data, UInt32 size, UInt32 *processedSize) +STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { - _writeBuffer.Write(data, (size_t)size); - if(processedSize != NULL) + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + Byte *buf = GetBufPtrForWriting(size); + if (!buf) + return E_OUTOFMEMORY; + memcpy(buf, data, size); + UpdateSize(size); + if (processedSize) *processedSize = size; return S_OK; } -STDMETHODIMP CSequentialOutStreamImp2::Write(const void *data, UInt32 size, UInt32 *processedSize) +STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { size_t rem = _size - _pos; - if (size < rem) + if (rem > size) rem = (size_t)size; memcpy(_buffer + _pos, data, rem); _pos += rem; - if (processedSize != NULL) + if (processedSize) *processedSize = (UInt32)rem; - return (rem == size ? S_OK : E_FAIL); + return (rem != 0 || size == 0) ? S_OK : E_FAIL; } -STDMETHODIMP CSequentialInStreamSizeCount::Read(void *data, UInt32 size, UInt32 *processedSize) +STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize; - HRESULT result = _stream->Read(data, size, &realProcessedSize); + HRESULT result = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; - if (processedSize != 0) + if (processedSize) *processedSize = realProcessedSize; return result; } -STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) +static const UInt64 kEmptyTag = (UInt64)(Int64)-1; + +void CCachedInStream::Free() { - UInt32 realProcessedSize; - HRESULT result = _stream->Write(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize != 0) - *processedSize = realProcessedSize; - return result; + MyFree(_tags); + _tags = 0; + MidFree(_data); + _data = 0; +} + +bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) +{ + unsigned sizeLog = blockSizeLog + numBlocksLog; + if (sizeLog >= sizeof(size_t) * 8) + return false; + size_t dataSize = (size_t)1 << sizeLog; + if (_data == 0 || dataSize != _dataSize) + { + MidFree(_data); + _data = (Byte *)MidAlloc(dataSize); + if (_data == 0) + return false; + _dataSize = dataSize; + } + if (_tags == 0 || numBlocksLog != _numBlocksLog) + { + MyFree(_tags); + _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); + if (_tags == 0) + return false; + _numBlocksLog = numBlocksLog; + } + _blockSizeLog = blockSizeLog; + return true; +} + +void CCachedInStream::Init(UInt64 size) +{ + _size = size; + _pos = 0; + size_t numBlocks = (size_t)1 << _numBlocksLog; + for (size_t i = 0; i < numBlocks; i++) + _tags[i] = kEmptyTag; +} + +STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_pos > _size) + return E_FAIL; + + { + UInt64 rem = _size - _pos; + if (size > rem) + size = (UInt32)rem; + } + + while (size != 0) + { + UInt64 cacheTag = _pos >> _blockSizeLog; + size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); + Byte *p = _data + (cacheIndex << _blockSizeLog); + if (_tags[cacheIndex] != cacheTag) + { + UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); + size_t blockSize = (size_t)1 << _blockSizeLog; + if (blockSize > remInBlock) + blockSize = (size_t)remInBlock; + RINOK(ReadBlock(cacheTag, p, blockSize)); + _tags[cacheIndex] = cacheTag; + } + size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1); + UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size); + memcpy(data, p + offset, cur); + if (processedSize) + *processedSize += cur; + data = (void *)((const Byte *)data + cur); + _pos += cur; + size -= cur; + } + + return S_OK; +} + +STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch(seekOrigin) + { + case STREAM_SEEK_SET: _pos = offset; break; + case STREAM_SEEK_CUR: _pos = _pos + offset; break; + case STREAM_SEEK_END: _pos = _size + offset; break; + default: return STG_E_INVALIDFUNCTION; + } + if (newPosition != 0) + *newPosition = _pos; + return S_OK; } diff --git a/CPP/7zip/Common/StreamObjects.h b/CPP/7zip/Common/StreamObjects.h index e94513ee..8cd95c70 100755 --- a/CPP/7zip/Common/StreamObjects.h +++ b/CPP/7zip/Common/StreamObjects.h @@ -3,7 +3,7 @@ #ifndef __STREAM_OBJECTS_H #define __STREAM_OBJECTS_H -#include "../../Common/DynamicBuffer.h" +#include "../../Common/Buffer.h" #include "../../Common/MyCom.h" #include "../IStream.h" @@ -34,39 +34,45 @@ public: void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.GetCapacity(), ref); } MY_UNKNOWN_IMP1(IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; -class CWriteBuffer +class CByteDynBuffer { - CByteDynamicBuffer _buffer; - size_t _size; + size_t _capacity; + Byte *_buf; public: - CWriteBuffer(): _size(0) {} - void Init() { _size = 0; } - void Write(const void *data, size_t size); - size_t GetSize() const { return _size; } - const CByteDynamicBuffer& GetBuffer() const { return _buffer; } + CByteDynBuffer(): _capacity(0), _buf(0) {}; + // there is no copy constructor. So don't copy this object. + ~CByteDynBuffer() { Free(); } + void Free(); + size_t GetCapacity() const { return _capacity; } + operator Byte*() const { return _buf; }; + operator const Byte*() const { return _buf; }; + bool EnsureCapacity(size_t capacity); }; -class CSequentialOutStreamImp: +class CDynBufSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { - CWriteBuffer _writeBuffer; + CByteDynBuffer _buffer; + size_t _size; public: - void Init() { _writeBuffer.Init(); } - size_t GetSize() const { return _writeBuffer.GetSize(); } - const CByteDynamicBuffer& GetBuffer() const { return _writeBuffer.GetBuffer(); } + CDynBufSeqOutStream(): _size(0) {} + void Init() { _size = 0; } + size_t GetSize() const { return _size; } + const Byte *GetBuffer() const { return _buffer; } + void CopyToBuffer(CByteBuffer &dest) const; + Byte *GetBufPtrForWriting(size_t addSize); + void UpdateSize(size_t addSize) { _size += addSize; } MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; -class CSequentialOutStreamImp2: +class CBufPtrSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { @@ -74,54 +80,56 @@ class CSequentialOutStreamImp2: size_t _size; size_t _pos; public: - void Init(Byte *buffer, size_t size) { _buffer = buffer; _pos = 0; _size = size; } - size_t GetPos() const { return _pos; } MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; -class CSequentialInStreamSizeCount: - public ISequentialInStream, +class CSequentialOutStreamSizeCount: + public ISequentialOutStream, public CMyUnknownImp { - CMyComPtr<ISequentialInStream> _stream; + CMyComPtr<ISequentialOutStream> _stream; UInt64 _size; public: - void Init(ISequentialInStream *stream) - { - _stream = stream; - _size = 0; - } + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void Init() { _size = 0; } UInt64 GetSize() const { return _size; } MY_UNKNOWN_IMP - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; -class CSequentialOutStreamSizeCount: - public ISequentialOutStream, +class CCachedInStream: + public IInStream, public CMyUnknownImp { - CMyComPtr<ISequentialOutStream> _stream; + UInt64 *_tags; + Byte *_data; + size_t _dataSize; + unsigned _blockSizeLog; + unsigned _numBlocksLog; UInt64 _size; + UInt64 _pos; +protected: + virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0; public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void Init() { _size = 0; } - UInt64 GetSize() const { return _size; } - - MY_UNKNOWN_IMP + CCachedInStream(): _tags(0), _data(0) {} + virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!! + void Free(); + bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog); + void Init(UInt64 size); - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; #endif diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt index 7876a1da..59a743b9 100755 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -128,6 +128,8 @@ Handler GUIDs: 0C xz 0D ppmd + D2 SquashFS + D3 CramFS D4 APM D5 Mslz D6 Flv diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h index 41e5ddbd..2ca5dbc2 100755 --- a/CPP/7zip/MyVersion.h +++ b/CPP/7zip/MyVersion.h @@ -1,8 +1,8 @@ #define MY_VER_MAJOR 9 -#define MY_VER_MINOR 17 +#define MY_VER_MINOR 18 #define MY_VER_BUILD 0 -#define MY_VERSION "9.17 beta" -#define MY_7ZIP_VERSION "7-Zip 9.17 beta" -#define MY_DATE "2010-10-04" +#define MY_VERSION "9.18 beta" +#define MY_7ZIP_VERSION "7-Zip 9.18 beta" +#define MY_DATE "2010-11-02" #define MY_COPYRIGHT "Copyright (c) 1999-2010 Igor Pavlov" #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE diff --git a/CPP/7zip/PropID.h b/CPP/7zip/PropID.h index d6f3a7c1..8f888526 100755 --- a/CPP/7zip/PropID.h +++ b/CPP/7zip/PropID.h @@ -60,6 +60,7 @@ enum kpidSectorSize, kpidPosixAttrib, kpidLink, + kpidError, kpidTotalSize = 0x1100, kpidFreeSpace, diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index 4db95c87..4a099308 100755 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -609,7 +609,7 @@ STDMETHODIMP CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value) CArc &arc = _archiveLink.Arcs[level]; switch(propID) { - case kpidType: prop = _codecs->Formats[arc.FormatIndex].Name; break; + case kpidType: prop = GetTypeOfArc(arc); break; case kpidPath: prop = arc.Path; break; default: return arc.Archive->GetArchiveProperty(propID, value); } diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h index c5efb411..454964bc 100755 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -206,6 +206,27 @@ public: const CArc &GetArc() { return _archiveLink.Arcs.Back(); } IInArchive *GetArchive() { if ( _archiveLink.Arcs.IsEmpty()) return 0; return GetArc().Archive; } bool CanUpdate() const { return _archiveLink.Arcs.Size() <= 1; } + + UString GetTypeOfArc(const CArc &arc) const { return _codecs->Formats[arc.FormatIndex].Name; } + UString GetErrorMessage() const + { + UString s; + for (int i = _archiveLink.Arcs.Size() - 1; i >= 0; i--) + { + const CArc &arc = _archiveLink.Arcs[i]; + if (arc.ErrorMessage.IsEmpty()) + continue; + if (!s.IsEmpty()) + s += L"--------------------\n"; + s += arc.ErrorMessage; + s += L"\n\n["; + s += GetTypeOfArc(arc); + s += L"] "; + s += arc.Path; + s += L"\n"; + } + return s; + } }; #ifdef NEW_FOLDER_INTERFACE diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index f4c126a4..ca2c8c73 100755 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -228,6 +228,15 @@ HRESULT DecompressArchives( } #endif + for (int v = 0; v < archiveLink.Arcs.Size(); v++) + { + const UString &s = archiveLink.Arcs[v].ErrorMessage; + if (!s.IsEmpty()) + { + RINOK(extractCallback->MessageError(s)); + } + } + CArc &arc = archiveLink.Arcs.Back(); arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); arc.MTime = fi.MTime; diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index 67a58372..8f31708b 100755 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../../C/Types.h" + #include "Common/Wildcard.h" #include "ExtractingFilePath.h" diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index d61c7f17..56a63046 100755 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -111,6 +111,7 @@ HRESULT CArc::OpenStream( IArchiveOpenCallback *callback) { Archive.Release(); + ErrorMessage.Empty(); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { @@ -298,6 +299,13 @@ HRESULT CArc::OpenStream( if (result == S_FALSE) continue; RINOK(result); + + { + NCOM::CPropVariant prop; + archive->GetArchiveProperty(kpidError, &prop); + if (prop.vt != VT_EMPTY) + ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; + } Archive = archive; const CArcInfoEx &format = codecs->Formats[FormatIndex]; diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h index 92103623..4a003ee6 100755 --- a/CPP/7zip/UI/Common/OpenArchive.h +++ b/CPP/7zip/UI/Common/OpenArchive.h @@ -24,6 +24,7 @@ struct CArc int SubfileIndex; FILETIME MTime; bool MTimeDefined; + UString ErrorMessage; CArc(): MTimeDefined(false) {} diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index daa57ef6..dacaca5f 100755 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -45,6 +45,7 @@ static const char g_WinAttrib[17] = "RHS8DAdNTsrCOnE_"; 16 VIRTUAL */ +static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; #define MY_ATTR_CHAR(a, n, c) ((a )& (1 << (n))) ? c : L'-'; UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool full) @@ -92,17 +93,21 @@ UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool ful UString res; UInt32 a = prop.ulVal; wchar_t temp[16]; - temp[0] = MY_ATTR_CHAR(a, 14, L'd'); + + temp[0] = kPosixTypes[(a >> 12) & 0xF]; for (int i = 6; i >= 0; i -= 3) { temp[7 - i] = MY_ATTR_CHAR(a, i + 2, L'r'); temp[8 - i] = MY_ATTR_CHAR(a, i + 1, L'w'); temp[9 - i] = MY_ATTR_CHAR(a, i + 0, L'x'); } + if ((a & 0x800) != 0) temp[3] = ((a & (1 << 6)) ? 's' : 'S'); + if ((a & 0x400) != 0) temp[6] = ((a & (1 << 3)) ? 's' : 'S'); + if ((a & 0x200) != 0) temp[9] = ((a & (1 << 0)) ? 't' : 'T'); temp[10] = 0; res = temp; - a &= ~0x1FF; - a &= ~0xC000; + + a &= ~(UInt32)0xFFFF; if (a != 0) { ConvertUInt32ToHex(a, temp); diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index b06641f2..f747cfda 100755 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -29,7 +29,7 @@ struct CPropIdToName const wchar_t *Name; }; -static CPropIdToName kPropIdToName[] = +static const CPropIdToName kPropIdToName[] = { { kpidPath, L"Path" }, { kpidName, L"Name" }, @@ -82,6 +82,7 @@ static CPropIdToName kPropIdToName[] = { kpidSectorSize, L"Sector Size" }, { kpidPosixAttrib, L"Mode" }, { kpidLink, L"Link" }, + { kpidError, L"Error" }, { kpidTotalSize, L"Total Size" }, { kpidFreeSpace, L"Free Space" }, @@ -505,6 +506,8 @@ HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices, g_StdOut << "--\n"; PrintPropPair(L"Path", arc.Path); PrintPropPair(L"Type", codecs->Formats[arc.FormatIndex].Name); + if (!arc.ErrorMessage.IsEmpty()) + PrintPropPair(L"Error", arc.ErrorMessage); UInt32 numProps; IInArchive *archive = arc.Archive; if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK) diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index 7cb2a396..9bd451f8 100755 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -26,7 +26,6 @@ #ifdef EXTERNAL_CODECS #include "../Common/LoadCodecs.h" #endif -#include "../Common/PropIDUtils.h" #include "BenchCon.h" #include "ExtractCallbackConsole.h" @@ -457,8 +456,8 @@ int Main2( << "Compressed: " << stat.PackSize << endl; if (options.CalcCrc) { - wchar_t s[16]; - ConvertUInt32ToHex(stat.CrcSum, s); + char s[16]; + ConvertUInt32ToHexWithZeros(stat.CrcSum, s); stdStream << "CRC: " << s << endl; } } diff --git a/CPP/7zip/UI/Far/Far.dsp b/CPP/7zip/UI/Far/Far.dsp index 4609c82c..394977bb 100755 --- a/CPP/7zip/UI/Far/Far.dsp +++ b/CPP/7zip/UI/Far/Far.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Program Files\Far2\Plugins\7-Zip\7-ZipFar.dll" /opt:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Program Files\Far\Plugins\7-Zip\7-ZipFar.dll" /opt:NOWIN98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "Far - Win32 Debug" @@ -80,7 +80,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Far2\Plugins\7-Zip\7-ZipFar.dll" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Far\Plugins\7-Zip\7-ZipFar.dll" /pdbtype:sept !ENDIF diff --git a/CPP/7zip/UI/Far/FarPlugin.h b/CPP/7zip/UI/Far/FarPlugin.h index 1408ef21..d9ea6dca 100755 --- a/CPP/7zip/UI/Far/FarPlugin.h +++ b/CPP/7zip/UI/Far/FarPlugin.h @@ -61,7 +61,7 @@ struct PluginPanelItem char **CustomColumnData; int CustomColumnNumber; DWORD_PTR UserData; - DWORD CRC32; + DWORD CRC32; DWORD_PTR Reserved[2]; }; @@ -484,34 +484,34 @@ enum OPERATION_MODES { /* EXTERN_C_BEGIN - void WINAPI _export ClosePluginW(HANDLE hPlugin); - int WINAPI _export CompareW(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned int Mode); - int WINAPI _export ConfigureW(int ItemNumber); - int WINAPI _export DeleteFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - void WINAPI _export ExitFARW(void); - void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export FreeVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - int WINAPI _export GetFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t **DestPath,int OpMode); - int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); - int WINAPI _export GetMinFarVersionW(void); - void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin,struct OpenPluginInfo *Info); - void WINAPI _export GetPluginInfoW(struct PluginInfo *Info); - int WINAPI _export GetVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const wchar_t *Path); - int WINAPI _export MakeDirectoryW(HANDLE hPlugin,const wchar_t **Name,int OpMode); - HANDLE WINAPI _export OpenFilePluginW(const wchar_t *Name,const unsigned char *Data,int DataSize,int OpMode); - HANDLE WINAPI _export OpenPluginW(int OpenFrom,INT_PTR Item); - int WINAPI _export ProcessDialogEventW(int Event,void *Param); - int WINAPI _export ProcessEditorEventW(int Event,void *Param); - int WINAPI _export ProcessEditorInputW(const INPUT_RECORD *Rec); - int WINAPI _export ProcessEventW(HANDLE hPlugin,int Event,void *Param); - int WINAPI _export ProcessHostFileW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - int WINAPI _export ProcessKeyW(HANDLE hPlugin,int Key,unsigned int ControlState); - int WINAPI _export ProcessSynchroEventW(int Event,void *Param); - int WINAPI _export ProcessViewerEventW(int Event,void *Param); - int WINAPI _export PutFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t *SrcPath,int OpMode); - int WINAPI _export SetDirectoryW(HANDLE hPlugin,const wchar_t *Dir,int OpMode); - int WINAPI _export SetFindListW(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo *Info); + void WINAPI _export ClosePluginW(HANDLE hPlugin); + int WINAPI _export CompareW(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned int Mode); + int WINAPI _export ConfigureW(int ItemNumber); + int WINAPI _export DeleteFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + void WINAPI _export ExitFARW(void); + void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export FreeVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + int WINAPI _export GetFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t **DestPath,int OpMode); + int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); + int WINAPI _export GetMinFarVersionW(void); + void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin,struct OpenPluginInfo *Info); + void WINAPI _export GetPluginInfoW(struct PluginInfo *Info); + int WINAPI _export GetVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const wchar_t *Path); + int WINAPI _export MakeDirectoryW(HANDLE hPlugin,const wchar_t **Name,int OpMode); + HANDLE WINAPI _export OpenFilePluginW(const wchar_t *Name,const unsigned char *Data,int DataSize,int OpMode); + HANDLE WINAPI _export OpenPluginW(int OpenFrom,INT_PTR Item); + int WINAPI _export ProcessDialogEventW(int Event,void *Param); + int WINAPI _export ProcessEditorEventW(int Event,void *Param); + int WINAPI _export ProcessEditorInputW(const INPUT_RECORD *Rec); + int WINAPI _export ProcessEventW(HANDLE hPlugin,int Event,void *Param); + int WINAPI _export ProcessHostFileW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + int WINAPI _export ProcessKeyW(HANDLE hPlugin,int Key,unsigned int ControlState); + int WINAPI _export ProcessSynchroEventW(int Event,void *Param); + int WINAPI _export ProcessViewerEventW(int Event,void *Param); + int WINAPI _export PutFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t *SrcPath,int OpMode); + int WINAPI _export SetDirectoryW(HANDLE hPlugin,const wchar_t *Dir,int OpMode); + int WINAPI _export SetFindListW(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo *Info); EXTERN_C_END */ diff --git a/CPP/7zip/UI/Far/Main.cpp b/CPP/7zip/UI/Far/Main.cpp index 7cd7d5ee..5e017b80 100755 --- a/CPP/7zip/UI/Far/Main.cpp +++ b/CPP/7zip/UI/Far/Main.cpp @@ -366,7 +366,8 @@ static HANDLE MyOpenFilePluginW(const wchar_t *name) // ::OutputDebugStringA("before OpenArchive\n"); - archiveHandler = new CAgent; + CAgent *agent = new CAgent; + archiveHandler = agent; CMyComBSTR archiveType; HRESULT result = archiveHandler->Open(NULL, GetUnicodeString(fullName, CP_OEMCP), UString(), &archiveType, openArchiveCallback); @@ -381,6 +382,10 @@ static HANDLE MyOpenFilePluginW(const wchar_t *name) return INVALID_HANDLE_VALUE; } + UString errorMessage = agent->GetErrorMessage(); + if (!errorMessage.IsEmpty()) + PrintErrorMessage("7-Zip", UnicodeStringToMultiByte(errorMessage, CP_OEMCP)); + // ::OutputDebugStringA("after OpenArchive\n"); CPlugin *plugin = new CPlugin( diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp index 97627517..a19b037c 100755 --- a/CPP/7zip/UI/Far/Plugin.cpp +++ b/CPP/7zip/UI/Far/Plugin.cpp @@ -326,7 +326,8 @@ static CPROPIDToName kPROPIDToName[] = { kpidSectorSize, NMessageID::kSectorSize }, { kpidPosixAttrib, NMessageID::kPosixAttrib }, { kpidLink, NMessageID::kLink }, - + { kpidError, NMessageID::kError }, + { kpidTotalSize, NMessageID::kTotalSize }, { kpidFreeSpace, NMessageID::kFreeSpace }, { kpidClusterSize, NMessageID::kClusterSize }, @@ -628,17 +629,20 @@ void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info) if (getProps->GetArcNumProps(level, &numProps) == S_OK) { InsertSeparator(m_InfoLines, numItems); - for (Int32 i = -2; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) + for (Int32 i = -3; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) { CMyComBSTR name; PROPID propID; VARTYPE vt; - if (i == -2) - propID = kpidPath; - else if (i == -1) - propID = kpidType; - else if (getProps->GetArcPropInfo(level, i, &name, &propID, &vt) != S_OK) - continue; + switch (i) + { + case -3: propID = kpidPath; break; + case -2: propID = kpidType; break; + case -1: propID = kpidError; break; + default: + if (getProps->GetArcPropInfo(level, i, &name, &propID, &vt) != S_OK) + continue; + } NCOM::CPropVariant prop; if (getProps->GetArcProp(level, propID, &prop) != S_OK) continue; diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index 29c99bfd..6b8fdba2 100755 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -9,6 +9,7 @@ #include "Windows/FileDir.h" #include "Windows/FileFind.h" #include "Windows/Process.h" +#include "Windows/PropVariant.h" #include "Windows/Thread.h" #include "../Common/ExtractingFilePath.h" @@ -113,6 +114,46 @@ HRESULT CPanel::OpenItemAsArchive(IInStream *inStream, _flatMode = _flatModeForArc; + CMyComPtr<IGetFolderArcProps> getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (getFolderArcProps) + { + CMyComPtr<IFolderArcProps> arcProps; + getFolderArcProps->GetFolderArcProps(&arcProps); + if (arcProps) + { + UString s; + UInt32 numLevels; + if (arcProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + for (UInt32 level2 = 0; level2 < numLevels; level2++) + { + UInt32 level = numLevels - 1 - level2; + PROPID propIDs[] = { kpidError, kpidPath, kpidType } ; + UString values[3]; + for (Int32 i = 0; i < 3; i++) + { + CMyComBSTR name; + NCOM::CPropVariant prop; + if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK) + continue; + if (prop.vt != VT_EMPTY) + values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; + } + if (!values[0].IsEmpty()) + { + if (!s.IsEmpty()) + s += L"--------------------\n"; + s += values[0]; s += L"\n\n["; + s += values[2]; s += L"] "; + s += values[1]; s += L"\n"; + } + } + if (!s.IsEmpty()) + MessageBox(s); + } + } + return S_OK; } diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp index c60751b5..549b28da 100755 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -188,17 +188,20 @@ void CPanel::Properties() if (getProps->GetArcNumProps(level, &numProps) == S_OK) { message += kSeparator; - for (Int32 i = -2; i < (Int32)numProps; i++) + for (Int32 i = -3; i < (Int32)numProps; i++) { CMyComBSTR name; PROPID propID; VARTYPE vt; - if (i == -2) - propID = kpidPath; - else if (i == -1) - propID = kpidType; - else if (getProps->GetArcPropInfo(level, i, &name, &propID, &vt) != S_OK) - continue; + switch (i) + { + case -3: propID = kpidPath; break; + case -2: propID = kpidType; break; + case -1: propID = kpidError; break; + default: + if (getProps->GetArcPropInfo(level, i, &name, &propID, &vt) != S_OK) + continue; + } NCOM::CPropVariant prop; if (getProps->GetArcProp(level, propID, &prop) != S_OK) continue; diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp index 7eabc9ef..186315b3 100755 --- a/CPP/7zip/UI/FileManager/PanelSort.cpp +++ b/CPP/7zip/UI/FileManager/PanelSort.cpp @@ -61,17 +61,19 @@ int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) // PROPID propID = panel->_properties[panel->_sortIndex].ID; PROPID propID = panel->_sortID; - NCOM::CPropVariant propVariant1, propVariant2; + NCOM::CPropVariant prop1, prop2; // Name must be first property - panel->_folder->GetProperty((UINT32)lParam1, propID, &propVariant1); - panel->_folder->GetProperty((UINT32)lParam2, propID, &propVariant2); - if (propVariant1.vt != propVariant2.vt) - return 0; // It means some BUG - if (propVariant1.vt == VT_BSTR) + panel->_folder->GetProperty((UINT32)lParam1, propID, &prop1); + panel->_folder->GetProperty((UINT32)lParam2, propID, &prop2); + if (prop1.vt != prop2.vt) { - return _wcsicmp(propVariant1.bstrVal, propVariant2.bstrVal); + return MyCompare(prop1.vt, prop2.vt); } - return propVariant1.Compare(propVariant2); + if (prop1.vt == VT_BSTR) + { + return _wcsicmp(prop1.bstrVal, prop2.bstrVal); + } + return prop1.Compare(prop2); // return 0; } diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.cpp b/CPP/7zip/UI/FileManager/ProgramLocation.cpp index 04c2c98c..ce2d178e 100755 --- a/CPP/7zip/UI/FileManager/ProgramLocation.cpp +++ b/CPP/7zip/UI/FileManager/ProgramLocation.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../../C/Types.h" + #include "ProgramLocation.h" #include "Windows/DLL.h" @@ -20,4 +22,3 @@ bool GetProgramFolderPath(UString &folder) folder = folder.Left(pos + 1); return true; } - diff --git a/CPP/7zip/UI/FileManager/PropertyName.cpp b/CPP/7zip/UI/FileManager/PropertyName.cpp index 79b09300..098bc47d 100755 --- a/CPP/7zip/UI/FileManager/PropertyName.cpp +++ b/CPP/7zip/UI/FileManager/PropertyName.cpp @@ -75,6 +75,7 @@ static CPropertyIDNamePair kPropertyIDNamePairs[] = { kpidSectorSize, IDS_PROP_SECTOR_SIZE, 0x02000234 }, { kpidPosixAttrib, IDS_PROP_POSIX_ATTRIB, 0x02000235 }, { kpidLink, IDS_PROP_LINK, 0x02000236 }, + { kpidError, IDS_PROP_ERROR, 0x02000605 }, { kpidTotalSize, IDS_PROP_TOTAL_SIZE, 0x03031100 }, { kpidFreeSpace, IDS_PROP_FREE_SPACE, 0x03031101 }, diff --git a/CPP/7zip/UI/FileManager/PropertyName.rc b/CPP/7zip/UI/FileManager/PropertyName.rc index 576b52cb..bdd6c8ed 100755 --- a/CPP/7zip/UI/FileManager/PropertyName.rc +++ b/CPP/7zip/UI/FileManager/PropertyName.rc @@ -56,4 +56,5 @@ BEGIN IDS_PROP_SECTOR_SIZE "Sector Size" IDS_PROP_POSIX_ATTRIB "Mode" IDS_PROP_LINK "Link" + IDS_PROP_ERROR "Error" END diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h index 00458a24..9cc9f7c5 100755 --- a/CPP/7zip/UI/FileManager/PropertyNameRes.h +++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h @@ -50,3 +50,4 @@ #define IDS_PROP_SECTOR_SIZE 52 #define IDS_PROP_POSIX_ATTRIB 53 #define IDS_PROP_LINK 54 +#define IDS_PROP_ERROR 55 diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index ea9d9c2c..da2b7924 100755 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -1038,7 +1038,13 @@ void CCompressDialog::SetDictionary() if (i == 20 && j > 0) continue; UInt32 dictionary = (1 << i) + (j << (i - 1)); - if (dictionary > (1 << 30)) + if (dictionary > + #ifdef _WIN64 + (1 << 30) + #else + (1 << 29) + #endif + ) continue; AddDictionarySize(dictionary); UInt64 decomprSize; |