Preserve legacy ZIP descriptor width probe

This commit is contained in:
Adam Hathcock
2026-10-24 12:02:27 +01:00
parent fafbb4a5fe
commit 9c555c41cc
3 changed files with 67 additions and 2 deletions

View File

@@ -160,7 +160,12 @@ internal sealed partial class StreamingZipHeaderFactory
.ReadUInt32Async(_cancellationToken)
.ConfigureAwait(false);
if (!IsHeader(headerBytes))
// Keep the legacy probe limited to local/central headers: other
// record signatures can be the low word of a 64-bit size.
if (
headerBytes != ENTRY_HEADER_BYTES
&& headerBytes != DIRECTORY_START_HEADER_BYTES
)
{
// Descriptor words are size data, including 0xFFFFFFFF; unlike
// local headers, descriptors do not contain size sentinels.

View File

@@ -88,7 +88,12 @@ internal sealed partial class StreamingZipHeaderFactory : ZipHeaderFactory
uncompSize = reader.ReadUInt32();
headerBytes = reader.ReadUInt32();
if (!IsHeader(headerBytes))
// Keep the legacy probe limited to local/central headers: other
// record signatures can be the low word of a 64-bit size.
if (
headerBytes != ENTRY_HEADER_BYTES
&& headerBytes != DIRECTORY_START_HEADER_BYTES
)
{
// Descriptor words are size data, including 0xFFFFFFFF; unlike
// local headers, descriptors do not contain size sentinels.

View File

@@ -72,6 +72,61 @@ public class Zip64DescriptorSizeTests
Assert.Equal("second", secondKey);
}
public static IEnumerable<object[]> LegacyDescriptorSizes()
{
foreach (var useAsync in new[] { false, true })
{
foreach (var signature in new[] { false, true })
{
foreach (
var size in new[]
{
0x08074B50UL,
0x05054B50UL,
0x06054B50UL,
0x30304B50UL,
0x06064B50UL,
0x07064B50UL,
}
)
{
yield return new object[] { useAsync, signature, size };
yield return new object[] { useAsync, signature, size | (1UL << 32) };
}
}
}
}
[Theory]
[MemberData(nameof(LegacyDescriptorSizes))]
public async Task Legacy_Descriptor_Preserves_Signature_Size_And_Next_Header(
bool useAsync,
bool signature,
ulong size
)
{
var zip = WriteZip64Archive();
var descriptor = FindDescriptor(zip);
BinaryPrimitives.WriteUInt64LittleEndian(zip.AsSpan(descriptor + 16), size);
// Simulate older writers that used 64-bit descriptors without declaring ZIP64.
BinaryPrimitives.WriteUInt32LittleEndian(zip.AsSpan(18), 0);
BinaryPrimitives.WriteUInt32LittleEndian(zip.AsSpan(22), 0);
var extra = 30 + BinaryPrimitives.ReadUInt16LittleEndian(zip.AsSpan(26));
BinaryPrimitives.WriteUInt16LittleEndian(zip.AsSpan(extra), 0xFFFF);
if (!signature)
{
zip = zip.Take(descriptor).Concat(zip.Skip(descriptor + 4)).ToArray();
}
var (firstSize, secondKey) = await ReadFirstTwoEntries(
zip,
useAsync,
expectedCompressedSize: 3
);
Assert.Equal((long)size, firstSize);
Assert.Equal("second", secondKey);
}
[Theory]
[InlineData(false, false, 0x04034B50)]
[InlineData(false, true, 0x04034B50)]