diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2009-08-29 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:01 +0300 |
commit | 2fed8721946901375d21d4a506fe8b114045b397 (patch) | |
tree | 30c688bd7e1c59c31081a4fe4bb5fc3a6497f066 /CPP/7zip/Archive | |
parent | c99f3ebdd639c2adb03d8b44001b10af18516504 (diff) |
9.07 beta
Diffstat (limited to 'CPP/7zip/Archive')
-rwxr-xr-x | CPP/7zip/Archive/DmgHandler.cpp | 201 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipIn.cpp | 86 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipIn.h | 3 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipUpdate.cpp | 2 |
4 files changed, 230 insertions, 62 deletions
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index e63542be..5040d518 100755 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -90,12 +90,14 @@ struct CBlock UInt64 UnpSize; UInt64 PackPos; UInt64 PackSize; + + UInt64 GetNextPackOffset() const { return PackPos + PackSize; } }; struct CFile { CByteBuffer Raw; - // UInt64 StartPos; + UInt64 StartPos; CRecordVector<CBlock> Blocks; UInt64 GetUnpackSize() const { @@ -139,6 +141,7 @@ enum METHOD_ZERO_0 = 0, METHOD_COPY = 1, METHOD_ZERO_2 = 2, + METHOD_ADC = 0x80000004, METHOD_ZLIB = 0x80000005, METHOD_BZIP2 = 0x80000006, METHOD_DUMMY = 0x7FFFFFFE, @@ -196,6 +199,7 @@ UString CMethods::GetString() const case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break; case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break; case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break; + case METHOD_ADC: s = L"adc"; break; case METHOD_ZLIB: s = L"zlib"; break; case METHOD_BZIP2: s = L"bzip2"; break; default: ConvertUInt64ToString(type, buf); s = buf; @@ -329,24 +333,15 @@ HRESULT CHandler::Open2(IInStream *stream) const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex]; - /* some DMG file has BUG: - PackPos for each new file is 0. - So we use additional "StartPos" to fix that BUG */ - - /* - UInt64 startPos = 0; - bool startPosIsDefined = false; - */ - - - for (int i = 0; i < arrItem.SubItems.Size(); i++) + int i; + for (i = 0; i < arrItem.SubItems.Size(); i++) { const CXmlItem &item = arrItem.SubItems[i]; if (!item.IsTagged("dict")) continue; CFile file; - // file.StartPos = startPos; + file.StartPos = 0; int destLen; { @@ -381,18 +376,6 @@ HRESULT CHandler::Open2(IInStream *stream) b.PackPos = Get64(p + 0x18); b.PackSize = Get64(p + 0x20); - /* - if (startPosIsdefined) - { - } - else - { - startPosIsdefined = true; - startPos = b.PackPos; - } - startPos += b.PackSize; - */ - file.Blocks.Add(b); PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", @@ -406,6 +389,28 @@ HRESULT CHandler::Open2(IInStream *stream) _fileIndices.Add(itemIndex); } } + + // PackPos for each new file is 0 in some DMG files. So we use additional StartPos + + bool allStartAreZeros = true; + for (i = 0; i < _files.Size(); i++) + { + const CFile &file = _files[i]; + if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0) + allStartAreZeros = false; + } + UInt64 startPos = 0; + if (allStartAreZeros) + { + for (i = 0; i < _files.Size(); i++) + { + CFile &file = _files[i]; + file.StartPos = startPos; + if (!file.Blocks.IsEmpty()) + startPos += file.Blocks.Back().GetNextPackOffset(); + } + } + return S_OK; } @@ -459,7 +464,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = RAW_PREFIX L"a.xml"; break; case kpidSize: - case kpidPackedSize: + case kpidPackSize: prop = (UInt64)_xml.Length(); break; } @@ -477,7 +482,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } case kpidSize: - case kpidPackedSize: + case kpidPackSize: prop = (UInt64)_files[rawIndex].Raw.GetCapacity(); break; } @@ -573,6 +578,135 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } +class CAdcDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + CInBuffer m_InStream; + + void ReleaseStreams() + { + m_OutWindowStream.ReleaseStream(); + m_InStream.ReleaseStream(); + } + + class CCoderReleaser + { + CAdcDecoder *m_Coder; + public: + bool NeedFlush; + CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + m_Coder->m_OutWindowStream.Flush(); + m_Coder->ReleaseStreams(); + } + }; + friend class CCoderReleaser; + +public: + MY_UNKNOWN_IMP + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); +}; + +STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (!m_OutWindowStream.Create(1 << 18)) + return E_OUTOFMEMORY; + if (!m_InStream.Create(1 << 18)) + return E_OUTOFMEMORY; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InStream.SetStream(inStream); + m_InStream.Init(); + + CCoderReleaser coderReleaser(this); + + const UInt32 kStep = (1 << 20); + UInt64 nextLimit = kStep; + + UInt64 pos = 0; + while (pos < *outSize) + { + if (pos > nextLimit && progress) + { + UInt64 packSize = m_InStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + nextLimit += kStep; + } + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + UInt64 rem = *outSize - pos; + if (b & 0x80) + { + unsigned num = (b & 0x7F) + 1; + if (num > rem) + return S_FALSE; + for (unsigned i = 0; i < num; i++) + { + if (!m_InStream.ReadByte(b)) + return S_FALSE; + m_OutWindowStream.PutByte(b); + } + pos += num; + continue; + } + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + + UInt32 len, distance; + + if (b & 0x40) + { + len = ((UInt32)b & 0x3F) + 4; + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + distance = ((UInt32)b1 << 8) + b2; + } + else + { + b &= 0x3F; + len = ((UInt32)b >> 2) + 3; + distance = (((UInt32)b & 3) << 8) + b1; + } + + if (distance >= pos || len > rem) + return S_FALSE; + m_OutWindowStream.CopyBlock(distance, len); + pos += len; + } + if (*inSize != m_InStream.GetProcessedSize()) + return S_FALSE; + coderReleaser.NeedFlush = false; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress);} + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -617,6 +751,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec; + CAdcDecoder *adcCoderSpec = new CAdcDecoder(); + CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec; + CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); @@ -691,7 +828,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, break; } - RINOK(_inStream->Seek(block.PackPos, STREAM_SEEK_SET, NULL)); + RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); streamSpec->Init(block.PackSize); // UInt64 startSize = outStreamSpec->GetSize(); bool realMethod = true; @@ -716,11 +853,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, res = copyCoder->Code(inStream, outStream, NULL, NULL, progress); break; + case METHOD_ADC: + { + res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress); + break; + } + case METHOD_ZLIB: { res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress); - if (res != S_OK) - break; break; } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 6943c9ed..a311e7f3 100755 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -305,6 +305,27 @@ HRESULT CInArchive::ReadLocalItem(CItemEx &item) return S_OK; } +static bool FlagsAreSame(CItem &i1, CItem &i2) +{ + if (i1.CompressionMethod != i2.CompressionMethod) + return false; + // i1.Time + + if (i1.Flags == i2.Flags) + return true; + UInt32 mask = 0xFFFF; + switch(i1.CompressionMethod) + { + case NFileHeader::NCompressionMethod::kDeflated: + mask = 0x7FF9; + break; + default: + if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded) + mask = 0x7FFF; + } + return ((i1.Flags & mask) == (i2.Flags & mask)); +} + HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) { if (item.FromLocal) @@ -316,25 +337,10 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) if (ReadUInt32() != NSignature::kLocalFileHeader) return S_FALSE; RINOK(ReadLocalItem(localItem)); - if (item.Flags != localItem.Flags) - { - UInt32 mask = 0xFFFF; - switch(item.CompressionMethod) - { - case NFileHeader::NCompressionMethod::kDeflated: - mask = 0x7FF9; - break; - default: - if (item.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded) - mask = 0x7FFF; - } - if ((item.Flags & mask) != (localItem.Flags & mask)) - return S_FALSE; - } + if (!FlagsAreSame(item, localItem)) + return S_FALSE; - if (item.CompressionMethod != localItem.CompressionMethod || - // item.Time != localItem.Time || - (!localItem.HasDescriptor() && + if ((!localItem.HasDescriptor() && ( item.FileCRC != localItem.FileCRC || item.PackSize != localItem.PackSize || @@ -597,9 +603,10 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt return res; } -HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset) +HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems) { items.Clear(); + numCdItems = 0; while (m_Signature == NSignature::kLocalFileHeader) { // FSeek points to next byte after signature @@ -616,10 +623,14 @@ HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt break; } cdOffset = m_Position - 4; - for (int i = 0; i < items.Size(); i++) + int i; + for (i = 0; i < items.Size(); i++, numCdItems++) { if (progress && i % 1000 == 0) RINOK(progress->SetCompleted(items.Size())); + if (m_Signature == NSignature::kEndOfCentralDir) + break; + if (m_Signature != NSignature::kCentralFileHeader) return S_FALSE; @@ -627,7 +638,20 @@ HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt RINOK(ReadCdItem(cdItem)); if (i == 0) - m_ArchiveInfo.Base = items[i].LocalHeaderPosition - cdItem.LocalHeaderPosition; + { + int j; + for (j = 0; j < items.Size(); j++) + { + CItemEx &item = items[j]; + if (item.Name == cdItem.Name) + { + m_ArchiveInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition; + break; + } + } + if (j == items.Size()) + return S_FALSE; + } int index; int left = 0, right = items.Size(); @@ -645,15 +669,13 @@ HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt left = index + 1; } CItemEx &item = items[index]; - item.LocalHeaderPosition = cdItem.LocalHeaderPosition; + // item.LocalHeaderPosition = cdItem.LocalHeaderPosition; item.MadeByVersion = cdItem.MadeByVersion; item.CentralExtra = cdItem.CentralExtra; if ( // item.ExtractVersion != cdItem.ExtractVersion || - item.Flags != cdItem.Flags || - item.CompressionMethod != cdItem.CompressionMethod || - // item.Time != cdItem.Time || + !FlagsAreSame(item, cdItem) || item.FileCRC != cdItem.FileCRC) return S_FALSE; @@ -670,6 +692,8 @@ HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt if (!ReadUInt32(m_Signature)) return S_FALSE; } + for (i = 0; i < items.Size(); i++) + items[i].LocalHeaderPosition -= m_ArchiveInfo.Base; return S_OK; } @@ -753,6 +777,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr res = S_FALSE; */ + int numCdItems = items.Size(); if (res == S_FALSE) { _inBufMode = false; @@ -762,7 +787,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr return S_FALSE; if (!ReadUInt32(m_Signature)) return S_FALSE; - RINOK(ReadLocalsAndCd(items, progress, cdStartOffset)); + RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems)); cdSize = (m_Position - 4) - cdStartOffset; cdStartOffset -= m_ArchiveInfo.Base; } @@ -785,8 +810,8 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr return S_FALSE; if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); - if (ecd64.numEntriesInCDOnThisDisk != items.Size() || - ecd64.numEntriesInCD != items.Size() || + if (ecd64.numEntriesInCDOnThisDisk != numCdItems || + ecd64.numEntriesInCD != numCdItems || ecd64.cdSize != cdSize || (ecd64.cdStartOffset != cdStartOffset && (!items.IsEmpty()))) @@ -822,8 +847,8 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); - if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)items.Size()) || - (UInt16)ecd64.numEntriesInCD != ((UInt16)items.Size()) || + if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) || + (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset && (!items.IsEmpty()))) @@ -831,6 +856,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr _inBufMode = false; _inBuffer.Free(); + IsOkHeaders = (numCdItems == items.Size()); return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index 5f4fe143..f0e88b03 100755 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -99,10 +99,11 @@ class CInArchive HRESULT FindCd(CCdInfo &cdInfo); HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress); HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress); - HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset); + HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems); public: CInArchiveInfo m_ArchiveInfo; bool IsZip64; + bool IsOkHeaders; HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress); HRESULT ReadLocalItemAfterCdItem(CItemEx &item); diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index c76ee488..056a8cd2 100755 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -817,7 +817,7 @@ HRESULT Update( if(inArchive != 0) { inArchive->GetArchiveInfo(archiveInfo); - if (archiveInfo.Base != 0) + if (archiveInfo.Base != 0 || !inArchive->IsOkHeaders) return E_NOTIMPL; } else |