From ea2986708f6be8e49bdd6fee75b94024cb34e02b Mon Sep 17 00:00:00 2001 From: Wleeaf <179125857+wleeaf@users.noreply.github.com> Date: Mon, 26 Oct 2026 16:48:33 +0000 Subject: [PATCH] Set the UTF-8 flag for zip entry names encoded as UTF-8 without a BOM --- .../Writers/Zip/ZipCentralDirectoryEntry.cs | 7 +++-- src/SharpCompress/Writers/Zip/ZipWriter.cs | 9 ++++-- .../SharpCompress.Test/Zip/ZipWriterTests.cs | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs index 3a498073..3f084d76 100644 --- a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs +++ b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs @@ -104,9 +104,10 @@ internal class ZipCentralDirectoryEntry version = 20; } - var flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) - ? HeaderFlags.Efs - : HeaderFlags.None; + var flags = + archiveEncoding.GetEncoding().CodePage == Encoding.UTF8.CodePage + ? HeaderFlags.Efs + : HeaderFlags.None; if (UsesDataDescriptor) { flags |= HeaderFlags.UsePostDataDescriptor; diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index 84debe9d..e1a1e5b6 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -207,9 +207,12 @@ public partial class ZipWriter : AbstractWriter { stream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA } - var flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) - ? HeaderFlags.Efs - : 0; + // Compare code pages: Encoding.Default on .NET Core is a UTF-8 encoding without a BOM, + // which isn't Equal to Encoding.UTF8. + var flags = + WriterOptions.ArchiveEncoding.GetEncoding().CodePage == Encoding.UTF8.CodePage + ? HeaderFlags.Efs + : 0; if (usesDataDescriptor) { flags |= HeaderFlags.UsePostDataDescriptor; diff --git a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs index 70c2632d..d22a857c 100644 --- a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -1,3 +1,5 @@ +using System; +using System.Buffers.Binary; using System.IO; using System.Text; using SharpCompress.Common; @@ -47,6 +49,32 @@ public class ZipWriterTests : WriterTests Assert.True(memoryStream.Length > 0); } + [Fact] + public void Zip_Write_Utf8_Name_Sets_Efs_Flag() + { + // Encoding.Default is a UTF-8 encoding without a BOM on .NET Core + using var memoryStream = new MemoryStream(); + var options = new WriterOptions(CompressionType.Deflate) + { + ArchiveEncoding = new ArchiveEncoding { Default = new UTF8Encoding(false) }, + }; + + using (var writer = WriterFactory.OpenWriter(memoryStream, ArchiveType.Zip, options)) + { + writer.Write("d\u00e9j\u00e0-vu.txt", new MemoryStream(new byte[] { 1, 2, 3 })); + } + + var zip = memoryStream.ToArray(); + var central = BinaryPrimitives.ReadInt32LittleEndian(zip.AsSpan(zip.Length - 6)); + + // Bit 11 of the general purpose flags marks the name as UTF-8 for other readers + Assert.Equal(0x800, BinaryPrimitives.ReadUInt16LittleEndian(zip.AsSpan(6)) & 0x800); + Assert.Equal( + 0x800, + BinaryPrimitives.ReadUInt16LittleEndian(zip.AsSpan(central + 8)) & 0x800 + ); + } + [Fact] public void Zip_Deflate_Write() => Write(