diff --git a/src/libraries/Common/tests/System/IO/Compression/ZipTestHelper.cs b/src/libraries/Common/tests/System/IO/Compression/ZipTestHelper.cs index 9666a16e2fb..16aa8a5a087 100644 --- a/src/libraries/Common/tests/System/IO/Compression/ZipTestHelper.cs +++ b/src/libraries/Common/tests/System/IO/Compression/ZipTestHelper.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading.Tasks; using Xunit; @@ -499,5 +500,17 @@ namespace System.IO.Compression.Tests yield return e; } } + + // Returns pairs encoded with Latin1, but decoded with UTF8. + // Returns: originalComment, expectedComment, transcoded expectedComment + public static IEnumerable MismatchingEncodingComment_Data() + { + foreach (object[] e in Latin1Comment_Data()) + { + byte[] expectedBytes = Encoding.Latin1.GetBytes(e[1] as string); + + yield return new object[] { e[0], e[1], Encoding.UTF8.GetString(expectedBytes) }; + } + } } } diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs index 20608092b95..5e3a616b0e1 100644 --- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs +++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs @@ -102,39 +102,39 @@ namespace System.IO.Compression /// If the file exists and is not a Zip file, a ZipArchiveException will be thrown. /// If the file exists and is empty or does not exist, a new Zip file will be created. /// Note that creating a Zip file with the ZipArchiveMode.Create mode is more efficient when creating a new Zip file. - /// The encoding to use when reading or writing entry names in this ZipArchive. + /// The encoding to use when reading or writing entry names and comments in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. /// However, this may be necessary for interoperability with ZIP archive tools and libraries that do not correctly support - /// UTF-8 encoding for entry names.
+ /// UTF-8 encoding for entry names or comments.
/// This value is used as follows:
/// Reading (opening) ZIP archive files: /// If entryNameEncoding is not specified (== null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the current system default code page (Encoding.Default) in order to decode the entry name. + /// use the current system default code page (Encoding.Default) in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// If entryNameEncoding is specified (!= null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the specified entryNameEncoding in order to decode the entry name. + /// use the specified entryNameEncoding in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// Writing (saving) ZIP archive files: /// If entryNameEncoding is not specified (== null): /// - /// For entry names that contain characters outside the ASCII range, + /// For entry names or comments that contain characters outside the ASCII range, /// the language encoding flag (EFS) will be set in the general purpose bit flag of the local file header, - /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name into bytes. - /// For entry names that do not contain characters outside the ASCII range, + /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name and comment into bytes. + /// For entry names or comments that do not contain characters outside the ASCII range, /// the language encoding flag (EFS) will not be set in the general purpose bit flag of the local file header, - /// and the current system default code page (Encoding.Default) will be used to encode the entry names into bytes. + /// and the current system default code page (Encoding.Default) will be used to encode the entry names and comments into bytes. /// /// If entryNameEncoding is specified (!= null): /// - /// The specified entryNameEncoding will always be used to encode the entry names into bytes. + /// The specified entryNameEncoding will always be used to encode the entry names and comments into bytes. /// The language encoding flag (EFS) in the general purpose bit flag of the local file header will be set if and only /// if the specified entryNameEncoding is a UTF-8 encoding. /// @@ -322,23 +322,23 @@ namespace System.IO.Compression /// true to indicate that a directory named sourceDirectoryName should /// be included at the root of the archive. false to indicate that the files and directories in sourceDirectoryName /// should be included directly in the archive. - /// The encoding to use when reading or writing entry names in this ZipArchive. + /// The encoding to use when reading or writing entry names and comments in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. /// However, this may be necessary for interoperability with ZIP archive tools and libraries that do not correctly support - /// UTF-8 encoding for entry names.
+ /// UTF-8 encoding for entry names or comments.
/// This value is used as follows while creating the archive:
/// If entryNameEncoding is not specified (== null): /// - /// For file names that contain characters outside the ASCII range:
+ /// For file names or comments that contain characters outside the ASCII range:
/// The language encoding flag (EFS) will be set in the general purpose bit flag of the local file header of the corresponding entry, - /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name into bytes.
- /// For file names that do not contain characters outside the ASCII range:
+ /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name and comment into bytes.
+ /// For file names or comments that do not contain characters outside the ASCII range:
/// the language encoding flag (EFS) will not be set in the general purpose bit flag of the local file header of the corresponding entry, - /// and the current system default code page (Encoding.Default) will be used to encode the entry names into bytes.
+ /// and the current system default code page (Encoding.Default) will be used to encode the entry names and comments into bytes.
///
/// If entryNameEncoding is specified (!= null): /// - /// The specified entryNameEncoding will always be used to encode the entry names into bytes. + /// The specified entryNameEncoding will always be used to encode the entry names and comments into bytes. /// The language encoding flag (EFS) in the general purpose bit flag of the local file header for each entry will be set if and only /// if the specified entryNameEncoding is a UTF-8 encoding. /// @@ -408,7 +408,7 @@ namespace System.IO.Compression /// The stream where the zip archive is to be stored. /// One of the enumeration values that indicates whether to emphasize speed or compression effectiveness when creating the entry. /// to include the directory name from at the root of the archive; to include only the contents of the directory. - /// The encoding to use when reading or writing entry names in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names. + /// The encoding to use when reading or writing entry names in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names or comments. /// /// The directory structure from the file system is preserved in the archive. If the directory is empty, an empty archive is created. /// Use this method overload to specify the compression level and character encoding, and whether to include the base directory in the archive. diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs index 3be8bcce1fa..cd2b78e64eb 100644 --- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs +++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs @@ -101,24 +101,24 @@ namespace System.IO.Compression /// /// The path to the archive on the file system that is to be extracted. /// The path to the directory on the file system. The directory specified must not exist, but the directory that it is contained in must exist. - /// The encoding to use when reading or writing entry names in this ZipArchive. + /// The encoding to use when reading or writing entry names and comments in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. /// However, this may be necessary for interoperability with ZIP archive tools and libraries that do not correctly support - /// UTF-8 encoding for entry names.
+ /// UTF-8 encoding for entry names or comments.
/// This value is used as follows:
/// If entryNameEncoding is not specified (== null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the current system default code page (Encoding.Default) in order to decode the entry name. + /// use the current system default code page (Encoding.Default) in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// If entryNameEncoding is specified (!= null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the specified entryNameEncoding in order to decode the entry name. + /// use the specified entryNameEncoding in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// Note that Unicode encodings other than UTF-8 may not be currently used for the entryNameEncoding, /// otherwise an is thrown. @@ -156,24 +156,24 @@ namespace System.IO.Compression /// The path to the archive on the file system that is to be extracted. /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. /// True to indicate overwrite. - /// The encoding to use when reading or writing entry names in this ZipArchive. + /// The encoding to use when reading or writing entry names and comments in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. /// However, this may be necessary for interoperability with ZIP archive tools and libraries that do not correctly support - /// UTF-8 encoding for entry names.
+ /// UTF-8 encoding for entry names or comments.
/// This value is used as follows:
/// If entryNameEncoding is not specified (== null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the current system default code page (Encoding.Default) in order to decode the entry name. + /// use the current system default code page (Encoding.Default) in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// If entryNameEncoding is specified (!= null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the specified entryNameEncoding in order to decode the entry name. + /// use the specified entryNameEncoding in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// Note that Unicode encodings other than UTF-8 may not be currently used for the entryNameEncoding, /// otherwise an is thrown. @@ -250,17 +250,17 @@ namespace System.IO.Compression /// /// The stream from which the zip archive is to be extracted. /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. - /// The encoding to use when reading or writing entry names in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names. + /// The encoding to use when reading or writing entry names and comments in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names or comments. /// This method creates the specified directory and all subdirectories. The destination directory cannot already exist. /// Exceptions related to validating the paths in the or the files in the zip archive contained in parameters are thrown before extraction. Otherwise, if an error occurs during extraction, the archive remains partially extracted. /// Each extracted file has the same relative path to the directory specified by as its source entry has to the root of the archive. /// If a file to be archived has an invalid last modified time, the first date and time representable in the Zip timestamp format (midnight on January 1, 1980) will be used. - /// If is set to a value other than , entry names are decoded according to the following rules: - /// - For entry names where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, the entry names are decoded by using the specified encoding. - /// - For entries where the language encoding flag is set, the entry names are decoded by using UTF-8. - /// If is set to , entry names are decoded according to the following rules: - /// - For entries where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, entry names are decoded by using the current system default code page. - /// - For entries where the language encoding flag is set, the entry names are decoded by using UTF-8. + /// If is set to a value other than , entry names and comments are decoded according to the following rules: + /// - For entry names and comments where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, the entry names and comments are decoded by using the specified encoding. + /// - For entries where the language encoding flag is set, the entry names and comments are decoded by using UTF-8. + /// If is set to , entry names and comments are decoded according to the following rules: + /// - For entries where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, entry names and comments are decoded by using the current system default code page. + /// - For entries where the language encoding flag is set, the entry names and comments are decoded by using UTF-8. /// > is , contains only white space, or contains at least one invalid character. /// -or- /// is set to a Unicode encoding other than UTF-8. @@ -287,18 +287,18 @@ namespace System.IO.Compression /// /// The stream from which the zip archive is to be extracted. /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. - /// The encoding to use when reading or writing entry names in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names. + /// The encoding to use when reading or writing entry names and comments in this archive. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names or comments. /// to overwrite files; otherwise. /// This method creates the specified directory and all subdirectories. The destination directory cannot already exist. /// Exceptions related to validating the paths in the or the files in the zip archive contained in parameters are thrown before extraction. Otherwise, if an error occurs during extraction, the archive remains partially extracted. /// Each extracted file has the same relative path to the directory specified by as its source entry has to the root of the archive. /// If a file to be archived has an invalid last modified time, the first date and time representable in the Zip timestamp format (midnight on January 1, 1980) will be used. - /// If is set to a value other than , entry names are decoded according to the following rules: - /// - For entry names where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, the entry names are decoded by using the specified encoding. - /// - For entries where the language encoding flag is set, the entry names are decoded by using UTF-8. - /// If is set to , entry names are decoded according to the following rules: + /// If is set to a value other than , entry names and comments are decoded according to the following rules: + /// - For entry names and comments where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, the entry names and comments are decoded by using the specified encoding. + /// - For entries where the language encoding flag is set, the entry names and comments are decoded by using UTF-8. + /// If is set to , entry names and comments are decoded according to the following rules: /// - For entries where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, entry names are decoded by using the current system default code page. - /// - For entries where the language encoding flag is set, the entry names are decoded by using UTF-8. + /// - For entries where the language encoding flag is set, the entry names and comments are decoded by using UTF-8. /// > is , contains only white space, or contains at least one invalid character. /// -or- /// is set to a Unicode encoding other than UTF-8. 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 2c0118270c0..1fc5ce279f7 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 @@ -77,7 +77,7 @@ namespace System.IO.Compression /// The input or output stream. /// See the description of the ZipArchiveMode enum. Read requires the stream to support reading, Create requires the stream to support writing, and Update requires the stream to support reading, writing, and seeking. /// true to leave the stream open upon disposing the ZipArchive, otherwise false. - /// The encoding to use when reading or writing entry names in this ZipArchive. + /// The encoding to use when reading or writing entry names and comments in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. /// However, this may be necessary for interoperability with ZIP archive tools and libraries that do not correctly support /// UTF-8 encoding for entry names.
@@ -86,30 +86,30 @@ namespace System.IO.Compression /// If entryNameEncoding is not specified (== null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the current system default code page (Encoding.Default) in order to decode the entry name. + /// use the current system default code page (Encoding.Default) in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// If entryNameEncoding is specified (!= null): /// /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is not set, - /// use the specified entryNameEncoding in order to decode the entry name. + /// use the specified entryNameEncoding in order to decode the entry name and comment. /// For entries where the language encoding flag (EFS) in the general purpose bit flag of the local file header is set, - /// use UTF-8 (Encoding.UTF8) in order to decode the entry name. + /// use UTF-8 (Encoding.UTF8) in order to decode the entry name and comment. /// /// Writing (saving) ZIP archive files: /// If entryNameEncoding is not specified (== null): /// - /// For entry names that contain characters outside the ASCII range, + /// For entry names and comments that contain characters outside the ASCII range, /// the language encoding flag (EFS) will be set in the general purpose bit flag of the local file header, - /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name into bytes. - /// For entry names that do not contain characters outside the ASCII range, + /// and UTF-8 (Encoding.UTF8) will be used in order to encode the entry name and comment into bytes. + /// For entry names and comments that do not contain characters outside the ASCII range, /// the language encoding flag (EFS) will not be set in the general purpose bit flag of the local file header, - /// and the current system default code page (Encoding.Default) will be used to encode the entry names into bytes. + /// and the current system default code page (Encoding.Default) will be used to encode the entry names and comments into bytes. /// /// If entryNameEncoding is specified (!= null): /// - /// The specified entryNameEncoding will always be used to encode the entry names into bytes. + /// The specified entryNameEncoding will always be used to encode the entry names and comments into bytes. /// The language encoding flag (EFS) in the general purpose bit flag of the local file header will be set if and only /// if the specified entryNameEncoding is a UTF-8 encoding. /// 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 1f861f7d715..abd90b45fbf 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 @@ -77,7 +77,7 @@ namespace System.IO.Compression _outstandingWriteStream = null; _storedEntryNameBytes = cd.Filename; - _storedEntryName = (_archive.EntryNameAndCommentEncoding ?? Encoding.UTF8).GetString(_storedEntryNameBytes); + _storedEntryName = DecodeEntryString(_storedEntryNameBytes); DetectEntryNameVersion(); _lhUnknownExtraFields = null; @@ -200,7 +200,7 @@ namespace System.IO.Compression [AllowNull] public string Comment { - get => (_archive.EntryNameAndCommentEncoding ?? Encoding.UTF8).GetString(_fileComment); + get => DecodeEntryString(_fileComment); set { _fileComment = ZipHelper.GetEncodedTruncatedBytesFromString(value, _archive.EntryNameAndCommentEncoding, ushort.MaxValue, out bool isUTF8); @@ -352,6 +352,18 @@ namespace System.IO.Compression return FullName; } + private string DecodeEntryString(byte[] entryStringBytes) + { + Debug.Assert(entryStringBytes != null); + + Encoding readEntryStringEncoding = + (_generalPurposeBitFlag & BitFlagValues.UnicodeFileNameAndComment) == BitFlagValues.UnicodeFileNameAndComment + ? Encoding.UTF8 + : _archive?.EntryNameAndCommentEncoding ?? Encoding.UTF8; + + return readEntryStringEncoding.GetString(entryStringBytes); + } + // Only allow opening ZipArchives with large ZipArchiveEntries in update mode when running in a 64-bit process. // This is for compatibility with old behavior that threw an exception for all process bitnesses, because this // will not work in a 32-bit process. diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.Comments.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.Comments.cs index d04ab6c6d1d..ca5b651e3f2 100644 --- a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.Comments.cs +++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_CreateTests.Comments.cs @@ -33,31 +33,65 @@ namespace System.IO.Compression.Tests public static void Create_Comment_Utf8EntryName_Utf8Encoding(string originalComment, string expectedComment) => Create_Comment_EntryName_Encoding_Internal(Utf8FileName, originalComment, expectedComment, Encoding.UTF8); + [Theory] + [MemberData(nameof(Utf8Comment_Data))] + public static void Create_Comment_Utf8EntryName_Utf8Encoding_Default(string originalComment, string expectedComment) => + Create_Comment_EntryName_Encoding_Internal(Utf8FileName, originalComment, expectedComment, expectedComment, Encoding.UTF8, null); + [Theory] [MemberData(nameof(Latin1Comment_Data))] public static void Create_Comment_Utf8EntryName_Latin1Encoding(string originalComment, string expectedComment) => // Emoji not supported by latin1 Create_Comment_EntryName_Encoding_Internal(Utf8AndLatin1FileName, originalComment, expectedComment, Encoding.Latin1); + [Theory] + [MemberData(nameof(Utf8Comment_Data))] + public static void Create_Comment_Utf8EntryName_Utf8Encoding_Prioritised(string originalComment, string expectedComment) + // UTF8 encoding bit is set in the general-purpose bit flags. The verification encoding of Latin1 should be ignored + => Create_Comment_EntryName_Encoding_Internal(Utf8FileName, originalComment, expectedComment, expectedComment, Encoding.UTF8, Encoding.Latin1); + + [Theory] + [MemberData(nameof(MismatchingEncodingComment_Data))] + public static void Create_Comment_AsciiEntryName_Utf8Decoding_Invalid(string originalComment, string expectedPreWriteComment, string expectedPostWriteComment) + // The UTF8 encoding bit in the general-purpose bit flags should not be set, filenames should be encoded with Latin1, and thus + // decoding with UTF8 should result in incorrect filenames. This is because the filenames and comments contain code points in the + // range 0xC0..0xFF (which Latin1 encodes in one byte, and UTF8 encodes in two bytes.) + => Create_Comment_EntryName_Encoding_Internal(AsciiFileName, originalComment, expectedPreWriteComment, expectedPostWriteComment, Encoding.Latin1, Encoding.UTF8); + + [Theory] + [MemberData(nameof(MismatchingEncodingComment_Data))] + public static void Create_Comment_AsciiEntryName_DefaultDecoding_Utf8(string originalComment, string expectedPreWriteComment, string expectedPostWriteComment) + // Filenames should be encoded with Latin1, resulting in the UTF8 encoding bit in the general-purpose bit flags not being set. + // However, failing to specify an encoding (or specifying a null encoding) for the read should result in UTF8 being used anyway. + // This should result in incorrect filenames, since the filenames and comments contain code points in the range 0xC0..0xFF (which + // Latin1 encodes in one byte, and UTF8 encodes in two bytes.) + => Create_Comment_EntryName_Encoding_Internal(AsciiFileName, originalComment, expectedPreWriteComment, expectedPostWriteComment, Encoding.Latin1, null); + private static void Create_Comment_EntryName_Encoding_Internal(string entryName, string originalComment, string expectedComment, Encoding encoding) + => Create_Comment_EntryName_Encoding_Internal(entryName, originalComment, expectedComment, expectedComment, encoding, encoding); + + private static void Create_Comment_EntryName_Encoding_Internal(string entryName, string originalComment, + string expectedPreWriteComment, string expectedPostWriteComment, + Encoding creationEncoding, Encoding verificationEncoding) { using var ms = new MemoryStream(); - using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true, encoding)) + using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true, creationEncoding)) { ZipArchiveEntry entry = zip.CreateEntry(entryName, CompressionLevel.NoCompression); entry.Comment = originalComment; - Assert.Equal(expectedComment, entry.Comment); + // The expected pre-write and post-write comment can be different when testing encodings which vary between operations. + Assert.Equal(expectedPreWriteComment, entry.Comment); } - using (var zip = new ZipArchive(ms, ZipArchiveMode.Read, leaveOpen: false, encoding)) + using (var zip = new ZipArchive(ms, ZipArchiveMode.Read, leaveOpen: false, verificationEncoding)) { foreach (ZipArchiveEntry entry in zip.Entries) { Assert.Equal(entryName, entry.Name); - Assert.Equal(expectedComment, entry.Comment); + Assert.Equal(expectedPostWriteComment, entry.Comment); } } } } -} \ No newline at end of file +}