From 2eb60a059819da595efb8e1de49f04c241f5b981 Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Mon, 4 Oct 2010 00:00:00 +0000 Subject: 9.17 --- CPP/7zip/Archive/7z/7zIn.cpp | 2 +- CPP/7zip/Archive/7z/7zProperties.cpp | 37 +++--- CPP/7zip/Archive/ArjHandler.cpp | 2 +- CPP/7zip/Archive/Chm/ChmIn.cpp | 13 +- CPP/7zip/Archive/CpioHandler.cpp | 10 +- CPP/7zip/Archive/LzhHandler.cpp | 5 +- CPP/7zip/Archive/MbrHandler.cpp | 2 +- CPP/7zip/Archive/NtfsHandler.cpp | 42 ++++++- CPP/7zip/Archive/PeHandler.cpp | 4 +- CPP/7zip/Archive/Udf/UdfHandler.h | 1 - CPP/7zip/Archive/Udf/UdfIn.cpp | 2 +- CPP/7zip/Archive/Wim/WimHandler.cpp | 41 ++++-- CPP/7zip/Archive/Wim/WimHandler.h | 2 + CPP/7zip/Archive/Wim/WimIn.cpp | 156 ++++++++++++++++++----- CPP/7zip/Archive/Wim/WimIn.h | 15 ++- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 5 +- CPP/7zip/Archive/Zip/ZipIn.cpp | 12 +- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 227 +++++++++++++++++++++++++++++++++- 18 files changed, 483 insertions(+), 95 deletions(-) (limited to 'CPP/7zip/Archive') diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 79d60fc5..686bb288 100755 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -120,7 +120,7 @@ public: kUnsupportedVersion = 0, kUnsupported, kIncorrect, - kEndOfData, + kEndOfData } Cause; CInArchiveException(CCauseType cause): Cause(cause) {}; }; diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp index 66d90785..fd4af49c 100755 --- a/CPP/7zip/Archive/7z/7zProperties.cpp +++ b/CPP/7zip/Archive/7z/7zProperties.cpp @@ -19,32 +19,33 @@ struct CPropMap CPropMap kPropMap[] = { - { NID::kName, NULL, kpidPath, VT_BSTR}, - { NID::kSize, NULL, kpidSize, VT_UI8}, - { NID::kPackInfo, NULL, kpidPackSize, VT_UI8}, + { NID::kName, { NULL, kpidPath, VT_BSTR } }, + { NID::kSize, { NULL, kpidSize, VT_UI8 } }, + { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } }, #ifdef _MULTI_PACK - { 100, L"Pack0", kpidPackedSize0, VT_UI8}, - { 101, L"Pack1", kpidPackedSize1, VT_UI8}, - { 102, L"Pack2", kpidPackedSize2, VT_UI8}, - { 103, L"Pack3", kpidPackedSize3, VT_UI8}, - { 104, L"Pack4", kpidPackedSize4, VT_UI8}, + { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } }, + { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } }, + { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } }, + { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } }, + { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } }, #endif - { NID::kCTime, NULL, kpidCTime, VT_FILETIME}, - { NID::kMTime, NULL, kpidMTime, VT_FILETIME}, - { NID::kATime, NULL, kpidATime, VT_FILETIME}, - { NID::kWinAttributes, NULL, kpidAttrib, VT_UI4}, - { NID::kStartPos, NULL, kpidPosition, VT_UI4}, + { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } }, + { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, + { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, + { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } }, + { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, - { NID::kCRC, NULL, kpidCRC, VT_UI4}, + { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, - { NID::kAnti, NULL, kpidIsAnti, VT_BOOL}, + { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } } #ifndef _SFX - { 97, NULL, kpidEncrypted, VT_BOOL}, - { 98, NULL, kpidMethod, VT_BSTR}, - { 99, NULL, kpidBlock, VT_UI4} + , + { 97, { NULL,kpidEncrypted, VT_BOOL } }, + { 98, { NULL,kpidMethod, VT_BSTR } }, + { 99, { NULL,kpidBlock, VT_UI4 } } #endif }; diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 0620ae84..4dd686ec 100755 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -264,7 +264,7 @@ struct CInArchiveException { kUnexpectedEndOfArchive = 0, kCRCError, - kIncorrectArchive, + kIncorrectArchive } Cause; CInArchiveException(CCauseType cause): Cause(cause) {}; diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index cc571937..d52b9ba6 100755 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -9,18 +9,15 @@ #include "ChmIn.h" -namespace NArchive{ -namespace NChm{ +namespace NArchive { +namespace NChm { // define CHM_LOW, if you want to see low level items // #define CHM_LOW -static const GUID kChmLzxGuid = - { 0x7FC28940, 0x9D31, 0x11D0, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C }; -static const GUID kHelp2LzxGuid = - { 0x0A9007C6, 0x4076, 0x11D3, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 }; -static const GUID kDesGuid = - { 0x67F6E4A2, 0x60BF, 0x11D3, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF }; +static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } }; +static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } }; +static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } }; static bool AreGuidsEqual(REFGUID g1, REFGUID g2) { diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 2e64d1cd..0f32ef66 100755 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -3,8 +3,8 @@ #include "StdAfx.h" #include "Common/ComTry.h" -#include "Common/StringToInt.h" #include "Common/StringConvert.h" +#include "Common/StringToInt.h" #include "Windows/PropVariant.h" #include "Windows/Time.h" @@ -25,10 +25,10 @@ namespace NFileHeader { namespace NMagic { - extern const char *kMagic1 = "070701"; - extern const char *kMagic2 = "070702"; - extern const char *kMagic3 = "070707"; - extern const char *kEndName = "TRAILER!!!"; + const char *kMagic1 = "070701"; + const char *kMagic2 = "070702"; + const char *kMagic3 = "070707"; + const char *kEndName = "TRAILER!!!"; const Byte kMagicForRecord2[2] = { 0xC7, 0x71 }; } diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index a7fcd676..c568ee4c 100755 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -378,7 +378,7 @@ static const char *GetOS(Byte osId) if (g_OsPairs[i].Id == osId) return g_OsPairs[i].Name; return kUnknownOS; -}; +} static STATPROPSTG kProps[] = { @@ -400,7 +400,7 @@ public: static UInt16 Table[256]; static void InitTable(); - CCRC(): _value(0){}; + CCRC(): _value(0) {} void Init() { _value = 0; } void Update(const void *data, size_t size); UInt16 GetDigest() const { return _value; } @@ -460,7 +460,6 @@ public: void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return _crc.GetDigest(); } void InitCRC() { _crc.Init(); } - }; STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index e2aa067f..b6d79182 100755 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -332,7 +332,7 @@ enum { kpidPrimary = kpidUserDefined, kpidBegChs, - kpidEndChs, + kpidEndChs }; STATPROPSTG kProps[] = diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 8670e164..505486fc 100755 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -156,7 +156,7 @@ struct CMftRef #define ATNAME(n) ATTR_TYPE_ ## n #define DEF_ATTR_TYPE(v, n) ATNAME(n) = v -typedef enum +enum { DEF_ATTR_TYPE(0x00, UNUSED), DEF_ATTR_TYPE(0x10, STANDARD_INFO), @@ -873,7 +873,7 @@ STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo return S_OK; } -HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector attrs, +static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector &attrs, int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector &Extents) { CExtent e; @@ -969,6 +969,7 @@ struct CMftRec void ParseDataNames(); HRESULT GetStream(IInStream *mainStream, int dataIndex, int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; + int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const; UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } @@ -1036,6 +1037,35 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, return S_OK; } +int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const +{ + if (dataIndex < 0) + return 0; + { + const CDataRef &ref = DataRefs[dataIndex]; + int numNonResident = 0; + int i; + for (i = ref.Start; i < ref.Start + ref.Num; i++) + if (DataAttrs[i].NonResident) + numNonResident++; + + const CAttr &attr0 = DataAttrs[ref.Start]; + + if (numNonResident != 0 || ref.Num != 1) + { + if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) + return 0; // error; + CRecordVector extents; + if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK) + return 0; // error; + return extents.Size() - 1; + } + // if (attr0.Data.GetCapacity() != 0) + // return 1; + return 0; + } +} + bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector *attrs) { @@ -1425,7 +1455,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -1435,10 +1465,11 @@ STATPROPSTG kProps[] = { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME}, { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidLinks, VT_UI4} + { NULL, kpidLinks, VT_UI4}, + { NULL, kpidNumBlocks, VT_UI4} }; -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidVolumeName, VT_BSTR}, { NULL, kpidFileSystem, VT_BSTR}, @@ -1582,6 +1613,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidLinks: prop = rec.MyNumNameLinks; break; case kpidSize: if (data) prop = data->GetSize(); break; case kpidPackSize: if (data) prop = data->GetPackSize(); break; + case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break; } prop.Detach(value); return S_OK; diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 5732e1f5..506e944a 100755 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -98,7 +98,7 @@ void CDirLink::Parse(const Byte *p) { Va = Get32(p); Size = Get32(p + 4); -}; +} enum { @@ -991,7 +991,7 @@ bool CBitmapInfoHeader::Parse(const Byte *p, size_t size) Compression = Get32(p + 16); SizeImage = Get32(p + 20); return true; -}; +} static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount) { diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index 63f859af..f513727d 100755 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -35,4 +35,3 @@ public: }} #endif - \ No newline at end of file diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index d2f9e731..60d5fc2a 100755 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -202,7 +202,7 @@ enum EDescriptorType DESC_TYPE_UnallocatedSpace = 263, DESC_TYPE_SpaceBitmap = 264, DESC_TYPE_PartitionIntegrity = 265, - DESC_TYPE_ExtendedFile = 266, + DESC_TYPE_ExtendedFile = 266 }; diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 9bea60dd..eaad1e7c 100755 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -55,6 +55,7 @@ static STATPROPSTG kArcProps[] = { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidComment, VT_BSTR}, + { NULL, kpidUnpackVer, VT_BSTR}, { NULL, kpidIsVolume, VT_BOOL}, { NULL, kpidVolume, VT_UI4}, { NULL, kpidNumVolumes, VT_UI4} @@ -226,6 +227,28 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } break; + case kpidUnpackVer: + { + UInt32 ver1 = _version >> 16; + UInt32 ver2 = (_version >> 8) & 0xFF; + UInt32 ver3 = (_version) & 0xFF; + + char s[16]; + ConvertUInt32ToString(ver1, s); + AString res = s; + res += '.'; + ConvertUInt32ToString(ver2, s); + res += s; + if (ver3 != 0) + { + res += '.'; + ConvertUInt32ToString(ver3, s); + res += s; + } + prop = res; + break; + } + case kpidIsVolume: if (_xmls.Size() > 0) { @@ -303,8 +326,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = _db.GetItemPath(realIndex); else { - char sz[32]; - ConvertUInt64ToString(item.StreamIndex, sz); + char sz[16]; + ConvertUInt32ToString(item.StreamIndex, sz); AString s = sz; while (s.Length() < _nameLenForStreams) s = '0' + s; @@ -342,8 +365,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - char sz[32]; - ConvertUInt64ToString(_xmls[index].VolIndex, sz); + char sz[16]; + ConvertUInt32ToString(_xmls[index].VolIndex, sz); prop = (AString)"[" + (AString)sz + "].xml"; break; } @@ -379,8 +402,8 @@ public: UString GetNextName(UInt32 index) { - wchar_t s[32]; - ConvertUInt64ToString((index), s); + wchar_t s[16]; + ConvertUInt32ToString(index, s); return _before + (UString)s + _after; } }; @@ -426,6 +449,8 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, continue; return res; } + _version = header.Version; + _isOldVersion = header.IsOldVersion(); if (firstVolumeIndex >= 0) if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header)) break; @@ -481,8 +506,8 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, _db.DetectPathMode(); RINOK(_db.Sort(_db.SkipRoot)); - wchar_t sz[32]; - ConvertUInt64ToString(_db.Streams.Size(), sz); + wchar_t sz[16]; + ConvertUInt32ToString(_db.Streams.Size(), sz); _nameLenForStreams = MyStringLen(sz); _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber); diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index d105e548..aa92069a 100755 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -51,6 +51,8 @@ class CHandler: public CMyUnknownImp { CDatabase _db; + UInt32 _version; + bool _isOldVersion; CObjectVector _volumes; CObjectVector _xmls; int _nameLenForStreams; diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index c2e8df69..5edfacc5 100755 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -264,9 +264,8 @@ static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s) if (oldVersion) { s.PartNumber = 1; - s.RefCount = 1; - // UInt32 id = Get32(p + 24); - // UInt32 unknown = Get32(p + 28); + s.Id = Get32(p + 24); + s.RefCount = Get32(p + 28); memcpy(s.Hash, p + 32, kHashSize); } else @@ -384,31 +383,48 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) DirProcessed += 8; return S_OK; } - if ((len & 7) != 0 || len < 0x28 || rem < len) + if ((len & 7) != 0 || rem < len) return S_FALSE; + if (!IsOldVersion) + if (len < 0x28) + return S_FALSE; DirProcessed += (size_t)len; if (DirProcessed > DirSize) return S_FALSE; - if (Get64(p + 8) == 0) + int extraOffset = 0; + if (IsOldVersion) + { + if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0)) + { + extraOffset = 0x10; + } + } + else if (Get64(p + 8) == 0) + extraOffset = 0x24; + if (extraOffset) { if (prevIndex == -1) return S_FALSE; - - UInt32 fileNameLen = Get16(p + 0x24); + UInt32 fileNameLen = Get16(p + extraOffset); if ((fileNameLen & 1) != 0) return S_FALSE; /* Probably different versions of ImageX can use different number of additional ZEROs. So we don't use exact check. */ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - if (((0x26 + fileNameLen2 + 6) & ~7) > len) + if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len) return S_FALSE; UString name; - RINOK(ReadName(p + 0x26, fileNameLen, name)); + RINOK(ReadName(p + extraOffset + 2, fileNameLen, name)); CItem &prevItem = Items[prevIndex]; if (name.IsEmpty() && !prevItem.HasStream()) - memcpy(prevItem.Hash, p + 0x10, kHashSize); + { + if (IsOldVersion) + prevItem.Id = Get32(p + 8); + else + memcpy(prevItem.Hash, p + 0x10, kHashSize); + } else { CItem item; @@ -416,7 +432,13 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) item.CTime = prevItem.CTime; item.ATime = prevItem.ATime; item.MTime = prevItem.MTime; - memcpy(item.Hash, p + 0x10, kHashSize); + if (IsOldVersion) + { + item.Id = Get32(p + 8); + memset(item.Hash, 0, kHashSize); + } + else + memcpy(item.Hash, p + 0x10, kHashSize); item.Attrib = 0; item.Order = Order++; item.Parent = parent; @@ -425,30 +447,41 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) pos += (size_t)len; continue; } - if (len < kDirRecordSize) + + UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + if (len < dirRecordSize) return S_FALSE; CItem item; item.Attrib = Get32(p + 8); // item.SecurityId = Get32(p + 0xC); UInt64 subdirOffset = Get64(p + 0x10); - GetFileTimeFromMem(p + 0x28, &item.CTime); - GetFileTimeFromMem(p + 0x30, &item.ATime); - GetFileTimeFromMem(p + 0x38, &item.MTime); - memcpy(item.Hash, p + 0x40, kHashSize); + UInt32 timeOffset = IsOldVersion ? 0x18: 0x28; + GetFileTimeFromMem(p + timeOffset, &item.CTime); + GetFileTimeFromMem(p + timeOffset + 8, &item.ATime); + GetFileTimeFromMem(p + timeOffset + 16, &item.MTime); + if (IsOldVersion) + { + item.Id = Get32(p + 0x10); + memset(item.Hash, 0, kHashSize); + } + else + { + memcpy(item.Hash, p + 0x40, kHashSize); + } + // UInt32 numStreams = Get16(p + dirRecordSize - 6); + UInt32 shortNameLen = Get16(p + dirRecordSize - 4); + UInt32 fileNameLen = Get16(p + dirRecordSize - 2); - UInt32 shortNameLen = Get16(p + 98); - UInt32 fileNameLen = Get16(p + 100); if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) return S_FALSE; UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - if (((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) + if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) return S_FALSE; - - p += kDirRecordSize; + p += dirRecordSize; RINOK(ReadName(p, fileNameLen, item.Name)); RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName)); @@ -458,9 +491,9 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) /* // there are some extra data for some files. - p -= kDirRecordSize; - p += ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); - if (((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len) + p -= dirRecordSize; + p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); + if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len) p = p; */ @@ -496,6 +529,29 @@ HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) return S_FALSE; const Byte *p = DirData; UInt32 totalLength = Get32(p); + if (IsOldVersion) + { + for (pos = 4;; pos += 8) + { + if (pos + 4 > DirSize) + return S_FALSE; + UInt32 n = Get32(p + pos); + if (n == 0) + break; + if (pos + 8 > DirSize) + return S_FALSE; + totalLength += Get32(p + pos + 4); + if (totalLength > DirSize) + return S_FALSE; + } + pos += totalLength + 4; + pos = (pos + 7) & ~(size_t)7; + if (pos > DirSize) + return S_FALSE; + } + else + { + // UInt32 numEntries = Get32(p + 4); pos += 8; { @@ -511,7 +567,7 @@ HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) sum += len; pos += 8; } - pos += sum; // skip security descriptors + pos += (size_t)sum; // skip security descriptors while ((pos & 7) != 0) pos++; if (pos != totalLength) @@ -524,6 +580,7 @@ HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) else pos = totalLength; } + } DirStartOffset = DirProcessed = pos; RINOK(ParseDirItem(pos, parent)); if (DirProcessed == DirSize) @@ -580,8 +637,6 @@ HRESULT CHeader::Parse(const Byte *p) BootIndex = Get32(p + 0x48); IntegrityResource.Parse(p + offset + 0x4C); } - if (IsOldVersion()) - return S_FALSE; return S_OK; } @@ -612,9 +667,18 @@ static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader & return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE; } +static bool IsEmptySha(const Byte *data) +{ + for (int i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback) { OpenCallback = openCallback; + IsOldVersion = h.IsOldVersion(); RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL)); RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this)); bool needBootMetadata = !h.MetadataResource.IsEmpty(); @@ -631,7 +695,8 @@ HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, Byte hash[kHashSize]; CByteBuffer metadata; RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); - if (memcmp(hash, si.Hash, kHashSize) != 0) + if (memcmp(hash, si.Hash, kHashSize) != 0 && + !(h.IsOldVersion() && IsEmptySha(si.Hash))) return S_FALSE; NumImages++; RINOK(ParseImageDirs(metadata, -(int)(++imageIndex))); @@ -660,12 +725,37 @@ static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, voi return MyCompare(p1->Resource.Offset, p2->Resource.Offset); } +static int CompareIDs(const int *p1, const int *p2, void *param) +{ + const CRecordVector &streams = *(const CRecordVector *)param; + return MyCompare(streams[*p1].Id, streams[*p2].Id); +} + static int CompareHashRefs(const int *p1, const int *p2, void *param) { const CRecordVector &streams = *(const CRecordVector *)param; return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); } +static int FindId(const CRecordVector &streams, + const CIntVector &sortedByHash, UInt32 id) +{ + int left = 0, right = streams.Size(); + while (left != right) + { + int mid = (left + right) / 2; + int streamIndex = sortedByHash[mid]; + UInt32 id2 = streams[streamIndex].Id; + if (id == id2) + return streamIndex; + if (id < id2) + right = mid; + else + left = mid + 1; + } + return -1; +} + static int FindHash(const CRecordVector &streams, const CIntVector &sortedByHash, const Byte *hash) { @@ -712,7 +802,10 @@ HRESULT CDatabase::Sort(bool skipRootDir) { for (int i = 0; i < Streams.Size(); i++) sortedByHash.Add(i); - sortedByHash.Sort(CompareHashRefs, &Streams); + if (IsOldVersion) + sortedByHash.Sort(CompareIDs, &Streams); + else + sortedByHash.Sort(CompareHashRefs, &Streams); } for (int i = 0; i < Items.Size(); i++) @@ -720,7 +813,10 @@ HRESULT CDatabase::Sort(bool skipRootDir) CItem &item = Items[i]; item.StreamIndex = -1; if (item.HasStream()) - item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash); + if (IsOldVersion) + item.StreamIndex = FindId(Streams, sortedByHash, item.Id); + else + item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash); } } diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index 2a40adb3..da3e28a5 100755 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -155,8 +155,8 @@ struct CHeader bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; } bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; } bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); } - bool IsOldVersion() const { return (Version == 0x010A00); } - bool IsNewVersion()const { return (Version > 0x010C00); } + bool IsOldVersion() const { return (Version <= 0x010A00); } + bool IsNewVersion() const { return (Version > 0x010C00); } bool AreFromOnArchive(const CHeader &h) { @@ -172,11 +172,13 @@ struct CStreamInfo CResource Resource; UInt16 PartNumber; UInt32 RefCount; + UInt32 Id; BYTE Hash[kHashSize]; void WriteTo(Byte *p) const; }; +const UInt32 kDirRecordSizeOld = 62; const UInt32 kDirRecordSize = 102; struct CItem @@ -186,25 +188,25 @@ struct CItem UInt32 Attrib; // UInt32 SecurityId; BYTE Hash[kHashSize]; + UInt32 Id; FILETIME CTime; FILETIME ATime; FILETIME MTime; // UInt32 ReparseTag; // UInt64 HardLink; // UInt16 NumStreams; - // UInt16 ShortNameLen; int StreamIndex; int Parent; unsigned Order; bool HasMetadata; - CItem(): HasMetadata(true), StreamIndex(-1) {} + CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {} bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); } bool HasStream() const { for (unsigned i = 0; i < kHashSize; i++) if (Hash[i] != 0) return true; - return false; + return Id != 0; } }; @@ -228,6 +230,8 @@ public: bool SkipRoot; bool ShowImageNumber; + bool IsOldVersion; + UInt64 GetUnpackSize() const { UInt64 res = 0; @@ -253,6 +257,7 @@ public: SkipRoot = true; ShowImageNumber = true; + IsOldVersion = false; } UString GetItemPath(int index) const; diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 3451e3f1..ae75a1a2 100755 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -146,6 +146,7 @@ HRESULT CAddCommon::Compress( opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; if (inCrcStreamSpec != 0) RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(outStream->SetSize(0)); RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); if (_options.PasswordIsDefined) { @@ -218,7 +219,7 @@ HRESULT CAddCommon::Compress( _options.Algo, _options.DicSize, _options.NumFastBytes, - (BSTR)(const wchar_t *)_options.MatchFinder, + const_cast((const wchar_t *)_options.MatchFinder), _options.NumMatchFinderCycles }; PROPID propIDs[] = @@ -373,7 +374,7 @@ HRESULT CAddCommon::Compress( RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); } opRes.Method = method; - return outStream->SetSize(opRes.PackSize); + return S_OK; } }} diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 1048b57d..b36b61be 100755 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -544,7 +544,17 @@ HRESULT CInArchive::FindCd(CCdInfo &cdInfo) UInt64 curPos = endPosition - bufSize + i; UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; if (curPos != cdEnd) - ArcInfo.Base = curPos - cdEnd; + { + /* + if (cdInfo.Offset <= 16 && cdInfo.Size != 0) + { + // here we support some rare ZIP files with Central directory at the start + ArcInfo.Base = 0; + } + else + */ + ArcInfo.Base = curPos - cdEnd; + } return S_OK; } } diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 6dd20f94..d4fdee3d 100755 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../../C/Alloc.h" + #include "Common/AutoPtr.h" #include "Common/Defs.h" #include "Common/StringConvert.h" @@ -16,6 +18,7 @@ #ifndef _7ZIP_ST #include "../../Common/ProgressMt.h" #endif +#include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" @@ -798,6 +801,216 @@ static HRESULT Update2( #endif } +static const size_t kCacheBlockSize = (1 << 20); +static const size_t kCacheSize = (kCacheBlockSize << 2); +static const size_t kCacheMask = (kCacheSize - 1); + +class CCacheOutStream: + public IOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + Byte *_cache; + UInt64 _virtPos; + UInt64 _virtSize; + UInt64 _phyPos; + UInt64 _phySize; // <= _virtSize + UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize + size_t _cachedSize; + + HRESULT MyWrite(size_t size); + HRESULT MyWriteBlock() + { + return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1))); + } + HRESULT FlushCache(); +public: + CCacheOutStream(): _cache(0) {} + ~CCacheOutStream(); + bool Allocate(); + HRESULT Init(IOutStream *stream); + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(UInt64 newSize); +}; + +bool CCacheOutStream::Allocate() +{ + if (!_cache) + _cache = (Byte *)::MidAlloc(kCacheSize); + return (_cache != NULL); +} + +HRESULT CCacheOutStream::Init(IOutStream *stream) +{ + _virtPos = _phyPos = 0; + _stream = stream; + RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)); + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)); + RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos)); + _phyPos = _virtPos; + _phySize = _virtSize; + _cachedPos = 0; + _cachedSize = 0; + return S_OK; +} + +HRESULT CCacheOutStream::MyWrite(size_t size) +{ + while (size != 0 && _cachedSize != 0) + { + if (_phyPos != _cachedPos) + { + RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos)); + } + size_t pos = (size_t)_cachedPos & kCacheMask; + size_t curSize = MyMin(kCacheSize - pos, _cachedSize); + curSize = MyMin(curSize, size); + RINOK(WriteStream(_stream, _cache + pos, curSize)); + _phyPos += curSize; + if (_phySize < _phyPos) + _phySize = _phyPos; + _cachedPos += curSize; + _cachedSize -= curSize; + size -= curSize; + } + return S_OK; +} + +HRESULT CCacheOutStream::FlushCache() +{ + return MyWrite(_cachedSize); +} + +CCacheOutStream::~CCacheOutStream() +{ + FlushCache(); + if (_virtSize != _phySize) + _stream->SetSize(_virtSize); + if (_virtPos != _phyPos) + _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL); + ::MidFree(_cache); +} + +STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + UInt64 zerosStart = _virtPos; + if (_cachedSize != 0) + { + if (_virtPos < _cachedPos) + { + RINOK(FlushCache()); + } + else + { + UInt64 cachedEnd = _cachedPos + _cachedSize; + if (cachedEnd < _virtPos) + { + if (cachedEnd < _phySize) + { + RINOK(FlushCache()); + } + else + zerosStart = cachedEnd; + } + } + } + + if (_cachedSize == 0 && _phySize < _virtPos) + _cachedPos = zerosStart = _phySize; + + if (zerosStart != _virtPos) + { + // write zeros to [cachedEnd ... _virtPos) + + for (;;) + { + UInt64 cachedEnd = _cachedPos + _cachedSize; + size_t endPos = (size_t)cachedEnd & kCacheMask; + size_t curSize = kCacheSize - endPos; + if (curSize > _virtPos - cachedEnd) + curSize = (size_t)(_virtPos - cachedEnd); + if (curSize == 0) + break; + while (curSize > (kCacheSize - _cachedSize)) + { + RINOK(MyWriteBlock()); + } + memset(_cache + endPos, 0, curSize); + _cachedSize += curSize; + } + } + + if (_cachedSize == 0) + _cachedPos = _virtPos; + + size_t pos = (size_t)_virtPos & kCacheMask; + size = (UInt32)MyMin((size_t)size, kCacheSize - pos); + UInt64 cachedEnd = _cachedPos + _cachedSize; + if (_virtPos != cachedEnd) // _virtPos < cachedEnd + size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos)); + else + { + // _virtPos == cachedEnd + if (_cachedSize == kCacheSize) + { + RINOK(MyWriteBlock()); + } + size_t startPos = (size_t)_cachedPos & kCacheMask; + if (startPos > pos) + size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos)); + _cachedSize += size; + } + memcpy(_cache + pos, data, size); + if (processedSize) + *processedSize = size; + _virtPos += size; + if (_virtSize < _virtPos) + _virtSize = _virtPos; + return S_OK; +} + +STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch(seekOrigin) + { + case STREAM_SEEK_SET: _virtPos = offset; break; + case STREAM_SEEK_CUR: _virtPos += offset; break; + case STREAM_SEEK_END: _virtPos = _virtSize + offset; break; + default: return STG_E_INVALIDFUNCTION; + } + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize) +{ + _virtSize = newSize; + if (newSize < _phySize) + { + RINOK(_stream->SetSize(newSize)); + _phySize = newSize; + } + if (newSize <= _cachedPos) + { + _cachedSize = 0; + _cachedPos = newSize; + } + if (newSize < _cachedPos + _cachedSize) + _cachedSize = (size_t)(newSize - _cachedPos); + return S_OK; +} + + HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS const CObjectVector &inputItems, @@ -808,9 +1021,17 @@ HRESULT Update( IArchiveUpdateCallback *updateCallback) { CMyComPtr outStream; - RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); - if (!outStream) - return E_NOTIMPL; + { + CMyComPtr outStreamReal; + seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); + if (!outStreamReal) + return E_NOTIMPL; + CCacheOutStream *cacheStream = new CCacheOutStream(); + outStream = cacheStream; + if (!cacheStream->Allocate()) + return E_OUTOFMEMORY; + RINOK(cacheStream->Init(outStreamReal)); + } if (inArchive) { -- cgit v1.2.3