This commit is contained in:
Igor Pavlov 2024-08-11 00:00:00 +00:00
parent a7a1d4a241
commit e008ce3976
42 changed files with 1567 additions and 799 deletions

View file

@ -1,7 +1,7 @@
#define MY_VER_MAJOR 24 #define MY_VER_MAJOR 24
#define MY_VER_MINOR 07 #define MY_VER_MINOR 8
#define MY_VER_BUILD 0 #define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "24.07" #define MY_VERSION_NUMBERS "24.08"
#define MY_VERSION MY_VERSION_NUMBERS #define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME #ifdef MY_CPU_NAME
@ -10,7 +10,7 @@
#define MY_VERSION_CPU MY_VERSION #define MY_VERSION_CPU MY_VERSION
#endif #endif
#define MY_DATE "2024-06-19" #define MY_DATE "2024-08-11"
#undef MY_COPYRIGHT #undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE #undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov" #define MY_AUTHOR_NAME "Igor Pavlov"

View file

@ -1,5 +1,5 @@
/* CpuArch.c -- CPU specific code /* CpuArch.c -- CPU specific code
2024-05-18 : Igor Pavlov : Public domain */ 2024-07-04 : Igor Pavlov : Public domain */
#include "Precomp.h" #include "Precomp.h"
@ -848,7 +848,11 @@ static unsigned long MY_getauxval(int aux)
#define MY_HWCAP_CHECK_FUNC(name) \ #define MY_HWCAP_CHECK_FUNC(name) \
BoolInt CPU_IsSupported_ ## name(void) { return 0; } BoolInt CPU_IsSupported_ ## name(void) { return 0; }
#if defined(__ARM_NEON)
BoolInt CPU_IsSupported_NEON(void) { return True; }
#else
MY_HWCAP_CHECK_FUNC(NEON) MY_HWCAP_CHECK_FUNC(NEON)
#endif
#endif // USE_HWCAP #endif // USE_HWCAP

View file

@ -628,6 +628,7 @@ static const char * const g_Machines[] =
static const CUInt32PCharPair g_MachinePairs[] = static const CUInt32PCharPair g_MachinePairs[] =
{ {
{ 243, "RISC-V" }, { 243, "RISC-V" },
{ 258, "LoongArch" },
{ 0x9026, "Alpha" }, // EM_ALPHA_EXP, obsolete, (used by NetBSD/alpha) (written in the absence of an ABI) { 0x9026, "Alpha" }, // EM_ALPHA_EXP, obsolete, (used by NetBSD/alpha) (written in the absence of an ABI)
{ 0xbaab, "Xilinx MicroBlaze" } { 0xbaab, "Xilinx MicroBlaze" }
}; };
@ -853,10 +854,9 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
else if (_header.Machine == k_Machine_MIPS) else if (_header.Machine == k_Machine_MIPS)
{ {
const UInt32 ver = flags >> 28; const UInt32 ver = flags >> 28;
s += "v"; s.Add_Char('v');
s.Add_UInt32(ver); s.Add_UInt32(ver);
flags &= ((UInt32)1 << 28) - 1; flags &= ((UInt32)1 << 28) - 1;
const UInt32 abi = (flags >> 12) & 7; const UInt32 abi = (flags >> 12) & 7;
if (abi) if (abi)
{ {
@ -864,7 +864,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
s.Add_UInt32(abi); s.Add_UInt32(abi);
} }
flags &= ~((UInt32)7 << 12); flags &= ~((UInt32)7 << 12);
s.Add_Space(); s.Add_Space();
s += FlagsToString(g_MIPS_Flags, Z7_ARRAY_SIZE(g_MIPS_Flags), flags); 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; flags &= ~(UInt32)6;
s += FlagsToString(g_RISCV_Flags, Z7_ARRAY_SIZE(g_RISCV_Flags), flags); 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 else
{ {
char sz[16]; char sz[16];

View file

@ -111,6 +111,12 @@ static const CPartType kPartTypes[] =
{ 0x0FC63DAF, NULL, "Linux Data" }, { 0x0FC63DAF, NULL, "Linux Data" },
{ 0x0657FD6D, NULL, "Linux Swap" }, { 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" }, { 0x83BD6B9D, NULL, "FreeBSD Boot" },
{ 0x516E7CB4, NULL, "FreeBSD Data" }, { 0x516E7CB4, NULL, "FreeBSD Data" },

View file

@ -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 enum
{ {
kDirLink_EXCEPTION = 3,
kDirLink_Certificate = 4, kDirLink_Certificate = 4,
kDirLink_BASERELOC = 5,
kDirLink_Debug = 6 kDirLink_Debug = 6
}; };
@ -229,7 +252,7 @@ struct COptHeader
UInt32 UninitDataSize; UInt32 UninitDataSize;
// UInt32 AddressOfEntryPoint; // UInt32 AddressOfEntryPoint;
// UInt32 BaseOfCode; // UInt32 BaseOfCode; // VA(.text) == 0x1000 in most cases
// UInt32 BaseOfData32; // UInt32 BaseOfData32;
UInt64 ImageBase; UInt64 ImageBase;
@ -273,6 +296,7 @@ struct COptHeader
} }
}; };
// size is 16-bit
bool COptHeader::Parse(const Byte *p, UInt32 size) bool COptHeader::Parse(const Byte *p, UInt32 size)
{ {
if (size < k_OptHeader32_Size_MIN) if (size < k_OptHeader32_Size_MIN)
@ -334,14 +358,18 @@ bool COptHeader::Parse(const Byte *p, UInt32 size)
pos = 92; pos = 92;
} }
G32(pos, NumDirItems); UInt32 numDirItems;
if (NumDirItems > (1 << 16)) G32(pos, numDirItems);
NumDirItems = numDirItems;
if (numDirItems > (1 << 13))
return false; return false;
pos += 4; pos += 4;
if (pos + 8 * NumDirItems > size) if (pos + 8 * numDirItems > size)
return false; return false;
memset((void *)DirItems, 0, sizeof(DirItems)); 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); DirItems[i].Parse(p + pos + i * 8);
return true; return true;
} }
@ -352,25 +380,39 @@ struct CSection
{ {
AString Name; AString Name;
UInt32 ExtractSize;
UInt32 VSize; UInt32 VSize;
UInt32 Va; UInt32 Va;
UInt32 PSize; UInt32 PSize;
UInt32 Pa; UInt32 Pa;
UInt32 Flags; UInt32 Flags;
UInt32 Time; UInt32 Time;
// UInt16 NumRelocs; // UInt16 NumRelocs; // is set to zero for executable images
bool IsRealSect; bool IsRealSect;
bool IsDebug; bool IsDebug;
bool IsAdditionalSection; 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; } void Set_Size_for_all(UInt32 size)
UInt32 GetSizeMin() const { return MyMin(PSize, VSize); } {
PSize = VSize = ExtractSize = size;
}
UInt32 GetSize_Extract() const
{
return ExtractSize;
}
void UpdateTotalSize(UInt32 &totalSize) const void UpdateTotalSize(UInt32 &totalSize) const
{ {
UInt32 t = Pa + PSize; const UInt32 t = Pa + PSize;
if (totalSize < t) if (totalSize < t)
totalSize = t; totalSize = t;
} }
@ -380,8 +422,8 @@ struct CSection
int Compare(const CSection &s) const int Compare(const CSection &s) const
{ {
RINOZ(MyCompare(Pa, s.Pa)) RINOZ(MyCompare(Pa, s.Pa))
UInt32 size1 = GetSizeExtract(); const UInt32 size1 = GetSize_Extract();
UInt32 size2 = s.GetSizeExtract(); const UInt32 size2 = s.GetSize_Extract();
return MyCompare(size1, size2); return MyCompare(size1, size2);
} }
}; };
@ -402,6 +444,10 @@ void CSection::Parse(const Byte *p)
G32(20, Pa); G32(20, Pa);
// G16(32, NumRelocs); // G16(32, NumRelocs);
G32(36, Flags); 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" }, { 0x01D3, "AM33" },
{ 0x01F0, "PPC" }, { 0x01F0, "PPC" },
{ 0x01F1, "PPC-FP" }, { 0x01F1, "PPC-FP" },
{ 0x01F2, "PPC-BE" },
{ 0x0200, "IA-64" }, { 0x0200, "IA-64" },
{ 0x0266, "MIPS-16" }, { 0x0266, "MIPS-16" },
{ 0x0284, "Alpha-64" }, { 0x0284, "Alpha-64" },
@ -830,11 +877,11 @@ enum
kpidStackReserve, kpidStackReserve,
kpidStackCommit, kpidStackCommit,
kpidHeapReserve, kpidHeapReserve,
kpidHeapCommit, kpidHeapCommit
kpidImageBase // , kpidImageBase
// kpidAddressOfEntryPoint, // , kpidAddressOfEntryPoint
// kpidBaseOfCode, // , kpidBaseOfCode
// kpidBaseOfData32, // , kpidBaseOfData32
}; };
static const CStatProp kArcProps[] = static const CStatProp kArcProps[] =
@ -864,14 +911,16 @@ static const CStatProp kArcProps[] =
{ "Stack Commit", kpidStackCommit, VT_UI8}, { "Stack Commit", kpidStackCommit, VT_UI8},
{ "Heap Reserve", kpidHeapReserve, VT_UI8}, { "Heap Reserve", kpidHeapReserve, VT_UI8},
{ "Heap Commit", kpidHeapCommit, VT_UI8}, { "Heap Commit", kpidHeapCommit, VT_UI8},
{ "Image Base", kpidImageBase, VT_UI8}, { NULL, kpidVa, VT_UI8 }, // "Image Base", kpidImageBase, VT_UI8
{ NULL, kpidComment, VT_BSTR}, { NULL, kpidComment, VT_BSTR}
// { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8}, // , { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8}
// { "Base Of Code", kpidBaseOfCode, VT_UI8}, // , { "Base Of Code", kpidBaseOfCode, VT_UI8}
// { "Base Of Data", kpidBaseOfData32, VT_UI8}, // , { "Base Of Data", kpidBaseOfData32, VT_UI8}
}; };
// #define kpid_NumRelocs 250
static const Byte kProps[] = static const Byte kProps[] =
{ {
kpidPath, kpidPath,
@ -880,7 +929,8 @@ static const Byte kProps[] =
kpidVirtualSize, kpidVirtualSize,
kpidCharacts, kpidCharacts,
kpidOffset, kpidOffset,
kpidVa, kpidVa
// , kpid_NumRelocs
}; };
IMP_IInArchive_Props IMP_IInArchive_Props
@ -899,7 +949,42 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
switch (propID) switch (propID)
{ {
case kpidPhySize: prop = _totalSize; break; 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: case kpidShortComment:
if (!_versionShortString.IsEmpty()) if (!_versionShortString.IsEmpty())
prop = _versionShortString; prop = _versionShortString;
@ -969,8 +1054,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
case kpidStackCommit: prop = _optHeader.StackCommit; break; case kpidStackCommit: prop = _optHeader.StackCommit; break;
case kpidHeapReserve: prop = _optHeader.HeapReserve; break; case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
case kpidHeapCommit: prop = _optHeader.HeapCommit; break; case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
case kpidVa: prop = _optHeader.ImageBase; break; // kpidImageBase:
case kpidImageBase: prop = _optHeader.ImageBase; break;
// case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break; // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
// case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break; // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
// case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; 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); prop = MultiByteToUnicodeString(s);
break; 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 kpidPackSize: prop = (UInt64)item.PSize; break;
case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break;
case kpidOffset: prop = item.Pa; break; case kpidOffset: prop = item.Pa; break;
@ -1229,7 +1314,7 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
sect.Time = de.Time; sect.Time = de.Time;
sect.Va = de.Va; sect.Va = de.Va;
sect.Pa = de.Pa; sect.Pa = de.Pa;
sect.PSize = sect.VSize = de.Size; sect.Set_Size_for_all(de.Size);
} }
buf += kEntrySize; buf += kEntrySize;
} }
@ -1757,7 +1842,7 @@ static void CopyToUString(const Byte *p, UString &s)
{ {
for (;;) for (;;)
{ {
wchar_t c = (wchar_t)Get16(p); const wchar_t c = (wchar_t)Get16(p);
p += 2; p += 2;
if (c == 0) if (c == 0)
return; 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) static bool CompareWStrStrings(const Byte *p, const char *s)
{ {
unsigned pos = 0; unsigned pos = 0;
@ -1783,7 +1878,7 @@ struct CVersionBlock
{ {
UInt32 TotalLen; UInt32 TotalLen;
UInt32 ValueLen; UInt32 ValueLen;
bool IsTextValue; unsigned IsTextValue;
unsigned StrSize; unsigned StrSize;
bool Parse(const Byte *p, UInt32 size); 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; static const unsigned k_ResoureBlockHeader_Size = 6;
bool CVersionBlock::Parse(const Byte *p, UInt32 size) bool CVersionBlock::Parse(const Byte *p, UInt32 size)
@ -1812,14 +1924,12 @@ bool CVersionBlock::Parse(const Byte *p, UInt32 size)
ValueLen = Get16(p + 2); ValueLen = Get16(p + 2);
if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size) if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size)
return false; return false;
switch (Get16(p + 4)) IsTextValue = Get16(p + 4);
{ if (IsTextValue > 1)
case 0: IsTextValue = false; break; return false;
case 1: IsTextValue = true; break;
default: return false;
}
StrSize = 0; 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) if (t < 0)
return false; return false;
StrSize = (unsigned)t; StrSize = (unsigned)t;
@ -1880,7 +1990,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
return false; return false;
if (vb.ValueLen != 0) if (vb.ValueLen != 0)
return false; return false;
UInt32 endPos = pos + vb.TotalLen; const UInt32 endPos = pos + vb.TotalLen;
pos += k_ResoureBlockHeader_Size; pos += k_ResoureBlockHeader_Size;
f.AddSpaces(2); f.AddSpaces(2);
@ -1901,7 +2011,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
CVersionBlock vb2; CVersionBlock vb2;
if (!vb2.Parse(p + pos, endPos - pos)) if (!vb2.Parse(p + pos, endPos - pos))
return false; return false;
UInt32 endPos2 = pos + vb2.TotalLen; const UInt32 endPos2 = pos + vb2.TotalLen;
if (vb2.IsTextValue) if (vb2.IsTextValue)
return false; return false;
pos += k_ResoureBlockHeader_Size; pos += k_ResoureBlockHeader_Size;
@ -1919,9 +2029,9 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
UInt32 num = (vb2.ValueLen >> 2); UInt32 num = (vb2.ValueLen >> 2);
for (; num != 0; num--, pos += 4) for (; num != 0; num--, pos += 4)
{ {
UInt32 dw = Get32(p + pos); const UInt32 dw = Get32(p + pos);
UInt32 lang = LOWORD(dw); const UInt32 lang = LOWORD(dw);
UInt32 codePage = HIWORD(dw); const UInt32 codePage = HIWORD(dw);
f.AddString(", "); f.AddString(", ");
PrintHex(f, lang); PrintHex(f, lang);
@ -1936,7 +2046,6 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
if (!CompareWStrStrings(p + pos, "StringFileInfo")) if (!CompareWStrStrings(p + pos, "StringFileInfo"))
return false; return false;
pos += vb.StrSize + 2; pos += vb.StrSize + 2;
for (;;) for (;;)
{ {
pos += (4 - pos) & 3; pos += (4 - pos) & 3;
@ -1945,7 +2054,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
CVersionBlock vb2; CVersionBlock vb2;
if (!vb2.Parse(p + pos, endPos - pos)) if (!vb2.Parse(p + pos, endPos - pos))
return false; return false;
UInt32 endPos2 = pos + vb2.TotalLen; const UInt32 endPos2 = pos + vb2.TotalLen;
if (vb2.ValueLen != 0) if (vb2.ValueLen != 0)
return false; return false;
pos += k_ResoureBlockHeader_Size; pos += k_ResoureBlockHeader_Size;
@ -1967,9 +2076,8 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector
CVersionBlock vb3; CVersionBlock vb3;
if (!vb3.Parse(p + pos, endPos2 - pos)) if (!vb3.Parse(p + pos, endPos2 - pos))
return false; return false;
// ValueLen sometimes is a number of characters (not bytes)? // ValueLen is a number of 16-bit characters (usually it includes zero tail character).
// So we don't use it. const UInt32 endPos3 = pos + vb3.TotalLen;
UInt32 endPos3 = pos + vb3.TotalLen;
pos += k_ResoureBlockHeader_Size; pos += k_ResoureBlockHeader_Size;
// we don't write string if it's not text // 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 += vb3.StrSize + 2;
pos += (4 - pos) & 3; pos += (4 - pos) & 3;
if (vb3.ValueLen > 0 && pos + 2 <= endPos3) if (vb3.ValueLen != 0 && pos /* + 2 */ <= endPos3)
{ {
f.AddChar(','); f.AddChar(',');
f.AddSpaces((34 - (int)vb3.StrSize) / 2); 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) if (sLen < 0)
return false; return false;
/*
if (vb3.ValueLen - 1 != (unsigned)sLen / 2 &&
vb3.ValueLen != (unsigned)sLen / 2)
return false;
*/
AddParamString(f, p + pos, (unsigned)sLen); AddParamString(f, p + pos, (unsigned)sLen);
CopyToUString(p + pos, value); CopyToUString_ByLen16(p + pos, (unsigned)sLen / 2, value);
pos += (unsigned)sLen + 2; // pos += (unsigned)sLen + 2;
} }
AddToUniqueUStringVector(keys, key, value); AddToUniqueUStringVector(keys, key, value);
} }
pos = endPos3; pos = endPos3;
f.NewLine(); f.NewLine();
} }
pos = endPos2;
f.CloseBlock(4); f.CloseBlock(4);
} }
} }
f.CloseBlock(2); f.CloseBlock(2);
pos = endPos;
} }
f.CloseBlock(0); f.CloseBlock(0);
@ -2218,7 +2335,7 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi
if (sect2.PSize != 0) if (sect2.PSize != 0)
{ {
sect2.VSize = sect2.PSize; sect2.ExtractSize = sect2.VSize = sect2.PSize;
sect2.Name = ".rsrc_1"; sect2.Name = ".rsrc_1";
sect2.Time = 0; sect2.Time = 0;
sect2.IsAdditionalSection = true; sect2.IsAdditionalSection = true;
@ -2337,6 +2454,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
CSection &sect = _sections.AddNew(); CSection &sect = _sections.AddNew();
sect.Parse(buffer + pos); sect.Parse(buffer + pos);
sect.IsRealSect = true; 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: /* PE pre-file in .hxs file has errors:
PSize of resource is larger than real size. PSize of resource is larger than real size.
@ -2390,7 +2521,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
sect.Name = "CERTIFICATE"; sect.Name = "CERTIFICATE";
sect.Va = 0; sect.Va = 0;
sect.Pa = certLink.Va; sect.Pa = certLink.Va;
sect.PSize = sect.VSize = certLink.Size; sect.Set_Size_for_all(certLink.Size);
sect.UpdateTotalSize(_totalSize); sect.UpdateTotalSize(_totalSize);
} }
@ -2448,7 +2579,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
sect.Name = "COFF_SYMBOLS"; sect.Name = "COFF_SYMBOLS";
sect.Va = 0; sect.Va = 0;
sect.Pa = _header.PointerToSymbolTable; sect.Pa = _header.PointerToSymbolTable;
sect.PSize = sect.VSize = size; sect.Set_Size_for_all(size);
sect.UpdateTotalSize(_totalSize); sect.UpdateTotalSize(_totalSize);
} }
@ -2464,11 +2595,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{ {
CSection &s2 = _sections.AddNew(); CSection &s2 = _sections.AddNew();
s2.Pa = s2.Va = limit; s2.Pa = s2.Va = limit;
s2.PSize = s2.VSize = s.Pa - limit; s2.Set_Size_for_all(s.Pa - limit);
s2.IsAdditionalSection = true; s2.IsAdditionalSection = true;
s2.Name = '['; s2.Name.Add_Char('[');
s2.Name.Add_UInt32(num++); s2.Name.Add_UInt32(num++);
s2.Name += ']'; s2.Name.Add_Char(']');
limit = s.Pa; limit = s.Pa;
} }
UInt32 next = s.Pa + s.PSize; 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) else if (mixItem.ResourceIndex >= 0)
size = _items[mixItem.ResourceIndex].GetSize(); size = _items[mixItem.ResourceIndex].GetSize();
else else
size = _sections[mixItem.SectionIndex].GetSizeExtract(); size = _sections[mixItem.SectionIndex].GetSize_Extract();
totalSize += size; totalSize += size;
} }
extractCallback->SetTotal(totalSize); RINOK(extractCallback->SetTotal(totalSize))
UInt64 currentTotalSize = 0; CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, false);
CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
inStream->SetStream(_stream);
totalSize = 0;
UInt64 currentItemSize; UInt64 currentItemSize;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); for (i = 0;; i++, totalSize += currentItemSize)
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
{ {
lps->InSize = lps->OutSize = currentTotalSize; lps->InSize = lps->OutSize = totalSize;
RINOK(lps->SetCur()) RINOK(lps->SetCur())
if (i >= numItems)
break;
const Int32 askMode = testMode ? const Int32 askMode = testMode ?
NExtract::NAskMode::kTest : NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract; NExtract::NAskMode::kExtract;
@ -2776,15 +2904,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
} }
else else
{ {
currentItemSize = sect.GetSizeExtract(); currentItemSize = sect.GetSize_Extract();
if (!testMode && !outStream) if (!testMode && !outStream)
continue; continue;
RINOK(extractCallback->PrepareOperation(askMode)) RINOK(extractCallback->PrepareOperation(askMode))
RINOK(InStream_SeekSet(_stream, sect.Pa)) RINOK(InStream_SeekSet(_stream, sect.Pa))
streamSpec->Init(currentItemSize); inStream->Init(currentItemSize);
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps))
isOk = (copyCoderSpec->TotalSize == currentItemSize); isOk = (copyCoder->TotalSize == currentItemSize);
} }
outStream.Release(); outStream.Release();
@ -2804,7 +2932,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
const CMixItem &mixItem = _mixItems[index]; const CMixItem &mixItem = _mixItems[index];
const CSection &sect = _sections[mixItem.SectionIndex]; const CSection &sect = _sections[mixItem.SectionIndex];
if (mixItem.IsSectionItem()) if (mixItem.IsSectionItem())
return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream); return CreateLimitedInStream(_stream, sect.Pa, sect.GetSize_Extract(), stream);
CBufInStream *inStreamSpec = new CBufInStream; CBufInStream *inStreamSpec = new CBufInStream;
CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec; CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
@ -2964,7 +3092,7 @@ bool CHeader::Parse(const Byte *p)
G32(12, BaseOfCode); G32(12, BaseOfCode);
G64(16, ImageBase); G64(16, ImageBase);
*/ */
for (int i = 0; i < 2; i++) for (unsigned i = 0; i < 2; i++)
{ {
CDataDir &dd = DataDir[i]; CDataDir &dd = DataDir[i];
dd.Parse(p + 24 + i * 8); dd.Parse(p + 24 + i * 8);
@ -2997,6 +3125,7 @@ struct CSection
{ {
Byte Name[NPe::kNameSize]; Byte Name[NPe::kNameSize];
UInt32 ExtractSize;
UInt32 VSize; UInt32 VSize;
UInt32 Va; UInt32 Va;
UInt32 PSize; UInt32 PSize;
@ -3013,6 +3142,7 @@ struct CSection
G32(20, Pa); G32(20, Pa);
// G32(p + 32, NumRelocs); // G32(p + 32, NumRelocs);
G32(36, Flags); G32(36, Flags);
ExtractSize = (VSize && VSize < PSize) ? VSize : PSize;
} }
bool Check() const bool Check() const
@ -3022,10 +3152,15 @@ struct CSection
PSize <= ((UInt32)1 << 30); PSize <= ((UInt32)1 << 30);
} }
UInt32 GetSize_Extract() const
{
return ExtractSize;
}
void UpdateTotalSize(UInt32 &totalSize) void UpdateTotalSize(UInt32 &totalSize)
{ {
UInt32 t = Pa + PSize; const UInt32 t = Pa + PSize;
if (t > totalSize) if (totalSize < t)
totalSize = t; totalSize = t;
} }
}; };
@ -3050,6 +3185,7 @@ static const Byte kProps[] =
{ {
kpidPath, kpidPath,
kpidSize, kpidSize,
kpidPackSize,
kpidVirtualSize, kpidVirtualSize,
kpidCharacts, kpidCharacts,
kpidOffset, kpidOffset,
@ -3108,7 +3244,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = MultiByteToUnicodeString(name); prop = MultiByteToUnicodeString(name);
break; break;
} }
case kpidSize: case kpidSize: prop = (UInt64)item.GetSize_Extract(); break;
case kpidPackSize: prop = (UInt64)item.PSize; break; case kpidPackSize: prop = (UInt64)item.PSize; break;
case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break;
case kpidOffset: prop = item.Pa; break; case kpidOffset: prop = item.Pa; break;
@ -3168,13 +3304,13 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
Close(); Close();
try // try
{ {
if (Open2(inStream) != S_OK) if (Open2(inStream) != S_OK)
return S_FALSE; return S_FALSE;
_stream = inStream; _stream = inStream;
} }
catch(...) { return S_FALSE; } // catch(...) { return S_FALSE; }
return S_OK; return S_OK;
COM_TRY_END COM_TRY_END
} }
@ -3205,26 +3341,25 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0; UInt64 totalSize = 0;
UInt32 i; UInt32 i;
for (i = 0; i < numItems; i++) for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].PSize; totalSize += _items[allFilesMode ? i : indices[i]].GetSize_Extract();
extractCallback->SetTotal(totalSize); RINOK(extractCallback->SetTotal(totalSize))
UInt64 currentTotalSize = 0; CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false); lps->Init(extractCallback, false);
CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
inStream->SetStream(_stream);
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; totalSize = 0;
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++) for (i = 0;; i++)
{ {
lps->InSize = lps->OutSize = currentTotalSize; lps->InSize = lps->OutSize = totalSize;
RINOK(lps->SetCur()) RINOK(lps->SetCur())
if (i >= numItems)
break;
int opRes;
{
CMyComPtr<ISequentialOutStream> realOutStream; CMyComPtr<ISequentialOutStream> realOutStream;
const Int32 askMode = testMode ? const Int32 askMode = testMode ?
NExtract::NAskMode::kTest : 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 UInt32 index = allFilesMode ? i : indices[i];
const CSection &item = _items[index]; const CSection &item = _items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
currentTotalSize += item.PSize; const UInt32 size = item.GetSize_Extract();
totalSize += size;
if (!testMode && !realOutStream) if (!testMode && !realOutStream)
continue; continue;
RINOK(extractCallback->PrepareOperation(askMode)) RINOK(extractCallback->PrepareOperation(askMode))
int res = NExtract::NOperationResult::kDataError;
RINOK(InStream_SeekSet(_stream, item.Pa)) RINOK(InStream_SeekSet(_stream, item.Pa))
streamSpec->Init(item.PSize); inStream->Init(size);
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)) RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
if (copyCoderSpec->TotalSize == item.PSize)
res = NExtract::NOperationResult::kOK;
realOutStream.Release(); opRes = (copyCoder->TotalSize == size) ?
RINOK(extractCallback->SetOperationResult(res)) NExtract::NOperationResult::kOK : (copyCoder->TotalSize < size) ?
NExtract::NOperationResult::kUnexpectedEnd :
NExtract::NOperationResult::kDataError;
}
RINOK(extractCallback->SetOperationResult(opRes))
} }
return S_OK; return S_OK;
COM_TRY_END COM_TRY_END
@ -3256,7 +3392,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
const CSection &item = _items[index]; 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 COM_TRY_END
} }

View file

@ -11,6 +11,7 @@
#include "../../Common/MyBuffer2.h" #include "../../Common/MyBuffer2.h"
#include "../../Windows/PropVariant.h" #include "../../Windows/PropVariant.h"
#include "../../Windows/PropVariantUtils.h"
#include "../Common/RegisterArc.h" #include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h" #include "../Common/StreamObjects.h"
@ -20,8 +21,8 @@
#include "HandlerCont.h" #include "HandlerCont.h"
#define Get32(p) GetBe32(p) #define Get32(p) GetBe32a(p)
#define Get64(p) GetBe64(p) #define Get64(p) GetBe64a(p)
using namespace NWindows; using namespace NWindows;
@ -32,9 +33,9 @@ static const Byte k_Signature[] = { 'Q', 'F', 'I', 0xFB, 0, 0, 0 };
/* /*
VA to PA maps: VA to PA maps:
high bits (L1) : : in L1 Table : the reference to L1 Table high bits (L1) : : index in L1 (_dir) : _dir[high_index] points to Table.
mid bits (L2) : _numMidBits : in L2 Table : the reference to cluster mid bits (L2) : _numMidBits : index in Table, Table[index] points to cluster start offset in arc file.
low bits : _clusterBits low bits : _clusterBits : offset inside cluster.
*/ */
Z7_class_CHandler_final: public CHandlerImg Z7_class_CHandler_final: public CHandlerImg
@ -49,30 +50,27 @@ Z7_class_CHandler_final: public CHandlerImg
CObjArray2<UInt32> _dir; CObjArray2<UInt32> _dir;
CAlignedBuffer _table; CAlignedBuffer _table;
UInt64 _cacheCluster;
CByteBuffer _cache; CByteBuffer _cache;
CByteBuffer _cacheCompressed; CByteBuffer _cacheCompressed;
UInt64 _cacheCluster;
UInt64 _comprPos; UInt64 _comprPos;
size_t _comprSize; size_t _comprSize;
UInt64 _phySize; bool _needCompression;
CBufInStream *_bufInStreamSpec;
CMyComPtr<ISequentialInStream> _bufInStream;
CBufPtrSeqOutStream *_bufOutStreamSpec;
CMyComPtr<ISequentialOutStream> _bufOutStream;
NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec;
CMyComPtr<ICompressCoder> _deflateDecoder;
bool _needDeflate;
bool _isArc; bool _isArc;
bool _unsupported; bool _unsupported;
Byte _compressionType;
UInt64 _phySize;
CMyComPtr2<ISequentialInStream, CBufInStream> _bufInStream;
CMyComPtr2<ISequentialOutStream, CBufPtrSeqOutStream> _bufOutStream;
CMyComPtr2<ICompressCoder, NCompress::NDeflate::NDecoder::CCOMCoder> _deflateDecoder;
UInt32 _version; UInt32 _version;
UInt32 _cryptMethod; UInt32 _cryptMethod;
UInt64 _incompatFlags;
HRESULT Seek2(UInt64 offset) HRESULT Seek2(UInt64 offset)
{ {
@ -96,13 +94,11 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
{ {
if (processedSize) if (processedSize)
*processedSize = 0; *processedSize = 0;
// printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size); // printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size);
if (_virtPos >= _size) if (_virtPos >= _size)
return S_OK; return S_OK;
{ {
UInt64 rem = _size - _virtPos; const UInt64 rem = _size - _virtPos;
if (size > rem) if (size > rem)
size = (UInt32)rem; size = (UInt32)rem;
if (size == 0) if (size == 0)
@ -115,11 +111,10 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
const size_t clusterSize = (size_t)1 << _clusterBits; const size_t clusterSize = (size_t)1 << _clusterBits;
const size_t lowBits = (size_t)_virtPos & (clusterSize - 1); const size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
{ {
size_t rem = clusterSize - lowBits; const size_t rem = clusterSize - lowBits;
if (size > rem) if (size > rem)
size = (UInt32)rem; size = (UInt32)rem;
} }
if (cluster == _cacheCluster) if (cluster == _cacheCluster)
{ {
memcpy(data, _cache + lowBits, size); memcpy(data, _cache + lowBits, size);
@ -130,32 +125,29 @@ Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
if (high < _dir.Size()) if (high < _dir.Size())
{ {
const UInt32 tabl = _dir[(unsigned)high]; const UInt32 tabl = _dir[(size_t)high];
if (tabl != kEmptyDirItem) 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 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); UInt64 v = Get64(p);
if (v != 0) if (v)
{ {
if ((v & _compressedFlag) != 0) if (v & _compressedFlag)
{ {
if (_version <= 1) if (_version <= 1)
return E_FAIL; return E_FAIL;
/* /*
the example of table record for 12-bit clusters (4KB uncompressed). the example of table record for 12-bit clusters (4KB uncompressed):
2 bits : isCompressed status 2 bits : isCompressed status
4 bits : num_sectors_minus1; packSize = (num_sectors_minus1 + 1) * 512; (4 == _clusterBits - 8) bits : (num_sectors - 1)
it uses one additional bit over unpacked cluster_bits packSize = num_sectors * 512;
49 bits : offset of 512-sector it uses one additional bit over unpacked cluster_bits.
9 bits : offset in 512-sector (49 == 61 - _clusterBits) bits : offset of 512-byte sector
9 bits : offset in 512-byte sector
*/ */
const unsigned numOffsetBits = 62 - (_clusterBits - 8);
const unsigned numOffsetBits = (62 - (_clusterBits - 9 + 1));
const UInt64 offset = v & (((UInt64)1 << 62) - 1); const UInt64 offset = v & (((UInt64)1 << 62) - 1);
const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
UInt64 sectorOffset = offset & (((UInt64)1 << 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 (sectorOffset >= _comprPos && offset2inCache < _comprSize)
{ {
if (offset2inCache != 0) if (offset2inCache)
{ {
_comprSize -= (size_t)offset2inCache; _comprSize -= (size_t)offset2inCache;
memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize); 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; const size_t dataSize3 = dataSize - _comprSize;
size_t dataSize2 = dataSize3; size_t dataSize2 = dataSize3;
// printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos); // 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; _posInArc += dataSize2;
RINOK(hres)
if (dataSize2 != dataSize3) if (dataSize2 != dataSize3)
return E_FAIL; return E_FAIL;
_comprSize += dataSize2; _comprSize += dataSize2;
} }
const size_t kSectorMask = (1 << 9) - 1; const size_t kSectorMask = (1 << 9) - 1;
const size_t offsetInSector = ((size_t)offset & kSectorMask); const size_t offsetInSector = (size_t)offset & kSectorMask;
_bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); _bufInStream->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector);
_cacheCluster = (UInt64)(Int64)-1; _cacheCluster = (UInt64)(Int64)-1;
if (_cache.Size() < clusterSize) if (_cache.Size() < clusterSize)
return E_FAIL; return E_FAIL;
_bufOutStreamSpec->Init(_cache, clusterSize); _bufOutStream->Init(_cache, clusterSize);
// Do we need to use smaller block than clusterSize for last cluster? // Do we need to use smaller block than clusterSize for last cluster?
const UInt64 blockSize64 = clusterSize; 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) if (_bufOutStreamSpec->GetPos() != clusterSize)
memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
*/ */
if (res == S_OK) if (res == S_OK)
if (!_deflateDecoderSpec->IsFinished() if (!_deflateDecoder->IsFinished()
|| _bufOutStreamSpec->GetPos() != clusterSize) || _bufOutStream->GetPos() != clusterSize)
res = S_FALSE; res = S_FALSE;
RINOK(res) RINOK(res)
_cacheCluster = cluster; _cacheCluster = cluster;
continue; continue;
/* /*
memcpy(data, _cache + lowBits, size); 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) if (((UInt32)v & 511) != 1)
{ {
v &= (_compressedFlag - 1); v &= _compressedFlag - 1;
v += lowBits; v += lowBits;
if (v != _posInArc) if (v != _posInArc)
{ {
// printf("\n%12I64x\n", v - _posInArc); // printf("\n%12I64x\n", v - _posInArc);
RINOK(Seek2(v)) RINOK(Seek2(v))
} }
HRESULT res = Stream->Read(data, size, &size); const HRESULT res = Stream->Read(data, size, &size);
_posInArc += size; _posInArc += size;
_virtPos += size; _virtPos += size;
if (processedSize) if (processedSize)
@ -274,13 +261,25 @@ static const Byte kProps[] =
static const Byte kArcProps[] = static const Byte kArcProps[] =
{ {
kpidClusterSize, kpidClusterSize,
kpidSectorSize, // actually we need variable to show table size
kpidHeadersSize,
kpidUnpackVer, kpidUnpackVer,
kpidMethod kpidMethod,
kpidCharacts
}; };
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps 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)) Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
@ -290,28 +289,54 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{ {
case kpidMainSubfile: prop = (UInt32)0; break; case kpidMainSubfile: prop = (UInt32)0; break;
case kpidClusterSize: prop = (UInt32)1 << _clusterBits; 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 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: case kpidMethod:
{ {
AString s; AString s;
if (_needDeflate) if (_compressionType)
s = "Deflate"; {
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(); s.Add_Space_if_NotEmpty();
if (_cryptMethod == 1) if (_cryptMethod == 1)
s += "AES"; s += "AES";
if (_cryptMethod == 2)
s += "LUKS";
else else
{
s += "Encryption:";
s.Add_UInt32(_cryptMethod); s.Add_UInt32(_cryptMethod);
} }
}
if (!s.IsEmpty()) if (!s.IsEmpty())
prop = s; prop = s;
break; break;
} }
@ -321,9 +346,9 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
// if (_headerError) v |= kpv_ErrorFlags_HeadersError; // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
if (!Stream && v == 0 && _isArc) if (!Stream && v == 0)
v = kpv_ErrorFlags_HeadersError; v = kpv_ErrorFlags_HeadersError;
if (v != 0) if (v)
prop = v; prop = v;
break; break;
} }
@ -355,74 +380,89 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
{ {
const unsigned kHeaderSize = 18 * 4; UInt64 buf64[0x70 / 8];
Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buf64, sizeof(buf64)))
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) const void *buf = (const void *)buf64;
// signature: { 'Q', 'F', 'I', 0xFB }
if (memcmp(buf, k_Signature, 4) != 0) if (*(const UInt32 *)buf != Z7_CONV_BE_TO_NATIVE_CONST32(0x514649fb))
return S_FALSE; return S_FALSE;
_version = Get32((const Byte *)(const void *)buf64 + 4);
_version = Get32(buf + 4);
if (_version < 1 || _version > 3) if (_version < 1 || _version > 3)
return S_FALSE; return S_FALSE;
const UInt64 backOffset = Get64(buf + 8); const UInt64 k_UncompressedSize_MAX = (UInt64)1 << 60;
// UInt32 backSize = Get32(buf + 0x10); const UInt64 k_CompressedSize_MAX = (UInt64)1 << 60;
UInt64 l1Offset; _size = Get64((const Byte *)(const void *)buf64 + 0x18);
UInt32 l1Size; if (_size > k_UncompressedSize_MAX)
return S_FALSE;
size_t l1Size;
UInt32 headerSize;
if (_version == 1) if (_version == 1)
{ {
// _mTime = Get32(buf + 0x14); // is unused im most images // _mTime = Get32((const Byte *)(const void *)buf64 + 0x14); // is unused in most images
_size = Get64(buf + 0x18); _clusterBits = ((const Byte *)(const void *)buf64)[0x20];
_clusterBits = buf[0x20]; _numMidBits = ((const Byte *)(const void *)buf64)[0x21];
_numMidBits = buf[0x21];
if (_clusterBits < 9 || _clusterBits > 30) if (_clusterBits < 9 || _clusterBits > 30)
return S_FALSE; return S_FALSE;
if (_numMidBits < 1 || _numMidBits > 28) if (_numMidBits < 1 || _numMidBits > 28)
return S_FALSE; return S_FALSE;
_cryptMethod = Get32(buf + 0x24); _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x24);
l1Offset = Get64(buf + 0x28); const unsigned numBits2 = _clusterBits + _numMidBits;
if (l1Offset < 0x30)
return S_FALSE;
const unsigned numBits2 = (_clusterBits + _numMidBits);
const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2; const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2;
if (l1Size64 > ((UInt32)1 << 31)) if (l1Size64 > ((UInt32)1 << 31))
return S_FALSE; return S_FALSE;
l1Size = (UInt32)l1Size64; l1Size = (size_t)l1Size64;
headerSize = 0x30;
} }
else else
{ {
_clusterBits = Get32(buf + 0x14); _clusterBits = Get32((const Byte *)(const void *)buf64 + 0x14);
if (_clusterBits < 9 || _clusterBits > 30) if (_clusterBits < 9 || _clusterBits > 30)
return S_FALSE; return S_FALSE;
_numMidBits = _clusterBits - 3; _numMidBits = _clusterBits - 3;
_size = Get64(buf + 0x18); _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x20);
_cryptMethod = Get32(buf + 0x20); l1Size = Get32((const Byte *)(const void *)buf64 + 0x24);
l1Size = Get32(buf + 0x24); headerSize = 0x48;
l1Offset = Get64(buf + 0x28); // must be aligned for cluster 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(buf + 0x30); // must be aligned for cluster const UInt64 refOffset = Get64((const Byte *)(const void *)buf64 + 0x30); // must be aligned for cluster
const UInt32 refClusters = Get32(buf + 0x38); const UInt32 refClusters = Get32((const Byte *)(const void *)buf64 + 0x38);
// UInt32 numSnapshots = Get32((const Byte *)(const void *)buf64 + 0x3C);
// UInt32 numSnapshots = Get32(buf + 0x3C); // UInt64 snapshotsOffset = Get64((const Byte *)(const void *)buf64 + 0x40); // must be aligned for cluster
// UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster
/* /*
if (numSnapshots != 0) if (numSnapshots)
return S_FALSE; return S_FALSE;
*/ */
if (refClusters)
if (refClusters != 0)
{ {
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; CByteBuffer refs;
refs.Alloc(numBytes); refs.Alloc(numBytes);
RINOK(InStream_SeekSet(stream, refOffset)) RINOK(InStream_SeekSet(stream, refOffset))
RINOK(ReadStream_FALSE(stream, refs, numBytes)); RINOK(ReadStream_FALSE(stream, refs, numBytes));
*/ */
const UInt64 end = refOffset + numBytes;
if (_phySize < end) if (_phySize < end)
_phySize = end; _phySize = end;
/* /*
@ -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;
{
const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8);
// UInt32 backSize = Get32((const Byte *)(const void *)buf64 + 0x10);
if (backOffset)
{ {
_unsupported = true; _unsupported = true;
return S_FALSE; return S_FALSE;
} }
}
UInt64 fileSize = 0;
RINOK(InStream_GetSize_SeekToBegin(stream, fileSize))
const size_t clusterSize = (size_t)1 << _clusterBits; const size_t clusterSize = (size_t)1 << _clusterBits;
CByteBuffer table;
{
const size_t t1SizeBytes = (size_t)l1Size << 3; const size_t t1SizeBytes = (size_t)l1Size << 3;
if ((t1SizeBytes >> 3) != l1Size)
return S_FALSE;
table.Alloc(t1SizeBytes);
RINOK(InStream_SeekSet(stream, l1Offset))
RINOK(ReadStream_FALSE(stream, table, t1SizeBytes))
{ {
UInt64 end = l1Offset + t1SizeBytes; const UInt64 end = l1Offset + t1SizeBytes;
// we need to uses align end for empty qcow files if (end > k_CompressedSize_MAX)
end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; return S_FALSE;
// 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) if (_phySize < end)
_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<UInt64> 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); _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62);
const UInt64 offsetMask = _compressedFlag - 1; const UInt64 offsetMask = _compressedFlag - 1;
const size_t midSize = (size_t)1 << (_numMidBits + 3);
UInt32 numTables = 0; size_t numTables = 0;
UInt32 i; size_t i;
for (i = 0; i < l1Size; i++) for (i = 0; i < l1Size; i++)
{ {
const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask; const UInt64 v = Get64(table64 + (size_t)i) & offsetMask;
if (v != 0) if (!v)
continue;
numTables++; 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); const size_t size = (size_t)numTables << (_numMidBits + 3);
if (size >> (_numMidBits + 3) != numTables) if (size >> (_numMidBits + 3) != numTables)
@ -485,48 +553,38 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
_table.Alloc(size); _table.Alloc(size);
if (!_table.IsAllocated()) if (!_table.IsAllocated())
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
}
_dir.SetSize(l1Size);
UInt32 curTable = 0;
if (openCallback) if (openCallback)
{ {
const UInt64 totalBytes = (UInt64)numTables << (_numMidBits + 3); const UInt64 totalBytes = size;
RINOK(openCallback->SetTotal(NULL, &totalBytes)) RINOK(openCallback->SetTotal(NULL, &totalBytes))
} }
}
_dir.SetSize((unsigned)l1Size);
UInt32 curTable = 0;
for (i = 0; i < l1Size; i++) for (i = 0; i < l1Size; i++)
{ {
Byte *buf2; 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) if (v == 0)
{ {
_dir[i] = kEmptyDirItem; _dir[i] = kEmptyDirItem;
continue; continue;
} }
_dir[i] = curTable; _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; buf2 = (Byte *)_table + tableOffset;
curTable++; curTable++;
if (openCallback && (tableOffset & 0xFFFFF) == 0) if (openCallback && (tableOffset & 0xFFFFF) == 0)
{ {
const UInt64 numBytes = tableOffset; const UInt64 numBytes = tableOffset;
RINOK(openCallback->SetCompleted(NULL, &numBytes)) RINOK(openCallback->SetCompleted(NULL, &numBytes))
} }
RINOK(InStream_SeekSet(stream, v)) RINOK(InStream_SeekSet(stream, v))
RINOK(ReadStream_FALSE(stream, buf2, midSize)) 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) for (size_t k = 0; k < midSize; k += 8)
@ -537,33 +595,30 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
UInt64 offset = v & offsetMask; UInt64 offset = v & offsetMask;
size_t dataSize = clusterSize; size_t dataSize = clusterSize;
if ((v & _compressedFlag) != 0) if (v & _compressedFlag)
{ {
if (_version <= 1) if (_version <= 1)
{ {
unsigned numOffsetBits = (63 - _clusterBits); const unsigned numOffsetBits = 63 - _clusterBits;
dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
offset &= ((UInt64)1 << numOffsetBits) - 1; offset &= ((UInt64)1 << numOffsetBits) - 1;
dataSize = 0; dataSize = 0; // why ?
// offset >>= 9; // offset &= ~(((UInt64)1 << 9) - 1);
// offset <<= 9;
} }
else else
{ {
unsigned numOffsetBits = (62 - (_clusterBits - 8)); const unsigned numOffsetBits = 62 - (_clusterBits - 8);
dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
offset &= ((UInt64)1 << numOffsetBits) - 1; offset &= ((UInt64)1 << numOffsetBits) - (1 << 9);
offset >>= 9;
offset <<= 9;
} }
_needDeflate = true; _needCompression = true;
} }
else else
{ {
UInt32 low = (UInt32)v & 511; const UInt32 low = (UInt32)v & 511;
if (low != 0) if (low)
{ {
// version 3 support zero clusters // version_3 supports zero clusters
if (_version < 3 || low != 1) if (_version < 3 || low != 1)
{ {
_unsupported = true; _unsupported = true;
@ -581,10 +636,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
if (curTable != numTables) if (curTable != numTables)
return E_FAIL; return E_FAIL;
if (_cryptMethod != 0) if (_cryptMethod)
_unsupported = true; _unsupported = true;
if (_needCompression && _version <= 1) // that case was not implemented
if (_needDeflate && _version <= 1) // that case was not implemented _unsupported = true;
if (_compressionType)
_unsupported = true; _unsupported = true;
Stream = stream; Stream = stream;
@ -596,16 +652,21 @@ Z7_COM7F_IMF(CHandler::Close())
{ {
_table.Free(); _table.Free();
_dir.Free(); _dir.Free();
// _cache.Free();
// _cacheCompressed.Free();
_phySize = 0; _phySize = 0;
_cacheCluster = (UInt64)(Int64)-1; _cacheCluster = (UInt64)(Int64)-1;
_comprPos = 0; _comprPos = 0;
_comprSize = 0; _comprSize = 0;
_needDeflate = false;
_needCompression = false;
_isArc = false; _isArc = false;
_unsupported = false; _unsupported = false;
_compressionType = 0;
_incompatFlags = 0;
// CHandlerImg: // CHandlerImg:
Clear_HandlerImg_Vars(); Clear_HandlerImg_Vars();
Stream.Release(); Stream.Release();
@ -617,39 +678,20 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
*stream = NULL; *stream = NULL;
if (_unsupported || !Stream)
if (_unsupported)
return S_FALSE; return S_FALSE;
if (_needCompression)
if (_needDeflate)
{ {
if (_version <= 1) if (_version <= 1 || _compressionType)
return S_FALSE; return S_FALSE;
_bufInStream.Create_if_Empty();
if (!_bufInStream) _bufOutStream.Create_if_Empty();
{ _deflateDecoder.Create_if_Empty();
_bufInStreamSpec = new CBufInStream; _deflateDecoder->Set_NeedFinishInput(true);
_bufInStream = _bufInStreamSpec;
}
if (!_bufOutStream)
{
_bufOutStreamSpec = new CBufPtrSeqOutStream();
_bufOutStream = _bufOutStreamSpec;
}
if (!_deflateDecoder)
{
_deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
_deflateDecoder = _deflateDecoderSpec;
_deflateDecoderSpec->Set_NeedFinishInput(true);
}
const size_t clusterSize = (size_t)1 << _clusterBits; const size_t clusterSize = (size_t)1 << _clusterBits;
_cache.AllocAtLeast(clusterSize); _cache.AllocAtLeast(clusterSize);
_cacheCompressed.AllocAtLeast(clusterSize * 2); _cacheCompressed.AllocAtLeast(clusterSize * 2);
} }
CMyComPtr<ISequentialInStream> streamTemp = this; CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek()) RINOK(InitAndSeek())
*stream = streamTemp.Detach(); *stream = streamTemp.Detach();

View file

@ -1456,7 +1456,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
} }
if (arcInfo->Locator.Is_Recovery()) if (arcInfo->Locator.Is_Recovery())
{ {
s += "Recovery:"; s.Add_OptSpaced("Recovery:");
s.Add_UInt64(arcInfo->Locator.Recovery); s.Add_UInt64(arcInfo->Locator.Recovery);
} }
} }

View file

@ -1755,16 +1755,17 @@ HRESULT CCacheOutStream::FlushFromCache(size_t size)
PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size)); PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size));
if (_hres != S_OK) if (_hres != S_OK)
return _hres; return _hres;
if (size == 0 || _cachedSize == 0) if (size > _cachedSize)
size = _cachedSize;
// (size <= _cachedSize)
if (size == 0)
return S_OK; return S_OK;
RINOK(SeekPhy(_cachedPos)) RINOK(SeekPhy(_cachedPos))
for (;;) for (;;)
{ {
// (_phyPos == _cachedPos) // (_phyPos == _cachedPos)
const size_t pos = (size_t)_cachedPos & kCacheMask; const size_t pos = (size_t)_cachedPos & kCacheMask;
size_t cur = kCacheSize - pos; const size_t cur = MyMin(kCacheSize - pos, size);
cur = MyMin(cur, _cachedSize);
cur = MyMin(cur, size);
_hres = SetRestriction_ForWrite(cur); _hres = SetRestriction_ForWrite(cur);
RINOK(_hres) RINOK(_hres)
PRF(printf("\n-- CCacheOutStream::WriteFromCache _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)cur)); 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; _cachedPos += cur;
_cachedSize -= cur; _cachedSize -= cur;
size -= cur; size -= cur;
if (size == 0 || _cachedSize == 0) if (size == 0)
return S_OK; return S_OK;
} }
} }
@ -1964,7 +1965,11 @@ Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize))
// so we reduce cache // so we reduce cache
_cachedSize = (size_t)offset; _cachedSize = (size_t)offset;
if (_phySize <= newSize) 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) // (_phySize > newSize)
// so we must reduce phyStream size to (newSize) or to (_cachedPos) // so we must reduce phyStream size to (newSize) or to (_cachedPos)
// newPhySize = _cachedPos; // optional reduce to _cachedPos // newPhySize = _cachedPos; // optional reduce to _cachedPos

View file

@ -3713,7 +3713,7 @@ HRESULT Bench(
} }
*/ */
bool ramSize_Defined = NSystem::GetRamSize(ramSize); const bool ramSize_Defined = NSystem::GetRamSize(ramSize);
UInt32 numThreadsSpecified = numCPUs; UInt32 numThreadsSpecified = numCPUs;
bool needSetComplexity = false; bool needSetComplexity = false;
@ -4002,16 +4002,29 @@ HRESULT Bench(
} }
} }
if (numThreadsSpecified >= 2)
if (printCallback || freqCallback) 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) if (printCallback)
printCallback->NewLine(); printCallback->NewLine();
/* it can show incorrect frequency for HT threads. /* it can show incorrect frequency for HT threads. */
so we reduce freq test to (numCPUs / 2) */
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) if (numThreads < 1)
numThreads = 1; numThreads = 1;

View file

@ -21,8 +21,8 @@
using namespace NWindows; using namespace NWindows;
static const unsigned kNumWinAtrribFlags = 21; static const unsigned kNumWinAtrribFlags = 30;
static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU"; static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEVvX.PU.M......B";
/* /*
FILE_ATTRIBUTE_ FILE_ATTRIBUTE_
@ -48,8 +48,9 @@ FILE_ATTRIBUTE_
18 RECALL_ON_OPEN or EA 18 RECALL_ON_OPEN or EA
19 PINNED 19 PINNED
20 UNPINNED 20 UNPINNED
21 STRICTLY_SEQUENTIAL 21 STRICTLY_SEQUENTIAL (10.0.16267)
22 RECALL_ON_DATA_ACCESS 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++) for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
{ {
UInt32 flag = (1 << i); const UInt32 flag = (UInt32)1 << i;
if ((wa & flag) != 0) if (wa & flag)
{ {
char c = g_WinAttribChars[i]; const char c = g_WinAttribChars[i];
if (c != '.') if (c != '.')
{ {
wa &= ~flag; wa &= ~flag;

View file

@ -1606,7 +1606,23 @@ HRESULT UpdateArchive(
if (!MyMoveFile(tempPath, us2fs(arcPath))) 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)); errorInfo.FileNames.Add(us2fs(arcPath));
return errorInfo.Get_HRESULT_Error(); return errorInfo.Get_HRESULT_Error();
} }

View file

@ -924,11 +924,11 @@ HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
} }
else else
{ {
NumArcsWithError++; // we don't update NumArcsWithError, if error is not related to archive data.
if (result == E_ABORT if (result == E_ABORT
|| result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL))
)
return result; return result;
NumArcsWithError++;
if (_se) if (_se)
{ {

View file

@ -534,7 +534,8 @@ bool FindExt(const char *p, const UString &name, CStringFinder &finder);
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(); 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 false;
return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1)); return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1));
} }

View file

@ -387,8 +387,8 @@ Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged))
return S_OK; return S_OK;
} }
DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); const DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
bool wasChangedLoc = (waitResult == WAIT_OBJECT_0); const bool wasChangedLoc = (waitResult == WAIT_OBJECT_0);
if (wasChangedLoc) if (wasChangedLoc)
{ {
_findChangeNotification.FindNext(); _findChangeNotification.FindNext();
@ -666,16 +666,10 @@ Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID
Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
{ {
const CAltStream &ss = Streams[index]; const CAltStream &ss = Streams[index];
*iconIndex = 0; return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
int iconIndexTemp; _pathPrefix + us2fs(ss.Name),
if (GetRealIconIndex(_pathPrefix + us2fs(ss.Name), FILE_ATTRIBUTE_ARCHIVE,
0 // fi.Attrib iconIndex);
, iconIndexTemp) != 0)
{
*iconIndex = iconIndexTemp;
return S_OK;
}
return GetLastError_noZero_HRESULT();
} }
/* /*

View file

@ -782,6 +782,7 @@ void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex)
if (useSrcPanel) if (useSrcPanel)
{ {
CCopyToOptions options; CCopyToOptions options;
// options.src_Is_IO_FS_Folder = useFullItemPaths;
options.folder = useTemp ? fs2us(tempDirPrefix) : destPath; options.folder = useTemp ? fs2us(tempDirPrefix) : destPath;
options.moveMode = move; options.moveMode = move;
options.includeAltStreams = true; options.includeAltStreams = true;

View file

@ -208,8 +208,8 @@ bool CBrowseDialog::OnInit()
_filterCombo.SetCurSel(FilterIndex); _filterCombo.SetCurSel(FilterIndex);
} }
_list.SetImageList(GetSysImageList(true), LVSIL_SMALL); _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL);
_list.SetImageList(GetSysImageList(false), LVSIL_NORMAL); _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL);
_list.InsertColumn(0, LangString(IDS_PROP_NAME), 100); _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100);
_list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100); _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100);
@ -690,8 +690,9 @@ HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selected
#ifndef UNDER_CE #ifndef UNDER_CE
if (isDrive) if (isDrive)
{ {
if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0) item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(
item.iImage = 0; fi.Name + FCHAR_PATH_SEPARATOR,
FILE_ATTRIBUTE_DIRECTORY);
} }
else else
#endif #endif
@ -702,6 +703,7 @@ HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selected
wchar_t s[64]; wchar_t s[64];
{ {
s[0] = 0; s[0] = 0;
if (!FILETIME_IsZero(fi.MTime))
ConvertUtcFileTimeToString(fi.MTime, s, ConvertUtcFileTimeToString(fi.MTime, s,
#ifndef UNDER_CE #ifndef UNDER_CE
kTimestampPrintLevel_MIN kTimestampPrintLevel_MIN

View file

@ -356,8 +356,8 @@ bool CBrowseDialog2::OnInit()
#endif #endif
} }
_list.SetImageList(GetSysImageList(true), LVSIL_SMALL); _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL);
_list.SetImageList(GetSysImageList(false), LVSIL_NORMAL); _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL);
unsigned columnIndex = 0; unsigned columnIndex = 0;
_list.InsertColumn(columnIndex++, LangString(IDS_PROP_NAME), 100); _list.InsertColumn(columnIndex++, LangString(IDS_PROP_NAME), 100);
@ -1639,15 +1639,15 @@ HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &s
#ifndef UNDER_CE #ifndef UNDER_CE
if (isDrive) if (isDrive)
{ {
if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0) item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(
item.iImage = 0; fi.Name + FCHAR_PATH_SEPARATOR,
FILE_ATTRIBUTE_DIRECTORY);
} }
else else
#endif #endif
item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
if (item.iImage < 0) if (item.iImage < 0)
item.iImage = 0; item.iImage = 0;
_list.InsertItem(&item); _list.InsertItem(&item);
wchar_t s[64]; wchar_t s[64];
{ {
@ -1662,7 +1662,6 @@ HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &s
); );
_list.SetSubItem(index, subItem++, s); _list.SetSubItem(index, subItem++, s);
} }
{ {
s[0] = 0; s[0] = 0;
Browse_ConvertSizeToString(bi, s); Browse_ConvertSizeToString(bi, s);

View file

@ -206,13 +206,15 @@ Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite(
{ {
COverwriteDialog dialog; COverwriteDialog dialog;
dialog.OldFileInfo.SetTime(existTime); dialog.OldFileInfo.SetTime2(existTime);
dialog.OldFileInfo.SetSize(existSize); dialog.OldFileInfo.SetSize2(existSize);
dialog.OldFileInfo.Name = existName; dialog.OldFileInfo.Path = existName;
dialog.OldFileInfo.Is_FileSystemFile = true;
dialog.NewFileInfo.SetTime(newTime); dialog.NewFileInfo.SetTime2(newTime);
dialog.NewFileInfo.SetSize(newSize); dialog.NewFileInfo.SetSize2(newSize);
dialog.NewFileInfo.Name = newName; dialog.NewFileInfo.Path = newName;
dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder;
ProgressDialog->WaitCreating(); ProgressDialog->WaitCreating();
INT_PTR writeAnswer = dialog.Create(*ProgressDialog); INT_PTR writeAnswer = dialog.Create(*ProgressDialog);

View file

@ -224,6 +224,8 @@ public:
bool ProcessAltStreams; bool ProcessAltStreams;
bool StreamMode; bool StreamMode;
bool ThereAreMessageErrors; bool ThereAreMessageErrors;
bool Src_Is_IO_FS_Folder;
#ifndef Z7_NO_CRYPTO #ifndef Z7_NO_CRYPTO
bool PasswordIsDefined; bool PasswordIsDefined;
bool PasswordWasAsked; bool PasswordWasAsked;
@ -286,6 +288,8 @@ public:
, MultiArcMode(false) , MultiArcMode(false)
, ProcessAltStreams(true) , ProcessAltStreams(true)
, StreamMode(false) , StreamMode(false)
, ThereAreMessageErrors(false)
, Src_Is_IO_FS_Folder(false)
#ifndef Z7_NO_CRYPTO #ifndef Z7_NO_CRYPTO
, PasswordIsDefined(false) , PasswordIsDefined(false)
, PasswordWasAsked(false) , PasswordWasAsked(false)

View file

@ -45,7 +45,8 @@ struct CPhysTempBuffer
~CPhysTempBuffer() { MidFree(buffer); } ~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) UInt32 bufferSize, UInt64 progressStart, IProgress *progress)
{ {
NIO::CInFile inFile; NIO::CInFile inFile;
@ -74,9 +75,11 @@ static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt
for (UInt64 pos = 0; pos < fileSize;) for (UInt64 pos = 0; pos < fileSize;)
{ {
UInt64 progressCur = progressStart + pos; {
const UInt64 progressCur = progressStart + pos;
RINOK(progress->SetCompleted(&progressCur)) RINOK(progress->SetCompleted(&progressCur))
UInt64 rem = fileSize - pos; }
const UInt64 rem = fileSize - pos;
UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize); UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize);
UInt32 processedSize; UInt32 processedSize;
if (!inFile.Read(tempBuffer.buffer, curSize, 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) if (curSize > bufferSize)
return E_FAIL; return E_FAIL;
} }
if (!outFile.Write(tempBuffer.buffer, curSize, processedSize)) if (!outFile.Write(tempBuffer.buffer, curSize, processedSize))
return GetLastError_noZero_HRESULT(); return GetLastError_noZero_HRESULT();
if (curSize != processedSize) if (curSize != processedSize)
@ -135,9 +137,7 @@ Z7_COM7F_IMF(CFSDrives::LoadItems())
FOR_VECTOR (i, driveStrings) FOR_VECTOR (i, driveStrings)
{ {
CDriveInfo di; CDriveInfo di;
const FString &driveName = driveStrings[i]; const FString &driveName = driveStrings[i];
di.FullSystemName = driveName; di.FullSystemName = driveName;
if (!driveName.IsEmpty()) if (!driveName.IsEmpty())
di.Name.SetFrom(driveName, driveName.Len() - 1); di.Name.SetFrom(driveName, driveName.Len() - 1);
@ -183,25 +183,24 @@ Z7_COM7F_IMF(CFSDrives::LoadItems())
{ {
FString name ("PhysicalDrive"); FString name ("PhysicalDrive");
name.Add_UInt32(n); name.Add_UInt32(n);
FString fullPath (kVolPrefix); FString fullPath (kVolPrefix);
fullPath += name; fullPath += name;
CFileInfo fi; CFileInfo fi;
if (!fi.Find(fullPath)) if (!fi.Find(fullPath))
continue; continue;
CDriveInfo di; CDriveInfo di;
di.Name = name; 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.ClusterSize = 0;
di.DriveSize = fi.Size; di.DriveSize = fi.Size;
di.FreeSpace = 0; di.FreeSpace = 0;
di.DriveType = 0; di.DriveType = 0;
di.IsPhysicalDrive = true; di.IsPhysicalDrive = true;
di.KnownSize = true; di.KnownSize = true;
_drives.Add(di); _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)) Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
{ {
if (itemIndex >= (UInt32)_drives.Size()) if (itemIndex >= _drives.Size())
return E_INVALIDARG; return E_INVALIDARG;
NCOM::CPropVariant prop; NCOM::CPropVariant prop;
const CDriveInfo &di = _drives[itemIndex]; 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)) Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
{ {
*resultFolder = NULL; *resultFolder = NULL;
if (index >= (UInt32)_drives.Size()) if (index >= _drives.Size())
return E_INVALIDARG; return E_INVALIDARG;
const CDriveInfo &di = _drives[index]; 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)) Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
{ {
*iconIndex = 0; *iconIndex = -1;
const CDriveInfo &di = _drives[index]; const CDriveInfo &di = _drives[index];
if (di.IsPhysicalDrive) return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
return S_OK; di.FullSystemName,
int iconIndexTemp; _volumeMode ?
if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0) FILE_ATTRIBUTE_ARCHIVE:
{ FILE_ATTRIBUTE_DIRECTORY,
*iconIndex = iconIndexTemp; iconIndex);
return S_OK;
}
return GetLastError_noZero_HRESULT();
} }
void CFSDrives::AddExt(FString &s, unsigned index) const 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) if (numItems == 0)
return S_OK; return S_OK;
if (moveMode) if (moveMode)
return E_NOTIMPL; return E_NOTIMPL;
if (!_volumeMode) if (!_volumeMode)
return E_NOTIMPL; 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->SetTotal(totalSize))
RINOK(callback->SetNumFiles(numItems)) RINOK(callback->SetNumFiles(numItems))
FString destPath = us2fs(path); const FString destPath = us2fs(path);
if (destPath.IsEmpty()) if (destPath.IsEmpty())
return E_INVALIDARG; return E_INVALIDARG;
bool isAltDest = NName::IsAltPathPrefix(destPath); const bool isAltDest = NName::IsAltPathPrefix(destPath);
bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
if (isDirectPath) if (isDirectPath)
{ {
@ -428,7 +422,7 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num
RINOK(callback->SetCompleted(&completedSize)) RINOK(callback->SetCompleted(&completedSize))
for (i = 0; i < numItems; i++) for (i = 0; i < numItems; i++)
{ {
unsigned index = indices[i]; const unsigned index = indices[i];
const CDriveInfo &di = _drives[index]; const CDriveInfo &di = _drives[index];
FString destPath2 = destPath; FString destPath2 = destPath;
@ -443,7 +437,7 @@ Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num
destPath2 += destName; destPath2 += destName;
} }
FString srcPath = di.GetDeviceFileIoName(); const FString srcPath = di.GetDeviceFileIoName();
UInt64 fileSize = 0; UInt64 fileSize = 0;
if (GetFileSize(index, fileSize) != S_OK) if (GetFileSize(index, fileSize) != S_OK)

View file

@ -535,7 +535,7 @@ Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
{ {
NCOM::CPropVariant prop; NCOM::CPropVariant prop;
/* /*
if (index >= (UInt32)Files.Size()) if (index >= Files.Size())
{ {
CAltStream &ss = Streams[index - Files.Size()]; CAltStream &ss = Streams[index - Files.Size()];
CDirItem &fi = Files[ss.Parent]; CDirItem &fi = Files[ss.Parent];
@ -561,7 +561,7 @@ Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
case kpidComment: break; case kpidComment: break;
default: index = ss.Parent; default: index = ss.Parent;
} }
if (index >= (UInt32)Files.Size()) if (index >= Files.Size())
{ {
prop.Detach(value); prop.Detach(value);
return S_OK; return S_OK;
@ -716,8 +716,8 @@ Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPI
/* /*
const CAltStream *ss1 = NULL; const CAltStream *ss1 = NULL;
const CAltStream *ss2 = NULL; const CAltStream *ss2 = NULL;
if (index1 >= (UInt32)Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; } if (index1 >= Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; }
if (index2 >= (UInt32)Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; } if (index2 >= Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; }
*/ */
CDirItem &fi1 = Files[index1]; CDirItem &fi1 = Files[index1];
CDirItem &fi2 = Files[index2]; 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)) Z7_COM7F_IMF(CFSFolder::CalcItemFullSize(UInt32 index, IProgress *progress))
{ {
if (index >= (UInt32)Files.Size()) if (index >= Files.Size())
return S_OK; return S_OK;
CDirItem &fi = Files[index]; CDirItem &fi = Files[index];
if (!fi.IsDir()) 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 */)) 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; return E_NOTIMPL;
const CDirItem &fi = Files[index]; const CDirItem &fi = Files[index];
// FString prefix; // FString prefix;
@ -1103,9 +1103,9 @@ Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress
UInt32 index = indices[i]; UInt32 index = indices[i];
bool result = true; 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) if (prevDeletedFileIndex != ss.Parent)
{ {
const CDirItem &fi = Files[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, Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID,
const PROPVARIANT *value, IProgress * /* progress */)) const PROPVARIANT *value, IProgress * /* progress */))
{ {
if (index >= (UInt32)Files.Size()) if (index >= Files.Size())
return E_INVALIDARG; return E_INVALIDARG;
CDirItem &fi = Files[index]; CDirItem &fi = Files[index];
if (fi.Parent >= 0) 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)) Z7_COM7F_IMF(CFSFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
{ {
if (index >= (UInt32)Files.Size()) *iconIndex = -1;
if (index >= Files.Size())
return E_INVALIDARG; return E_INVALIDARG;
const CDirItem &fi = Files[index]; const CDirItem &fi = Files[index];
*iconIndex = 0; return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
int iconIndexTemp; _path + GetRelPath(fi), fi.Attrib, iconIndex);
if (GetRealIconIndex(_path + GetRelPath(fi), fi.Attrib, iconIndexTemp) != 0)
{
*iconIndex = iconIndexTemp;
return S_OK;
}
return GetLastError_noZero_HRESULT();
} }
Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode)) Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode))

View file

@ -22,11 +22,11 @@ class CFSFolder;
struct CDirItem: public NWindows::NFile::NFind::CFileInfo struct CDirItem: public NWindows::NFile::NFind::CFileInfo
{ {
#ifndef UNDER_CE #ifndef UNDER_CE
UInt64 PackSize; UInt64 PackSize;
#endif #endif
#ifdef FS_SHOW_LINKS_INFO #ifdef FS_SHOW_LINKS_INFO
FILETIME ChangeTime; FILETIME ChangeTime;
UInt64 FileIndex; UInt64 FileIndex;
UInt32 NumLinks; UInt32 NumLinks;
@ -34,22 +34,21 @@ struct CDirItem: public NWindows::NFile::NFind::CFileInfo
bool FileInfo_WasRequested; bool FileInfo_WasRequested;
bool ChangeTime_Defined; bool ChangeTime_Defined;
bool ChangeTime_WasRequested; bool ChangeTime_WasRequested;
#endif #endif
#ifndef UNDER_CE #ifndef UNDER_CE
bool PackSize_Defined; bool PackSize_Defined;
#endif #endif
bool FolderStat_Defined; bool FolderStat_Defined;
int Parent;
#ifndef UNDER_CE #ifndef UNDER_CE
CByteBuffer Reparse; CByteBuffer Reparse;
#endif #endif
UInt64 NumFolders; UInt64 NumFolders;
UInt64 NumFiles; UInt64 NumFiles;
int Parent;
}; };
/* /*
@ -126,20 +125,18 @@ class CFSFolder Z7_final:
Z7_IFACE_COM7_IMP(IFolderSetFlatMode) Z7_IFACE_COM7_IMP(IFolderSetFlatMode)
// Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode) // Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode)
private: bool _flatMode;
FString _path; bool _commentsAreLoaded;
// bool _scanAltStreams;
FString _path;
CObjectVector<CDirItem> Files; CObjectVector<CDirItem> Files;
FStringVector Folders; FStringVector Folders;
// CObjectVector<CAltStream> Streams; // CObjectVector<CAltStream> Streams;
// CMyComPtr<IFolderFolder> _parentFolder; // CMyComPtr<IFolderFolder> _parentFolder;
bool _commentsAreLoaded;
CPairsStorage _comments; CPairsStorage _comments;
// bool _scanAltStreams;
bool _flatMode;
#ifdef _WIN32 #ifdef _WIN32
NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification;
#endif #endif
@ -163,7 +160,9 @@ public:
HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); } HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); }
#endif #endif
CFSFolder() : _flatMode(false) CFSFolder():
_flatMode(false),
_commentsAreLoaded(false)
// , _scanAltStreams(false) // , _scanAltStreams(false)
{} {}

View file

@ -515,8 +515,22 @@ static HRESULT CopyFile_Ask(
RINOK(state.ProgressInfo.ProgressResult) RINOK(state.ProgressInfo.ProgressResult)
if (!res) 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. // 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; return E_ABORT;
} }
state.ProgressInfo.StartPos += state.ProgressInfo.FileSize; state.ProgressInfo.StartPos += state.ProgressInfo.FileSize;

View file

@ -254,28 +254,23 @@ Z7_COM7F_IMF(CNetFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
{ {
if (index >= (UInt32)_items.Size()) *iconIndex = -1;
if (index >= _items.Size())
return E_INVALIDARG; return E_INVALIDARG;
*iconIndex = 0;
const CResourceW &resource = _items[index]; const CResourceW &resource = _items[index];
int iconIndexTemp;
if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER || if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER ||
resource.Usage == RESOURCEUSAGE_CONNECTABLE) resource.Usage == RESOURCEUSAGE_CONNECTABLE)
{ {
if (GetRealIconIndex(us2fs(resource.RemoteName), 0, iconIndexTemp)) return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
{ us2fs(resource.RemoteName), FILE_ATTRIBUTE_DIRECTORY, iconIndex);
*iconIndex = iconIndexTemp;
return S_OK;
}
} }
else else
{ {
if (GetRealIconIndex(FTEXT(""), FILE_ATTRIBUTE_DIRECTORY, iconIndexTemp)) #if 0
{ return S_FALSE;
*iconIndex = iconIndexTemp; #else
return S_OK; return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
FTEXT("__DIR__"), FILE_ATTRIBUTE_DIRECTORY, iconIndex);
#endif
} }
// *anIconIndex = GetRealIconIndex(0, L"\\\\HOME");
}
return GetLastError_noZero_HRESULT();
} }

View file

@ -2,8 +2,10 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h" #include "../../../Common/StringConvert.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/PropVariantConv.h" #include "../../../Windows/PropVariantConv.h"
#include "../../../Windows/ResourceString.h" #include "../../../Windows/ResourceString.h"
@ -29,12 +31,16 @@ static const UInt32 kLangIDs[] =
}; };
#endif #endif
static const unsigned kCurrentFileNameSizeLimit = 82; static const unsigned kCurrentFileNameSizeLimit = 72;
static const unsigned kCurrentFileNameSizeLimit2 = 30;
void COverwriteDialog::ReduceString(UString &s) 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) if (s.Len() > size)
{ {
s.Delete(size / 2, s.Len() - size); s.Delete(size / 2, s.Len() - size);
@ -42,35 +48,67 @@ void COverwriteDialog::ReduceString(UString &s)
} }
if (!s.IsEmpty() && s.Back() == ' ') if (!s.IsEmpty() && s.Back() == ' ')
{ {
// s += (wchar_t)(0x2423); // s += (wchar_t)(0x2423); // visible space
s.InsertAtFront(L'\"'); 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)
{ {
UString sizeString; NControl::CStatic staticContol;
if (fileInfo.SizeIsDefined) staticContol.Attach(GetItem(iconID));
sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size)); hIcon = staticContol.SetIcon(hIcon);
if (hIcon)
DestroyIcon(hIcon);
}
const UString &fileName = fileInfo.Name; void AddSizeValue(UString &s, UInt64 value);
int slashPos = fileName.ReverseFind_PathSepar(); void AddSizeValue(UString &s, UInt64 value)
UString s1 = fileName.Left((unsigned)(slashPos + 1)); {
UString s2 = fileName.Ptr((unsigned)(slashPos + 1)); {
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";
}
}
ReduceString(s1);
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); ReduceString(s2);
UString s = s1;
s.Add_LF();
s += s2; s += s2;
}
s.Add_LF(); s.Add_LF();
s += sizeString; if (fileInfo.Size_IsDefined)
AddSizeValue(s, fileInfo.Size);
s.Add_LF(); s.Add_LF();
if (fileInfo.Time_IsDefined)
if (fileInfo.TimeIsDefined)
{ {
AddLangString(s, IDS_PROP_MTIME); AddLangString(s, IDS_PROP_MTIME);
s += ": "; s += ": ";
@ -78,30 +116,133 @@ void COverwriteDialog::SetFileInfoControl(unsigned textID, unsigned iconID,
ConvertUtcFileTimeToString(fileInfo.Time, t); ConvertUtcFileTimeToString(fileInfo.Time, t);
s += 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.
NControl::CDialogChildControl control; if (name.Len() >= MAX_PATH))
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))
{ {
NControl::CStatic staticContol; it can return:
staticContol.Attach(GetItem(iconID)); return 0.
staticContol.SetIcon(shellFileInfo.hIcon); 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++)
{
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() bool COverwriteDialog::OnInit()
{ {
#ifdef Z7_LANG #ifdef Z7_LANG
LangSetWindowText(*this, IDD_OVERWRITE); LangSetWindowText(*this, IDD_OVERWRITE);
LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
#endif #endif
SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo); SetFileInfoControl(OldFileInfo,
SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo); 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(); NormalizePosition();
if (!ShowExtraButtons) if (!ShowExtraButtons)
@ -122,6 +263,15 @@ bool COverwriteDialog::OnInit()
return CModalDialog::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) bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
{ {
switch (buttonID) switch (buttonID)

View file

@ -12,68 +12,78 @@ namespace NOverwriteDialog
{ {
struct CFileInfo struct CFileInfo
{ {
bool SizeIsDefined; bool Size_IsDefined;
bool TimeIsDefined; bool Time_IsDefined;
bool Is_FileSystemFile;
UInt64 Size; UInt64 Size;
FILETIME Time; FILETIME Time;
UString Name; UString Path;
void SetTime(const FILETIME *t) void SetTime(const FILETIME &t)
{
Time = t;
Time_IsDefined = true;
}
void SetTime2(const FILETIME *t)
{ {
if (!t) if (!t)
TimeIsDefined = false; Time_IsDefined = false;
else else
{ SetTime(*t);
TimeIsDefined = true;
Time = *t;
}
} }
void SetSize(UInt64 size) void SetSize(UInt64 size)
{ {
SizeIsDefined = true;
Size = size; Size = size;
Size_IsDefined = true;
} }
void SetSize(const UInt64 *size) void SetSize2(const UInt64 *size)
{ {
if (!size) if (!size)
SizeIsDefined = false; Size_IsDefined = false;
else else
SetSize(*size); SetSize(*size);
} }
CFileInfo():
Size_IsDefined(false),
Time_IsDefined(false),
Is_FileSystemFile(false)
{}
}; };
} }
class COverwriteDialog: public NWindows::NControl::CModalDialog class COverwriteDialog: public NWindows::NControl::CModalDialog
{ {
#ifdef UNDER_CE
bool _isBig; 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 OnInit() Z7_override;
virtual bool OnDestroy() Z7_override;
virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
void ReduceString(UString &s); void ReduceString(UString &s);
public: public:
bool ShowExtraButtons; bool ShowExtraButtons;
bool DefaultButton_is_NO; bool DefaultButton_is_NO;
NOverwriteDialog::CFileInfo OldFileInfo;
NOverwriteDialog::CFileInfo NewFileInfo;
COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {} COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {}
INT_PTR Create(HWND parent = NULL) INT_PTR Create(HWND parent = NULL)
{ {
#ifdef UNDER_CE
BIG_DIALOG_SIZE(280, 200); BIG_DIALOG_SIZE(280, 200);
#ifdef UNDER_CE
_isBig = isBig; _isBig = isBig;
#else #endif
_isBig = true;
#endif
return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent); return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent);
} }
NOverwriteDialog::CFileInfo OldFileInfo;
NOverwriteDialog::CFileInfo NewFileInfo;
}; };
#endif #endif

View file

@ -1,7 +1,7 @@
#include "OverwriteDialogRes.h" #include "OverwriteDialogRes.h"
#include "../../GuiCommon.rc" #include "../../GuiCommon.rc"
#define xc 280 #define xc 340
#define yc 200 #define yc 200
#undef iconSize #undef iconSize
@ -25,11 +25,13 @@ BEGIN
LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8 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, 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 "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX
LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8 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, 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 LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX
PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys

View file

@ -11,7 +11,9 @@
#define IDB_NO_TO_ALL 441 #define IDB_NO_TO_ALL 441
#define IDI_OVERWRITE_OLD_FILE 100 #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_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

View file

@ -420,8 +420,8 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
_listView._panel = this; _listView._panel = this;
_listView.SetWindowProc(); _listView.SetWindowProc();
_listView.SetImageList(GetSysImageList(true), LVSIL_SMALL); _listView.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL);
_listView.SetImageList(GetSysImageList(false), LVSIL_NORMAL); _listView.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL);
// _exStyle |= LVS_EX_HEADERDRAGDROP; // _exStyle |= LVS_EX_HEADERDRAGDROP;
// DWORD extendedStyle = _listView.GetExtendedListViewStyle(); // DWORD extendedStyle = _listView.GetExtendedListViewStyle();
@ -506,17 +506,15 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
#endif #endif
, NULL, , NULL,
WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL, WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,
0, 0, 100, 520, 0, 0, 100, 620,
(_headerReBar ? _headerToolBar : (HWND)*this), (_headerReBar ? _headerToolBar : (HWND)*this),
(HMENU)(UINT_PTR)(_comboBoxID), (HMENU)(UINT_PTR)(_comboBoxID),
g_hInstance, NULL); g_hInstance, NULL);
#ifndef UNDER_CE
#ifndef UNDER_CE
_headerComboBox.SetUnicodeFormat(true); _headerComboBox.SetUnicodeFormat(true);
_headerComboBox.SetImageList(Shell_Get_SysImageList_smallIcons(true));
_headerComboBox.SetImageList(GetSysImageList(true));
_headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC); _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);
/* /*
_headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox)); _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox));
_headerComboBox._panel = this; _headerComboBox._panel = this;
@ -525,9 +523,7 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
LONG_PTR(ComboBoxSubclassProc)); LONG_PTR(ComboBoxSubclassProc));
*/ */
_comboBoxEdit.Attach(_headerComboBox.GetEditControl()); _comboBoxEdit.Attach(_headerComboBox.GetEditControl());
// _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0); // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0);
_comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit)); _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit));
_comboBoxEdit._panel = this; _comboBoxEdit._panel = this;
#ifndef _UNICODE #ifndef _UNICODE
@ -538,8 +534,7 @@ bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
#endif #endif
_comboBoxEdit._origWindowProc = _comboBoxEdit._origWindowProc =
(WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
#endif
#endif
if (_headerReBar) if (_headerReBar)
{ {

View file

@ -147,11 +147,11 @@ public:
struct CTempFileInfo struct CTempFileInfo
{ {
UInt32 FileIndex; // index of file in folder UInt32 FileIndex; // index of file in folder
bool NeedDelete;
UString RelPath; // Relative path of file from Folder UString RelPath; // Relative path of file from Folder
FString FolderPath; FString FolderPath;
FString FilePath; FString FilePath;
NWindows::NFile::NFind::CFileInfo FileInfo; NWindows::NFile::NFind::CFileInfo FileInfo;
bool NeedDelete;
CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {} CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {}
void DeleteDirAndFile() const void DeleteDirAndFile() const
@ -171,15 +171,15 @@ struct CTempFileInfo
struct CFolderLink: public CTempFileInfo struct CFolderLink: public CTempFileInfo
{ {
bool IsVirtual;
bool UsePassword;
NWindows::NDLL::CLibrary Library; NWindows::NDLL::CLibrary Library;
CMyComPtr<IFolderFolder> ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0]) CMyComPtr<IFolderFolder> 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) UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level)
bool UsePassword;
UString Password; UString Password;
bool IsVirtual;
UString VirtualPath; // without tail slash UString VirtualPath; // without tail slash
CFolderLink(): UsePassword(false), IsVirtual(false) {} CFolderLink(): IsVirtual(false), UsePassword(false) {}
bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const
{ {
@ -310,7 +310,7 @@ struct COpenResult
class CPanel Z7_final: public NWindows::NControl::CWindow2 class CPanel Z7_final: public NWindows::NControl::CWindow2
{ {
CExtToIconMap _extToIconMap; // CExtToIconMap _extToIconMap;
UINT _baseID; UINT _baseID;
unsigned _comboBoxID; unsigned _comboBoxID;
UINT _statusBarID; UINT _statusBarID;
@ -324,7 +324,7 @@ class CPanel Z7_final: public NWindows::NControl::CWindow2
virtual void OnDestroy() Z7_override; virtual void OnDestroy() Z7_override;
virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result) 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); bool OnComboBoxCommand(UINT code, LPARAM param, LRESULT &result);
@ -355,7 +355,7 @@ public:
HWND _mainWindow; HWND _mainWindow;
CPanelCallback *_panelCallback; CPanelCallback *_panelCallback;
void SysIconsWereChanged() { _extToIconMap.Clear(); } // void SysIconsWereChanged() { _extToIconMap.Clear(); }
void DeleteItems(bool toRecycleBin); void DeleteItems(bool toRecycleBin);
void CreateFolder(); void CreateFolder();

View file

@ -189,7 +189,9 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options,
extracter.ExtractCallbackSpec = new CExtractCallbackImp; extracter.ExtractCallbackSpec = new CExtractCallbackImp;
extracter.ExtractCallback = extracter.ExtractCallbackSpec; extracter.ExtractCallback = extracter.ExtractCallbackSpec;
extracter.ExtractCallbackSpec->Src_Is_IO_FS_Folder =
IsFSFolder() || IsAltStreamsFolder();
// options.src_Is_IO_FS_Folder;
extracter.options = &options; extracter.options = &options;
extracter.ExtractCallbackSpec->ProgressDialog = &extracter; extracter.ExtractCallbackSpec->ProgressDialog = &extracter;
extracter.CompressingMode = false; extracter.CompressingMode = false;

View file

@ -368,14 +368,41 @@ void CPanel::LoadFullPath()
_currentFolderPrefix += GetFolderPath(_folder); _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; int index = -1;
if (GetRealIconIndex(path, attributes, index) != 0) if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(path, attrib, index))
if (index >= 0)
return index; return index;
return -1; 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() void CPanel::LoadFullPathAndShow()
{ {
LoadFullPath(); LoadFullPath();
@ -387,30 +414,97 @@ void CPanel::LoadFullPathAndShow()
COMBOBOXEXITEM item; COMBOBOXEXITEM item;
item.mask = 0; item.mask = 0;
item.iImage = -1;
UString path = _currentFolderPrefix; UString path = _currentFolderPrefix;
if (path.Len() > // path = "\\\\.\\PhysicalDrive1\\"; // for debug
#ifdef _WIN32 // path = "\\\\.\\y:\\"; // for debug
3 if (!path.IsEmpty())
#else {
1 const unsigned rootPrefixSize = NName::GetRootPrefixSize(path);
#endif if (rootPrefixSize == 0 && path[0] != '\\')
&& IS_PATH_SEPAR(path.Back())) {
path.DeleteBack(); int iconIndex = -1;
UString name_Computer = RootFolder_GetName_Computer(iconIndex);
DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; name_Computer.Add_PathSepar();
if (path == name_Computer
// GetRealIconIndex is slow for direct DVD/UDF path. So we use dummy path || path == L"\\\\?\\")
if (path.IsPrefixedBy(L"\\\\.\\")) item.iImage = iconIndex;
path = "_TestFolder_";
else else
{ {
CFileInfo fi; UString name = RootFolder_GetName_Network(iconIndex);
if (fi.Find(us2fs(path))) name.Add_PathSepar();
attrib = fi.Attrib; if (path == name)
item.iImage = iconIndex;
}
} }
item.iImage = GetRealIconIndex(us2fs(path), attrib);
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));
}
}
}
}
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) if (item.iImage >= 0)
{ {
item.iSelectedImage = item.iImage; item.iSelectedImage = item.iImage;
@ -495,13 +589,13 @@ bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result)
} }
#endif #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 #ifdef UNDER_CE
UString s; UString s;
iconIndex = iconIndex; iconIndex = iconIndex;
for (int i = 0; i < indent; i++) for (unsigned i = 0; i < indent; i++)
s += " "; s += " ";
_headerComboBox.AddString(s + name); _headerComboBox.AddString(s + name);
@ -509,23 +603,26 @@ void CPanel::AddComboBoxItem(const UString &name, int iconIndex, int indent, boo
COMBOBOXEXITEMW item; COMBOBOXEXITEMW item;
item.mask = CBEIF_TEXT | CBEIF_INDENT; item.mask = CBEIF_TEXT | CBEIF_INDENT;
if (iconIndex < 0)
iconIndex = g_Ext_to_Icon_Map.GetIconIndex_DIR();
item.iSelectedImage = item.iImage = iconIndex; item.iSelectedImage = item.iImage = iconIndex;
if (iconIndex >= 0) if (iconIndex >= 0)
item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
item.iItem = -1; item.iItem = -1;
item.iIndent = indent; item.iIndent = (int)indent;
item.pszText = name.Ptr_non_const(); item.pszText = name.Ptr_non_const();
_headerComboBox.InsertItem(&item); _headerComboBox.InsertItem(&item);
#endif #endif
if (addToList) 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) bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
{ {
@ -537,56 +634,168 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
ComboBoxPaths.Clear(); ComboBoxPaths.Clear();
_headerComboBox.ResetContent(); _headerComboBox.ResetContent();
unsigned i; UString sumPath;
UStringVector pathParts; UStringVector pathParts;
unsigned indent = 0;
SplitPathToParts(_currentFolderPrefix, pathParts);
UString sumPass;
if (!pathParts.IsEmpty())
pathParts.DeleteBack();
for (i = 0; i < pathParts.Size(); i++)
{ {
const UString name = pathParts[i]; UString path = _currentFolderPrefix;
sumPass += name; // path = L"\\\\.\\y:\\"; // for debug
sumPass.Add_PathSepar(); UString prefix0;
CFileInfo info; if (path.IsPrefixedBy_Ascii_NoCase("\\\\"))
DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; {
if (info.Find(us2fs(sumPass))) const int separ = FindCharPosInString(path.Ptr(2), '\\');
attrib = info.Attrib; if (separ > 0
AddComboBoxItem( && (separ > 1 || path[2] != '.')) // "\\\\.\\" will be processed later
name.IsEmpty() ? L"\\" : name, {
GetRealIconIndex(us2fs(sumPass), attrib), const UString s = path.Left(2 + separ);
(int)i, // iIndent prefix0 = s;
prefix0.Add_PathSepar();
AddComboBoxItem(s,
GetRealIconIndex_for_DirPath(us2fs(prefix0), FILE_ATTRIBUTE_DIRECTORY),
indent++,
false); // addToList false); // addToList
ComboBoxPaths.Add(sumPass); ComboBoxPaths.Add(prefix0);
}
} }
#ifndef UNDER_CE 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);
}
// 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);
// const bool is_devicePrefix = (sumPath == L"\\\\.\\");
if (pathParts.Size() > 1)
if (!sumPath.IsEmpty()
|| pathParts.Size() != 2
|| pathParts[0] != name_Computer)
for (unsigned i = 0; i + 1 < pathParts.Size(); i++)
{
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
}
#ifndef UNDER_CE
{
int iconIndex; int iconIndex;
UString name; const UString name = RootFolder_GetName_Documents(iconIndex);
name = RootFolder_GetName_Documents(iconIndex); // iconIndex = -1; // for debug
AddComboBoxItem(name, iconIndex, 0, true); AddComboBoxItem(name, iconIndex, 0, true);
}
name = RootFolder_GetName_Computer(iconIndex); AddComboBoxItem(name_Computer, iconIndex_Computer, 0, true);
AddComboBoxItem(name, iconIndex, 0, true); {
FStringVector driveStrings; FStringVector driveStrings;
MyGetLogicalDriveStrings(driveStrings); MyGetLogicalDriveStrings(driveStrings);
for (i = 0; i < driveStrings.Size(); i++) FOR_VECTOR (i, driveStrings)
{ {
FString s = driveStrings[i]; FString s = driveStrings[i];
ComboBoxPaths.Add(fs2us(s)); ComboBoxPaths.Add(fs2us(s));
int iconIndex2 = GetRealIconIndex(s, 0); int iconIndex2 = GetRealIconIndex_for_DirPath(s, FILE_ATTRIBUTE_DIRECTORY);
if (s.Len() > 0 && s.Back() == FCHAR_PATH_SEPARATOR) if (!s.IsEmpty())
{
const FChar c = s.Back();
if (IS_PATH_SEPAR(c))
s.DeleteBack(); s.DeleteBack();
}
// iconIndex2 = -1; // for debug
AddComboBoxItem(fs2us(s), iconIndex2, 1, false); AddComboBoxItem(fs2us(s), iconIndex2, 1, false);
} }
}
name = RootFolder_GetName_Network(iconIndex); {
int iconIndex;
const UString name = RootFolder_GetName_Network(iconIndex);
AddComboBoxItem(name, iconIndex, 0, true); AddComboBoxItem(name, iconIndex, 0, true);
}
#endif #endif
return false; return false;
} }
@ -596,10 +805,10 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
int index = _headerComboBox.GetCurSel(); int index = _headerComboBox.GetCurSel();
if (index >= 0) if (index >= 0)
{ {
UString pass = ComboBoxPaths[index]; const UString path = ComboBoxPaths[index];
_headerComboBox.SetCurSel(-1); _headerComboBox.SetCurSel(-1);
// _headerComboBox.SetText(pass); // it's fix for seclecting by mouse. // _headerComboBox.SetText(pass); // it's fix for selecting by mouse.
if (BindToPathAndRefresh(pass) == S_OK) if (BindToPathAndRefresh(path) == S_OK)
{ {
PostMsg(kSetFocusToListView); PostMsg(kSetFocusToListView);
#ifdef UNDER_CE #ifdef UNDER_CE

View file

@ -583,8 +583,13 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
int cursorIndex = -1; int cursorIndex = -1;
CMyComPtr<IFolderGetSystemIconIndex> folderGetSystemIconIndex; CMyComPtr<IFolderGetSystemIconIndex> folderGetSystemIconIndex;
#if 1 // 0 : for debug local icons loading
if (!Is_Slow_Icon_Folder() || _showRealFileIcons) if (!Is_Slow_Icon_Folder() || _showRealFileIcons)
_folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex);
#endif
const bool isFSDrivesFolder = IsFSDrivesFolder();
const bool isArcFolder = IsArcFolder();
if (!IsFSFolder()) if (!IsFSFolder())
{ {
@ -631,8 +636,9 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
#else #else
item.pszText = LPSTR_TEXTCALLBACKW; item.pszText = LPSTR_TEXTCALLBACKW;
#endif #endif
const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY; // const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY;
item.iImage = _extToIconMap.GetIconIndex(attrib, itemName); item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR();
// g_Ext_to_Icon_Map.GetIconIndex(attrib, itemName);
if (item.iImage < 0) if (item.iImage < 0)
item.iImage = 0; item.iImage = 0;
if (_listView.InsertItem(&item) == -1) if (_listView.InsertItem(&item) == -1)
@ -755,11 +761,52 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
} }
bool defined = false; bool defined = false;
item.iImage = -1;
if (folderGetSystemIconIndex) if (folderGetSystemIconIndex)
{ {
folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage); const HRESULT res = folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage);
if (res == S_OK)
{
// item.iImage = -1; // for debug
defined = (item.iImage > 0); 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) if (!defined)
@ -769,26 +816,37 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
NCOM::CPropVariant prop; NCOM::CPropVariant prop;
RINOK(_folder->GetProperty(i, kpidAttrib, &prop)) RINOK(_folder->GetProperty(i, kpidAttrib, &prop))
if (prop.vt == VT_UI4) if (prop.vt == VT_UI4)
{
attrib = prop.ulVal; 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)) if (IsItem_Folder(i))
attrib |= FILE_ATTRIBUTE_DIRECTORY; attrib |= FILE_ATTRIBUTE_DIRECTORY;
if (_currentFolderPrefix.IsEmpty())
{
int iconIndexTemp;
GetRealIconIndex(us2fs((UString)name) + FCHAR_PATH_SEPARATOR, attrib, iconIndexTemp);
item.iImage = iconIndexTemp;
}
else 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) if (item.iImage < 0)
item.iImage = 0; item.iImage = 0; // default image
if (_listView.InsertItem(&item) == -1) if (_listView.InsertItem(&item) == -1)
return E_FAIL; return E_FAIL;
listViewItemCount++; listViewItemCount++;
@ -858,8 +916,8 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
sprintf(s, sprintf(s,
// "attribMap = %5d, extMap = %5d, " // "attribMap = %5d, extMap = %5d, "
"delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d", "delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d",
// _extToIconMap._attribMap.Size(), // g_Ext_to_Icon_Map._attribMap.Size(),
// _extToIconMap._extMap.Size(), // g_Ext_to_Icon_Map._extMap.Size(),
tickCount1 - tickCount0, tickCount1 - tickCount0,
tickCount2 - tickCount1, tickCount2 - tickCount1,
tickCount3 - tickCount2, tickCount3 - tickCount2,

View file

@ -54,9 +54,9 @@ UString RootFolder_GetName_Computer(int &iconIndex);
UString RootFolder_GetName_Computer(int &iconIndex) UString RootFolder_GetName_Computer(int &iconIndex)
{ {
#ifdef USE_WIN_PATHS #ifdef USE_WIN_PATHS
iconIndex = GetIconIndexForCSIDL(CSIDL_DRIVES); iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES);
#else #else
GetRealIconIndex(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, iconIndex); iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY);
#endif #endif
return LangString(IDS_COMPUTER); 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);
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); return LangString(IDS_NETWORK);
} }
UString RootFolder_GetName_Documents(int &iconIndex); UString RootFolder_GetName_Documents(int &iconIndex);
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); 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_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]);
_names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]); _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]);
_names[ROOT_INDEX_VOLUMES] = kVolPrefix; _names[ROOT_INDEX_VOLUMES] = kVolPrefix;
_iconIndices[ROOT_INDEX_VOLUMES] = GetIconIndexForCSIDL(CSIDL_DRIVES); _iconIndices[ROOT_INDEX_VOLUMES] = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES);
#endif #endif
} }

View file

@ -20,16 +20,19 @@
extern bool g_IsNT; extern bool g_IsNT;
#endif #endif
int GetIconIndexForCSIDL(int csidl) CExtToIconMap g_Ext_to_Icon_Map;
int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl)
{ {
LPITEMIDLIST pidl = NULL; LPITEMIDLIST pidl = NULL;
SHGetSpecialFolderLocation(NULL, csidl, &pidl); SHGetSpecialFolderLocation(NULL, csidl, &pidl);
if (pidl) if (pidl)
{ {
SHFILEINFO shellInfo; SHFILEINFO shFileInfo;
shellInfo.iIcon = 0; shFileInfo.iIcon = -1;
const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), FILE_ATTRIBUTE_NORMAL, const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl),
&shellInfo, sizeof(shellInfo), FILE_ATTRIBUTE_DIRECTORY,
&shFileInfo, sizeof(shFileInfo),
SHGFI_PIDL | SHGFI_SYSICONINDEX); SHGFI_PIDL | SHGFI_SYSICONINDEX);
/* /*
IMalloc *pMalloc; IMalloc *pMalloc;
@ -43,9 +46,9 @@ int GetIconIndexForCSIDL(int csidl)
// we use OLE2.dll function here // we use OLE2.dll function here
CoTaskMemFree(pidl); CoTaskMemFree(pidl);
if (res) if (res)
return shellInfo.iIcon; return shFileInfo.iIcon;
} }
return 0; return -1;
} }
#ifndef _UNICODE #ifndef _UNICODE
@ -60,69 +63,111 @@ static struct C_SHGetFileInfo_Init
f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS( f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS(
Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"), Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"),
"SHGetFileInfoW"); "SHGetFileInfoW");
// f_SHGetFileInfoW = NULL; // for debug
} }
} g_SHGetFileInfo_Init; } g_SHGetFileInfo_Init;
#endif #endif
#ifdef _UNICODE
#define My_SHGetFileInfoW SHGetFileInfoW
#else
static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags) 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) if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW)
return 0; return 0;
return g_SHGetFileInfo_Init.f_SHGetFileInfoW return g_SHGetFileInfo_Init.f_SHGetFileInfoW(pszPath, attrib, psfi, cbFileInfo, uFlags);
#endif
(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 #ifndef _UNICODE
if (!g_IsNT) if (!g_IsNT || !g_SHGetFileInfo_Init.f_SHGetFileInfoW)
{ {
SHFILEINFO shellInfo; SHFILEINFO shFileInfo;
const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, // ZeroMemory(&shFileInfo, sizeof(shFileInfo));
sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); shFileInfo.iIcon = -1; // optional
iconIndex = shellInfo.iIcon; const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path),
attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE,
&shFileInfo, sizeof(shFileInfo),
SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
iconIndex = shFileInfo.iIcon;
return res; return res;
} }
else else
#endif #endif
{ {
SHFILEINFOW shellInfo; SHFILEINFOW shFileInfo;
const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, // ZeroMemory(&shFileInfo, sizeof(shFileInfo));
sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); shFileInfo.iIcon = -1; // optional
iconIndex = shellInfo.iIcon; 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; 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 #ifndef _UNICODE
if (!g_IsNT) if (!g_IsNT)
{ {
SHFILEINFO shellInfo; SHFILEINFO shFileInfo;
shellInfo.szTypeName[0] = 0; shFileInfo.szTypeName[0] = 0;
DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo,
sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (typeName) if (typeName)
*typeName = GetUnicodeString(shellInfo.szTypeName); *typeName = GetUnicodeString(shFileInfo.szTypeName);
iconIndex = shellInfo.iIcon; iconIndex = shFileInfo.iIcon;
return res; return res;
} }
else else
#endif #endif
{ {
SHFILEINFOW shellInfo; SHFILEINFOW shFileInfo;
shellInfo.szTypeName[0] = 0; shFileInfo.szTypeName[0] = 0;
DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo, DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo,
sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (typeName) if (typeName)
*typeName = shellInfo.szTypeName; *typeName = shFileInfo.szTypeName;
iconIndex = shellInfo.iIcon; iconIndex = shFileInfo.iIcon;
return res; return res;
} }
} }
@ -164,6 +209,9 @@ static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar
return -1; return -1;
} }
// bool DoItemAlwaysStart(const UString &name);
int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */) int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
{ {
int dotPos = -1; int dotPos = -1;
@ -175,6 +223,8 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin
break; break;
if (c == '.') if (c == '.')
dotPos = (int)i; 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; unsigned insertPos = 0;
const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos); const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
if (index >= 0) if (index >= 0)
@ -197,33 +250,43 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin
return _attribMap[(unsigned)index].IconIndex; return _attribMap[(unsigned)index].IconIndex;
} }
CAttribIconPair pair; CAttribIconPair pair;
GetRealIconIndex( pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(
#ifdef UNDER_CE #ifdef UNDER_CE
FTEXT("\\") FTEXT("\\")
#endif #endif
FTEXT("__DIR__") FTEXT("__DIR__")
, attrib, pair.IconIndex , attrib
// , pair.TypeName // , pair.TypeName
); );
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]; char s[256];
sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib); sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
OutputDebugStringA(s); OutputDebugStringA(s);
*/ */
pair.Attrib = attrib; pair.Attrib = attrib;
_attribMap.Insert(insertPos, pair); _attribMap.Insert(insertPos, pair);
// if (typeName) *typeName = pair.TypeName; // if (typeName) *typeName = pair.TypeName;
return pair.IconIndex; return pair.IconIndex;
} }
if (pair.IconIndex >= 0)
return pair.IconIndex;
attrib = (attrib & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_ATTRIBUTE_DIRECTORY :
FILE_ATTRIBUTE_ARCHIVE;
}
CObjectVector<CExtIconPair> &map =
(attrib & FILE_ATTRIBUTE_COMPRESSED) ?
_extMap_Compressed : _extMap_Normal;
const wchar_t *ext = fileName + dotPos + 1; const wchar_t *ext = fileName + dotPos + 1;
unsigned insertPos = 0; unsigned insertPos = 0;
const int index = FindInSorted_Ext(_extMap, ext, insertPos); const int index = FindInSorted_Ext(map, ext, insertPos);
if (index >= 0) if (index >= 0)
{ {
const CExtIconPair &pa = _extMap[index]; const CExtIconPair &pa = map[index];
// if (typeName) *typeName = pa.TypeName; // if (typeName) *typeName = pa.TypeName;
return pa.IconIndex; return pa.IconIndex;
} }
@ -238,14 +301,14 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin
} }
if (i != 0 && ext[i] == 0) 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) if (!SplitIconIndex_Defined)
{ {
GetRealIconIndex( Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
#ifdef UNDER_CE #ifdef UNDER_CE
FTEXT("\\") FTEXT("\\")
#endif #endif
FTEXT("__FILE__.001"), 0, SplitIconIndex); FTEXT("__FILE__.001"), FILE_ATTRIBUTE_ARCHIVE, SplitIconIndex);
SplitIconIndex_Defined = true; SplitIconIndex_Defined = true;
} }
return SplitIconIndex; return SplitIconIndex;
@ -253,27 +316,36 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin
CExtIconPair pair; CExtIconPair pair;
pair.Ext = ext; pair.Ext = ext;
GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex); pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(
_extMap.Insert(insertPos, pair); 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; // if (typeName) *typeName = pair.TypeName;
return pair.IconIndex; 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; SHFILEINFO shFileInfo;
return (HIMAGELIST)SHGetFileInfo(TEXT(""), // shFileInfo.hIcon = NULL; // optional
FILE_ATTRIBUTE_NORMAL | const DWORD_PTR res = SHGetFileInfo(TEXT(""),
/* FILE_ATTRIBUTE_ARCHIVE | */
FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_DIRECTORY,
&shellInfo, sizeof(shellInfo), &shFileInfo, sizeof(shFileInfo),
SHGFI_USEFILEATTRIBUTES | SHGFI_USEFILEATTRIBUTES |
SHGFI_SYSICONINDEX | 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;
} }

View file

@ -14,7 +14,6 @@ struct CExtIconPair
UString Ext; UString Ext;
int IconIndex; int IconIndex;
// UString TypeName; // UString TypeName;
// int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); } // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); }
}; };
@ -23,15 +22,15 @@ struct CAttribIconPair
DWORD Attrib; DWORD Attrib;
int IconIndex; int IconIndex;
// UString TypeName; // UString TypeName;
// int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); } // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); }
}; };
class CExtToIconMap
struct CExtToIconMap
{ {
public:
CRecordVector<CAttribIconPair> _attribMap; CRecordVector<CAttribIconPair> _attribMap;
CObjectVector<CExtIconPair> _extMap; CObjectVector<CExtIconPair> _extMap_Normal;
CObjectVector<CExtIconPair> _extMap_Compressed;
int SplitIconIndex; int SplitIconIndex;
int SplitIconIndex_Defined; int SplitIconIndex_Defined;
@ -40,16 +39,27 @@ public:
void Clear() void Clear()
{ {
SplitIconIndex_Defined = false; SplitIconIndex_Defined = false;
_extMap.Clear(); _extMap_Normal.Clear();
_extMap_Compressed.Clear();
_attribMap.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 wchar_t *fileName /* , UString *typeName */);
// int GetIconIndex(DWORD attrib, const UString &fileName);
}; };
DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex); extern CExtToIconMap g_Ext_to_Icon_Map;
int GetIconIndexForCSIDL(int csidl);
HIMAGELIST GetSysImageList(bool smallIcons); 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 Shell_Get_SysImageList_smallIcons(bool smallIcons);
#endif #endif

View file

@ -387,13 +387,13 @@ void CApp::VerCtrl(unsigned id)
*/ */
COverwriteDialog dialog; COverwriteDialog dialog;
dialog.OldFileInfo.SetTime(&fdi.Info.ftLastWriteTime); dialog.OldFileInfo.SetTime(fdi.Info.ftLastWriteTime);
dialog.OldFileInfo.SetSize(fdi.GetSize()); 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.SetSize(fdi2.GetSize());
dialog.NewFileInfo.Name = fs2us(path2); dialog.NewFileInfo.Path = fs2us(path2);
dialog.ShowExtraButtons = false; dialog.ShowExtraButtons = false;
dialog.DefaultButton_is_NO = true; dialog.DefaultButton_is_NO = true;

View file

@ -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) void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value)
{ {
CProperty &pair = pairs.AddNew(); CProperty &pair = pairs.AddNew();

View file

@ -157,6 +157,31 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize,
#endif #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 #endif

View file

@ -5,6 +5,7 @@
#include "../../C/CpuArch.h" #include "../../C/CpuArch.h"
#include "../Common/IntToString.h" #include "../Common/IntToString.h"
#include "../Common/StringConvert.h"
#ifdef _WIN32 #ifdef _WIN32
@ -511,8 +512,6 @@ void GetSysInfo(AString &s1, AString &s2)
} }
void GetCpuName(AString &s);
static void AddBracedString(AString &dest, AString &src) static void AddBracedString(AString &dest, AString &src)
{ {
if (!src.IsEmpty()) if (!src.IsEmpty())
@ -554,9 +553,7 @@ void CCpuName::Fill()
#ifdef MY_CPU_X86_OR_AMD64 #ifdef MY_CPU_X86_OR_AMD64
{ {
#if !defined(MY_CPU_AMD64) #if !defined(MY_CPU_AMD64)
if (!z7_x86_cpuid_GetMaxFunc()) if (z7_x86_cpuid_GetMaxFunc())
s += "x86";
else
#endif #endif
{ {
x86cpuid_to_String(s); x86cpuid_to_String(s);
@ -583,43 +580,26 @@ void CCpuName::Fill()
#endif #endif
if (s.IsEmpty()) #ifdef _WIN32
{
#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
{ {
NRegistry::CKey key; NRegistry::CKey key;
if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) 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]; LONG res[2];
CByteBuffer bufs[2]; CByteBuffer bufs[2];
{ {
@ -628,7 +608,8 @@ void CCpuName::Fill()
UInt32 size = 0; UInt32 size = 0;
res[i] = key.QueryValue(i == 0 ? res[i] = key.QueryValue(i == 0 ?
TEXT("Previous Update Revision") : TEXT("Previous Update Revision") :
TEXT("Update Revision"), bufs[i], size); TEXT("Update Revision"),
bufs[i], size);
if (res[i] == ERROR_SUCCESS) if (res[i] == ERROR_SUCCESS)
if (size != bufs[i].Size()) if (size != bufs[i].Size())
res[i] = ERROR_SUCCESS + 1; 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 #ifdef Z7_LARGE_PAGES
Add_LargePages_String(LargePages); Add_LargePages_String(LargePages);
@ -900,7 +909,7 @@ void GetSystemInfoText(AString &sRes)
} }
{ {
AString s; AString s;
GetCpuName(s); GetCpuName_MultiLine(s);
if (!s.IsEmpty()) if (!s.IsEmpty())
{ {
sRes += s; 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);
void GetCpuName_MultiLine(AString &s) void GetCpuName_MultiLine(AString &s)
{ {

View file

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<?define VerMajor = "24" ?> <?define VerMajor = "24" ?>
<?define VerMinor = "07" ?> <?define VerMinor = "08" ?>
<?define VerBuild = "00" ?> <?define VerBuild = "00" ?>
<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>

View file

@ -1,6 +1,17 @@
HISTORY of the 7-Zip source code 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 24.07 2024-06-19
------------------------- -------------------------
- Changes in files: - Changes in files: