diff --git a/NanaZip.Core/SevenZip/C/7zVersion.h b/NanaZip.Core/SevenZip/C/7zVersion.h index 55ea82aa9..eb6f1f380 100644 --- a/NanaZip.Core/SevenZip/C/7zVersion.h +++ b/NanaZip.Core/SevenZip/C/7zVersion.h @@ -1,7 +1,7 @@ #define MY_VER_MAJOR 24 -#define MY_VER_MINOR 07 +#define MY_VER_MINOR 8 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "24.07" +#define MY_VERSION_NUMBERS "24.08" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,7 +10,7 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2024-06-19" +#define MY_DATE "2024-08-11" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" diff --git a/NanaZip.Core/SevenZip/C/CpuArch.c b/NanaZip.Core/SevenZip/C/CpuArch.c index bb47869d5..61b9bfab6 100644 --- a/NanaZip.Core/SevenZip/C/CpuArch.c +++ b/NanaZip.Core/SevenZip/C/CpuArch.c @@ -1,5 +1,5 @@ /* CpuArch.c -- CPU specific code -2024-05-18 : Igor Pavlov : Public domain */ +2024-07-04 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -848,7 +848,11 @@ static unsigned long MY_getauxval(int aux) #define MY_HWCAP_CHECK_FUNC(name) \ BoolInt CPU_IsSupported_ ## name(void) { return 0; } +#if defined(__ARM_NEON) + BoolInt CPU_IsSupported_NEON(void) { return True; } +#else MY_HWCAP_CHECK_FUNC(NEON) +#endif #endif // USE_HWCAP diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/ElfHandler.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/ElfHandler.cpp index 19449bdf6..83be744fd 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/ElfHandler.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/ElfHandler.cpp @@ -628,6 +628,7 @@ static const char * const g_Machines[] = static const CUInt32PCharPair g_MachinePairs[] = { { 243, "RISC-V" }, + { 258, "LoongArch" }, { 0x9026, "Alpha" }, // EM_ALPHA_EXP, obsolete, (used by NetBSD/alpha) (written in the absence of an ABI) { 0xbaab, "Xilinx MicroBlaze" } }; @@ -853,10 +854,9 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) else if (_header.Machine == k_Machine_MIPS) { const UInt32 ver = flags >> 28; - s += "v"; + s.Add_Char('v'); s.Add_UInt32(ver); flags &= ((UInt32)1 << 28) - 1; - const UInt32 abi = (flags >> 12) & 7; if (abi) { @@ -864,7 +864,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) s.Add_UInt32(abi); } flags &= ~((UInt32)7 << 12); - s.Add_Space(); s += FlagsToString(g_MIPS_Flags, Z7_ARRAY_SIZE(g_MIPS_Flags), flags); } @@ -885,6 +884,31 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) flags &= ~(UInt32)6; s += FlagsToString(g_RISCV_Flags, Z7_ARRAY_SIZE(g_RISCV_Flags), flags); } +#if 0 +#define k_Machine_LOONGARCH 258 + else if (_header.Machine == k_Machine_LOONGARCH) + { + s += "ABI:"; + s.Add_UInt32((flags >> 6) & 3); + s.Add_Dot(); + s.Add_UInt32((flags >> 3) & 7); + s.Add_Dot(); +#if 1 + s.Add_UInt32(flags & 7); +#else + static const char k_LoongArch_Float_Type[8] = { '0', 's', 'f', 'd', '4' ,'5', '6', '7' }; + s.Add_Char(k_LoongArch_Float_Type[flags & 7]); +#endif + flags &= ~(UInt32)0xff; + if (flags) + { + s.Add_Colon(); + char sz[16]; + ConvertUInt32ToHex(flags, sz); + s += sz; + } + } +#endif else { char sz[16]; diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/GptHandler.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/GptHandler.cpp index 91b3c88c9..dd54542a5 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/GptHandler.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/GptHandler.cpp @@ -111,6 +111,12 @@ static const CPartType kPartTypes[] = { 0x0FC63DAF, NULL, "Linux Data" }, { 0x0657FD6D, NULL, "Linux Swap" }, + { 0x44479540, NULL, "Linux root (x86)" }, + { 0x4F68BCE3, NULL, "Linux root (x86-64)" }, + { 0x69DAD710, NULL, "Linux root (ARM)" }, + { 0xB921B045, NULL, "Linux root (ARM64)" }, + { 0x993D8D3D, NULL, "Linux root (IA-64)" }, + { 0x83BD6B9D, NULL, "FreeBSD Boot" }, { 0x516E7CB4, NULL, "FreeBSD Data" }, diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/PeHandler.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/PeHandler.cpp index 944d5cb2d..b5da4ca13 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/PeHandler.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/PeHandler.cpp @@ -180,9 +180,32 @@ struct CDirLink } }; + +// IMAGE_DIRECTORY_ENTRY_* +static const char * const g_Dir_Names[] = +{ + "EXPORT" + , "IMPORT" + , "RESOURCE" + , "EXCEPTION" + , "SECURITY" + , "BASERELOC" + , "DEBUG" + , "ARCHITECTURE" // "COPYRIGHT" + , "GLOBALPTR" + , "TLS" + , "LOAD_CONFIG" + , "BOUND_IMPORT" + , "IAT" + , "DELAY_IMPORT" + , "COM_DESCRIPTOR" +}; + enum { + kDirLink_EXCEPTION = 3, kDirLink_Certificate = 4, + kDirLink_BASERELOC = 5, kDirLink_Debug = 6 }; @@ -229,7 +252,7 @@ struct COptHeader UInt32 UninitDataSize; // UInt32 AddressOfEntryPoint; - // UInt32 BaseOfCode; + // UInt32 BaseOfCode; // VA(.text) == 0x1000 in most cases // UInt32 BaseOfData32; UInt64 ImageBase; @@ -273,6 +296,7 @@ struct COptHeader } }; +// size is 16-bit bool COptHeader::Parse(const Byte *p, UInt32 size) { if (size < k_OptHeader32_Size_MIN) @@ -334,14 +358,18 @@ bool COptHeader::Parse(const Byte *p, UInt32 size) pos = 92; } - G32(pos, NumDirItems); - if (NumDirItems > (1 << 16)) + UInt32 numDirItems; + G32(pos, numDirItems); + NumDirItems = numDirItems; + if (numDirItems > (1 << 13)) return false; pos += 4; - if (pos + 8 * NumDirItems > size) + if (pos + 8 * numDirItems > size) return false; memset((void *)DirItems, 0, sizeof(DirItems)); - for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++) + if (numDirItems > kNumDirItemsMax) + numDirItems = kNumDirItemsMax; + for (UInt32 i = 0; i < numDirItems; i++) DirItems[i].Parse(p + pos + i * 8); return true; } @@ -352,27 +380,41 @@ struct CSection { AString Name; + UInt32 ExtractSize; UInt32 VSize; UInt32 Va; UInt32 PSize; UInt32 Pa; UInt32 Flags; UInt32 Time; - // UInt16 NumRelocs; + // UInt16 NumRelocs; // is set to zero for executable images bool IsRealSect; bool IsDebug; bool IsAdditionalSection; - CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {} + CSection(): + ExtractSize(0), + IsRealSect(false), + IsDebug(false), + IsAdditionalSection(false) + // , NumRelocs(0) + {} - UInt32 GetSizeExtract() const { return PSize; } - UInt32 GetSizeMin() const { return MyMin(PSize, VSize); } + void Set_Size_for_all(UInt32 size) + { + PSize = VSize = ExtractSize = size; + } + + UInt32 GetSize_Extract() const + { + return ExtractSize; + } void UpdateTotalSize(UInt32 &totalSize) const { - UInt32 t = Pa + PSize; + const UInt32 t = Pa + PSize; if (totalSize < t) - totalSize = t; + totalSize = t; } void Parse(const Byte *p); @@ -380,8 +422,8 @@ struct CSection int Compare(const CSection &s) const { RINOZ(MyCompare(Pa, s.Pa)) - UInt32 size1 = GetSizeExtract(); - UInt32 size2 = s.GetSizeExtract(); + const UInt32 size1 = GetSize_Extract(); + const UInt32 size2 = s.GetSize_Extract(); return MyCompare(size1, size2); } }; @@ -402,6 +444,10 @@ void CSection::Parse(const Byte *p) G32(20, Pa); // G16(32, NumRelocs); G32(36, Flags); + // v24.08: we extract only useful data (without extra padding bytes). + // VSize == 0 is not expected, but we support that case too. + // return (VSize && VSize < PSize) ? VSize : PSize; + ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; } @@ -508,6 +554,7 @@ static const CUInt32PCharPair g_MachinePairs[] = { 0x01D3, "AM33" }, { 0x01F0, "PPC" }, { 0x01F1, "PPC-FP" }, + { 0x01F2, "PPC-BE" }, { 0x0200, "IA-64" }, { 0x0266, "MIPS-16" }, { 0x0284, "Alpha-64" }, @@ -830,11 +877,11 @@ enum kpidStackReserve, kpidStackCommit, kpidHeapReserve, - kpidHeapCommit, - kpidImageBase - // kpidAddressOfEntryPoint, - // kpidBaseOfCode, - // kpidBaseOfData32, + kpidHeapCommit + // , kpidImageBase + // , kpidAddressOfEntryPoint + // , kpidBaseOfCode + // , kpidBaseOfData32 }; static const CStatProp kArcProps[] = @@ -864,14 +911,16 @@ static const CStatProp kArcProps[] = { "Stack Commit", kpidStackCommit, VT_UI8}, { "Heap Reserve", kpidHeapReserve, VT_UI8}, { "Heap Commit", kpidHeapCommit, VT_UI8}, - { "Image Base", kpidImageBase, VT_UI8}, - { NULL, kpidComment, VT_BSTR}, + { NULL, kpidVa, VT_UI8 }, // "Image Base", kpidImageBase, VT_UI8 + { NULL, kpidComment, VT_BSTR} - // { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8}, - // { "Base Of Code", kpidBaseOfCode, VT_UI8}, - // { "Base Of Data", kpidBaseOfData32, VT_UI8}, + // , { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8} + // , { "Base Of Code", kpidBaseOfCode, VT_UI8} + // , { "Base Of Data", kpidBaseOfData32, VT_UI8} }; +// #define kpid_NumRelocs 250 + static const Byte kProps[] = { kpidPath, @@ -880,7 +929,8 @@ static const Byte kProps[] = kpidVirtualSize, kpidCharacts, kpidOffset, - kpidVa, + kpidVa + // , kpid_NumRelocs }; IMP_IInArchive_Props @@ -899,7 +949,42 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) switch (propID) { case kpidPhySize: prop = _totalSize; break; - case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break; + case kpidComment: + { + UString s (_versionFullString); + s.Add_LF(); + s += "Data Directories: "; + s.Add_UInt32(_optHeader.NumDirItems); + s.Add_LF(); + s.Add_Char('{'); + s.Add_LF(); + for (unsigned i = 0; i < _optHeader.NumDirItems + && i < Z7_ARRAY_SIZE(_optHeader.DirItems); i++) + { + const CDirLink &di = _optHeader.DirItems[i]; + if (di.Va == 0 && di.Size == 0) + continue; + s += "index="; + s.Add_UInt32(i); + + if (i < Z7_ARRAY_SIZE(g_Dir_Names)) + { + s += " name="; + s += g_Dir_Names[i]; + } + s += " VA=0x"; + char temp[16]; + ConvertUInt32ToHex(di.Va, temp); + s += temp; + s += " Size="; + s.Add_UInt32(di.Size); + s.Add_LF(); + } + s.Add_Char('}'); + s.Add_LF(); + prop = s; + break; + } case kpidShortComment: if (!_versionShortString.IsEmpty()) prop = _versionShortString; @@ -969,8 +1054,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) case kpidStackCommit: prop = _optHeader.StackCommit; break; case kpidHeapReserve: prop = _optHeader.HeapReserve; break; case kpidHeapCommit: prop = _optHeader.HeapCommit; break; - - case kpidImageBase: prop = _optHeader.ImageBase; break; + case kpidVa: prop = _optHeader.ImageBase; break; // kpidImageBase: // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break; // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break; // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break; @@ -1130,7 +1214,8 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = MultiByteToUnicodeString(s); break; } - case kpidSize: prop = (UInt64)item.PSize; break; + case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; + // case kpid_NumRelocs: prop = (UInt32)item.NumRelocs; break; case kpidPackSize: prop = (UInt64)item.PSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidOffset: prop = item.Pa; break; @@ -1229,7 +1314,7 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) sect.Time = de.Time; sect.Va = de.Va; sect.Pa = de.Pa; - sect.PSize = sect.VSize = de.Size; + sect.Set_Size_for_all(de.Size); } buf += kEntrySize; } @@ -1757,7 +1842,7 @@ static void CopyToUString(const Byte *p, UString &s) { for (;;) { - wchar_t c = (wchar_t)Get16(p); + const wchar_t c = (wchar_t)Get16(p); p += 2; if (c == 0) return; @@ -1765,6 +1850,16 @@ static void CopyToUString(const Byte *p, UString &s) } } +static void CopyToUString_ByLen16(const Byte *p, unsigned numChars16, UString &s) +{ + for (; numChars16; numChars16--) + { + const wchar_t c = (wchar_t)Get16(p); + p += 2; + s += c; + } +} + static bool CompareWStrStrings(const Byte *p, const char *s) { unsigned pos = 0; @@ -1783,7 +1878,7 @@ struct CVersionBlock { UInt32 TotalLen; UInt32 ValueLen; - bool IsTextValue; + unsigned IsTextValue; unsigned StrSize; bool Parse(const Byte *p, UInt32 size); @@ -1802,6 +1897,23 @@ static int Get_Utf16Str_Len_InBytes(const Byte *p, size_t size) } } +static int Get_Utf16Str_Len_InBytes_AllowNonZeroTail(const Byte *p, size_t size) +{ + unsigned pos = 0; + for (;;) + { + if (pos + 1 >= size) + { + if (pos == size) + return (int)pos; + return -1; + } + if (Get16(p + pos) == 0) + return (int)pos; + pos += 2; + } +} + static const unsigned k_ResoureBlockHeader_Size = 6; bool CVersionBlock::Parse(const Byte *p, UInt32 size) @@ -1812,14 +1924,12 @@ bool CVersionBlock::Parse(const Byte *p, UInt32 size) ValueLen = Get16(p + 2); if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size) return false; - switch (Get16(p + 4)) - { - case 0: IsTextValue = false; break; - case 1: IsTextValue = true; break; - default: return false; - } + IsTextValue = Get16(p + 4); + if (IsTextValue > 1) + return false; StrSize = 0; - const int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); + const int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, + TotalLen - k_ResoureBlockHeader_Size); if (t < 0) return false; StrSize = (unsigned)t; @@ -1859,7 +1969,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector // if (size != vb.TotalLen) return false; */ if (size > vb.TotalLen) - size = vb.TotalLen; + size = vb.TotalLen; CMy_VS_FIXEDFILEINFO FixedFileInfo; if (!FixedFileInfo.Parse(p + pos)) return false; @@ -1880,7 +1990,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector return false; if (vb.ValueLen != 0) return false; - UInt32 endPos = pos + vb.TotalLen; + const UInt32 endPos = pos + vb.TotalLen; pos += k_ResoureBlockHeader_Size; f.AddSpaces(2); @@ -1901,7 +2011,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector CVersionBlock vb2; if (!vb2.Parse(p + pos, endPos - pos)) return false; - UInt32 endPos2 = pos + vb2.TotalLen; + const UInt32 endPos2 = pos + vb2.TotalLen; if (vb2.IsTextValue) return false; pos += k_ResoureBlockHeader_Size; @@ -1919,9 +2029,9 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector UInt32 num = (vb2.ValueLen >> 2); for (; num != 0; num--, pos += 4) { - UInt32 dw = Get32(p + pos); - UInt32 lang = LOWORD(dw); - UInt32 codePage = HIWORD(dw); + const UInt32 dw = Get32(p + pos); + const UInt32 lang = LOWORD(dw); + const UInt32 codePage = HIWORD(dw); f.AddString(", "); PrintHex(f, lang); @@ -1936,7 +2046,6 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector if (!CompareWStrStrings(p + pos, "StringFileInfo")) return false; pos += vb.StrSize + 2; - for (;;) { pos += (4 - pos) & 3; @@ -1945,7 +2054,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector CVersionBlock vb2; if (!vb2.Parse(p + pos, endPos - pos)) return false; - UInt32 endPos2 = pos + vb2.TotalLen; + const UInt32 endPos2 = pos + vb2.TotalLen; if (vb2.ValueLen != 0) return false; pos += k_ResoureBlockHeader_Size; @@ -1967,9 +2076,8 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector CVersionBlock vb3; if (!vb3.Parse(p + pos, endPos2 - pos)) return false; - // ValueLen sometimes is a number of characters (not bytes)? - // So we don't use it. - UInt32 endPos3 = pos + vb3.TotalLen; + // ValueLen is a number of 16-bit characters (usually it includes zero tail character). + const UInt32 endPos3 = pos + vb3.TotalLen; pos += k_ResoureBlockHeader_Size; // we don't write string if it's not text @@ -1984,26 +2092,35 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector pos += vb3.StrSize + 2; pos += (4 - pos) & 3; - if (vb3.ValueLen > 0 && pos + 2 <= endPos3) + if (vb3.ValueLen != 0 && pos /* + 2 */ <= endPos3) { f.AddChar(','); f.AddSpaces((34 - (int)vb3.StrSize) / 2); - const int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos); + // vb3.TotalLen for some PE files (not from msvc) doesn't include tail zero at the end of Value string. + // we allow that minor error. + const int sLen = Get_Utf16Str_Len_InBytes_AllowNonZeroTail(p + pos, endPos3 - pos); if (sLen < 0) return false; + /* + if (vb3.ValueLen - 1 != (unsigned)sLen / 2 && + vb3.ValueLen != (unsigned)sLen / 2) + return false; + */ AddParamString(f, p + pos, (unsigned)sLen); - CopyToUString(p + pos, value); - pos += (unsigned)sLen + 2; + CopyToUString_ByLen16(p + pos, (unsigned)sLen / 2, value); + // pos += (unsigned)sLen + 2; } AddToUniqueUStringVector(keys, key, value); } pos = endPos3; f.NewLine(); } + pos = endPos2; f.CloseBlock(4); } } f.CloseBlock(2); + pos = endPos; } f.CloseBlock(0); @@ -2218,7 +2335,7 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi if (sect2.PSize != 0) { - sect2.VSize = sect2.PSize; + sect2.ExtractSize = sect2.VSize = sect2.PSize; sect2.Name = ".rsrc_1"; sect2.Time = 0; sect2.IsAdditionalSection = true; @@ -2337,6 +2454,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) CSection § = _sections.AddNew(); sect.Parse(buffer + pos); sect.IsRealSect = true; + if (sect.Name.IsEqualTo(".reloc")) + { + const CDirLink &dl = _optHeader.DirItems[kDirLink_BASERELOC]; + if (dl.Va == sect.Va && + dl.Size <= sect.PSize) + sect.ExtractSize = dl.Size; + } + else if (sect.Name.IsEqualTo(".pdata")) + { + const CDirLink &dl = _optHeader.DirItems[kDirLink_EXCEPTION]; + if (dl.Va == sect.Va && + dl.Size <= sect.PSize) + sect.ExtractSize = dl.Size; + } /* PE pre-file in .hxs file has errors: PSize of resource is larger than real size. @@ -2390,7 +2521,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) sect.Name = "CERTIFICATE"; sect.Va = 0; sect.Pa = certLink.Va; - sect.PSize = sect.VSize = certLink.Size; + sect.Set_Size_for_all(certLink.Size); sect.UpdateTotalSize(_totalSize); } @@ -2448,7 +2579,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) sect.Name = "COFF_SYMBOLS"; sect.Va = 0; sect.Pa = _header.PointerToSymbolTable; - sect.PSize = sect.VSize = size; + sect.Set_Size_for_all(size); sect.UpdateTotalSize(_totalSize); } @@ -2464,11 +2595,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { CSection &s2 = _sections.AddNew(); s2.Pa = s2.Va = limit; - s2.PSize = s2.VSize = s.Pa - limit; + s2.Set_Size_for_all(s.Pa - limit); s2.IsAdditionalSection = true; - s2.Name = '['; + s2.Name.Add_Char('['); s2.Name.Add_UInt32(num++); - s2.Name += ']'; + s2.Name.Add_Char(']'); limit = s.Pa; } UInt32 next = s.Pa + s.PSize; @@ -2700,29 +2831,26 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, else if (mixItem.ResourceIndex >= 0) size = _items[mixItem.ResourceIndex].GetSize(); else - size = _sections[mixItem.SectionIndex].GetSizeExtract(); + size = _sections[mixItem.SectionIndex].GetSize_Extract(); totalSize += size; } - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - UInt64 currentItemSize; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; + RINOK(extractCallback->SetTotal(totalSize)) - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + totalSize = 0; + UInt64 currentItemSize; + + for (i = 0;; i++, totalSize += currentItemSize) { - lps->InSize = lps->OutSize = currentTotalSize; + lps->InSize = lps->OutSize = totalSize; RINOK(lps->SetCur()) + if (i >= numItems) + break; const Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; @@ -2776,15 +2904,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, } else { - currentItemSize = sect.GetSizeExtract(); + currentItemSize = sect.GetSize_Extract(); if (!testMode && !outStream) continue; RINOK(extractCallback->PrepareOperation(askMode)) RINOK(InStream_SeekSet(_stream, sect.Pa)) - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - isOk = (copyCoderSpec->TotalSize == currentItemSize); + inStream->Init(currentItemSize); + RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) + isOk = (copyCoder->TotalSize == currentItemSize); } outStream.Release(); @@ -2804,7 +2932,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) const CMixItem &mixItem = _mixItems[index]; const CSection § = _sections[mixItem.SectionIndex]; if (mixItem.IsSectionItem()) - return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream); + return CreateLimitedInStream(_stream, sect.Pa, sect.GetSize_Extract(), stream); CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr streamTemp = inStreamSpec; @@ -2964,7 +3092,7 @@ bool CHeader::Parse(const Byte *p) G32(12, BaseOfCode); G64(16, ImageBase); */ - for (int i = 0; i < 2; i++) + for (unsigned i = 0; i < 2; i++) { CDataDir &dd = DataDir[i]; dd.Parse(p + 24 + i * 8); @@ -2997,6 +3125,7 @@ struct CSection { Byte Name[NPe::kNameSize]; + UInt32 ExtractSize; UInt32 VSize; UInt32 Va; UInt32 PSize; @@ -3013,6 +3142,7 @@ struct CSection G32(20, Pa); // G32(p + 32, NumRelocs); G32(36, Flags); + ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; } bool Check() const @@ -3022,11 +3152,16 @@ struct CSection PSize <= ((UInt32)1 << 30); } + UInt32 GetSize_Extract() const + { + return ExtractSize; + } + void UpdateTotalSize(UInt32 &totalSize) { - UInt32 t = Pa + PSize; - if (t > totalSize) - totalSize = t; + const UInt32 t = Pa + PSize; + if (totalSize < t) + totalSize = t; } }; @@ -3050,6 +3185,7 @@ static const Byte kProps[] = { kpidPath, kpidSize, + kpidPackSize, kpidVirtualSize, kpidCharacts, kpidOffset, @@ -3108,7 +3244,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = MultiByteToUnicodeString(name); break; } - case kpidSize: + case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; case kpidPackSize: prop = (UInt64)item.PSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidOffset: prop = item.Pa; break; @@ -3168,13 +3304,13 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, { COM_TRY_BEGIN Close(); - try + // try { if (Open2(inStream) != S_OK) return S_FALSE; _stream = inStream; } - catch(...) { return S_FALSE; } + // catch(...) { return S_FALSE; } return S_OK; COM_TRY_END } @@ -3205,26 +3341,25 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].PSize; - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; + totalSize += _items[allFilesMode ? i : indices[i]].GetSize_Extract(); + RINOK(extractCallback->SetTotal(totalSize)) - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); + totalSize = 0; - for (i = 0; i < numItems; i++) + for (i = 0;; i++) { - lps->InSize = lps->OutSize = currentTotalSize; + lps->InSize = lps->OutSize = totalSize; RINOK(lps->SetCur()) + if (i >= numItems) + break; + int opRes; + { CMyComPtr realOutStream; const Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -3232,21 +3367,22 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, const UInt32 index = allFilesMode ? i : indices[i]; const CSection &item = _items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - currentTotalSize += item.PSize; + const UInt32 size = item.GetSize_Extract(); + totalSize += size; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)) - int res = NExtract::NOperationResult::kDataError; - RINOK(InStream_SeekSet(_stream, item.Pa)) - streamSpec->Init(item.PSize); - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)) - if (copyCoderSpec->TotalSize == item.PSize) - res = NExtract::NOperationResult::kOK; + inStream->Init(size); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(res)) + opRes = (copyCoder->TotalSize == size) ? + NExtract::NOperationResult::kOK : (copyCoder->TotalSize < size) ? + NExtract::NOperationResult::kUnexpectedEnd : + NExtract::NOperationResult::kDataError; + } + RINOK(extractCallback->SetOperationResult(opRes)) } return S_OK; COM_TRY_END @@ -3256,7 +3392,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) { COM_TRY_BEGIN const CSection &item = _items[index]; - return CreateLimitedInStream(_stream, item.Pa, item.PSize, stream); + return CreateLimitedInStream(_stream, item.Pa, item.GetSize_Extract(), stream); COM_TRY_END } diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/QcowHandler.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/QcowHandler.cpp index 511778350..b1a237d0a 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/QcowHandler.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/QcowHandler.cpp @@ -11,6 +11,7 @@ #include "../../Common/MyBuffer2.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamObjects.h" @@ -20,8 +21,8 @@ #include "HandlerCont.h" -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) +#define Get32(p) GetBe32a(p) +#define Get64(p) GetBe64a(p) using namespace NWindows; @@ -32,9 +33,9 @@ static const Byte k_Signature[] = { 'Q', 'F', 'I', 0xFB, 0, 0, 0 }; /* VA to PA maps: - high bits (L1) : : in L1 Table : the reference to L1 Table - mid bits (L2) : _numMidBits : in L2 Table : the reference to cluster - low bits : _clusterBits + high bits (L1) : : index in L1 (_dir) : _dir[high_index] points to Table. + mid bits (L2) : _numMidBits : index in Table, Table[index] points to cluster start offset in arc file. + low bits : _clusterBits : offset inside cluster. */ Z7_class_CHandler_final: public CHandlerImg @@ -49,30 +50,27 @@ Z7_class_CHandler_final: public CHandlerImg CObjArray2 _dir; CAlignedBuffer _table; - UInt64 _cacheCluster; CByteBuffer _cache; CByteBuffer _cacheCompressed; + UInt64 _cacheCluster; UInt64 _comprPos; size_t _comprSize; - UInt64 _phySize; - - CBufInStream *_bufInStreamSpec; - CMyComPtr _bufInStream; - - CBufPtrSeqOutStream *_bufOutStreamSpec; - CMyComPtr _bufOutStream; - - NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec; - CMyComPtr _deflateDecoder; - - bool _needDeflate; + bool _needCompression; bool _isArc; bool _unsupported; + Byte _compressionType; + + UInt64 _phySize; + + CMyComPtr2 _bufInStream; + CMyComPtr2 _bufOutStream; + CMyComPtr2 _deflateDecoder; UInt32 _version; UInt32 _cryptMethod; + UInt64 _incompatFlags; HRESULT Seek2(UInt64 offset) { @@ -96,13 +94,11 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) { if (processedSize) *processedSize = 0; - // printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size); - if (_virtPos >= _size) return S_OK; { - UInt64 rem = _size - _virtPos; + const UInt64 rem = _size - _virtPos; if (size > rem) size = (UInt32)rem; if (size == 0) @@ -115,47 +111,43 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) const size_t clusterSize = (size_t)1 << _clusterBits; const size_t lowBits = (size_t)_virtPos & (clusterSize - 1); { - size_t rem = clusterSize - lowBits; + const size_t rem = clusterSize - lowBits; if (size > rem) size = (UInt32)rem; } - if (cluster == _cacheCluster) { memcpy(data, _cache + lowBits, size); break; } - + const UInt64 high = cluster >> _numMidBits; if (high < _dir.Size()) { - const UInt32 tabl = _dir[(unsigned)high]; - + const UInt32 tabl = _dir[(size_t)high]; if (tabl != kEmptyDirItem) { - const Byte *buffer = _table + ((size_t)tabl << (_numMidBits + 3)); const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1); - const Byte *p = (const Byte *)buffer + (midBits << 3); + const Byte *p = _table + ((((size_t)tabl << _numMidBits) + midBits) << 3); UInt64 v = Get64(p); - if (v != 0) + if (v) { - if ((v & _compressedFlag) != 0) + if (v & _compressedFlag) { if (_version <= 1) return E_FAIL; - /* - the example of table record for 12-bit clusters (4KB uncompressed). - 2 bits : isCompressed status - 4 bits : num_sectors_minus1; packSize = (num_sectors_minus1 + 1) * 512; - it uses one additional bit over unpacked cluster_bits - 49 bits : offset of 512-sector - 9 bits : offset in 512-sector + the example of table record for 12-bit clusters (4KB uncompressed): + 2 bits : isCompressed status + (4 == _clusterBits - 8) bits : (num_sectors - 1) + packSize = num_sectors * 512; + it uses one additional bit over unpacked cluster_bits. + (49 == 61 - _clusterBits) bits : offset of 512-byte sector + 9 bits : offset in 512-byte sector */ - - const unsigned numOffsetBits = (62 - (_clusterBits - 9 + 1)); + const unsigned numOffsetBits = 62 - (_clusterBits - 8); const UInt64 offset = v & (((UInt64)1 << 62) - 1); const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; UInt64 sectorOffset = offset & (((UInt64)1 << numOffsetBits) - (1 << 9)); @@ -167,7 +159,7 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) if (sectorOffset >= _comprPos && offset2inCache < _comprSize) { - if (offset2inCache != 0) + if (offset2inCache) { _comprSize -= (size_t)offset2inCache; memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize); @@ -193,39 +185,34 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) const size_t dataSize3 = dataSize - _comprSize; size_t dataSize2 = dataSize3; // printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos); - RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2)) + const HRESULT hres = ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2); _posInArc += dataSize2; + RINOK(hres) if (dataSize2 != dataSize3) return E_FAIL; _comprSize += dataSize2; } const size_t kSectorMask = (1 << 9) - 1; - const size_t offsetInSector = ((size_t)offset & kSectorMask); - _bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); - + const size_t offsetInSector = (size_t)offset & kSectorMask; + _bufInStream->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); _cacheCluster = (UInt64)(Int64)-1; if (_cache.Size() < clusterSize) return E_FAIL; - _bufOutStreamSpec->Init(_cache, clusterSize); - + _bufOutStream->Init(_cache, clusterSize); // Do we need to use smaller block than clusterSize for last cluster? const UInt64 blockSize64 = clusterSize; - HRESULT res = _deflateDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); - + HRESULT res = _deflateDecoder.Interface()->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); /* if (_bufOutStreamSpec->GetPos() != clusterSize) memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); */ - if (res == S_OK) - if (!_deflateDecoderSpec->IsFinished() - || _bufOutStreamSpec->GetPos() != clusterSize) + if (!_deflateDecoder->IsFinished() + || _bufOutStream->GetPos() != clusterSize) res = S_FALSE; - RINOK(res) _cacheCluster = cluster; - continue; /* memcpy(data, _cache + lowBits, size); @@ -233,17 +220,17 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) */ } - // version 3 support zero clusters + // version_3 supports zero clusters if (((UInt32)v & 511) != 1) { - v &= (_compressedFlag - 1); + v &= _compressedFlag - 1; v += lowBits; if (v != _posInArc) { // printf("\n%12I64x\n", v - _posInArc); RINOK(Seek2(v)) } - HRESULT res = Stream->Read(data, size, &size); + const HRESULT res = Stream->Read(data, size, &size); _posInArc += size; _virtPos += size; if (processedSize) @@ -274,13 +261,25 @@ static const Byte kProps[] = static const Byte kArcProps[] = { kpidClusterSize, + kpidSectorSize, // actually we need variable to show table size + kpidHeadersSize, kpidUnpackVer, - kpidMethod + kpidMethod, + kpidCharacts }; IMP_IInArchive_Props IMP_IInArchive_ArcProps +static const CUInt32PCharPair g_IncompatFlags_Characts[] = +{ + { 0, "Dirty" }, + { 1, "Corrupt" }, + { 2, "External_Data_File" }, + { 3, "Compression" }, + { 4, "Extended_L2" } +}; + Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) { COM_TRY_BEGIN @@ -290,28 +289,54 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) { case kpidMainSubfile: prop = (UInt32)0; break; case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break; - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidSectorSize: prop = (UInt32)1 << (_numMidBits + 3); break; + case kpidHeadersSize: prop = _table.Size() + (UInt64)_dir.Size() * 8; break; + case kpidPhySize: if (_phySize) prop = _phySize; break; case kpidUnpackVer: prop = _version; break; - + case kpidCharacts: + { + if (_incompatFlags) + { + AString s ("incompatible: "); + // we need to show also high 32-bits. + s += FlagsToString(g_IncompatFlags_Characts, + Z7_ARRAY_SIZE(g_IncompatFlags_Characts), (UInt32)_incompatFlags); + prop = s; + } + break; + } case kpidMethod: { AString s; - if (_needDeflate) - s = "Deflate"; + if (_compressionType) + { + if (_compressionType == 1) + s += "ZSTD"; + else + { + s += "Compression:"; + s.Add_UInt32(_compressionType); + } + } + else if (_needCompression) + s.Add_OptSpaced("Deflate"); - if (_cryptMethod != 0) + if (_cryptMethod) { s.Add_Space_if_NotEmpty(); if (_cryptMethod == 1) s += "AES"; + if (_cryptMethod == 2) + s += "LUKS"; else + { + s += "Encryption:"; s.Add_UInt32(_cryptMethod); + } } - if (!s.IsEmpty()) prop = s; - break; } @@ -321,9 +346,9 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; // if (_headerError) v |= kpv_ErrorFlags_HeadersError; - if (!Stream && v == 0 && _isArc) + if (!Stream && v == 0) v = kpv_ErrorFlags_HeadersError; - if (v != 0) + if (v) prop = v; break; } @@ -355,76 +380,91 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) { - const unsigned kHeaderSize = 18 * 4; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) - - if (memcmp(buf, k_Signature, 4) != 0) + UInt64 buf64[0x70 / 8]; + RINOK(ReadStream_FALSE(stream, buf64, sizeof(buf64))) + const void *buf = (const void *)buf64; + // signature: { 'Q', 'F', 'I', 0xFB } + if (*(const UInt32 *)buf != Z7_CONV_BE_TO_NATIVE_CONST32(0x514649fb)) return S_FALSE; - - _version = Get32(buf + 4); + _version = Get32((const Byte *)(const void *)buf64 + 4); if (_version < 1 || _version > 3) return S_FALSE; - const UInt64 backOffset = Get64(buf + 8); - // UInt32 backSize = Get32(buf + 0x10); - - UInt64 l1Offset; - UInt32 l1Size; + const UInt64 k_UncompressedSize_MAX = (UInt64)1 << 60; + const UInt64 k_CompressedSize_MAX = (UInt64)1 << 60; + + _size = Get64((const Byte *)(const void *)buf64 + 0x18); + if (_size > k_UncompressedSize_MAX) + return S_FALSE; + size_t l1Size; + UInt32 headerSize; if (_version == 1) { - // _mTime = Get32(buf + 0x14); // is unused im most images - _size = Get64(buf + 0x18); - _clusterBits = buf[0x20]; - _numMidBits = buf[0x21]; + // _mTime = Get32((const Byte *)(const void *)buf64 + 0x14); // is unused in most images + _clusterBits = ((const Byte *)(const void *)buf64)[0x20]; + _numMidBits = ((const Byte *)(const void *)buf64)[0x21]; if (_clusterBits < 9 || _clusterBits > 30) return S_FALSE; if (_numMidBits < 1 || _numMidBits > 28) return S_FALSE; - _cryptMethod = Get32(buf + 0x24); - l1Offset = Get64(buf + 0x28); - if (l1Offset < 0x30) - return S_FALSE; - const unsigned numBits2 = (_clusterBits + _numMidBits); + _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x24); + const unsigned numBits2 = _clusterBits + _numMidBits; const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2; if (l1Size64 > ((UInt32)1 << 31)) return S_FALSE; - l1Size = (UInt32)l1Size64; + l1Size = (size_t)l1Size64; + headerSize = 0x30; } else { - _clusterBits = Get32(buf + 0x14); + _clusterBits = Get32((const Byte *)(const void *)buf64 + 0x14); if (_clusterBits < 9 || _clusterBits > 30) return S_FALSE; _numMidBits = _clusterBits - 3; - _size = Get64(buf + 0x18); - _cryptMethod = Get32(buf + 0x20); - l1Size = Get32(buf + 0x24); - l1Offset = Get64(buf + 0x28); // must be aligned for cluster - - const UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster - const UInt32 refClusters = Get32(buf + 0x38); - - // UInt32 numSnapshots = Get32(buf + 0x3C); - // UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster + _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x20); + l1Size = Get32((const Byte *)(const void *)buf64 + 0x24); + headerSize = 0x48; + if (_version >= 3) + { + _incompatFlags = Get64((const Byte *)(const void *)buf64 + 0x48); + // const UInt64 CompatFlags = Get64((const Byte *)(const void *)buf64 + 0x50); + // const UInt64 AutoClearFlags = Get64((const Byte *)(const void *)buf64 + 0x58); + // const UInt32 RefCountOrder = Get32((const Byte *)(const void *)buf64 + 0x60); + headerSize = 0x68; + const UInt32 headerSize2 = Get32((const Byte *)(const void *)buf64 + 0x64); + if (headerSize2 > (1u << 30)) + return S_FALSE; + if (headerSize < headerSize2) + headerSize = headerSize2; + if (headerSize2 >= 0x68 + 1) + _compressionType = ((const Byte *)(const void *)buf64)[0x68]; + } + + const UInt64 refOffset = Get64((const Byte *)(const void *)buf64 + 0x30); // must be aligned for cluster + const UInt32 refClusters = Get32((const Byte *)(const void *)buf64 + 0x38); + // UInt32 numSnapshots = Get32((const Byte *)(const void *)buf64 + 0x3C); + // UInt64 snapshotsOffset = Get64((const Byte *)(const void *)buf64 + 0x40); // must be aligned for cluster /* - if (numSnapshots != 0) + if (numSnapshots) return S_FALSE; */ - - if (refClusters != 0) + if (refClusters) { - const size_t numBytes = refClusters << _clusterBits; + if (refOffset > k_CompressedSize_MAX) + return S_FALSE; + const UInt64 numBytes = (UInt64)refClusters << _clusterBits; + const UInt64 end = refOffset + numBytes; + if (end > k_CompressedSize_MAX) + return S_FALSE; /* CByteBuffer refs; refs.Alloc(numBytes); RINOK(InStream_SeekSet(stream, refOffset)) RINOK(ReadStream_FALSE(stream, refs, numBytes)); */ - const UInt64 end = refOffset + numBytes; if (_phySize < end) - _phySize = end; + _phySize = end; /* for (size_t i = 0; i < numBytes; i += 2) { @@ -436,48 +476,76 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) } } - _isArc = true; + const UInt64 l1Offset = Get64((const Byte *)(const void *)buf64 + 0x28); // must be aligned for cluster ? + if (l1Offset < headerSize || l1Offset > k_CompressedSize_MAX) + return S_FALSE; + if (_phySize < headerSize) + _phySize = headerSize; - if (backOffset != 0) + _isArc = true; { - _unsupported = true; - return S_FALSE; + const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8); + // UInt32 backSize = Get32((const Byte *)(const void *)buf64 + 0x10); + if (backOffset) + { + _unsupported = true; + return S_FALSE; + } } - const size_t clusterSize = (size_t)1 << _clusterBits; + UInt64 fileSize = 0; + RINOK(InStream_GetSize_SeekToBegin(stream, fileSize)) - CByteBuffer table; + const size_t clusterSize = (size_t)1 << _clusterBits; + const size_t t1SizeBytes = (size_t)l1Size << 3; { - const size_t t1SizeBytes = (size_t)l1Size << 3; - if ((t1SizeBytes >> 3) != l1Size) + const UInt64 end = l1Offset + t1SizeBytes; + if (end > k_CompressedSize_MAX) return S_FALSE; - table.Alloc(t1SizeBytes); - RINOK(InStream_SeekSet(stream, l1Offset)) - RINOK(ReadStream_FALSE(stream, table, t1SizeBytes)) - - { - UInt64 end = l1Offset + t1SizeBytes; - // we need to uses align end for empty qcow files - end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; - if (_phySize < end) + // we need to use align end for empty qcow files + // some files has no cluster alignment padding at the end + // but has sector alignment + // end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; + if (_phySize < end) _phySize = end; + if (end > fileSize) + return S_FALSE; + if (_phySize < fileSize) + { + const UInt64 end2 = (end + 511) & ~(UInt64)511; + if (end2 == fileSize) + _phySize = end2; } } + CObjArray table64(l1Size); + { + // if ((t1SizeBytes >> 3) != l1Size) return S_FALSE; + RINOK(InStream_SeekSet(stream, l1Offset)) + RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes)) + } _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); const UInt64 offsetMask = _compressedFlag - 1; + const size_t midSize = (size_t)1 << (_numMidBits + 3); + size_t numTables = 0; + size_t i; - UInt32 numTables = 0; - UInt32 i; - for (i = 0; i < l1Size; i++) { - const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask; - if (v != 0) - numTables++; + const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; + if (!v) + continue; + numTables++; + const UInt64 end = v + midSize; + if (end > k_CompressedSize_MAX) + return S_FALSE; + if (_phySize < end) + _phySize = end; + if (end > fileSize) + return S_FALSE; } - if (numTables != 0) + if (numTables) { const size_t size = (size_t)numTables << (_numMidBits + 3); if (size >> (_numMidBits + 3) != numTables) @@ -485,48 +553,38 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) _table.Alloc(size); if (!_table.IsAllocated()) return E_OUTOFMEMORY; + if (openCallback) + { + const UInt64 totalBytes = size; + RINOK(openCallback->SetTotal(NULL, &totalBytes)) + } } - _dir.SetSize(l1Size); + _dir.SetSize((unsigned)l1Size); UInt32 curTable = 0; - if (openCallback) - { - const UInt64 totalBytes = (UInt64)numTables << (_numMidBits + 3); - RINOK(openCallback->SetTotal(NULL, &totalBytes)) - } - for (i = 0; i < l1Size; i++) { Byte *buf2; - const size_t midSize = (size_t)1 << (_numMidBits + 3); - { - const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask; + const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; if (v == 0) { _dir[i] = kEmptyDirItem; continue; } - _dir[i] = curTable; - const size_t tableOffset = ((size_t)curTable << (_numMidBits + 3)); + const size_t tableOffset = (size_t)curTable << (_numMidBits + 3); buf2 = (Byte *)_table + tableOffset; curTable++; - if (openCallback && (tableOffset & 0xFFFFF) == 0) { const UInt64 numBytes = tableOffset; RINOK(openCallback->SetCompleted(NULL, &numBytes)) } - RINOK(InStream_SeekSet(stream, v)) RINOK(ReadStream_FALSE(stream, buf2, midSize)) - - const UInt64 end = v + midSize; - if (_phySize < end) - _phySize = end; } for (size_t k = 0; k < midSize; k += 8) @@ -537,33 +595,30 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) UInt64 offset = v & offsetMask; size_t dataSize = clusterSize; - if ((v & _compressedFlag) != 0) + if (v & _compressedFlag) { if (_version <= 1) { - unsigned numOffsetBits = (63 - _clusterBits); + const unsigned numOffsetBits = 63 - _clusterBits; dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; offset &= ((UInt64)1 << numOffsetBits) - 1; - dataSize = 0; - // offset >>= 9; - // offset <<= 9; + dataSize = 0; // why ? + // offset &= ~(((UInt64)1 << 9) - 1); } else { - unsigned numOffsetBits = (62 - (_clusterBits - 8)); + const unsigned numOffsetBits = 62 - (_clusterBits - 8); dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; - offset &= ((UInt64)1 << numOffsetBits) - 1; - offset >>= 9; - offset <<= 9; + offset &= ((UInt64)1 << numOffsetBits) - (1 << 9); } - _needDeflate = true; + _needCompression = true; } else { - UInt32 low = (UInt32)v & 511; - if (low != 0) + const UInt32 low = (UInt32)v & 511; + if (low) { - // version 3 support zero clusters + // version_3 supports zero clusters if (_version < 3 || low != 1) { _unsupported = true; @@ -574,17 +629,18 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) const UInt64 end = offset + dataSize; if (_phySize < end) - _phySize = end; + _phySize = end; } } if (curTable != numTables) return E_FAIL; - if (_cryptMethod != 0) + if (_cryptMethod) _unsupported = true; - - if (_needDeflate && _version <= 1) // that case was not implemented + if (_needCompression && _version <= 1) // that case was not implemented + _unsupported = true; + if (_compressionType) _unsupported = true; Stream = stream; @@ -596,16 +652,21 @@ Z7_COM7F_IMF(CHandler::Close()) { _table.Free(); _dir.Free(); + // _cache.Free(); + // _cacheCompressed.Free(); _phySize = 0; _cacheCluster = (UInt64)(Int64)-1; _comprPos = 0; _comprSize = 0; - _needDeflate = false; + _needCompression = false; _isArc = false; _unsupported = false; + _compressionType = 0; + _incompatFlags = 0; + // CHandlerImg: Clear_HandlerImg_Vars(); Stream.Release(); @@ -617,39 +678,20 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea { COM_TRY_BEGIN *stream = NULL; - - if (_unsupported) + if (_unsupported || !Stream) return S_FALSE; - - if (_needDeflate) + if (_needCompression) { - if (_version <= 1) + if (_version <= 1 || _compressionType) return S_FALSE; - - if (!_bufInStream) - { - _bufInStreamSpec = new CBufInStream; - _bufInStream = _bufInStreamSpec; - } - - if (!_bufOutStream) - { - _bufOutStreamSpec = new CBufPtrSeqOutStream(); - _bufOutStream = _bufOutStreamSpec; - } - - if (!_deflateDecoder) - { - _deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder(); - _deflateDecoder = _deflateDecoderSpec; - _deflateDecoderSpec->Set_NeedFinishInput(true); - } - + _bufInStream.Create_if_Empty(); + _bufOutStream.Create_if_Empty(); + _deflateDecoder.Create_if_Empty(); + _deflateDecoder->Set_NeedFinishInput(true); const size_t clusterSize = (size_t)1 << _clusterBits; _cache.AllocAtLeast(clusterSize); _cacheCompressed.AllocAtLeast(clusterSize * 2); } - CMyComPtr streamTemp = this; RINOK(InitAndSeek()) *stream = streamTemp.Detach(); diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/Rar/Rar5Handler.cpp index ef5c4dd41..daa9df8cd 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -1456,7 +1456,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) } if (arcInfo->Locator.Is_Recovery()) { - s += "Recovery:"; + s.Add_OptSpaced("Recovery:"); s.Add_UInt64(arcInfo->Locator.Recovery); } } diff --git a/NanaZip.Core/SevenZip/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/NanaZip.Core/SevenZip/CPP/7zip/Archive/Zip/ZipUpdate.cpp index d16df01d5..d75669c4e 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -1755,16 +1755,17 @@ HRESULT CCacheOutStream::FlushFromCache(size_t size) PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size)); if (_hres != S_OK) return _hres; - if (size == 0 || _cachedSize == 0) + if (size > _cachedSize) + size = _cachedSize; + // (size <= _cachedSize) + if (size == 0) return S_OK; RINOK(SeekPhy(_cachedPos)) for (;;) { // (_phyPos == _cachedPos) const size_t pos = (size_t)_cachedPos & kCacheMask; - size_t cur = kCacheSize - pos; - cur = MyMin(cur, _cachedSize); - cur = MyMin(cur, size); + const size_t cur = MyMin(kCacheSize - pos, size); _hres = SetRestriction_ForWrite(cur); RINOK(_hres) PRF(printf("\n-- CCacheOutStream::WriteFromCache _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)cur)); @@ -1776,7 +1777,7 @@ HRESULT CCacheOutStream::FlushFromCache(size_t size) _cachedPos += cur; _cachedSize -= cur; size -= cur; - if (size == 0 || _cachedSize == 0) + if (size == 0) return S_OK; } } @@ -1964,7 +1965,11 @@ Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize)) // so we reduce cache _cachedSize = (size_t)offset; if (_phySize <= newSize) - return S_OK; // _phySize will be restored later after cache flush + { + // _phySize will be restored later after cache flush + _virtSize = newSize; + return S_OK; + } // (_phySize > newSize) // so we must reduce phyStream size to (newSize) or to (_cachedPos) // newPhySize = _cachedPos; // optional reduce to _cachedPos diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/Common/PropIDUtils.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/Common/PropIDUtils.cpp index 10fc46fcd..f37b1fe75 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -21,8 +21,8 @@ using namespace NWindows; -static const unsigned kNumWinAtrribFlags = 21; -static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU"; +static const unsigned kNumWinAtrribFlags = 30; +static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEVvX.PU.M......B"; /* FILE_ATTRIBUTE_ @@ -48,8 +48,9 @@ FILE_ATTRIBUTE_ 18 RECALL_ON_OPEN or EA 19 PINNED 20 UNPINNED -21 STRICTLY_SEQUENTIAL +21 STRICTLY_SEQUENTIAL (10.0.16267) 22 RECALL_ON_DATA_ACCESS +29 STRICTLY_SEQUENTIAL (10.0.17134+) (SMR Blob) */ @@ -107,10 +108,10 @@ void ConvertWinAttribToString(char *s, UInt32 wa) throw() for (unsigned i = 0; i < kNumWinAtrribFlags; i++) { - UInt32 flag = (1 << i); - if ((wa & flag) != 0) + const UInt32 flag = (UInt32)1 << i; + if (wa & flag) { - char c = g_WinAttribChars[i]; + const char c = g_WinAttribChars[i]; if (c != '.') { wa &= ~flag; diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index 1e96a514c..490f38531 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -924,11 +924,11 @@ HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result) } else { - NumArcsWithError++; + // we don't update NumArcsWithError, if error is not related to archive data. if (result == E_ABORT - || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) - ) + || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)) return result; + NumArcsWithError++; if (_se) { diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/BrowseDialog.cpp index 4b4b16498..1b7fd0387 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/BrowseDialog.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/BrowseDialog.cpp @@ -211,8 +211,8 @@ bool CBrowseDialog::OnInit() _filterCombo.SetCurSel(FilterIndex); } - _list.SetImageList(GetSysImageList(true), LVSIL_SMALL); - _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL); + _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); + _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100); _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100); @@ -693,19 +693,21 @@ HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selected #ifndef UNDER_CE if (isDrive) { - if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0) - item.iImage = 0; + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path( + fi.Name + FCHAR_PATH_SEPARATOR, + FILE_ATTRIBUTE_DIRECTORY); } else #endif item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); if (item.iImage < 0) - item.iImage = 0; + item.iImage = 0; _list.InsertItem(&item); wchar_t s[64]; { s[0] = 0; - ConvertUtcFileTimeToString(fi.MTime, s, + if (!FILETIME_IsZero(fi.MTime)) + ConvertUtcFileTimeToString(fi.MTime, s, #ifndef UNDER_CE kTimestampPrintLevel_MIN #else diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.cpp index e5b39b49e..a9e76a73b 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.cpp @@ -206,13 +206,15 @@ Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( { COverwriteDialog dialog; - dialog.OldFileInfo.SetTime(existTime); - dialog.OldFileInfo.SetSize(existSize); - dialog.OldFileInfo.Name = existName; - - dialog.NewFileInfo.SetTime(newTime); - dialog.NewFileInfo.SetSize(newSize); - dialog.NewFileInfo.Name = newName; + dialog.OldFileInfo.SetTime2(existTime); + dialog.OldFileInfo.SetSize2(existSize); + dialog.OldFileInfo.Path = existName; + dialog.OldFileInfo.Is_FileSystemFile = true; + + dialog.NewFileInfo.SetTime2(newTime); + dialog.NewFileInfo.SetSize2(newSize); + dialog.NewFileInfo.Path = newName; + dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder; ProgressDialog->WaitCreating(); INT_PTR writeAnswer = dialog.Create(*ProgressDialog); diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.h b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.h index 52088b7a0..971fbb0ac 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/ExtractCallback.h @@ -224,6 +224,8 @@ class CExtractCallbackImp Z7_final: bool ProcessAltStreams; bool StreamMode; bool ThereAreMessageErrors; + bool Src_Is_IO_FS_Folder; + #ifndef Z7_NO_CRYPTO bool PasswordIsDefined; bool PasswordWasAsked; @@ -286,6 +288,8 @@ class CExtractCallbackImp Z7_final: , MultiArcMode(false) , ProcessAltStreams(true) , StreamMode(false) + , ThereAreMessageErrors(false) + , Src_Is_IO_FS_Folder(false) #ifndef Z7_NO_CRYPTO , PasswordIsDefined(false) , PasswordWasAsked(false) diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.cpp index d4f72f23d..ba628ed7d 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.cpp @@ -2,8 +2,10 @@ #include "StdAfx.h" +#include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" +#include "../../../Windows/FileFind.h" #include "../../../Windows/PropVariantConv.h" #include "../../../Windows/ResourceString.h" @@ -29,12 +31,16 @@ static const UInt32 kLangIDs[] = }; #endif -static const unsigned kCurrentFileNameSizeLimit = 82; -static const unsigned kCurrentFileNameSizeLimit2 = 30; +static const unsigned kCurrentFileNameSizeLimit = 72; void COverwriteDialog::ReduceString(UString &s) { - unsigned size = _isBig ? kCurrentFileNameSizeLimit : kCurrentFileNameSizeLimit2; + const unsigned size = +#ifdef UNDER_CE + !_isBig ? 30 : // kCurrentFileNameSizeLimit2 +#endif + kCurrentFileNameSizeLimit; + if (s.Len() > size) { s.Delete(size / 2, s.Len() - size); @@ -42,66 +48,201 @@ void COverwriteDialog::ReduceString(UString &s) } if (!s.IsEmpty() && s.Back() == ' ') { - // s += (wchar_t)(0x2423); + // s += (wchar_t)(0x2423); // visible space s.InsertAtFront(L'\"'); - s += L'\"'; + s.Add_Char('\"'); } } -void COverwriteDialog::SetFileInfoControl(unsigned textID, unsigned iconID, - const NOverwriteDialog::CFileInfo &fileInfo) + +void COverwriteDialog::SetItemIcon(unsigned iconID, HICON hIcon) +{ + NControl::CStatic staticContol; + staticContol.Attach(GetItem(iconID)); + hIcon = staticContol.SetIcon(hIcon); + if (hIcon) + DestroyIcon(hIcon); +} + +void AddSizeValue(UString &s, UInt64 value); +void AddSizeValue(UString &s, UInt64 value) { - UString sizeString; - if (fileInfo.SizeIsDefined) - sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size)); - - const UString &fileName = fileInfo.Name; - int slashPos = fileName.ReverseFind_PathSepar(); - UString s1 = fileName.Left((unsigned)(slashPos + 1)); - UString s2 = fileName.Ptr((unsigned)(slashPos + 1)); - - ReduceString(s1); - ReduceString(s2); - - UString s = s1; - s.Add_LF(); - s += s2; - s.Add_LF(); - s += sizeString; - s.Add_LF(); - - if (fileInfo.TimeIsDefined) { - AddLangString(s, IDS_PROP_MTIME); - s += ": "; - char t[64]; - ConvertUtcFileTimeToString(fileInfo.Time, t); - s += t; + wchar_t sz[32]; + ConvertUInt64ToString(value, sz); + s += MyFormatNew(IDS_FILE_SIZE, sz); } + if (value >= (1 << 10)) + { + char c; + if (value >= ((UInt64)10 << 30)) { value >>= 30; c = 'G'; } + else if (value >= (10 << 20)) { value >>= 20; c = 'M'; } + else { value >>= 10; c = 'K'; } + s += " : "; + s.Add_UInt64(value); + s.Add_Space(); + s.Add_Char(c); + s += "iB"; + } +} - NControl::CDialogChildControl control; - control.Init(*this, textID); - control.SetText(s); - SHFILEINFO shellFileInfo; - if (::SHGetFileInfo( - GetSystemString(fileInfo.Name), FILE_ATTRIBUTE_NORMAL, &shellFileInfo, - sizeof(shellFileInfo), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_LARGEICON)) +void COverwriteDialog::SetFileInfoControl( + const NOverwriteDialog::CFileInfo &fileInfo, + unsigned textID, + unsigned iconID, + unsigned iconID_2) +{ + { + const UString &path = fileInfo.Path; + const int slashPos = path.ReverseFind_PathSepar(); + UString s = path.Left((unsigned)(slashPos + 1)); + ReduceString(s); + s.Add_LF(); + { + UString s2 = path.Ptr((unsigned)(slashPos + 1)); + ReduceString(s2); + s += s2; + } + s.Add_LF(); + if (fileInfo.Size_IsDefined) + AddSizeValue(s, fileInfo.Size); + s.Add_LF(); + if (fileInfo.Time_IsDefined) + { + AddLangString(s, IDS_PROP_MTIME); + s += ": "; + char t[64]; + ConvertUtcFileTimeToString(fileInfo.Time, t); + s += t; + } + SetItemText(textID, s); + } +/* + SHGetFileInfo(): + DOCs: If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX, + the return value is nonzero if successful, or zero otherwise. + We don't use SHGFI_EXETYPE or SHGFI_SYSICONINDEX here. + win10: we call with SHGFI_ICON flag set. + it returns 0: if error : (shFileInfo::*) members are not set. + it returns non_0, if successful, and retrieve: + { shFileInfo.hIcon != NULL : the handle to icon (must be destroyed by our code) + shFileInfo.iIcon is index of the icon image within the system image list. + } + Note: + If we send path to ".exe" file, + SHGFI_USEFILEATTRIBUTES flag is ignored, and it tries to open file. + and return icon from that exe file. + So we still need to reduce path, if want to get raw icon of exe file. + + if (name.Len() >= MAX_PATH)) + { + it can return: + return 0. + return 1 and: + { shFileInfo.hIcon != NULL : is some default icon for file + shFileInfo.iIcon == 0 + } + return results (0 or 1) can depend from: + - unicode/non-unicode + - (SHGFI_USEFILEATTRIBUTES) flag + - exact file extension (.exe). + } +*/ + int iconIndex = -1; + for (unsigned i = 0; i < 2; i++) { - NControl::CStatic staticContol; - staticContol.Attach(GetItem(iconID)); - staticContol.SetIcon(shellFileInfo.hIcon); + CSysString name = GetSystemString(fileInfo.Path); + if (i != 0) + { + if (!fileInfo.Is_FileSystemFile) + break; + if (name.Len() < 4 || + (!StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".exe") && + !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".ico"))) + break; + // if path for ".exe" file is long, it returns default icon (shFileInfo.iIcon == 0). + // We don't want to show that default icon. + // But we will check for default icon later instead of MAX_PATH check here. + // if (name.Len() >= MAX_PATH) break; // optional + } + else + { + // we need only file extension with dot + const int separ = name.ReverseFind_PathSepar(); + name.DeleteFrontal((unsigned)(separ + 1)); + // if (name.Len() >= MAX_PATH) + { + const int dot = name.ReverseFind_Dot(); + if (dot >= 0) + name.DeleteFrontal((unsigned)dot); + // else name.Empty(); to set default name below + } + // name.Empty(); // for debug + } + + if (name.IsEmpty()) + { + // If we send empty name, SHGetFileInfo() returns some strange icon. + // So we use common dummy name without extension, + // and SHGetFileInfo() will return default icon (iIcon == 0) + name = "__file__"; + } + + DWORD attrib = FILE_ATTRIBUTE_ARCHIVE; + if (fileInfo.Is_FileSystemFile) + { + NFile::NFind::CFileInfo fi; + if (fi.Find(us2fs(fileInfo.Path)) && !fi.IsAltStream && !fi.IsDir()) + attrib = fi.Attrib; + } + + SHFILEINFO shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); // optional + shFileInfo.hIcon = NULL; // optional + shFileInfo.iIcon = -1; // optional + // memset(&shFileInfo, 1, sizeof(shFileInfo)); // for debug + const DWORD_PTR res = ::SHGetFileInfo(name, attrib, + &shFileInfo, sizeof(shFileInfo), + SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE | + // (i == 0 ? SHGFI_USEFILEATTRIBUTES : 0) + SHGFI_USEFILEATTRIBUTES + // we use SHGFI_USEFILEATTRIBUTES for second icon, because + // it still returns real icon from exe files + ); + if (res && shFileInfo.hIcon) + { + // we don't show second icon, if icon index (iIcon) is same + // as first icon index of first shown icon (exe file without icon) + if ( shFileInfo.iIcon >= 0 + && shFileInfo.iIcon != iconIndex + && (shFileInfo.iIcon != 0 || i == 0)) // we don't want default icon for second icon + { + iconIndex = shFileInfo.iIcon; + SetItemIcon(i == 0 ? iconID : iconID_2, shFileInfo.hIcon); + } + else + DestroyIcon(shFileInfo.hIcon); + } } } + + bool COverwriteDialog::OnInit() { #ifdef Z7_LANG LangSetWindowText(*this, IDD_OVERWRITE); LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); #endif - SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo); - SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo); + SetFileInfoControl(OldFileInfo, + IDT_OVERWRITE_OLD_FILE_SIZE_TIME, + IDI_OVERWRITE_OLD_FILE, + IDI_OVERWRITE_OLD_FILE_2); + SetFileInfoControl(NewFileInfo, + IDT_OVERWRITE_NEW_FILE_SIZE_TIME, + IDI_OVERWRITE_NEW_FILE, + IDI_OVERWRITE_NEW_FILE_2); NormalizePosition(); if (!ShowExtraButtons) @@ -122,6 +263,15 @@ bool COverwriteDialog::OnInit() return CModalDialog::OnInit(); } +bool COverwriteDialog::OnDestroy() +{ + SetItemIcon(IDI_OVERWRITE_OLD_FILE, NULL); + SetItemIcon(IDI_OVERWRITE_OLD_FILE_2, NULL); + SetItemIcon(IDI_OVERWRITE_NEW_FILE, NULL); + SetItemIcon(IDI_OVERWRITE_NEW_FILE_2, NULL); + return false; // we return (false) to perform default dialog operation +} + bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) { switch (buttonID) diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.h b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.h index 3aaedf695..4ec2c1655 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.h +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.h @@ -12,68 +12,78 @@ namespace NOverwriteDialog { struct CFileInfo { - bool SizeIsDefined; - bool TimeIsDefined; + bool Size_IsDefined; + bool Time_IsDefined; + bool Is_FileSystemFile; UInt64 Size; FILETIME Time; - UString Name; + UString Path; + + void SetTime(const FILETIME &t) + { + Time = t; + Time_IsDefined = true; + } - void SetTime(const FILETIME *t) + void SetTime2(const FILETIME *t) { if (!t) - TimeIsDefined = false; + Time_IsDefined = false; else - { - TimeIsDefined = true; - Time = *t; - } + SetTime(*t); } void SetSize(UInt64 size) { - SizeIsDefined = true; Size = size; + Size_IsDefined = true; } - void SetSize(const UInt64 *size) + void SetSize2(const UInt64 *size) { if (!size) - SizeIsDefined = false; + Size_IsDefined = false; else SetSize(*size); } + + CFileInfo(): + Size_IsDefined(false), + Time_IsDefined(false), + Is_FileSystemFile(false) + {} }; } class COverwriteDialog: public NWindows::NControl::CModalDialog { +#ifdef UNDER_CE bool _isBig; +#endif - void SetFileInfoControl(unsigned textID, unsigned iconID, const NOverwriteDialog::CFileInfo &fileInfo); + void SetItemIcon(unsigned iconID, HICON hIcon); + void SetFileInfoControl(const NOverwriteDialog::CFileInfo &fileInfo, unsigned textID, unsigned iconID, unsigned iconID_2); virtual bool OnInit() Z7_override; + virtual bool OnDestroy() Z7_override; virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; void ReduceString(UString &s); public: bool ShowExtraButtons; bool DefaultButton_is_NO; - + NOverwriteDialog::CFileInfo OldFileInfo; + NOverwriteDialog::CFileInfo NewFileInfo; COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {} INT_PTR Create(HWND parent = NULL) { +#ifdef UNDER_CE BIG_DIALOG_SIZE(280, 200); - #ifdef UNDER_CE _isBig = isBig; - #else - _isBig = true; - #endif +#endif return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent); } - - NOverwriteDialog::CFileInfo OldFileInfo; - NOverwriteDialog::CFileInfo NewFileInfo; }; #endif diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.rc index 7bd71bfe4..dfc76483a 100644 Binary files a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.rc and b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialog.rc differ diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialogRes.h b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialogRes.h index 2265c4e14..5fcd0e6a5 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialogRes.h +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/OverwriteDialogRes.h @@ -11,7 +11,9 @@ #define IDB_NO_TO_ALL 441 #define IDI_OVERWRITE_OLD_FILE 100 -#define IDI_OVERWRITE_NEW_FILE 101 - +#define IDI_OVERWRITE_OLD_FILE_2 101 #define IDT_OVERWRITE_OLD_FILE_SIZE_TIME 102 -#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 103 + +#define IDI_OVERWRITE_NEW_FILE 110 +#define IDI_OVERWRITE_NEW_FILE_2 111 +#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 112 diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.cpp index 058f4e1c8..78db5fd58 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.cpp @@ -20,16 +20,19 @@ extern bool g_IsNT; #endif -int GetIconIndexForCSIDL(int csidl) +CExtToIconMap g_Ext_to_Icon_Map; + +int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl) { LPITEMIDLIST pidl = NULL; SHGetSpecialFolderLocation(NULL, csidl, &pidl); if (pidl) { - SHFILEINFO shellInfo; - shellInfo.iIcon = 0; - const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), FILE_ATTRIBUTE_NORMAL, - &shellInfo, sizeof(shellInfo), + SHFILEINFO shFileInfo; + shFileInfo.iIcon = -1; + const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), + FILE_ATTRIBUTE_DIRECTORY, + &shFileInfo, sizeof(shFileInfo), SHGFI_PIDL | SHGFI_SYSICONINDEX); /* IMalloc *pMalloc; @@ -43,9 +46,9 @@ int GetIconIndexForCSIDL(int csidl) // we use OLE2.dll function here CoTaskMemFree(pidl); if (res) - return shellInfo.iIcon; + return shFileInfo.iIcon; } - return 0; + return -1; } #ifndef _UNICODE @@ -60,69 +63,111 @@ static struct C_SHGetFileInfo_Init f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS( Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); + // f_SHGetFileInfoW = NULL; // for debug } } g_SHGetFileInfo_Init; #endif +#ifdef _UNICODE +#define My_SHGetFileInfoW SHGetFileInfoW +#else static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags) { - #ifdef _UNICODE - return SHGetFileInfo - #else if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW) return 0; - return g_SHGetFileInfo_Init.f_SHGetFileInfoW - #endif - (pszPath, attrib, psfi, cbFileInfo, uFlags); + return g_SHGetFileInfo_Init.f_SHGetFileInfoW(pszPath, attrib, psfi, cbFileInfo, uFlags); } +#endif -DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex) +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + CFSTR path, DWORD attrib, int &iconIndex) { - #ifndef _UNICODE - if (!g_IsNT) +#ifndef _UNICODE + if (!g_IsNT || !g_SHGetFileInfo_Init.f_SHGetFileInfoW) { - SHFILEINFO shellInfo; - const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, - sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); - iconIndex = shellInfo.iIcon; + SHFILEINFO shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); + shFileInfo.iIcon = -1; // optional + const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), + attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, + &shFileInfo, sizeof(shFileInfo), + SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); + iconIndex = shFileInfo.iIcon; return res; } else - #endif +#endif { - SHFILEINFOW shellInfo; - const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, - sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); - iconIndex = shellInfo.iIcon; + SHFILEINFOW shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); + shFileInfo.iIcon = -1; // optional + const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), + attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, + &shFileInfo, sizeof(shFileInfo), + SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); + // (shFileInfo.iIcon == 0) returned for unknown extensions and files without extension + iconIndex = shFileInfo.iIcon; + // we use SHGFI_USEFILEATTRIBUTES, and + // (res != 0) is expected for main cases, even if there are no such file. + // (res == 0) for path with kSuperPrefix \\?\ + // Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe. + // So we can use SHGFI_USEFILEATTRIBUTES for any case. + // UString temp = fs2us(path); // for debug + // UString tempName = temp.Ptr(temp.ReverseFind_PathSepar() + 1); // for debug + // iconIndex = -1; // for debug return res; } } +int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib) +{ + int iconIndex = -1; + if (!Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + path, attrib, iconIndex)) + iconIndex = -1; + return iconIndex; +} + + +HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + CFSTR path, DWORD attrib, Int32 *iconIndex) +{ + *iconIndex = -1; + int iconIndexTemp; + if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + path, attrib, iconIndexTemp)) + { + *iconIndex = iconIndexTemp; + return S_OK; + } + return GetLastError_noZero_HRESULT(); +} + /* -DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName) +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName) { #ifndef _UNICODE if (!g_IsNT) { - SHFILEINFO shellInfo; - shellInfo.szTypeName[0] = 0; - DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, - sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); + SHFILEINFO shFileInfo; + shFileInfo.szTypeName[0] = 0; + DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, + sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); if (typeName) - *typeName = GetUnicodeString(shellInfo.szTypeName); - iconIndex = shellInfo.iIcon; + *typeName = GetUnicodeString(shFileInfo.szTypeName); + iconIndex = shFileInfo.iIcon; return res; } else #endif { - SHFILEINFOW shellInfo; - shellInfo.szTypeName[0] = 0; - DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, - sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); + SHFILEINFOW shFileInfo; + shFileInfo.szTypeName[0] = 0; + DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, + sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); if (typeName) - *typeName = shellInfo.szTypeName; - iconIndex = shellInfo.iIcon; + *typeName = shFileInfo.szTypeName; + iconIndex = shFileInfo.iIcon; return res; } } @@ -164,6 +209,9 @@ static int FindInSorted_Ext(const CObjectVector &vect, const wchar return -1; } + +// bool DoItemAlwaysStart(const UString &name); + int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */) { int dotPos = -1; @@ -175,6 +223,8 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin break; if (c == '.') dotPos = (int)i; + // we don't need IS_PATH_SEPAR check, because (fileName) doesn't include path prefix. + // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; } /* @@ -187,8 +237,11 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin } */ - if ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 || dotPos < 0) + if ((attrib & FILE_ATTRIBUTE_DIRECTORY) || dotPos < 0) + for (unsigned k = 0;; k++) { + if (k >= 2) + return -1; unsigned insertPos = 0; const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos); if (index >= 0) @@ -197,33 +250,43 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin return _attribMap[(unsigned)index].IconIndex; } CAttribIconPair pair; - GetRealIconIndex( + pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( #ifdef UNDER_CE FTEXT("\\") #endif FTEXT("__DIR__") - , attrib, pair.IconIndex + , attrib // , pair.TypeName ); - - /* - char s[256]; - sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib); - OutputDebugStringA(s); - */ - - pair.Attrib = attrib; - _attribMap.Insert(insertPos, pair); - // if (typeName) *typeName = pair.TypeName; - return pair.IconIndex; + if (_attribMap.Size() < (1u << 16) // we limit cache size + || attrib < (1u << 15)) // we want to put all items with basic attribs to cache + { + /* + char s[256]; + sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib); + OutputDebugStringA(s); + */ + pair.Attrib = attrib; + _attribMap.Insert(insertPos, pair); + // if (typeName) *typeName = pair.TypeName; + return pair.IconIndex; + } + if (pair.IconIndex >= 0) + return pair.IconIndex; + attrib = (attrib & FILE_ATTRIBUTE_DIRECTORY) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; } + CObjectVector &map = + (attrib & FILE_ATTRIBUTE_COMPRESSED) ? + _extMap_Compressed : _extMap_Normal; const wchar_t *ext = fileName + dotPos + 1; unsigned insertPos = 0; - const int index = FindInSorted_Ext(_extMap, ext, insertPos); + const int index = FindInSorted_Ext(map, ext, insertPos); if (index >= 0) { - const CExtIconPair &pa = _extMap[index]; + const CExtIconPair &pa = map[index]; // if (typeName) *typeName = pa.TypeName; return pa.IconIndex; } @@ -238,14 +301,14 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin } if (i != 0 && ext[i] == 0) { - // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003 + // Shell_GetFileInfo_SysIconIndex_for_Path is too slow for big number of split extensions: .001, .002, .003 if (!SplitIconIndex_Defined) { - GetRealIconIndex( + Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( #ifdef UNDER_CE FTEXT("\\") #endif - FTEXT("__FILE__.001"), 0, SplitIconIndex); + FTEXT("__FILE__.001"), FILE_ATTRIBUTE_ARCHIVE, SplitIconIndex); SplitIconIndex_Defined = true; } return SplitIconIndex; @@ -253,27 +316,36 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin CExtIconPair pair; pair.Ext = ext; - GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex); - _extMap.Insert(insertPos, pair); + pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( + us2fs(fileName + dotPos), + attrib & FILE_ATTRIBUTE_COMPRESSED ? + FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED: + FILE_ATTRIBUTE_ARCHIVE); + if (map.Size() < (1u << 16) // we limit cache size + // || DoItemAlwaysStart(fileName + dotPos) // we want some popular extensions in cache + ) + map.Insert(insertPos, pair); // if (typeName) *typeName = pair.TypeName; return pair.IconIndex; } -/* -int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName) -{ - return GetIconIndex(attrib, fileName, NULL); -} -*/ -HIMAGELIST GetSysImageList(bool smallIcons) +HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons) { - SHFILEINFO shellInfo; - return (HIMAGELIST)SHGetFileInfo(TEXT(""), - FILE_ATTRIBUTE_NORMAL | + SHFILEINFO shFileInfo; + // shFileInfo.hIcon = NULL; // optional + const DWORD_PTR res = SHGetFileInfo(TEXT(""), + /* FILE_ATTRIBUTE_ARCHIVE | */ FILE_ATTRIBUTE_DIRECTORY, - &shellInfo, sizeof(shellInfo), + &shFileInfo, sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | - (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON)); + (smallIcons ? SHGFI_SMALLICON : SHGFI_LARGEICON)); +#if 0 + // (shFileInfo.hIcon == NULL), because we don't use SHGFI_ICON. + // so DestroyIcon() is not required + if (res && shFileInfo.hIcon) // unexpected + DestroyIcon(shFileInfo.hIcon); +#endif + return (HIMAGELIST)res; } diff --git a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.h b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.h index 3d103f269..b55082088 100644 --- a/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.h +++ b/NanaZip.Core/SevenZip/CPP/7zip/UI/FileManager/SysIconUtils.h @@ -14,7 +14,6 @@ struct CExtIconPair UString Ext; int IconIndex; // UString TypeName; - // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); } }; @@ -23,15 +22,15 @@ struct CAttribIconPair DWORD Attrib; int IconIndex; // UString TypeName; - // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); } }; -class CExtToIconMap + +struct CExtToIconMap { -public: CRecordVector _attribMap; - CObjectVector _extMap; + CObjectVector _extMap_Normal; + CObjectVector _extMap_Compressed; int SplitIconIndex; int SplitIconIndex_Defined; @@ -40,16 +39,27 @@ class CExtToIconMap void Clear() { SplitIconIndex_Defined = false; - _extMap.Clear(); + _extMap_Normal.Clear(); + _extMap_Compressed.Clear(); _attribMap.Clear(); } + int GetIconIndex_DIR(DWORD attrib = FILE_ATTRIBUTE_DIRECTORY) + { + return GetIconIndex(attrib, L"__DIR__"); + } int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */); - // int GetIconIndex(DWORD attrib, const UString &fileName); }; -DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex); -int GetIconIndexForCSIDL(int csidl); +extern CExtToIconMap g_Ext_to_Icon_Map; + +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + CFSTR path, DWORD attrib, int &iconIndex); +HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + CFSTR path, DWORD attrib, Int32 *iconIndex); +int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib); + +int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl); -HIMAGELIST GetSysImageList(bool smallIcons); +HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons); #endif