diff --git a/C/7zVersion.h b/C/7zVersion.h index 9a335a0..1ddef80 100644 --- a/C/7zVersion.h +++ b/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/C/CpuArch.c b/C/CpuArch.c index c131a68..e792f39 100644 --- a/C/CpuArch.c +++ b/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/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 305173b..df22995 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/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/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 23a1db6..4c291c4 100644 --- a/CPP/7zip/Archive/GptHandler.cpp +++ b/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/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 0cab820..8a0ff05 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/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/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp index 5a80daa..b072880 100644 --- a/CPP/7zip/Archive/QcowHandler.cpp +++ b/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/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp index b786f3e..34615c2 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/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/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index b2742b7..bc047b7 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/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/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 87a2df4..e1ca846 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -3713,7 +3713,7 @@ HRESULT Bench( } */ - bool ramSize_Defined = NSystem::GetRamSize(ramSize); + const bool ramSize_Defined = NSystem::GetRamSize(ramSize); UInt32 numThreadsSpecified = numCPUs; bool needSetComplexity = false; @@ -4002,16 +4002,29 @@ HRESULT Bench( } } - if (numThreadsSpecified >= 2) if (printCallback || freqCallback) + for (unsigned test = 0; test < 3; test++) { + if (numThreadsSpecified < 2) + { + // if (test == 1) + break; + } + if (test == 2 && numThreadsSpecified <= numCPUs) + break; if (printCallback) printCallback->NewLine(); - /* it can show incorrect frequency for HT threads. - so we reduce freq test to (numCPUs / 2) */ + /* it can show incorrect frequency for HT threads. */ - UInt32 numThreads = (numThreadsSpecified >= numCPUs / 2 ? numCPUs / 2 : numThreadsSpecified); + UInt32 numThreads = numThreadsSpecified; + if (test < 2) + { + if (numThreads >= numCPUs) + numThreads = numCPUs; + if (test == 0) + numThreads /= 2; + } if (numThreads < 1) numThreads = 1; diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index 0b1357f..d73680b 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/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/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index 978630e..ed48605 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -1606,7 +1606,23 @@ HRESULT UpdateArchive( if (!MyMoveFile(tempPath, us2fs(arcPath))) { - errorInfo.SetFromLastError("cannot move the file", tempPath); + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = "cannot move the file"; + if (errorInfo.SystemError == ERROR_INVALID_PARAMETER) + { + NFind::CFileInfo fi; + if (fi.Find(tempPath) && + fi.Size > (UInt32)(Int32)-1) + { + // bool isFsDetected = false; + // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected) + { + errorInfo.Message.Add_LF(); + errorInfo.Message += "Archive file size exceeds 4 GB"; + } + } + } + errorInfo.FileNames.Add(tempPath); errorInfo.FileNames.Add(us2fs(arcPath)); return errorInfo.Get_HRESULT_Error(); } diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index 376fbf3..f59d4c1 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/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/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp index d79bab1..fab3493 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp @@ -534,7 +534,8 @@ bool FindExt(const char *p, const UString &name, CStringFinder &finder); bool FindExt(const char *p, const UString &name, CStringFinder &finder) { const int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0 || dotPos == (int)name.Len() - 1) + int len = (int)name.Len() - (dotPos + 1); + if (len == 0 || len > 32 || dotPos < 0) return false; return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1)); } diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp index 446f6de..685ac70 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp @@ -387,8 +387,8 @@ Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged)) return S_OK; } - DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); - bool wasChangedLoc = (waitResult == WAIT_OBJECT_0); + const DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); + const bool wasChangedLoc = (waitResult == WAIT_OBJECT_0); if (wasChangedLoc) { _findChangeNotification.FindNext(); @@ -666,16 +666,10 @@ Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) { const CAltStream &ss = Streams[index]; - *iconIndex = 0; - int iconIndexTemp; - if (GetRealIconIndex(_pathPrefix + us2fs(ss.Name), - 0 // fi.Attrib - , iconIndexTemp) != 0) - { - *iconIndex = iconIndexTemp; - return S_OK; - } - return GetLastError_noZero_HRESULT(); + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + _pathPrefix + us2fs(ss.Name), + FILE_ATTRIBUTE_ARCHIVE, + iconIndex); } /* diff --git a/CPP/7zip/UI/FileManager/App.cpp b/CPP/7zip/UI/FileManager/App.cpp index d049fc9..06c2e8b 100644 --- a/CPP/7zip/UI/FileManager/App.cpp +++ b/CPP/7zip/UI/FileManager/App.cpp @@ -782,6 +782,7 @@ void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex) if (useSrcPanel) { CCopyToOptions options; + // options.src_Is_IO_FS_Folder = useFullItemPaths; options.folder = useTemp ? fs2us(tempDirPrefix) : destPath; options.moveMode = move; options.includeAltStreams = true; diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/CPP/7zip/UI/FileManager/BrowseDialog.cpp index 6464ed8..b12d8e8 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.cpp +++ b/CPP/7zip/UI/FileManager/BrowseDialog.cpp @@ -208,8 +208,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); @@ -690,19 +690,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/CPP/7zip/UI/FileManager/BrowseDialog2.cpp b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp index 4bb8a34..ee98ab4 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog2.cpp +++ b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp @@ -356,8 +356,8 @@ bool CBrowseDialog2::OnInit() #endif } - _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); unsigned columnIndex = 0; _list.InsertColumn(columnIndex++, LangString(IDS_PROP_NAME), 100); @@ -1639,15 +1639,15 @@ HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &s #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]; { @@ -1662,7 +1662,6 @@ HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &s ); _list.SetSubItem(index, subItem++, s); } - { s[0] = 0; Browse_ConvertSizeToString(bi, s); diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp index 093534b..6ec6065 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/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/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h index daef5ec..5c459aa 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/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/CPP/7zip/UI/FileManager/FSDrives.cpp b/CPP/7zip/UI/FileManager/FSDrives.cpp index 19d0814..70354c7 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.cpp +++ b/CPP/7zip/UI/FileManager/FSDrives.cpp @@ -45,7 +45,8 @@ struct CPhysTempBuffer ~CPhysTempBuffer() { MidFree(buffer); } }; -static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt64 fileSize, +static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, + bool writeToDisk, UInt64 fileSize, UInt32 bufferSize, UInt64 progressStart, IProgress *progress) { NIO::CInFile inFile; @@ -74,9 +75,11 @@ static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt for (UInt64 pos = 0; pos < fileSize;) { - UInt64 progressCur = progressStart + pos; - RINOK(progress->SetCompleted(&progressCur)) - UInt64 rem = fileSize - pos; + { + const UInt64 progressCur = progressStart + pos; + RINOK(progress->SetCompleted(&progressCur)) + } + const UInt64 rem = fileSize - pos; UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize); UInt32 processedSize; if (!inFile.Read(tempBuffer.buffer, curSize, processedSize)) @@ -91,7 +94,6 @@ static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt if (curSize > bufferSize) return E_FAIL; } - if (!outFile.Write(tempBuffer.buffer, curSize, processedSize)) return GetLastError_noZero_HRESULT(); if (curSize != processedSize) @@ -135,9 +137,7 @@ Z7_COM7F_IMF(CFSDrives::LoadItems()) FOR_VECTOR (i, driveStrings) { CDriveInfo di; - const FString &driveName = driveStrings[i]; - di.FullSystemName = driveName; if (!driveName.IsEmpty()) di.Name.SetFrom(driveName, driveName.Len() - 1); @@ -183,25 +183,24 @@ Z7_COM7F_IMF(CFSDrives::LoadItems()) { FString name ("PhysicalDrive"); name.Add_UInt32(n); - FString fullPath (kVolPrefix); fullPath += name; - CFileInfo fi; if (!fi.Find(fullPath)) continue; CDriveInfo di; di.Name = name; - di.FullSystemName = fullPath; + // if (_volumeMode == true) we use CDriveInfo::FullSystemName only in GetSystemIconIndex(). + // And we need name without "\\\\.\\" prefix in GetSystemIconIndex(). + // So we don't set di.FullSystemName = fullPath; + di.FullSystemName = name; di.ClusterSize = 0; di.DriveSize = fi.Size; di.FreeSpace = 0; di.DriveType = 0; - di.IsPhysicalDrive = true; di.KnownSize = true; - _drives.Add(di); } } @@ -217,7 +216,7 @@ Z7_COM7F_IMF(CFSDrives::GetNumberOfItems(UInt32 *numItems)) Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) { - if (itemIndex >= (UInt32)_drives.Size()) + if (itemIndex >= _drives.Size()) return E_INVALIDARG; NCOM::CPropVariant prop; const CDriveInfo &di = _drives[itemIndex]; @@ -268,7 +267,7 @@ HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder) Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) { *resultFolder = NULL; - if (index >= (UInt32)_drives.Size()) + if (index >= _drives.Size()) return E_INVALIDARG; const CDriveInfo &di = _drives[index]; /* @@ -322,17 +321,14 @@ Z7_COM7F_IMF(CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value)) Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) { - *iconIndex = 0; + *iconIndex = -1; const CDriveInfo &di = _drives[index]; - if (di.IsPhysicalDrive) - return S_OK; - int iconIndexTemp; - if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0) - { - *iconIndex = iconIndexTemp; - return S_OK; - } - return GetLastError_noZero_HRESULT(); + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + di.FullSystemName, + _volumeMode ? + FILE_ATTRIBUTE_ARCHIVE: + FILE_ATTRIBUTE_DIRECTORY, + iconIndex); } void CFSDrives::AddExt(FString &s, unsigned index) const @@ -393,10 +389,8 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num { if (numItems == 0) return S_OK; - if (moveMode) return E_NOTIMPL; - if (!_volumeMode) return E_NOTIMPL; @@ -411,12 +405,12 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num RINOK(callback->SetTotal(totalSize)) RINOK(callback->SetNumFiles(numItems)) - FString destPath = us2fs(path); + const FString destPath = us2fs(path); if (destPath.IsEmpty()) return E_INVALIDARG; - bool isAltDest = NName::IsAltPathPrefix(destPath); - bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); + const bool isAltDest = NName::IsAltPathPrefix(destPath); + const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); if (isDirectPath) { @@ -428,7 +422,7 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num RINOK(callback->SetCompleted(&completedSize)) for (i = 0; i < numItems; i++) { - unsigned index = indices[i]; + const unsigned index = indices[i]; const CDriveInfo &di = _drives[index]; FString destPath2 = destPath; @@ -443,7 +437,7 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num destPath2 += destName; } - FString srcPath = di.GetDeviceFileIoName(); + const FString srcPath = di.GetDeviceFileIoName(); UInt64 fileSize = 0; if (GetFileSize(index, fileSize) != S_OK) diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp index 26a2ccf..7956d86 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -535,7 +535,7 @@ Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { NCOM::CPropVariant prop; /* - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) { CAltStream &ss = Streams[index - Files.Size()]; CDirItem &fi = Files[ss.Parent]; @@ -561,7 +561,7 @@ Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va case kpidComment: break; default: index = ss.Parent; } - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) { prop.Detach(value); return S_OK; @@ -716,8 +716,8 @@ Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPI /* const CAltStream *ss1 = NULL; const CAltStream *ss2 = NULL; - if (index1 >= (UInt32)Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; } - if (index2 >= (UInt32)Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; } + if (index1 >= Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; } + if (index2 >= Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; } */ CDirItem &fi1 = Files[index1]; CDirItem &fi2 = Files[index2]; @@ -1034,7 +1034,7 @@ Z7_COM7F_IMF(CFSFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgr Z7_COM7F_IMF(CFSFolder::CalcItemFullSize(UInt32 index, IProgress *progress)) { - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) return S_OK; CDirItem &fi = Files[index]; if (!fi.IsDir()) @@ -1080,7 +1080,7 @@ Z7_COM7F_IMF(CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress Z7_COM7F_IMF(CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */)) { - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) return E_NOTIMPL; const CDirItem &fi = Files[index]; // FString prefix; @@ -1103,9 +1103,9 @@ Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress UInt32 index = indices[i]; bool result = true; /* - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) { - const CAltStream &ss = Streams[index - (UInt32)Files.Size()]; + const CAltStream &ss = Streams[index - Files.Size()]; if (prevDeletedFileIndex != ss.Parent) { const CDirItem &fi = Files[ss.Parent]; @@ -1134,7 +1134,7 @@ Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress * /* progress */)) { - if (index >= (UInt32)Files.Size()) + if (index >= Files.Size()) return E_INVALIDARG; CDirItem &fi = Files[index]; if (fi.Parent >= 0) @@ -1172,17 +1172,12 @@ Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID, Z7_COM7F_IMF(CFSFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) { - if (index >= (UInt32)Files.Size()) + *iconIndex = -1; + if (index >= Files.Size()) return E_INVALIDARG; const CDirItem &fi = Files[index]; - *iconIndex = 0; - int iconIndexTemp; - if (GetRealIconIndex(_path + GetRelPath(fi), fi.Attrib, iconIndexTemp) != 0) - { - *iconIndex = iconIndexTemp; - return S_OK; - } - return GetLastError_noZero_HRESULT(); + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + _path + GetRelPath(fi), fi.Attrib, iconIndex); } Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode)) diff --git a/CPP/7zip/UI/FileManager/FSFolder.h b/CPP/7zip/UI/FileManager/FSFolder.h index fe8538a..e2edf5f 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.h +++ b/CPP/7zip/UI/FileManager/FSFolder.h @@ -22,11 +22,11 @@ class CFSFolder; struct CDirItem: public NWindows::NFile::NFind::CFileInfo { - #ifndef UNDER_CE +#ifndef UNDER_CE UInt64 PackSize; - #endif +#endif - #ifdef FS_SHOW_LINKS_INFO +#ifdef FS_SHOW_LINKS_INFO FILETIME ChangeTime; UInt64 FileIndex; UInt32 NumLinks; @@ -34,22 +34,21 @@ struct CDirItem: public NWindows::NFile::NFind::CFileInfo bool FileInfo_WasRequested; bool ChangeTime_Defined; bool ChangeTime_WasRequested; - #endif +#endif - #ifndef UNDER_CE +#ifndef UNDER_CE bool PackSize_Defined; - #endif +#endif bool FolderStat_Defined; + int Parent; - #ifndef UNDER_CE +#ifndef UNDER_CE CByteBuffer Reparse; - #endif +#endif UInt64 NumFolders; UInt64 NumFiles; - - int Parent; }; /* @@ -126,20 +125,18 @@ class CFSFolder Z7_final: Z7_IFACE_COM7_IMP(IFolderSetFlatMode) // Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode) -private: + bool _flatMode; + bool _commentsAreLoaded; + // bool _scanAltStreams; + FString _path; - CObjectVector Files; FStringVector Folders; // CObjectVector Streams; // CMyComPtr _parentFolder; - bool _commentsAreLoaded; CPairsStorage _comments; - // bool _scanAltStreams; - bool _flatMode; - #ifdef _WIN32 NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; #endif @@ -163,9 +160,11 @@ class CFSFolder Z7_final: HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); } #endif - CFSFolder() : _flatMode(false) + CFSFolder(): + _flatMode(false), + _commentsAreLoaded(false) // , _scanAltStreams(false) - {} + {} void GetFullPath(const CDirItem &item, FString &path) const { diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp index 67499fc..3582be0 100644 --- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp +++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp @@ -515,8 +515,22 @@ static HRESULT CopyFile_Ask( RINOK(state.ProgressInfo.ProgressResult) if (!res) { + const DWORD errorCode = GetLastError(); + UString errorMessage = NError::MyFormatMessage(Return_LastError_or_FAIL()); + if (errorCode == ERROR_INVALID_PARAMETER) + { + NFind::CFileInfo fi; + if (fi.Find(srcPath) && + fi.Size > (UInt32)(Int32)-1) + { + // bool isFsDetected = false; + // if (NSystem::Is_File_LimitedBy_4GB(destPathNew, isFsDetected) || !isFsDetected) + errorMessage += " File size exceeds 4 GB"; + } + } + // GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL. - RINOK(SendMessageError(state.Callback, GetLastErrorMessage(), destPathNew)) + RINOK(SendMessageError(state.Callback, errorMessage, destPathNew)) return E_ABORT; } state.ProgressInfo.StartPos += state.ProgressInfo.FileSize; diff --git a/CPP/7zip/UI/FileManager/NetFolder.cpp b/CPP/7zip/UI/FileManager/NetFolder.cpp index 879f1db..e91e67f 100644 --- a/CPP/7zip/UI/FileManager/NetFolder.cpp +++ b/CPP/7zip/UI/FileManager/NetFolder.cpp @@ -254,28 +254,23 @@ Z7_COM7F_IMF(CNetFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) { - if (index >= (UInt32)_items.Size()) + *iconIndex = -1; + if (index >= _items.Size()) return E_INVALIDARG; - *iconIndex = 0; const CResourceW &resource = _items[index]; - int iconIndexTemp; if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER || resource.Usage == RESOURCEUSAGE_CONNECTABLE) { - if (GetRealIconIndex(us2fs(resource.RemoteName), 0, iconIndexTemp)) - { - *iconIndex = iconIndexTemp; - return S_OK; - } + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + us2fs(resource.RemoteName), FILE_ATTRIBUTE_DIRECTORY, iconIndex); } else { - if (GetRealIconIndex(FTEXT(""), FILE_ATTRIBUTE_DIRECTORY, iconIndexTemp)) - { - *iconIndex = iconIndexTemp; - return S_OK; - } - // *anIconIndex = GetRealIconIndex(0, L"\\\\HOME"); +#if 0 + return S_FALSE; +#else + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + FTEXT("__DIR__"), FILE_ATTRIBUTE_DIRECTORY, iconIndex); +#endif } - return GetLastError_noZero_HRESULT(); } diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp index f63277a..b15c702 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp +++ b/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/CPP/7zip/UI/FileManager/OverwriteDialog.h b/CPP/7zip/UI/FileManager/OverwriteDialog.h index a9ca991..9f0801d 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.h +++ b/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/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/CPP/7zip/UI/FileManager/OverwriteDialog.rc index 29f9912..112d5d8 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.rc +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.rc @@ -1,7 +1,7 @@ #include "OverwriteDialogRes.h" #include "../../GuiCommon.rc" -#define xc 280 +#define xc 340 #define yc 200 #undef iconSize @@ -25,11 +25,13 @@ BEGIN LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8 ICON "", IDI_OVERWRITE_OLD_FILE, m, 44, iconSize, iconSize + ICON "", IDI_OVERWRITE_OLD_FILE_2, m, 44 + iconSize, iconSize, iconSize LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8 ICON "", IDI_OVERWRITE_NEW_FILE, m, 114, iconSize, iconSize + ICON "", IDI_OVERWRITE_NEW_FILE_2, m, 114 + iconSize, iconSize, iconSize LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys diff --git a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h index b480ba1..24beb33 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h +++ b/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/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp index cdb5ba4..f3fb38e 100644 --- a/CPP/7zip/UI/FileManager/Panel.cpp +++ b/CPP/7zip/UI/FileManager/Panel.cpp @@ -420,8 +420,8 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) _listView._panel = this; _listView.SetWindowProc(); - _listView.SetImageList(GetSysImageList(true), LVSIL_SMALL); - _listView.SetImageList(GetSysImageList(false), LVSIL_NORMAL); + _listView.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); + _listView.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); // _exStyle |= LVS_EX_HEADERDRAGDROP; // DWORD extendedStyle = _listView.GetExtendedListViewStyle(); @@ -506,17 +506,15 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) #endif , NULL, WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL, - 0, 0, 100, 520, + 0, 0, 100, 620, (_headerReBar ? _headerToolBar : (HWND)*this), (HMENU)(UINT_PTR)(_comboBoxID), g_hInstance, NULL); - #ifndef UNDER_CE - _headerComboBox.SetUnicodeFormat(true); - - _headerComboBox.SetImageList(GetSysImageList(true)); +#ifndef UNDER_CE + _headerComboBox.SetUnicodeFormat(true); + _headerComboBox.SetImageList(Shell_Get_SysImageList_smallIcons(true)); _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC); - /* _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox)); _headerComboBox._panel = this; @@ -525,9 +523,7 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) LONG_PTR(ComboBoxSubclassProc)); */ _comboBoxEdit.Attach(_headerComboBox.GetEditControl()); - // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0); - _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit)); _comboBoxEdit._panel = this; #ifndef _UNICODE @@ -538,8 +534,7 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) #endif _comboBoxEdit._origWindowProc = (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); - - #endif +#endif if (_headerReBar) { diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index 5cbc35d..1b708f7 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h @@ -147,11 +147,11 @@ class CPropColumns: public CObjectVector struct CTempFileInfo { UInt32 FileIndex; // index of file in folder + bool NeedDelete; UString RelPath; // Relative path of file from Folder FString FolderPath; FString FilePath; NWindows::NFile::NFind::CFileInfo FileInfo; - bool NeedDelete; CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {} void DeleteDirAndFile() const @@ -171,15 +171,15 @@ struct CTempFileInfo struct CFolderLink: public CTempFileInfo { + bool IsVirtual; + bool UsePassword; NWindows::NDLL::CLibrary Library; CMyComPtr ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0]) UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level) - bool UsePassword; UString Password; - bool IsVirtual; UString VirtualPath; // without tail slash - CFolderLink(): UsePassword(false), IsVirtual(false) {} + CFolderLink(): IsVirtual(false), UsePassword(false) {} bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const { @@ -310,7 +310,7 @@ struct COpenResult class CPanel Z7_final: public NWindows::NControl::CWindow2 { - CExtToIconMap _extToIconMap; + // CExtToIconMap _extToIconMap; UINT _baseID; unsigned _comboBoxID; UINT _statusBarID; @@ -324,7 +324,7 @@ class CPanel Z7_final: public NWindows::NControl::CWindow2 virtual void OnDestroy() Z7_override; virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result) Z7_override; - void AddComboBoxItem(const UString &name, int iconIndex, int indent, bool addToList); + void AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList); bool OnComboBoxCommand(UINT code, LPARAM param, LRESULT &result); @@ -355,7 +355,7 @@ class CPanel Z7_final: public NWindows::NControl::CWindow2 HWND _mainWindow; CPanelCallback *_panelCallback; - void SysIconsWereChanged() { _extToIconMap.Clear(); } + // void SysIconsWereChanged() { _extToIconMap.Clear(); } void DeleteItems(bool toRecycleBin); void CreateFolder(); diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp index 40a347f..36a0f6d 100644 --- a/CPP/7zip/UI/FileManager/PanelCopy.cpp +++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp @@ -189,7 +189,9 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options, extracter.ExtractCallbackSpec = new CExtractCallbackImp; extracter.ExtractCallback = extracter.ExtractCallbackSpec; - + extracter.ExtractCallbackSpec->Src_Is_IO_FS_Folder = + IsFSFolder() || IsAltStreamsFolder(); + // options.src_Is_IO_FS_Folder; extracter.options = &options; extracter.ExtractCallbackSpec->ProgressDialog = &extracter; extracter.CompressingMode = false; diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp index 406e304..c34cb74 100644 --- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp +++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp @@ -368,14 +368,41 @@ void CPanel::LoadFullPath() _currentFolderPrefix += GetFolderPath(_folder); } -static int GetRealIconIndex(CFSTR path, DWORD attributes) + + +static int GetRealIconIndex_for_DirPath(CFSTR path, DWORD attrib) { + attrib |= FILE_ATTRIBUTE_DIRECTORY; // optional int index = -1; - if (GetRealIconIndex(path, attributes, index) != 0) - return index; - return -1; + if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(path, attrib, index)) + if (index >= 0) + return index; + return g_Ext_to_Icon_Map.GetIconIndex_DIR(attrib); +} + + +extern UString RootFolder_GetName_Computer(int &iconIndex); +extern UString RootFolder_GetName_Network(int &iconIndex); +extern UString RootFolder_GetName_Documents(int &iconIndex); + + +static int Find_FileExtension_DotPos_in_path(const wchar_t *path) +{ + int dotPos = -1; + unsigned i; + for (i = 0;; i++) + { + const wchar_t c = path[i]; + if (c == 0) + return dotPos; + if (c == '.') + dotPos = (int)i; + else if (IS_PATH_SEPAR(c) || c == ':') + dotPos = -1; + } } + void CPanel::LoadFullPathAndShow() { LoadFullPath(); @@ -387,30 +414,97 @@ void CPanel::LoadFullPathAndShow() COMBOBOXEXITEM item; item.mask = 0; + item.iImage = -1; UString path = _currentFolderPrefix; - if (path.Len() > - #ifdef _WIN32 - 3 - #else - 1 - #endif - && IS_PATH_SEPAR(path.Back())) - path.DeleteBack(); - - DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; - - // GetRealIconIndex is slow for direct DVD/UDF path. So we use dummy path - if (path.IsPrefixedBy(L"\\\\.\\")) - path = "_TestFolder_"; - else + // path = "\\\\.\\PhysicalDrive1\\"; // for debug + // path = "\\\\.\\y:\\"; // for debug + if (!path.IsEmpty()) { - CFileInfo fi; - if (fi.Find(us2fs(path))) - attrib = fi.Attrib; + const unsigned rootPrefixSize = NName::GetRootPrefixSize(path); + if (rootPrefixSize == 0 && path[0] != '\\') + { + int iconIndex = -1; + UString name_Computer = RootFolder_GetName_Computer(iconIndex); + name_Computer.Add_PathSepar(); + if (path == name_Computer + || path == L"\\\\?\\") + item.iImage = iconIndex; + else + { + UString name = RootFolder_GetName_Network(iconIndex); + name.Add_PathSepar(); + if (path == name) + item.iImage = iconIndex; + } + } + + if (item.iImage < 0) + { + if (rootPrefixSize == 0 || rootPrefixSize == path.Len()) + { + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + CFileInfo info; + if (info.Find(us2fs(path))) + attrib = info.Attrib; + NName::If_IsSuperPath_RemoveSuperPrefix(path); + item.iImage = GetRealIconIndex_for_DirPath(us2fs(path), attrib); + } + else if (rootPrefixSize == NName::kDevicePathPrefixSize + && NName::IsDevicePath(us2fs(path.Left(path.Len() - 1)))) + { + if (path.IsPrefixedBy_Ascii_NoCase("\\\\.\\")) + path.DeleteFrontal(4); + if (path.Len() > 3) // is not "c:\\" + { + // PhysicalDrive + if (path.Back() == '\\') + path.DeleteBack(); + } + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), FILE_ATTRIBUTE_ARCHIVE); + } + else + { + if (path.Back() == '\\') + path.DeleteBack(); + bool need_Fs_Check = true; + bool is_File = false; + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &link = _parentFolders.Back(); + if (link.VirtualPath == path) + { + is_File = true; + if (_parentFolders.Size() != 1) + need_Fs_Check = false; + } + else + need_Fs_Check = false; + } + if (need_Fs_Check) + { + CFileInfo info; + const bool finded = info.Find(us2fs(path)); + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + if (finded) + attrib = info.Attrib; + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), attrib); + } + if (item.iImage <= 0 && is_File) + { + int dotPos = Find_FileExtension_DotPos_in_path(path); + if (dotPos < 0) + dotPos = (int)path.Len(); + item.iImage = g_Ext_to_Icon_Map.GetIconIndex(FILE_ATTRIBUTE_ARCHIVE, path.Ptr(dotPos)); + } + } + } } - item.iImage = GetRealIconIndex(us2fs(path), attrib); + if (item.iImage < 0) + item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); + // if (item.iImage < 0) item.iImage = 0; + // item.iImage = -1; // for debug if (item.iImage >= 0) { item.iSelectedImage = item.iImage; @@ -495,13 +589,13 @@ bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result) } #endif -void CPanel::AddComboBoxItem(const UString &name, int iconIndex, int indent, bool addToList) +void CPanel::AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList) { #ifdef UNDER_CE UString s; iconIndex = iconIndex; - for (int i = 0; i < indent; i++) + for (unsigned i = 0; i < indent; i++) s += " "; _headerComboBox.AddString(s + name); @@ -509,23 +603,26 @@ void CPanel::AddComboBoxItem(const UString &name, int iconIndex, int indent, boo COMBOBOXEXITEMW item; item.mask = CBEIF_TEXT | CBEIF_INDENT; + if (iconIndex < 0) + iconIndex = g_Ext_to_Icon_Map.GetIconIndex_DIR(); item.iSelectedImage = item.iImage = iconIndex; if (iconIndex >= 0) item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); item.iItem = -1; - item.iIndent = indent; + item.iIndent = (int)indent; item.pszText = name.Ptr_non_const(); _headerComboBox.InsertItem(&item); #endif if (addToList) - ComboBoxPaths.Add(name); + { + UString s = name; + s.Add_PathSepar(); + ComboBoxPaths.Add(s); + } } -extern UString RootFolder_GetName_Computer(int &iconIndex); -extern UString RootFolder_GetName_Network(int &iconIndex); -extern UString RootFolder_GetName_Documents(int &iconIndex); bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) { @@ -537,56 +634,168 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) ComboBoxPaths.Clear(); _headerComboBox.ResetContent(); - unsigned i; + UString sumPath; UStringVector pathParts; - - SplitPathToParts(_currentFolderPrefix, pathParts); - UString sumPass; - if (!pathParts.IsEmpty()) - pathParts.DeleteBack(); - for (i = 0; i < pathParts.Size(); i++) + unsigned indent = 0; { - const UString name = pathParts[i]; - sumPass += name; - sumPass.Add_PathSepar(); - CFileInfo info; - DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; - if (info.Find(us2fs(sumPass))) - attrib = info.Attrib; - AddComboBoxItem( - name.IsEmpty() ? L"\\" : name, - GetRealIconIndex(us2fs(sumPass), attrib), - (int)i, // iIndent - false); // addToList - ComboBoxPaths.Add(sumPass); + UString path = _currentFolderPrefix; + // path = L"\\\\.\\y:\\"; // for debug + UString prefix0; + if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) + { + const int separ = FindCharPosInString(path.Ptr(2), '\\'); + if (separ > 0 + && (separ > 1 || path[2] != '.')) // "\\\\.\\" will be processed later + { + const UString s = path.Left(2 + separ); + prefix0 = s; + prefix0.Add_PathSepar(); + AddComboBoxItem(s, + GetRealIconIndex_for_DirPath(us2fs(prefix0), FILE_ATTRIBUTE_DIRECTORY), + indent++, + false); // addToList + ComboBoxPaths.Add(prefix0); + } + } + + unsigned rootPrefixSize = NName::GetRootPrefixSize(path); + + sumPath = path; + + if (rootPrefixSize <= prefix0.Len()) + { + rootPrefixSize = prefix0.Len(); + sumPath.DeleteFrom(rootPrefixSize); + } + else + { + // rootPrefixSize > prefix0.Len() + sumPath.DeleteFrom(rootPrefixSize); + + CFileInfo info; + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + if (info.Find(us2fs(sumPath)) && info.IsDir()) + attrib = info.Attrib; + UString s = sumPath.Ptr(prefix0.Len()); + if (!s.IsEmpty()) + { + const wchar_t c = s.Back(); + if (IS_PATH_SEPAR(c)) + s.DeleteBack(); + } + UString path_for_icon = sumPath; + NName::If_IsSuperPath_RemoveSuperPrefix(path_for_icon); + + AddComboBoxItem(s, + GetRealIconIndex_for_DirPath(us2fs(path_for_icon), attrib), + indent++, + false); // addToList + ComboBoxPaths.Add(sumPath); + } + + path.DeleteFrontal(rootPrefixSize); + SplitPathToParts(path, pathParts); } - #ifndef UNDER_CE + // it's expected that pathParts.Back() is empty, because _currentFolderPrefix has PathSeparator. + unsigned next_Arc_index = 0; + int iconIndex_Computer; + const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); - int iconIndex; - UString name; - name = RootFolder_GetName_Documents(iconIndex); - AddComboBoxItem(name, iconIndex, 0, true); + // const bool is_devicePrefix = (sumPath == L"\\\\.\\"); - name = RootFolder_GetName_Computer(iconIndex); - AddComboBoxItem(name, iconIndex, 0, true); - - FStringVector driveStrings; - MyGetLogicalDriveStrings(driveStrings); - for (i = 0; i < driveStrings.Size(); i++) + if (pathParts.Size() > 1) + if (!sumPath.IsEmpty() + || pathParts.Size() != 2 + || pathParts[0] != name_Computer) + for (unsigned i = 0; i + 1 < pathParts.Size(); i++) { - FString s = driveStrings[i]; - ComboBoxPaths.Add(fs2us(s)); - int iconIndex2 = GetRealIconIndex(s, 0); - if (s.Len() > 0 && s.Back() == FCHAR_PATH_SEPARATOR) - s.DeleteBack(); - AddComboBoxItem(fs2us(s), iconIndex2, 1, false); + UString name = pathParts[i]; + sumPath += name; + + bool isRootDir_inLink = false; + if (next_Arc_index < _parentFolders.Size()) + { + const CFolderLink &link = _parentFolders[next_Arc_index]; + if (link.VirtualPath == sumPath) + { + isRootDir_inLink = true; + next_Arc_index++; + } + } + + int iconIndex = -1; + DWORD attrib = isRootDir_inLink ? + FILE_ATTRIBUTE_ARCHIVE: + FILE_ATTRIBUTE_DIRECTORY; + if (next_Arc_index == 0 + || (next_Arc_index == 1 && isRootDir_inLink)) + { + if (i == 0 && NName::IsDevicePath(us2fs(sumPath))) + { + UString path = name; + path.Add_PathSepar(); + attrib = FILE_ATTRIBUTE_ARCHIVE; + // FILE_ATTRIBUTE_DIRECTORY; + } + else + { + CFileInfo info; + if (info.Find(us2fs(sumPath))) + attrib = info.Attrib; + } + iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(sumPath), attrib); + } + + if (iconIndex < 0) + iconIndex = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); + // iconIndex = -1; // for debug + if (iconIndex < 0 && isRootDir_inLink) + iconIndex = 0; // default file + + sumPath.Add_PathSepar(); + + ComboBoxPaths.Add(sumPath); + if (name.IsEmpty()) + name.Add_PathSepar(); + AddComboBoxItem(name, iconIndex, indent++, + false); // addToList } - name = RootFolder_GetName_Network(iconIndex); - AddComboBoxItem(name, iconIndex, 0, true); +#ifndef UNDER_CE - #endif + { + int iconIndex; + const UString name = RootFolder_GetName_Documents(iconIndex); + // iconIndex = -1; // for debug + AddComboBoxItem(name, iconIndex, 0, true); + } + AddComboBoxItem(name_Computer, iconIndex_Computer, 0, true); + { + FStringVector driveStrings; + MyGetLogicalDriveStrings(driveStrings); + FOR_VECTOR (i, driveStrings) + { + FString s = driveStrings[i]; + ComboBoxPaths.Add(fs2us(s)); + int iconIndex2 = GetRealIconIndex_for_DirPath(s, FILE_ATTRIBUTE_DIRECTORY); + if (!s.IsEmpty()) + { + const FChar c = s.Back(); + if (IS_PATH_SEPAR(c)) + s.DeleteBack(); + } + // iconIndex2 = -1; // for debug + AddComboBoxItem(fs2us(s), iconIndex2, 1, false); + } + } + { + int iconIndex; + const UString name = RootFolder_GetName_Network(iconIndex); + AddComboBoxItem(name, iconIndex, 0, true); + } + +#endif return false; } @@ -596,10 +805,10 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) int index = _headerComboBox.GetCurSel(); if (index >= 0) { - UString pass = ComboBoxPaths[index]; + const UString path = ComboBoxPaths[index]; _headerComboBox.SetCurSel(-1); - // _headerComboBox.SetText(pass); // it's fix for seclecting by mouse. - if (BindToPathAndRefresh(pass) == S_OK) + // _headerComboBox.SetText(pass); // it's fix for selecting by mouse. + if (BindToPathAndRefresh(path) == S_OK) { PostMsg(kSetFocusToListView); #ifdef UNDER_CE diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp index 2335fc0..544e9bf 100644 --- a/CPP/7zip/UI/FileManager/PanelItems.cpp +++ b/CPP/7zip/UI/FileManager/PanelItems.cpp @@ -583,8 +583,13 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) int cursorIndex = -1; CMyComPtr folderGetSystemIconIndex; +#if 1 // 0 : for debug local icons loading if (!Is_Slow_Icon_Folder() || _showRealFileIcons) _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); +#endif + + const bool isFSDrivesFolder = IsFSDrivesFolder(); + const bool isArcFolder = IsArcFolder(); if (!IsFSFolder()) { @@ -631,10 +636,11 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) #else item.pszText = LPSTR_TEXTCALLBACKW; #endif - const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY; - item.iImage = _extToIconMap.GetIconIndex(attrib, itemName); + // const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY; + item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); + // g_Ext_to_Icon_Map.GetIconIndex(attrib, itemName); if (item.iImage < 0) - item.iImage = 0; + item.iImage = 0; if (_listView.InsertItem(&item) == -1) return E_FAIL; listViewItemCount++; @@ -755,11 +761,52 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) } bool defined = false; + item.iImage = -1; if (folderGetSystemIconIndex) { - folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage); - defined = (item.iImage > 0); + const HRESULT res = folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage); + if (res == S_OK) + { + // item.iImage = -1; // for debug + defined = (item.iImage > 0); +#if 0 // 0: can be slower: 2 attempts for some paths. + // 1: faster, but we can get default icon for some cases (where non default icon is possible) + + if (item.iImage == 0) + { + // (item.iImage == 0) means default icon. + // But (item.iImage == 0) also can be returned for exe/ico files, + // if filePath is LONG PATH (path_len() >= MAX_PATH). + // Also we want to show split icon (.001) for any split extension: 001 002 003. + // Are there another cases for (item.iImage == 0) for files with known extensions? + // We don't want to do second attempt to request icon, + // if it also will return (item.iImage == 0). + + int dotPos = -1; + for (unsigned k = 0;; k++) + { + const wchar_t c = name[k]; + if (c == 0) + break; + if (c == '.') + dotPos = (int)i; + // we don't need IS_PATH_SEPAR check, because we have only (fileName) doesn't include path prefix. + // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; + } + defined = true; + if (dotPos >= 0) + { +#if 0 + const wchar_t *ext = name + dotPos; + if (StringsAreEqualNoCase_Ascii(ext, ".exe") || + StringsAreEqualNoCase_Ascii(ext, ".ico")) +#endif + defined = false; + } + } +#endif + } } if (!defined) @@ -769,26 +816,37 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) NCOM::CPropVariant prop; RINOK(_folder->GetProperty(i, kpidAttrib, &prop)) if (prop.vt == VT_UI4) + { attrib = prop.ulVal; + if (isArcFolder) + { + // if attrib (high 16-bits) is supposed from posix, + // we keep only low bits (basic Windows attrib flags): + if (attrib & 0xF0000000) + attrib &= 0x3FFF; + } + } } if (IsItem_Folder(i)) attrib |= FILE_ATTRIBUTE_DIRECTORY; - - if (_currentFolderPrefix.IsEmpty()) - { - int iconIndexTemp; - GetRealIconIndex(us2fs((UString)name) + FCHAR_PATH_SEPARATOR, attrib, iconIndexTemp); - item.iImage = iconIndexTemp; - } else + attrib &= ~(UInt32)FILE_ATTRIBUTE_DIRECTORY; + + item.iImage = -1; + if (isFSDrivesFolder) { - item.iImage = _extToIconMap.GetIconIndex(attrib, name); + FString fs (us2fs((UString)name)); + fs.Add_PathSepar(); + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(fs, attrib); + // item.iImage = 0; // for debug } + if (item.iImage < 0) // <= 0 check? + item.iImage = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); } + // item.iImage = -1; // for debug if (item.iImage < 0) - item.iImage = 0; - + item.iImage = 0; // default image if (_listView.InsertItem(&item) == -1) return E_FAIL; listViewItemCount++; @@ -858,8 +916,8 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) sprintf(s, // "attribMap = %5d, extMap = %5d, " "delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d", - // _extToIconMap._attribMap.Size(), - // _extToIconMap._extMap.Size(), + // g_Ext_to_Icon_Map._attribMap.Size(), + // g_Ext_to_Icon_Map._extMap.Size(), tickCount1 - tickCount0, tickCount2 - tickCount1, tickCount3 - tickCount2, diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp index 606fb7f..192f660 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.cpp +++ b/CPP/7zip/UI/FileManager/RootFolder.cpp @@ -54,9 +54,9 @@ UString RootFolder_GetName_Computer(int &iconIndex); UString RootFolder_GetName_Computer(int &iconIndex) { #ifdef USE_WIN_PATHS - iconIndex = GetIconIndexForCSIDL(CSIDL_DRIVES); + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); #else - GetRealIconIndex(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, iconIndex); + iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY); #endif return LangString(IDS_COMPUTER); } @@ -64,14 +64,14 @@ UString RootFolder_GetName_Computer(int &iconIndex) UString RootFolder_GetName_Network(int &iconIndex); UString RootFolder_GetName_Network(int &iconIndex) { - iconIndex = GetIconIndexForCSIDL(CSIDL_NETWORK); + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_NETWORK); return LangString(IDS_NETWORK); } UString RootFolder_GetName_Documents(int &iconIndex); UString RootFolder_GetName_Documents(int &iconIndex) { - iconIndex = GetIconIndexForCSIDL(CSIDL_PERSONAL); + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_PERSONAL); return LangString(IDS_DOCUMENTS); } @@ -96,7 +96,7 @@ void CRootFolder::Init() _names[ROOT_INDEX_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]); _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]); _names[ROOT_INDEX_VOLUMES] = kVolPrefix; - _iconIndices[ROOT_INDEX_VOLUMES] = GetIconIndexForCSIDL(CSIDL_DRIVES); + _iconIndices[ROOT_INDEX_VOLUMES] = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); #endif } diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp index c893ea9..406c9e1 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/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/CPP/7zip/UI/FileManager/SysIconUtils.h b/CPP/7zip/UI/FileManager/SysIconUtils.h index 1d34ef6..975ce25 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.h +++ b/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 diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp index f1353b8..c1ca643 100644 --- a/CPP/7zip/UI/FileManager/VerCtrl.cpp +++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp @@ -387,13 +387,13 @@ void CApp::VerCtrl(unsigned id) */ COverwriteDialog dialog; - dialog.OldFileInfo.SetTime(&fdi.Info.ftLastWriteTime); + dialog.OldFileInfo.SetTime(fdi.Info.ftLastWriteTime); dialog.OldFileInfo.SetSize(fdi.GetSize()); - dialog.OldFileInfo.Name = fs2us(path); + dialog.OldFileInfo.Path = fs2us(path); - dialog.NewFileInfo.SetTime(&fdi2.Info.ftLastWriteTime); + dialog.NewFileInfo.SetTime(fdi2.Info.ftLastWriteTime); dialog.NewFileInfo.SetSize(fdi2.GetSize()); - dialog.NewFileInfo.Name = fs2us(path2); + dialog.NewFileInfo.Path = fs2us(path2); dialog.ShowExtraButtons = false; dialog.DefaultButton_is_NO = true; diff --git a/CPP/7zip/UI/GUI/HashGUI.cpp b/CPP/7zip/UI/GUI/HashGUI.cpp index b96e413..231bab5 100644 --- a/CPP/7zip/UI/GUI/HashGUI.cpp +++ b/CPP/7zip/UI/GUI/HashGUI.cpp @@ -66,28 +66,6 @@ void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) } -void AddSizeValue(UString &s, UInt64 value) -{ - { - 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 += (wchar_t)c; - s += "iB)"; - } -} - void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) { CProperty &pair = pairs.AddNew(); diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp index d11f02e..b402306 100644 --- a/CPP/Windows/FileSystem.cpp +++ b/CPP/Windows/FileSystem.cpp @@ -157,6 +157,31 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, #endif +/* +bool Is_File_LimitedBy_4GB(CFSTR _path, bool &isFsDetected) +{ + isFsDetected = false; + FString path (_path); + path.DeleteFrom(NName::GetRootPrefixSize(path)); + // GetVolumeInformation supports super paths. + // NName::If_IsSuperPath_RemoveSuperPrefix(path); + if (!path.IsEmpty()) + { + DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags; + UString volName, fileSystemName; + if (MyGetVolumeInformation(path, volName, + &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags, + fileSystemName)) + { + isFsDetected = true; + if (fileSystemName.IsPrefixedBy_Ascii_NoCase("fat")) + return true; + } + } + return false; +} +*/ + }}} #endif diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp index d23e84b..cfc6a90 100644 --- a/CPP/Windows/SystemInfo.cpp +++ b/CPP/Windows/SystemInfo.cpp @@ -5,6 +5,7 @@ #include "../../C/CpuArch.h" #include "../Common/IntToString.h" +#include "../Common/StringConvert.h" #ifdef _WIN32 @@ -511,8 +512,6 @@ void GetSysInfo(AString &s1, AString &s2) } -void GetCpuName(AString &s); - static void AddBracedString(AString &dest, AString &src) { if (!src.IsEmpty()) @@ -554,9 +553,7 @@ void CCpuName::Fill() #ifdef MY_CPU_X86_OR_AMD64 { #if !defined(MY_CPU_AMD64) - if (!z7_x86_cpuid_GetMaxFunc()) - s += "x86"; - else + if (z7_x86_cpuid_GetMaxFunc()) #endif { x86cpuid_to_String(s); @@ -583,43 +580,26 @@ void CCpuName::Fill() #endif - if (s.IsEmpty()) - { - #ifdef MY_CPU_LE - s += "LE"; - #elif defined(MY_CPU_BE) - s += "BE"; - #endif - } - - #ifdef __APPLE__ - { - AString s2; - UInt32 v = 0; - if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) - { - s2.Add_UInt32(v); - s2 += 'C'; - } - if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) - { - s2.Add_UInt32(v); - s2 += 'T'; - } - if (!s2.IsEmpty()) - { - s.Add_Space_if_NotEmpty(); - s += s2; - } - } - #endif - - - #ifdef _WIN32 +#ifdef _WIN32 { NRegistry::CKey key; if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) { + // s.Empty(); // for debug + { + CSysString name; + if (s.IsEmpty()) + if (key.QueryValue(TEXT("ProcessorNameString"), name) == ERROR_SUCCESS) + { + s += GetAnsiString(name); + } + if (key.QueryValue(TEXT("Identifier"), name) == ERROR_SUCCESS) + { + if (!Revision.IsEmpty()) + Revision += " : "; + Revision += GetAnsiString(name); + } + } LONG res[2]; CByteBuffer bufs[2]; { @@ -627,8 +607,9 @@ void CCpuName::Fill() { UInt32 size = 0; res[i] = key.QueryValue(i == 0 ? - TEXT("Previous Update Revision") : - TEXT("Update Revision"), bufs[i], size); + TEXT("Previous Update Revision") : + TEXT("Update Revision"), + bufs[i], size); if (res[i] == ERROR_SUCCESS) if (size != bufs[i].Size()) res[i] = ERROR_SUCCESS + 1; @@ -657,8 +638,36 @@ void CCpuName::Fill() } } } - #endif +#endif + if (s.IsEmpty()) + { + #ifdef MY_CPU_NAME + s += MY_CPU_NAME; + #endif + } + + #ifdef __APPLE__ + { + AString s2; + UInt32 v = 0; + if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) + { + s2.Add_UInt32(v); + s2.Add_Char('C'); + } + if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) + { + s2.Add_UInt32(v); + s2.Add_Char('T'); + } + if (!s2.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += s2; + } + } + #endif #ifdef Z7_LARGE_PAGES Add_LargePages_String(LargePages); @@ -900,7 +909,7 @@ void GetSystemInfoText(AString &sRes) } { AString s; - GetCpuName(s); + GetCpuName_MultiLine(s); if (!s.IsEmpty()) { sRes += s; @@ -923,18 +932,6 @@ void GetSystemInfoText(AString &sRes) } -void GetCpuName(AString &s); -void GetCpuName(AString &s) -{ - CCpuName cpuName; - cpuName.Fill(); - s = cpuName.CpuName; - AString s2; - cpuName.Get_Revision_Microcode_LargePages(s2); - s.Add_OptSpaced(s2); -} - - void GetCpuName_MultiLine(AString &s); void GetCpuName_MultiLine(AString &s) { diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index f3fba10..f41b393 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,7 +1,7 @@ - + diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 2d0ba98..1653c07 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt @@ -1,6 +1,17 @@ HISTORY of the 7-Zip source code -------------------------------- +24.08 2024-08-11 +------------------------- +- The bug in 7-Zip 24.00-24.07 was fixed: + For creating a zip archive: 7-Zip could write extra zero bytes after the end of the archive, + if a file included to archive cannot be compressed to a size smaller than original. + The created zip archive is correct except for the useless zero bytes after the end of the archive. + When unpacking such a zip archive, 7-Zip displays a warning: + "WARNING: There are data after the end of archive". +- Some bugs were fixed. + + 24.07 2024-06-19 ------------------------- - Changes in files: