diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-12-31 03:00:00 +0300 |
---|---|---|
committer | Kornel Lesiński <kornel@geekhood.net> | 2016-05-28 02:16:58 +0300 |
commit | 9608215ad8deb58355bae27692669fda067c4f43 (patch) | |
tree | 1227131a3f19bc36e5da4ba11791154d05cc08af /CPP/7zip/Archive | |
parent | 5de23c1deb52b8be4c43ad9f694c64bbddd0c38a (diff) |
15.1315.13
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r-- | CPP/7zip/Archive/7z/7zUpdate.cpp | 11 | ||||
-rw-r--r-- | CPP/7zip/Archive/Cab/CabHandler.cpp | 16 | ||||
-rw-r--r-- | CPP/7zip/Archive/Cab/CabIn.cpp | 22 | ||||
-rw-r--r-- | CPP/7zip/Archive/Cab/CabIn.h | 5 | ||||
-rw-r--r-- | CPP/7zip/Archive/ComHandler.cpp | 9 | ||||
-rw-r--r-- | CPP/7zip/Archive/ExtHandler.cpp | 27 | ||||
-rw-r--r-- | CPP/7zip/Archive/FatHandler.cpp | 7 | ||||
-rw-r--r-- | CPP/7zip/Archive/Iso/IsoIn.h | 2 | ||||
-rw-r--r-- | CPP/7zip/Archive/PeHandler.cpp | 26 | ||||
-rw-r--r-- | CPP/7zip/Archive/PpmdHandler.cpp | 19 | ||||
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipHandler.cpp | 28 | ||||
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipHeader.h | 2 | ||||
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipIn.cpp | 3 | ||||
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipItem.cpp | 94 | ||||
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipItem.h | 78 |
15 files changed, 250 insertions, 99 deletions
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index c2478a29..7e9478fc 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -567,14 +567,17 @@ static const char *g_Exts = " iso bin nrg mdf img pdi tar cpio xpi" " vfd vhd vud vmc vsv" " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" - " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" + " inl inc idl acf asa" + " h hpp hxx c cpp cxx m mm go swift" + " rc java cs rs pas bas vb cls ctl frm dlg def" " f77 f f90 f95" - " asm sql manifest dep" + " asm s" + " sql manifest dep" " mak clw csproj vcproj sln dsp dsw" " class" - " bat cmd" + " bat cmd bash sh" " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" - " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs" + " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" " abw afp cwk lwp wpd wps wpt wrf wri" diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 711bfdf7..e31de4fe 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -781,6 +781,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe realProcessed += size; if (processedSize) *processedSize = realProcessed; + m_PosInFolder += size; return S_OK; // return E_FAIL; } @@ -843,7 +844,7 @@ HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex) return S_OK; } - const unsigned kBufSize = (1 << 10); + const unsigned kBufSize = (1 << 12); Byte buf[kBufSize]; for (unsigned i = 0; i < kBufSize; i++) buf[i] = 0; @@ -937,8 +938,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CRecordVector<bool> extractStatuses; - for (i = 0; i < numItems;) + for (i = 0;;) { + lps->OutSize = totalUnPacked; + lps->InSize = totalPacked; + RINOK(lps->SetCur()); + + if (i >= numItems) + break; + unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; @@ -1003,10 +1011,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, curUnpack = item.GetEndOffset(); } - lps->OutSize = totalUnPacked; - lps->InSize = totalPacked; - RINOK(lps->SetCur()); - CFolderOutStream *cabFolderOutStream = new CFolderOutStream; CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index a72e05f7..ca0052bf 100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -67,6 +67,7 @@ void CInArchive::ReadOtherArc(COtherArc &oa) ReadName(oa.DiskName); } + struct CSignatureFinder { Byte *Buf; @@ -100,6 +101,7 @@ struct CSignatureFinder HRESULT Find(); }; + HRESULT CSignatureFinder::Find() { for (;;) @@ -156,6 +158,7 @@ HRESULT CSignatureFinder::Find() } } + bool CInArcInfo::Parse(const Byte *p) { if (Get32(p + 0x0C) != 0 || @@ -177,6 +180,7 @@ bool CInArcInfo::Parse(const Byte *p) return true; } + HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) { IsArc = false; @@ -286,7 +290,9 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) if (ai.IsThereNext()) ReadOtherArc(ai.NextArc); UInt32 i; + db.Folders.ClearAndReserve(ai.NumFolders); + for (i = 0; i < ai.NumFolders; i++) { Read(p, 8); @@ -311,6 +317,7 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) } db.Items.ClearAndReserve(ai.NumFiles); + for (i = 0; i < ai.NumFiles; i++) { Read(p, 16); @@ -324,6 +331,7 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) item.Attributes = Get16(p + 14); ReadName(item.Name); + if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) { HeaderError = true; @@ -336,6 +344,7 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) return S_OK; } + HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) { try @@ -370,6 +379,7 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) return MyCompare(p1->ItemIndex, p2->ItemIndex); } + bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) { const CMvItem *p1 = &Items[i1]; @@ -384,12 +394,15 @@ bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) && item1.Name == item2.Name; } + void CMvDatabaseEx::FillSortAndShrink() { Items.Clear(); StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); + int offset = 0; + FOR_VECTOR (v, Volumes) { const CDatabaseEx &db = Volumes[v]; @@ -422,11 +435,12 @@ void CMvDatabaseEx::FillSortAndShrink() FOR_VECTOR (i, Items) { int folderIndex = GetFolderIndex(&Items[i]); - if (folderIndex >= (int)FolderStartFileIndex.Size()) + while (folderIndex >= (int)FolderStartFileIndex.Size()) FolderStartFileIndex.Add(i); } } + bool CMvDatabaseEx::Check() { for (unsigned v = 1; v < Volumes.Size(); v++) @@ -444,9 +458,11 @@ bool CMvDatabaseEx::Check() return false; } } + UInt32 beginPos = 0; UInt64 endPos = 0; int prevFolder = -2; + FOR_VECTOR (i, Items) { const CMvItem &mvItem = Items[i]; @@ -456,15 +472,19 @@ bool CMvDatabaseEx::Check() const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) continue; + int folderIndex = GetFolderIndex(&mvItem); + if (folderIndex != prevFolder) prevFolder = folderIndex; else if (item.Offset < endPos && (item.Offset != beginPos || item.GetEndOffset() != endPos)) return false; + beginPos = item.Offset; endPos = item.GetEndOffset(); } + return true; } diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index baeeb7b2..a1fc6bdc 100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -25,6 +25,7 @@ struct COtherArc } }; + struct CArchInfo { Byte VersionMinor; // cabinet file format version, minor @@ -65,6 +66,7 @@ struct CArchInfo } }; + struct CInArcInfo: public CArchInfo { UInt32 Size; // size of this cabinet file in bytes @@ -105,17 +107,20 @@ struct CDatabase } }; + struct CDatabaseEx: public CDatabase { CMyComPtr<IInStream> Stream; }; + struct CMvItem { unsigned VolumeIndex; unsigned ItemIndex; }; + class CMvDatabaseEx { bool AreItemsEqual(unsigned i1, unsigned i2); diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index 3a4834cd..e39dbab5 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -571,6 +571,7 @@ HRESULT CDatabase::Open(IInStream *inStream) RINOK(AddNode(-1, root.SonDid)); unsigned numCabs = 0; + FOR_VECTOR (i, Refs) { const CItem &item = Items[Refs[i].Did]; @@ -578,16 +579,20 @@ HRESULT CDatabase::Open(IInStream *inStream) continue; bool isMsiName; UString msiName = ConvertName(item.Name, isMsiName); - if (isMsiName) + if (isMsiName && !msiName.IsEmpty()) { + bool isThereExt = (msiName.Find(L'.') >= 0); + bool isMsiSpec = (msiName[0] == k_Msi_SpecChar); if (msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab") - || msiName.Len() >= 3 && msiName[0] != k_Msi_SpecChar && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")) + || !isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe") + || !isMsiSpec && !isThereExt) { numCabs++; MainSubfile = i; } } } + if (numCabs > 1) MainSubfile = -1; diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index a9d0facb..606aeed1 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -1118,7 +1118,7 @@ HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, siz { if (block == 0 || block >= _h.NumBlocks) return S_FALSE; - if (((size + (1 << _h.BlockBits) + 1) >> _h.BlockBits) > _h.NumBlocks - block) + if (((size + ((size_t)1 << _h.BlockBits) - 1) >> _h.BlockBits) > _h.NumBlocks - block) return S_FALSE; RINOK(inStream->Seek((UInt64)block << _h.BlockBits, STREAM_SEEK_SET, NULL)); _totalRead += size; @@ -1167,6 +1167,9 @@ HRESULT CHandler::Open2(IInStream *inStream) RINOK(_openCallback->SetTotal(NULL, &_phySize)); } + UInt64 fileSize = 0; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); + CRecordVector<CGroupDescriptor> groups; { @@ -1213,6 +1216,21 @@ HRESULT CHandler::Open2(IInStream *inStream) if (_h.NumInodes < _h.NumFreeInodes) return S_FALSE; + + UInt32 numNodes = _h.InodesPerGroup; + if (numNodes > _h.NumInodes) + numNodes = _h.NumInodes; + size_t nodesDataSize = (size_t)numNodes * _h.InodeSize; + + if (nodesDataSize / _h.InodeSize != numNodes) + return S_FALSE; + + // that code to reduce false detecting cases + if (nodesDataSize > fileSize) + { + if (numNodes > (1 << 24)) + return S_FALSE; + } UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1; // numReserveInodes = _h.NumInodes + 1; @@ -1222,13 +1240,6 @@ HRESULT CHandler::Open2(IInStream *inStream) _refs.Reserve(numReserveInodes); } - UInt32 numNodes = _h.InodesPerGroup; - if (numNodes > _h.NumInodes) - numNodes = _h.NumInodes; - size_t nodesDataSize = numNodes * _h.InodeSize; - if (nodesDataSize / _h.InodeSize != numNodes) - return S_FALSE; - CByteBuffer nodesData; nodesData.Alloc(nodesDataSize); diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index e8340f1d..9c37c062 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -160,10 +160,13 @@ bool CHeader::Parse(const Byte *p) if (NumFats < 1 || NumFats > 4) return false; + // we also support images that contain 0 in offset field. + bool isOkOffset = (codeOffset == 0 || (p[0] == 0xEB && p[1] == 0)); + UInt16 numRootDirEntries = Get16(p + 17); if (numRootDirEntries == 0) { - if (codeOffset < 90) + if (codeOffset < 90 && !isOkOffset) return false; NumFatBits = 32; NumRootDirSectors = 0; @@ -171,7 +174,7 @@ bool CHeader::Parse(const Byte *p) else { // Some FAT12s don't contain VolFields - if (codeOffset < 62 - 24) + if (codeOffset < 62 - 24 && !isOkOffset) return false; NumFatBits = 0; UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 5c1a4bcf..4000fc92 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -170,7 +170,7 @@ struct CBootInitialEntry // Partition Table found in the boot image. UInt16 SectorCount; // This is the number of virtual/emulated sectors the system // will store at Load Segment during the initial boot procedure. - UInt32 LoadRBA; // This is the start address of the virtual disk. CD’s use + UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use // Relative/Logical block addressing. Byte VendorSpec[20]; diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 9cbc7c3c..28562007 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -347,18 +347,24 @@ struct CSection CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {} + // const UInt32 GetSize() const { return PSize; } + const UInt32 GetSize() const { return MyMin(PSize, VSize); } + void UpdateTotalSize(UInt32 &totalSize) const { UInt32 t = Pa + PSize; if (totalSize < t) totalSize = t; } + void Parse(const Byte *p); int Compare(const CSection &s) const { RINOZ(MyCompare(Pa, s.Pa)); - return MyCompare(PSize, s.PSize); + UInt32 size1 = GetSize(); + UInt32 size2 = s.GetSize(); + return MyCompare(size1, size2); } }; @@ -1039,7 +1045,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val switch (propID) { case kpidPath: prop = MultiByteToUnicodeString(item.Name); break; - case kpidSize: prop = (UInt64)MyMin(item.PSize, item.VSize); break; + case kpidSize: prop = (UInt64)item.GetSize(); break; case kpidPackSize: prop = (UInt64)item.PSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidOffset: prop = item.Pa; break; @@ -1883,14 +1889,17 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector } f.CloseBlock(2); } + f.CloseBlock(0); return true; } + HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback) { const CSection § = _sections[sectionIndex]; - size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!! + const size_t fileSize = sect.GetSize(); + if (fileSize > kFileSizeMax) return S_FALSE; { @@ -2031,8 +2040,8 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi { UInt32 mask = (1 << numBits) - 1; size_t end = ((maxOffset + mask) & ~mask); - // 9.29: we use only PSize. PSize can be larger than VSize - if (/* end < sect.VSize && */ end <= sect.PSize) + + if (/* end < sect.VSize && */ end <= sect.GetSize()) { CSection sect2; sect2.Flags = 0; @@ -2050,7 +2059,8 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi // 9.29: we use sect.PSize instead of sect.VSize to support some CAB-SFX // the code for .rsrc_2 is commented. - sect2.PSize = sect.PSize - (UInt32)maxOffset; + sect2.PSize = sect.GetSize() - (UInt32)maxOffset; + if (sect2.PSize != 0) { sect2.VSize = sect2.PSize; @@ -2463,7 +2473,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else if (mixItem.ResourceIndex >= 0) size = _items[mixItem.ResourceIndex].GetSize(); else - size = _sections[mixItem.SectionIndex].PSize; + size = _sections[mixItem.SectionIndex].GetSize(); totalSize += size; } extractCallback->SetTotal(totalSize); @@ -2539,7 +2549,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } else { - currentItemSize = sect.PSize; + currentItemSize = sect.GetSize(); if (!testMode && !outStream) continue; diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 86927f8f..528c5ceb 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -1,5 +1,5 @@ -/* PpmdHandler.c -- PPMd format handler -2010-03-10 : Igor Pavlov : Public domain +/* PpmdHandler.cpp -- PPMd format handler +2015-11-30 : Igor Pavlov : Public domain This code is based on: PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ @@ -349,6 +349,7 @@ struct CPpmdCpp } }; + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -386,13 +387,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CPpmdCpp ppmd(_item.Ver); if (!ppmd.Alloc(_item.MemInMB)) return E_OUTOFMEMORY; + Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod; + if (_item.IsSupported()) { opRes = NExtract::NOperationResult::kDataError; + ppmd.Init(_item.Order, _item.Restor); inBuf.Init(); UInt64 outSize = 0; + if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK) for (;;) { @@ -431,6 +436,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { RINOK(WriteStream(realOutStream, outBuf.Buf, i)); } + + if (inBuf.Extra) + { + opRes = NExtract::NOperationResult::kUnexpectedEnd; + break; + } + if (sym < 0) { if (sym == -1 && ppmd.IsFinishedOK()) @@ -438,12 +450,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, break; } } + RINOK(inBuf.Res); } + realOutStream.Release(); return extractCallback->SetOperationResult(opRes); } + static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 }; REGISTER_ARC_I( diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index a65c9e32..092dcbc9 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -4,6 +4,7 @@ #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/TimeUtils.h" @@ -241,12 +242,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; const CItemEx &item = m_Items[index]; + const CExtraBlock &extra = item.GetMainExtra(); + switch (propID) { case kpidPath: { UString res; - item.GetUnicodeString(item.Name, res, _forceCodePage, _specifiedCodePage); + item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); NItemName::ConvertToOSName2(res); prop = res; break; @@ -261,9 +264,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val FILETIME ft; UInt32 unixTime; UInt32 type; - if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) + if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) type = NFileTimeType::kWindows; - else if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) + else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) type = NFileTimeType::kUnix; else type = NFileTimeType::kDOS; @@ -274,7 +277,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidCTime: { FILETIME ft; - if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft)) + if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft)) prop = ft; break; } @@ -282,7 +285,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidATime: { FILETIME ft; - if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft)) + if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft)) prop = ft; break; } @@ -291,10 +294,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { FILETIME utc; bool defined = true; - if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) { UInt32 unixTime = 0; - if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) NTime::UnixTimeToFileTime(unixTime, utc); else { @@ -328,7 +331,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.Comment.Size() != 0) { UString res; - item.GetUnicodeString(BytesToString(item.Comment), res, _forceCodePage, _specifiedCodePage); + item.GetUnicodeString(res, BytesToString(item.Comment), true, _forceCodePage, _specifiedCodePage); prop = res; } break; @@ -347,7 +350,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { m += kMethod_AES; CWzAesExtra aesField; - if (item.CentralExtra.GetWzAes(aesField)) + if (extra.GetWzAes(aesField)) { char s[16]; s[0] = '-'; @@ -360,7 +363,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { CStrongCryptoExtra f; f.AlgId = 0; - if (item.CentralExtra.GetStrongCrypto(f)) + if (extra.GetStrongCrypto(f)) { const char *s = FindNameForId(k_StrongCryptoPairs, ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId); if (s) @@ -427,6 +430,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = (UInt32)item.ExtractVersion.Version; break; } + prop.Detach(value); return S_OK; COM_TRY_END @@ -617,7 +621,7 @@ HRESULT CZipDecoder::Decode( if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtra aesField; - if (item.CentralExtra.GetWzAes(aesField)) + if (item.GetMainExtra().GetWzAes(aesField)) { wzAesMode = true; needCRC = aesField.NeedCrc(); @@ -653,7 +657,7 @@ HRESULT CZipDecoder::Decode( if (wzAesMode) { CWzAesExtra aesField; - if (!item.CentralExtra.GetWzAes(aesField)) + if (!item.GetMainExtra().GetWzAes(aesField)) return S_OK; id = aesField.Method; if (!_wzAesDecoder) diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index 18ba064a..82e46eb6 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -84,6 +84,8 @@ namespace NFileHeader kNTFS = 0x0A, kStrongEncrypt = 0x17, kUnixTime = 0x5455, + kIzUnicodeComment = 0x6375, + kIzUnicodeName = 0x7075, kWzAES = 0x9901 }; } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 77ca89ea..2ba7e3fa 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -203,7 +203,8 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) const Byte *p2 = p + kLocalHeaderSize; for (size_t i = 0; i < rem; i++) if (p2[i] == 0) - return k_IsArc_Res_NO; + if (i != nameSize - 1) + return k_IsArc_Res_NO; } if (size < extraOffset) diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index 9e1f5e00..e732df7c 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -3,8 +3,10 @@ #include "StdAfx.h" #include "../../../../C/CpuArch.h" +#include "../../../../C/7zCrc.h" #include "../../../Common/MyLinux.h" +#include "../../../Common/StringConvert.h" #include "../Common/ItemNameUtils.h" @@ -80,6 +82,30 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res return false; } + +bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const +{ + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kNTFS) + return sb.ExtractNtfsTime(index, ft); + } + return false; +} + +bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const +{ + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kUnixTime) + return sb.ExtractUnixTime(isCentral, index, res); + } + return false; +} + + bool CLocalItem::IsDir() const { return NItemName::HasTailSlash(Name, GetCodePage()); @@ -89,12 +115,29 @@ bool CItem::IsDir() const { if (NItemName::HasTailSlash(Name, GetCodePage())) return true; + + Byte hostOS = GetHostOS(); + + if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\') + { + // do we need to use CharPrevExA? + // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers? + // so we support that case + switch (hostOS) + { + case NHostOS::kFAT: + case NHostOS::kNTFS: + case NHostOS::kHPFS: + case NHostOS::kVFAT: + return true; + } + } + if (!FromCentral) return false; UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF); - Byte hostOS = GetHostOS(); switch (hostOS) { case NHostOS::kAMIGA: @@ -158,4 +201,53 @@ bool CItem::GetPosixAttrib(UInt32 &attrib) const return false; } +void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const +{ + bool isUtf8 = IsUtf8(); + bool ignore_Utf8_Errors = true; + + if (!isUtf8) + { + { + const unsigned id = isComment ? + NFileHeader::NExtraID::kIzUnicodeComment: + NFileHeader::NExtraID::kIzUnicodeName; + const CObjectVector<CExtraSubBlock> &subBlocks = GetMainExtra().SubBlocks; + + FOR_VECTOR (i, subBlocks) + { + const CExtraSubBlock &sb = subBlocks[i]; + if (sb.ID == id) + { + AString utf; + if (sb.ExtractIzUnicode(CrcCalc(s, s.Len()), utf)) + if (ConvertUTF8ToUnicode(utf, res)) + return; + break; + } + } + } + + if (useSpecifiedCodePage) + isUtf8 = (codePage == CP_UTF8); + #ifdef _WIN32 + else if (GetHostOS() == NFileHeader::NHostOS::kUnix) + { + /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. + We try to get name as UTF-8. + Do we need to do it in POSIX version also? */ + isUtf8 = true; + ignore_Utf8_Errors = false; + } + #endif + } + + + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) + return; + + MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); +} + }} diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index c01ede8d..5f078b60 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -7,7 +7,6 @@ #include "../../../Common/MyBuffer.h" #include "../../../Common/MyString.h" -#include "../../../Common/StringConvert.h" #include "../../../Common/UTFConvert.h" #include "ZipHeader.h" @@ -28,6 +27,23 @@ struct CExtraSubBlock bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; + + bool ExtractIzUnicode(UInt32 crc, AString &name) const + { + unsigned size = (unsigned)Data.Size(); + if (size < 1 + 4) + return false; + const Byte *p = (const Byte *)Data; + if (p[0] > 1) + return false; + if (crc != GetUi32(p + 1)) + return false; + size -= 5; + name.SetFrom_CalcLen((const char *)p + 5, size); + if (size != name.Len()) + return false; + return CheckUTF8(name, false); + } }; const unsigned k_WzAesExtra_Size = 7; @@ -157,27 +173,8 @@ struct CExtraBlock } */ - bool GetNtfsTime(unsigned index, FILETIME &ft) const - { - FOR_VECTOR (i, SubBlocks) - { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kNTFS) - return sb.ExtractNtfsTime(index, ft); - } - return false; - } - - bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const - { - FOR_VECTOR (i, SubBlocks) - { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kUnixTime) - return sb.ExtractUnixTime(isCentral, index, res); - } - return false; - } + bool GetNtfsTime(unsigned index, FILETIME &ft) const; + bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const; void RemoveUnknownSubBlocks() { @@ -274,45 +271,22 @@ public: MadeByVersion.HostOS = 0; } + const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); } + bool IsDir() const; UInt32 GetWinAttrib() const; bool GetPosixAttrib(UInt32 &attrib) const; Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : ExtractVersion.HostOS; } - void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const - { - bool isUtf8 = IsUtf8(); - bool ignore_Utf8_Errors = true; - - #ifdef _WIN32 - if (!isUtf8) - { - if (useSpecifiedCodePage) - isUtf8 = (codePage == CP_UTF8); - else if (GetHostOS() == NFileHeader::NHostOS::kUnix) - { - /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. - We try to get name as UTF-8. - Do we need to do it in POSIX version also? */ - isUtf8 = true; - ignore_Utf8_Errors = false; - } - } - #endif - - if (isUtf8) - if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) - return; - MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); - } + void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const; bool IsThereCrc() const { if (Method == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtra aesField; - if (CentralExtra.GetWzAes(aesField)) + if (GetMainExtra().GetWzAes(aesField)) return aesField.NeedCrc(); } return (Crc != 0 || !IsDir()); @@ -322,8 +296,10 @@ public: { Byte hostOS = GetHostOS(); return (UINT)(( - hostOS == NFileHeader::NHostOS::kFAT || - hostOS == NFileHeader::NHostOS::kNTFS) ? CP_OEMCP : CP_ACP); + hostOS == NFileHeader::NHostOS::kFAT + || hostOS == NFileHeader::NHostOS::kNTFS + || hostOS == NFileHeader::NHostOS::kUnix // do we need it? + ) ? CP_OEMCP : CP_ACP); } }; |