Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2015-12-31 03:00:00 +0300
committerKornel Lesiński <kornel@geekhood.net>2016-05-28 02:16:58 +0300
commit9608215ad8deb58355bae27692669fda067c4f43 (patch)
tree1227131a3f19bc36e5da4ba11791154d05cc08af /CPP/7zip/Archive
parent5de23c1deb52b8be4c43ad9f694c64bbddd0c38a (diff)
15.1315.13
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.cpp11
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp16
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.cpp22
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.h5
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp9
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp27
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp7
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.h2
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp26
-rw-r--r--CPP/7zip/Archive/PpmdHandler.cpp19
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp28
-rw-r--r--CPP/7zip/Archive/Zip/ZipHeader.h2
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp3
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.cpp94
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.h78
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 &sect = _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);
}
};