From 994e451ac0d6bb795a3bfb54df2bd23d7da379a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:19:03 -0700 Subject: [PATCH 01/10] Autogenerated and unavoidable sln changes. --- .../System.IO.Compression.sln | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.IO.Compression/System.IO.Compression.sln b/src/libraries/System.IO.Compression/System.IO.Compression.sln index e30ab5d5be0d97..22534750f35e34 100644 --- a/src/libraries/System.IO.Compression/System.IO.Compression.sln +++ b/src/libraries/System.IO.Compression/System.IO.Compression.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.35910.201 main +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamConformanceTests", "..\Common\tests\StreamConformanceTests\StreamConformanceTests.csproj", "{8E53503F-A553-410C-A285-9400625CC5E5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{6F1E1397-7610-4E99-BA7E-895ABC8E5ACB}" @@ -37,11 +41,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8541C42E-9FC EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{BA616F42-6B1E-4333-9698-C39EA13AEEA2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{D61359E8-8A03-4D16-BC52-32FFE3D0974A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{D61359E8-8A03-4D16-BC52-32FFE3D0974A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{F26573FA-11F7-4E0D-8D66-D8273C5814D6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F26573FA-11F7-4E0D-8D66-D8273C5814D6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{29BE512B-0070-4939-8993-7B0C8B993F11}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{29BE512B-0070-4939-8993-7B0C8B993F11}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{9118055E-B74F-4FF4-AC92-FB4AF9D54CEE}" EndProject @@ -118,24 +122,28 @@ Global GlobalSection(NestedProjects) = preSolution {8E53503F-A553-410C-A285-9400625CC5E5} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {6F1E1397-7610-4E99-BA7E-895ABC8E5ACB} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} - {DDD2055F-5FB6-41CD-ABE8-6FB45F6CF44A} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {9BFD204A-0DB1-466A-9704-0E869AC8940F} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} - {BB89CCB0-227A-480D-B6D4-91D680278211} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} {ED776381-E13D-4A0B-ACB4-74C5A784BD25} = {8541C42E-9FC4-4077-B828-720BD028F1F5} + {DDD2055F-5FB6-41CD-ABE8-6FB45F6CF44A} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {6CD1A771-F838-4F58-A174-203C02644EDE} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {0C920E27-5F89-42F9-AC79-2D8B886F7C1A} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {77B12FDD-F00D-4EA0-A802-2A0C12D0CE96} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {9A07A277-2896-48FC-8A20-5E290069B07D} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} + {BB89CCB0-227A-480D-B6D4-91D680278211} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} {A51CB0A3-A6A1-402E-B3AF-E6293EE28FB8} = {D61359E8-8A03-4D16-BC52-32FFE3D0974A} {FA8DBFE2-5D0E-448F-B179-9FD391F6FB5A} = {D61359E8-8A03-4D16-BC52-32FFE3D0974A} - {D61359E8-8A03-4D16-BC52-32FFE3D0974A} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} {B9BCBA20-C5E1-43CF-84BE-0ACA23B69CA5} = {F26573FA-11F7-4E0D-8D66-D8273C5814D6} {3E6E5B6B-22E9-4CCC-A476-6C59DCD321DB} = {F26573FA-11F7-4E0D-8D66-D8273C5814D6} - {F26573FA-11F7-4E0D-8D66-D8273C5814D6} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} {F2ACABDD-3AFC-451D-8459-204BAC5626B3} = {29BE512B-0070-4939-8993-7B0C8B993F11} + {D61359E8-8A03-4D16-BC52-32FFE3D0974A} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} + {F26573FA-11F7-4E0D-8D66-D8273C5814D6} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} {29BE512B-0070-4939-8993-7B0C8B993F11} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0F6F5B24-5CE5-45F2-9169-FEBEF2A3FE80} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{3e6e5b6b-22e9-4ccc-a476-6c59dcd321db}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{fa8dbfe2-5d0e-448f-b179-9fd391f6fb5a}*SharedItemsImports = 5 + EndGlobalSection EndGlobal From 60b94ac92d2004b54d0a2a24db2d1d3feebbc610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:19:28 -0700 Subject: [PATCH 02/10] Change ZipBlocks structs to classes. Update the places where they're used. --- .../src/System/IO/Compression/ZipArchive.cs | 2 +- .../System/IO/Compression/ZipArchiveEntry.cs | 4 +- .../IO/Compression/ZipBlocks.FieldLengths.cs | 18 ++-- .../Compression/ZipBlocks.FieldLocations.cs | 18 ++-- .../src/System/IO/Compression/ZipBlocks.cs | 96 +++++++++++-------- 5 files changed, 78 insertions(+), 60 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs index f0b289954012c4..b849cae7d7b90e 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs @@ -530,7 +530,7 @@ private void ReadCentralDirectory() while (continueReadingCentralDirectory && currPosition + ZipCentralDirectoryFileHeader.BlockConstantSectionSize < sizedFileBuffer.Length) { - ZipCentralDirectoryFileHeader currentHeader = default; + ZipCentralDirectoryFileHeader currentHeader = new(); continueReadingCentralDirectory = continueReadingCentralDirectory && ZipCentralDirectoryFileHeader.TryReadBlock(sizedFileBuffer.Slice(currPosition), _archiveStream, diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs index 93250857111adf..30367b56fef0e0 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs @@ -491,7 +491,7 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) Debug.Assert(_fileComment.Length <= ushort.MaxValue); // decide if we need the Zip64 extra field: - Zip64ExtraField zip64ExtraField = default; + Zip64ExtraField zip64ExtraField = new(); uint compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated; bool zip64Needed = false; @@ -908,7 +908,7 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue); // decide if we need the Zip64 extra field: - Zip64ExtraField zip64ExtraField = default; + Zip64ExtraField zip64ExtraField = new(); bool zip64Used = false; uint compressedSizeTruncated, uncompressedSizeTruncated; diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs index 6ccf16c82522fe..84513ca898e007 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs @@ -3,7 +3,7 @@ namespace System.IO.Compression { - internal partial struct ZipGenericExtraField + internal sealed partial class ZipGenericExtraField { private static class FieldLengths { @@ -12,7 +12,7 @@ private static class FieldLengths } } - internal partial struct Zip64ExtraField + internal sealed partial class Zip64ExtraField { internal static class FieldLengths { @@ -23,7 +23,7 @@ internal static class FieldLengths } } - internal partial struct Zip64EndOfCentralDirectoryLocator + internal sealed partial class Zip64EndOfCentralDirectoryLocator { internal static class FieldLengths { @@ -34,7 +34,7 @@ internal static class FieldLengths } } - internal partial struct Zip64EndOfCentralDirectoryRecord + internal sealed partial class Zip64EndOfCentralDirectoryRecord { private static class FieldLengths { @@ -51,7 +51,7 @@ private static class FieldLengths } } - internal readonly partial struct ZipLocalFileHeader + internal sealed partial class ZipLocalFileHeader { internal static class FieldLengths { @@ -67,7 +67,7 @@ internal static class FieldLengths public const int ExtraFieldLength = sizeof(ushort); } - internal readonly partial struct ZipDataDescriptor + internal sealed partial class ZipDataDescriptor { internal static class FieldLengths { @@ -78,7 +78,7 @@ internal static class FieldLengths } } - internal readonly partial struct Zip64DataDescriptor + internal sealed partial class Zip64DataDescriptor { internal static class FieldLengths { @@ -90,7 +90,7 @@ internal static class FieldLengths } } - internal partial struct ZipCentralDirectoryFileHeader + internal sealed partial class ZipCentralDirectoryFileHeader { internal static class FieldLengths { @@ -114,7 +114,7 @@ internal static class FieldLengths } } - internal partial struct ZipEndOfCentralDirectoryBlock + internal sealed partial class ZipEndOfCentralDirectoryBlock { internal static class FieldLengths { diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs index d2cc3376f30e3a..3d995b749a6de1 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs @@ -3,7 +3,7 @@ namespace System.IO.Compression { - internal partial struct ZipGenericExtraField + internal sealed partial class ZipGenericExtraField { internal static class FieldLocations { @@ -13,7 +13,7 @@ internal static class FieldLocations } } - internal partial struct Zip64ExtraField + internal sealed partial class Zip64ExtraField { internal static class FieldLocations { @@ -26,7 +26,7 @@ internal static class FieldLocations } } - internal partial struct Zip64EndOfCentralDirectoryLocator + internal sealed partial class Zip64EndOfCentralDirectoryLocator { private static class FieldLocations { @@ -37,7 +37,7 @@ private static class FieldLocations } } - internal partial struct Zip64EndOfCentralDirectoryRecord + internal sealed partial class Zip64EndOfCentralDirectoryRecord { private static class FieldLocations { @@ -54,7 +54,7 @@ private static class FieldLocations } } - internal readonly partial struct ZipLocalFileHeader + internal sealed partial class ZipLocalFileHeader { internal static class FieldLocations { @@ -71,7 +71,7 @@ internal static class FieldLocations public static readonly int DynamicData = ExtraFieldLength + FieldLengths.ExtraFieldLength; } - internal readonly partial struct ZipDataDescriptor + internal sealed partial class ZipDataDescriptor { internal static class FieldLocations { @@ -82,7 +82,7 @@ internal static class FieldLocations } } - internal readonly partial struct Zip64DataDescriptor + internal sealed partial class Zip64DataDescriptor { internal static class FieldLocations { @@ -94,7 +94,7 @@ internal static class FieldLocations } } - internal partial struct ZipCentralDirectoryFileHeader + internal sealed partial class ZipCentralDirectoryFileHeader { internal static class FieldLocations { @@ -119,7 +119,7 @@ internal static class FieldLocations } } - internal partial struct ZipEndOfCentralDirectoryBlock + internal sealed partial class ZipEndOfCentralDirectoryBlock { private static class FieldLocations { diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs index 6365fafab66b96..9b66851cc6f378 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs @@ -10,18 +10,25 @@ namespace System.IO.Compression // All blocks.TryReadBlock do a check to see if signature is correct. Generic extra field is slightly different // all of the TryReadBlocks will throw if there are not enough bytes in the stream - internal partial struct ZipGenericExtraField + internal sealed partial class ZipGenericExtraField { private const int SizeOfHeader = FieldLengths.Tag + FieldLengths.Size; private ushort _tag; private ushort _size; - private byte[] _data; + private byte[]? _data; public ushort Tag => _tag; // returns size of data, not of the entire block public ushort Size => _size; - public byte[] Data => _data; + public byte[] Data + { + get + { + _data ??= []; + return _data; + } + } public void WriteBlock(Stream stream) { @@ -37,7 +44,7 @@ public void WriteBlock(Stream stream) // assumes that bytes starts at the beginning of an extra field subfield public static bool TryReadBlock(ReadOnlySpan bytes, out int bytesConsumed, out ZipGenericExtraField field) { - field = default; + field = new(); bytesConsumed = 0; // not enough bytes to read tag + size @@ -94,7 +101,7 @@ public static void WriteAllBlocks(List fields, Stream stre } } - internal partial struct Zip64ExtraField + internal sealed partial class Zip64ExtraField { // Size is size of the record not including the tag or size fields // If the extra field is going in the local header, it cannot include only @@ -180,12 +187,13 @@ public static Zip64ExtraField GetJustZip64Block(ReadOnlySpan extraFieldDat } } - zip64Field = default; - - zip64Field._compressedSize = null; - zip64Field._uncompressedSize = null; - zip64Field._localHeaderOffset = null; - zip64Field._startDiskNumber = null; + zip64Field = new() + { + _compressedSize = null, + _uncompressedSize = null, + _localHeaderOffset = null, + _startDiskNumber = null, + }; return zip64Field; } @@ -196,12 +204,13 @@ private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField e out Zip64ExtraField zip64Block) { const int MaximumExtraFieldLength = FieldLengths.UncompressedSize + FieldLengths.CompressedSize + FieldLengths.LocalHeaderOffset + FieldLengths.StartDiskNumber; - zip64Block = default; - - zip64Block._compressedSize = null; - zip64Block._uncompressedSize = null; - zip64Block._localHeaderOffset = null; - zip64Block._startDiskNumber = null; + zip64Block = new() + { + _compressedSize = null, + _uncompressedSize = null, + _localHeaderOffset = null, + _startDiskNumber = null, + }; if (extraField.Tag != TagConstant) { @@ -302,12 +311,13 @@ public static Zip64ExtraField GetAndRemoveZip64Block(List bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber) { - Zip64ExtraField zip64Field = default; - - zip64Field._compressedSize = null; - zip64Field._uncompressedSize = null; - zip64Field._localHeaderOffset = null; - zip64Field._startDiskNumber = null; + Zip64ExtraField zip64Field = new() + { + _compressedSize = null, + _uncompressedSize = null, + _localHeaderOffset = null, + _startDiskNumber = null, + }; bool zip64FieldFound = false; @@ -373,7 +383,7 @@ public void WriteBlock(Stream stream) } } - internal partial struct Zip64EndOfCentralDirectoryLocator + internal sealed partial class Zip64EndOfCentralDirectoryLocator { // The Zip File Format Specification references 0x07064B50, this is a big endian representation. // ZIP files store values in little endian, so this is reversed. @@ -391,7 +401,7 @@ public static bool TryReadBlock(Stream stream, out Zip64EndOfCentralDirectoryLoc Span blockContents = stackalloc byte[TotalSize]; int bytesRead; - zip64EOCDLocator = default; + zip64EOCDLocator = new(); bytesRead = stream.Read(blockContents); if (bytesRead < TotalSize) @@ -426,7 +436,7 @@ public static void WriteBlock(Stream stream, long zip64EOCDRecordStart) } } - internal partial struct Zip64EndOfCentralDirectoryRecord + internal sealed partial class Zip64EndOfCentralDirectoryRecord { // The Zip File Format Specification references 0x06064B50, this is a big endian representation. // ZIP files store values in little endian, so this is reversed. @@ -451,7 +461,7 @@ public static bool TryReadBlock(Stream stream, out Zip64EndOfCentralDirectoryRec Span blockContents = stackalloc byte[BlockConstantSectionSize]; int bytesRead; - zip64EOCDRecord = default; + zip64EOCDRecord = new(); bytesRead = stream.Read(blockContents); if (bytesRead < BlockConstantSectionSize) @@ -503,7 +513,7 @@ public static void WriteBlock(Stream stream, long numberOfEntries, long startOfC } } - internal readonly partial struct ZipLocalFileHeader + internal sealed partial class ZipLocalFileHeader { // The Zip File Format Specification references 0x08074B50 and 0x04034B50, these are big endian representations. // ZIP files store values in little endian, so these are reversed. @@ -591,7 +601,7 @@ public static bool TrySkipBlock(Stream stream) } } - internal partial struct ZipCentralDirectoryFileHeader + internal sealed partial class ZipCentralDirectoryFileHeader { // The Zip File Format Specification references 0x02014B50, this is a big endian representation. // ZIP files store values in little endian, so this is reversed. @@ -617,8 +627,8 @@ internal partial struct ZipCentralDirectoryFileHeader public uint ExternalFileAttributes; public long RelativeOffsetOfLocalHeader; - public byte[] Filename; - public byte[] FileComment; + public byte[] Filename = []; + public byte[] FileComment = []; public List? ExtraFields; // if saveExtraFieldsAndComments is false, FileComment and ExtraFields will be null @@ -627,7 +637,7 @@ public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, { const int StackAllocationThreshold = 512; - header = default; + header = new(); bytesRead = 0; // the buffer will always be large enough for at least the constant section to be verified @@ -706,7 +716,7 @@ public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, ReadOnlySpan zipExtraFields = dynamicHeader.Slice(header.FilenameLength, header.ExtraFieldLength); - zip64 = default; + zip64 = new(); if (saveExtraFieldsAndComments) { header.ExtraFields = ZipGenericExtraField.ParseExtraField(zipExtraFields); @@ -743,7 +753,7 @@ public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, } } - internal partial struct ZipEndOfCentralDirectoryBlock + internal sealed partial class ZipEndOfCentralDirectoryBlock { // The Zip File Format Specification references 0x06054B50, this is a big endian representation. // ZIP files store values in little endian, so this is reversed. @@ -766,7 +776,15 @@ internal partial struct ZipEndOfCentralDirectoryBlock public ushort NumberOfEntriesInTheCentralDirectory; public uint SizeOfCentralDirectory; public uint OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; - public byte[] ArchiveComment; + private byte[]? _archiveComment; + public byte[] ArchiveComment + { + get + { + _archiveComment ??= []; + return _archiveComment; + } + } public static void WriteBlock(Stream stream, long numberOfEntries, long startOfCentralDirectory, long sizeOfCentralDirectory, byte[] archiveComment) { @@ -809,7 +827,7 @@ public static bool TryReadBlock(Stream stream, out ZipEndOfCentralDirectoryBlock Span blockContents = stackalloc byte[TotalSize]; int bytesRead; - eocdBlock = default; + eocdBlock = new(); bytesRead = stream.Read(blockContents); if (bytesRead < TotalSize) @@ -840,12 +858,12 @@ public static bool TryReadBlock(Stream stream, out ZipEndOfCentralDirectoryBlock if (commentLength == 0) { - eocdBlock.ArchiveComment = Array.Empty(); + eocdBlock._archiveComment = []; } else { - eocdBlock.ArchiveComment = new byte[commentLength]; - stream.ReadExactly(eocdBlock.ArchiveComment); + eocdBlock._archiveComment = new byte[commentLength]; + stream.ReadExactly(eocdBlock._archiveComment); } return true; From 452e3eb72fb40280dc11911f4744670a313c3991 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 14 Mar 2025 10:37:49 -0700 Subject: [PATCH 03/10] Revert "Autogenerated and unavoidable sln changes." This reverts commit 994e451ac0d6bb795a3bfb54df2bd23d7da379a1. --- .../System.IO.Compression.sln | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.IO.Compression/System.IO.Compression.sln b/src/libraries/System.IO.Compression/System.IO.Compression.sln index 22534750f35e34..e30ab5d5be0d97 100644 --- a/src/libraries/System.IO.Compression/System.IO.Compression.sln +++ b/src/libraries/System.IO.Compression/System.IO.Compression.sln @@ -1,8 +1,4 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.14.35910.201 main -MinimumVisualStudioVersion = 10.0.40219.1 +Microsoft Visual Studio Solution File, Format Version 12.00 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamConformanceTests", "..\Common\tests\StreamConformanceTests\StreamConformanceTests.csproj", "{8E53503F-A553-410C-A285-9400625CC5E5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{6F1E1397-7610-4E99-BA7E-895ABC8E5ACB}" @@ -41,11 +37,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8541C42E-9FC EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{BA616F42-6B1E-4333-9698-C39EA13AEEA2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{D61359E8-8A03-4D16-BC52-32FFE3D0974A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{D61359E8-8A03-4D16-BC52-32FFE3D0974A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F26573FA-11F7-4E0D-8D66-D8273C5814D6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{F26573FA-11F7-4E0D-8D66-D8273C5814D6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{29BE512B-0070-4939-8993-7B0C8B993F11}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{29BE512B-0070-4939-8993-7B0C8B993F11}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{9118055E-B74F-4FF4-AC92-FB4AF9D54CEE}" EndProject @@ -122,28 +118,24 @@ Global GlobalSection(NestedProjects) = preSolution {8E53503F-A553-410C-A285-9400625CC5E5} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {6F1E1397-7610-4E99-BA7E-895ABC8E5ACB} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} + {DDD2055F-5FB6-41CD-ABE8-6FB45F6CF44A} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {9BFD204A-0DB1-466A-9704-0E869AC8940F} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} + {BB89CCB0-227A-480D-B6D4-91D680278211} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} {ED776381-E13D-4A0B-ACB4-74C5A784BD25} = {8541C42E-9FC4-4077-B828-720BD028F1F5} - {DDD2055F-5FB6-41CD-ABE8-6FB45F6CF44A} = {BB657E6F-1D06-4E7A-B4C2-B40A071A2A44} {6CD1A771-F838-4F58-A174-203C02644EDE} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {0C920E27-5F89-42F9-AC79-2D8B886F7C1A} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {77B12FDD-F00D-4EA0-A802-2A0C12D0CE96} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} {9A07A277-2896-48FC-8A20-5E290069B07D} = {BA616F42-6B1E-4333-9698-C39EA13AEEA2} - {BB89CCB0-227A-480D-B6D4-91D680278211} = {350F6B1E-B006-4EA5-BA9E-41F57FF84FF1} {A51CB0A3-A6A1-402E-B3AF-E6293EE28FB8} = {D61359E8-8A03-4D16-BC52-32FFE3D0974A} {FA8DBFE2-5D0E-448F-B179-9FD391F6FB5A} = {D61359E8-8A03-4D16-BC52-32FFE3D0974A} + {D61359E8-8A03-4D16-BC52-32FFE3D0974A} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} {B9BCBA20-C5E1-43CF-84BE-0ACA23B69CA5} = {F26573FA-11F7-4E0D-8D66-D8273C5814D6} {3E6E5B6B-22E9-4CCC-A476-6C59DCD321DB} = {F26573FA-11F7-4E0D-8D66-D8273C5814D6} - {F2ACABDD-3AFC-451D-8459-204BAC5626B3} = {29BE512B-0070-4939-8993-7B0C8B993F11} - {D61359E8-8A03-4D16-BC52-32FFE3D0974A} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} {F26573FA-11F7-4E0D-8D66-D8273C5814D6} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} + {F2ACABDD-3AFC-451D-8459-204BAC5626B3} = {29BE512B-0070-4939-8993-7B0C8B993F11} {29BE512B-0070-4939-8993-7B0C8B993F11} = {9118055E-B74F-4FF4-AC92-FB4AF9D54CEE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0F6F5B24-5CE5-45F2-9169-FEBEF2A3FE80} EndGlobalSection - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{3e6e5b6b-22e9-4ccc-a476-6c59dcd321db}*SharedItemsImports = 5 - ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{fa8dbfe2-5d0e-448f-b179-9fd391f6fb5a}*SharedItemsImports = 5 - EndGlobalSection EndGlobal From 8ca57705b3af05bda3a042e326280057c7389543 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 14 Mar 2025 10:52:30 -0700 Subject: [PATCH 04/10] _data ??= [] as a single expression --- .../src/System/IO/Compression/ZipBlocks.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs index 9b66851cc6f378..0ab371e1ba54c3 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs @@ -21,14 +21,7 @@ internal sealed partial class ZipGenericExtraField public ushort Tag => _tag; // returns size of data, not of the entire block public ushort Size => _size; - public byte[] Data - { - get - { - _data ??= []; - return _data; - } - } + public byte[] Data => _data ??= []; public void WriteBlock(Stream stream) { From ea9827e2969805ed4c7178997d65d95fecf4839f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:34:26 -0700 Subject: [PATCH 05/10] Update nullability usage around ZipCentralDirectoryFileHeader.TryReadBlock. --- .../src/System/IO/Compression/ZipArchive.cs | 14 ++--- .../src/System/IO/Compression/ZipBlocks.cs | 56 +++++++------------ 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs index b849cae7d7b90e..95fb602c867cc8 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs @@ -530,14 +530,11 @@ private void ReadCentralDirectory() while (continueReadingCentralDirectory && currPosition + ZipCentralDirectoryFileHeader.BlockConstantSectionSize < sizedFileBuffer.Length) { - ZipCentralDirectoryFileHeader currentHeader = new(); - - continueReadingCentralDirectory = continueReadingCentralDirectory && - ZipCentralDirectoryFileHeader.TryReadBlock(sizedFileBuffer.Slice(currPosition), _archiveStream, - saveExtraFieldsAndComments, out bytesConsumed, out currentHeader); - - if (!continueReadingCentralDirectory) + if (!continueReadingCentralDirectory || + !ZipCentralDirectoryFileHeader.TryReadBlock(sizedFileBuffer.Slice(currPosition), _archiveStream, + saveExtraFieldsAndComments, out bytesConsumed, out ZipCentralDirectoryFileHeader? currentHeader)) { + continueReadingCentralDirectory = false; break; } @@ -662,8 +659,7 @@ private void TryReadZip64EndOfCentralDirectory(ZipEndOfCentralDirectoryBlock eoc Zip64EndOfCentralDirectoryLocator.FieldLengths.Signature)) { // use locator to get to Zip64-EOCD - Zip64EndOfCentralDirectoryLocator locator; - bool zip64eocdLocatorProper = Zip64EndOfCentralDirectoryLocator.TryReadBlock(_archiveStream, out locator); + bool zip64eocdLocatorProper = Zip64EndOfCentralDirectoryLocator.TryReadBlock(_archiveStream, out Zip64EndOfCentralDirectoryLocator locator); Debug.Assert(zip64eocdLocatorProper); // we just found this using the signature finder, so it should be okay if (locator.OffsetOfZip64EOCD > long.MaxValue) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs index 9b66851cc6f378..039ee6c4ed1fb9 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs @@ -4,12 +4,12 @@ using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.IO.Compression { // All blocks.TryReadBlock do a check to see if signature is correct. Generic extra field is slightly different // all of the TryReadBlocks will throw if there are not enough bytes in the stream - internal sealed partial class ZipGenericExtraField { private const int SizeOfHeader = FieldLengths.Tag + FieldLengths.Size; @@ -21,14 +21,7 @@ internal sealed partial class ZipGenericExtraField public ushort Tag => _tag; // returns size of data, not of the entire block public ushort Size => _size; - public byte[] Data - { - get - { - _data ??= []; - return _data; - } - } + public byte[] Data => _data ??= []; public void WriteBlock(Stream stream) { @@ -633,11 +626,12 @@ internal sealed partial class ZipCentralDirectoryFileHeader // if saveExtraFieldsAndComments is false, FileComment and ExtraFields will be null // in either case, the zip64 extra field info will be incorporated into other fields - public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, bool saveExtraFieldsAndComments, out int bytesRead, out ZipCentralDirectoryFileHeader header) + public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, bool saveExtraFieldsAndComments, out int bytesRead, [NotNullWhen(returnValue: true)] out ZipCentralDirectoryFileHeader? header) { + header = null; + const int StackAllocationThreshold = 512; - header = new(); bytesRead = 0; // the buffer will always be large enough for at least the constant section to be verified @@ -648,26 +642,25 @@ public static bool TryReadBlock(ReadOnlySpan buffer, Stream furtherReads, return false; } - header.VersionMadeBySpecification = buffer[FieldLocations.VersionMadeBySpecification]; - header.VersionMadeByCompatibility = buffer[FieldLocations.VersionMadeByCompatibility]; - header.VersionNeededToExtract = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.VersionNeededToExtract..]); - header.GeneralPurposeBitFlag = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.GeneralPurposeBitFlags..]); - header.CompressionMethod = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.CompressionMethod..]); - header.LastModified = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.LastModified..]); - header.Crc32 = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.Crc32..]); + header = new() + { + VersionMadeBySpecification = buffer[FieldLocations.VersionMadeBySpecification], + VersionMadeByCompatibility = buffer[FieldLocations.VersionMadeByCompatibility], + VersionNeededToExtract = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.VersionNeededToExtract..]), + GeneralPurposeBitFlag = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.GeneralPurposeBitFlags..]), + CompressionMethod = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.CompressionMethod..]), + LastModified = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.LastModified..]), + Crc32 = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.Crc32..]), + FilenameLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.FilenameLength..]), + ExtraFieldLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.ExtraFieldLength..]), + FileCommentLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.FileCommentLength..]), + InternalFileAttributes = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.InternalFileAttributes..]), + ExternalFileAttributes = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.ExternalFileAttributes..]) + }; uint compressedSizeSmall = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.CompressedSize..]); uint uncompressedSizeSmall = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.UncompressedSize..]); - - header.FilenameLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.FilenameLength..]); - header.ExtraFieldLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.ExtraFieldLength..]); - header.FileCommentLength = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.FileCommentLength..]); - ushort diskNumberStartSmall = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.DiskNumberStart..]); - - header.InternalFileAttributes = BinaryPrimitives.ReadUInt16LittleEndian(buffer[FieldLocations.InternalFileAttributes..]); - header.ExternalFileAttributes = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.ExternalFileAttributes..]); - uint relativeOffsetOfLocalHeaderSmall = BinaryPrimitives.ReadUInt32LittleEndian(buffer[FieldLocations.RelativeOffsetOfLocalHeader..]); // Assemble the dynamic header in a separate buffer. We can't guarantee that it's all in the input buffer, @@ -777,14 +770,7 @@ internal sealed partial class ZipEndOfCentralDirectoryBlock public uint SizeOfCentralDirectory; public uint OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; private byte[]? _archiveComment; - public byte[] ArchiveComment - { - get - { - _archiveComment ??= []; - return _archiveComment; - } - } + public byte[] ArchiveComment => _archiveComment ??= []; public static void WriteBlock(Stream stream, long numberOfEntries, long startOfCentralDirectory, long sizeOfCentralDirectory, byte[] archiveComment) { From 44af7b8e6ad35d7d48c24aa845a244dcfebfee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:45:22 -0700 Subject: [PATCH 06/10] Adjust nullability for zip64ExtraField. --- .../System/IO/Compression/ZipArchiveEntry.cs | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs index 30367b56fef0e0..b604bf37df832b 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs @@ -491,24 +491,24 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) Debug.Assert(_fileComment.Length <= ushort.MaxValue); // decide if we need the Zip64 extra field: - Zip64ExtraField zip64ExtraField = new(); + Zip64ExtraField? zip64ExtraField = null; uint compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated; - bool zip64Needed = false; - if (AreSizesTooLarge #if DEBUG_FORCE_ZIP64 || _archive._forceZip64 #endif ) { - zip64Needed = true; compressedSizeTruncated = ZipHelper.Mask32Bit; uncompressedSizeTruncated = ZipHelper.Mask32Bit; // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways - zip64ExtraField.CompressedSize = _compressedSize; - zip64ExtraField.UncompressedSize = _uncompressedSize; + zip64ExtraField = new() + { + CompressedSize = _compressedSize, + UncompressedSize = _uncompressedSize + }; } else { @@ -523,27 +523,32 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) #endif ) { - zip64Needed = true; offsetOfLocalHeaderTruncated = ZipHelper.Mask32Bit; // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways - zip64ExtraField.LocalHeaderOffset = _offsetOfLocalHeader; + zip64ExtraField = new() + { + LocalHeaderOffset = _offsetOfLocalHeader + }; } else { offsetOfLocalHeaderTruncated = (uint)_offsetOfLocalHeader; } - if (zip64Needed) + if (zip64ExtraField != null) + { VersionToExtractAtLeast(ZipVersionNeededValues.Zip64); + } + // determine if we can fit zip64 extra field and original extra fields all in - int bigExtraFieldLength = (zip64Needed ? zip64ExtraField.TotalSize : 0) + int bigExtraFieldLength = (zip64ExtraField != null ? zip64ExtraField.TotalSize : 0) + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0); ushort extraFieldLength; if (bigExtraFieldLength > ushort.MaxValue) { - extraFieldLength = (ushort)(zip64Needed ? zip64ExtraField.TotalSize : 0); + extraFieldLength = (ushort)(zip64ExtraField != null ? zip64ExtraField.TotalSize : 0); _cdUnknownExtraFields = null; } else @@ -555,7 +560,7 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) { long centralDirectoryHeaderLength = ZipCentralDirectoryFileHeader.FieldLocations.DynamicData + _storedEntryNameBytes.Length - + (zip64Needed ? zip64ExtraField.TotalSize : 0) + + (zip64ExtraField != null ? zip64ExtraField.TotalSize : 0) + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0) + _fileComment.Length; @@ -605,13 +610,19 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) _archive.ArchiveStream.Write(_storedEntryNameBytes); // write extra fields - if (zip64Needed) + if (zip64ExtraField != null) + { zip64ExtraField.WriteBlock(_archive.ArchiveStream); + } if (_cdUnknownExtraFields != null) + { ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream); + } if (_fileComment.Length > 0) + { _archive.ArchiveStream.Write(_fileComment); + } } } From 0cb27fcc55fa216925497aeead3dd7f55a3e3b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:48:17 -0700 Subject: [PATCH 07/10] revert ZipLocalFileHeader type change, it can stay readonly partial struct. --- .../src/System/IO/Compression/ZipBlocks.FieldLengths.cs | 2 +- .../src/System/IO/Compression/ZipBlocks.FieldLocations.cs | 2 +- .../src/System/IO/Compression/ZipBlocks.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs index 84513ca898e007..62b31842d67cce 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLengths.cs @@ -51,7 +51,7 @@ private static class FieldLengths } } - internal sealed partial class ZipLocalFileHeader + internal readonly partial struct ZipLocalFileHeader { internal static class FieldLengths { diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs index 3d995b749a6de1..5d7a5127ed5722 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.FieldLocations.cs @@ -54,7 +54,7 @@ private static class FieldLocations } } - internal sealed partial class ZipLocalFileHeader + internal readonly partial struct ZipLocalFileHeader { internal static class FieldLocations { diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs index 039ee6c4ed1fb9..6d978f66d9012a 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs @@ -506,7 +506,7 @@ public static void WriteBlock(Stream stream, long numberOfEntries, long startOfC } } - internal sealed partial class ZipLocalFileHeader + internal readonly partial struct ZipLocalFileHeader { // The Zip File Format Specification references 0x08074B50 and 0x04034B50, these are big endian representations. // ZIP files store values in little endian, so these are reversed. From 53515fba230dfd9969db6dd563a7e4e03ede41e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:51:32 -0700 Subject: [PATCH 08/10] Fix null propagation error, but add a comment so it's not easily ignored. --- .../src/System/IO/Compression/ZipArchiveEntry.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs index b604bf37df832b..72242253bfad0a 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs @@ -609,11 +609,9 @@ internal void WriteCentralDirectoryFileHeader(bool forceWrite) _archive.ArchiveStream.Write(cdStaticHeader); _archive.ArchiveStream.Write(_storedEntryNameBytes); - // write extra fields - if (zip64ExtraField != null) - { - zip64ExtraField.WriteBlock(_archive.ArchiveStream); - } + // write extra fields, and only write zip64ExtraField if we decided we need it (it's not null) + zip64ExtraField?.WriteBlock(_archive.ArchiveStream); + if (_cdUnknownExtraFields != null) { ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream); From da476404301972ee4ed578078bcb30bffb0435cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:56:16 -0700 Subject: [PATCH 09/10] Simpler if condition. --- .../src/System/IO/Compression/ZipArchive.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs index 95fb602c867cc8..22cd16b6fafdac 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs @@ -530,8 +530,7 @@ private void ReadCentralDirectory() while (continueReadingCentralDirectory && currPosition + ZipCentralDirectoryFileHeader.BlockConstantSectionSize < sizedFileBuffer.Length) { - if (!continueReadingCentralDirectory || - !ZipCentralDirectoryFileHeader.TryReadBlock(sizedFileBuffer.Slice(currPosition), _archiveStream, + if (!ZipCentralDirectoryFileHeader.TryReadBlock(sizedFileBuffer.Slice(currPosition), _archiveStream, saveExtraFieldsAndComments, out bytesConsumed, out ZipCentralDirectoryFileHeader? currentHeader)) { continueReadingCentralDirectory = false; From b263a5a306f8f9b16240e7cf256edcb6dbd8f48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:08:05 -0700 Subject: [PATCH 10/10] Improve nullability in the rest of the Zip64ExtraField usages. --- .../System/IO/Compression/ZipArchiveEntry.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs index 72242253bfad0a..2ff22deca89144 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs @@ -917,8 +917,7 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue); // decide if we need the Zip64 extra field: - Zip64ExtraField zip64ExtraField = new(); - bool zip64Used = false; + Zip64ExtraField? zip64ExtraField = null; uint compressedSizeTruncated, uncompressedSizeTruncated; // save offset @@ -941,7 +940,6 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) if (_archive.Mode == ZipArchiveMode.Create && _archive.ArchiveStream.CanSeek == false) { _generalPurposeBitFlag |= BitFlagValues.DataDescriptor; - zip64Used = false; compressedSizeTruncated = 0; uncompressedSizeTruncated = 0; // the crc should not have been set if we are in create mode, but clear it just to be sure @@ -957,19 +955,20 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) #endif ) { - zip64Used = true; compressedSizeTruncated = ZipHelper.Mask32Bit; uncompressedSizeTruncated = ZipHelper.Mask32Bit; // prepare Zip64 extra field object. If we have one of the sizes, the other must go in there - zip64ExtraField.CompressedSize = _compressedSize; - zip64ExtraField.UncompressedSize = _uncompressedSize; + zip64ExtraField = new() + { + CompressedSize = _compressedSize, + UncompressedSize = _uncompressedSize, + }; VersionToExtractAtLeast(ZipVersionNeededValues.Zip64); } else { - zip64Used = false; compressedSizeTruncated = (uint)_compressedSize; uncompressedSizeTruncated = (uint)_uncompressedSize; } @@ -980,12 +979,12 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) _offsetOfLocalHeader = _archive.ArchiveStream.Position; // calculate extra field. if zip64 stuff + original extraField aren't going to fit, dump the original extraField, because this is more important - int bigExtraFieldLength = (zip64Used ? zip64ExtraField.TotalSize : 0) + int bigExtraFieldLength = (zip64ExtraField != null ? zip64ExtraField.TotalSize : 0) + (_lhUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0); ushort extraFieldLength; if (bigExtraFieldLength > ushort.MaxValue) { - extraFieldLength = (ushort)(zip64Used ? zip64ExtraField.TotalSize : 0); + extraFieldLength = (ushort)(zip64ExtraField != null ? zip64ExtraField.TotalSize : 0); _lhUnknownExtraFields = null; } else @@ -999,7 +998,7 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) { _archive.ArchiveStream.Seek(ZipLocalFileHeader.SizeOfLocalHeader + _storedEntryNameBytes.Length, SeekOrigin.Current); - if (zip64Used) + if (zip64ExtraField != null) { _archive.ArchiveStream.Seek(zip64ExtraField.TotalSize, SeekOrigin.Current); } @@ -1027,13 +1026,14 @@ private bool WriteLocalFileHeader(bool isEmptyFile, bool forceWrite) _archive.ArchiveStream.Write(_storedEntryNameBytes); - if (zip64Used) - zip64ExtraField.WriteBlock(_archive.ArchiveStream); + // Only when handling zip64 + zip64ExtraField?.WriteBlock(_archive.ArchiveStream); + if (_lhUnknownExtraFields != null) ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream); } - return zip64Used; + return zip64ExtraField != null; } private void WriteLocalFileHeaderAndDataIfNeeded(bool forceWrite)