Fix reading standard Zip64 extended information fields

This commit is contained in:
Roger Sanders 2025-04-03 14:18:53 +11:00
parent 65f34b6f2a
commit 9a43bff533

View file

@ -1114,34 +1114,46 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo
}
else
{
size_t expectedExtraRecordSize = 16 + (cdItem && (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos) || ZIP64_IS_16_MAX(cdItem->Disk)) ? 8 : 0) + (cdItem && ZIP64_IS_16_MAX(cdItem->Disk) ? 4 : 0);
size_t nonStandardExtraRecordSize = (ZIP64_IS_32_MAX(unpackSize) ? 8 : 0) + (ZIP64_IS_32_MAX(packSize) ? 8 : 0) + (cdItem && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos) ? 8 : 0) + (cdItem && ZIP64_IS_16_MAX(cdItem->Disk) ? 4 : 0);
if (expectedExtraRecordSize == size)
{
// Record seems standards compliant. Read it as per the standard.
size -= 8; unpackSize = ReadUInt64();
size -= 8; packSize = ReadUInt64();
if (cdItem && (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos) || ZIP64_IS_16_MAX(cdItem->Disk)))
{
size -= 8; cdItem->LocalHeaderPos = ReadUInt64();
}
if (cdItem && ZIP64_IS_16_MAX(cdItem->Disk))
{
size -= 4; cdItem->Disk = ReadUInt32();
}
}
else if (nonStandardExtraRecordSize == size)
{
// Record is not standards compliant, but appears to match previous 7zip behaviour.
if (ZIP64_IS_32_MAX(unpackSize))
{ if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }}
if (isOK && ZIP64_IS_32_MAX(packSize))
{ if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }}
if (cdItem)
{
if (isOK)
{
if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
{ if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
/*
else if (size == 8)
{
size -= 8;
const UInt64 v = ReadUInt64();
// soong_zip, an AOSP tool (written in the Go) writes incorrect value.
// we can ignore that minor error here
if (v != cdItem->LocalHeaderPos)
isOK = false; // ignore error
// isOK = false; // force error
size -= 8; unpackSize = ReadUInt64();
}
*/
if (ZIP64_IS_32_MAX(packSize))
{
size -= 8; packSize = ReadUInt64();
}
if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
{ if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
if (cdItem && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
{
size -= 8; cdItem->LocalHeaderPos = ReadUInt64();
}
if (cdItem && ZIP64_IS_16_MAX(cdItem->Disk))
{
size -= 4; cdItem->Disk = ReadUInt32();
}
}
else
{
// Record doesn't match any known encoding. We can't safely interpret anything in it.
isOK = false;
}
}