77using System . Collections . Generic ;
88using System . Collections . ObjectModel ;
99using System . Diagnostics ;
10+ using System . Diagnostics . CodeAnalysis ;
1011using System . Text ;
1112
1213namespace System . IO . Compression
@@ -27,8 +28,8 @@ public class ZipArchive : IDisposable
2728 private uint _numberOfThisDisk ; //only valid after ReadCentralDirectory
2829 private long _expectedNumberOfEntries ;
2930 private Stream ? _backingStream ;
30- private byte [ ] ? _archiveComment ;
31- private Encoding ? _entryNameEncoding ;
31+ private byte [ ] _archiveComment ;
32+ private Encoding ? _entryNameAndCommentEncoding ;
3233
3334#if DEBUG_FORCE_ZIP64
3435 public bool _forceZip64 ;
@@ -121,7 +122,7 @@ public ZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding?
121122 if ( stream == null )
122123 throw new ArgumentNullException ( nameof ( stream ) ) ;
123124
124- EntryNameEncoding = entryNameEncoding ;
125+ EntryNameAndCommentEncoding = entryNameEncoding ;
125126 Stream ? extraTempStream = null ;
126127
127128 try
@@ -173,7 +174,7 @@ public ZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding?
173174 _centralDirectoryStart = 0 ; // invalid until ReadCentralDirectory
174175 _isDisposed = false ;
175176 _numberOfThisDisk = 0 ; // invalid until ReadCentralDirectory
176- _archiveComment = null ;
177+ _archiveComment = Array . Empty < byte > ( ) ;
177178
178179 switch ( mode )
179180 {
@@ -211,6 +212,20 @@ public ZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding?
211212 }
212213 }
213214
215+ /// <summary>
216+ /// Gets or sets the optional archive comment.
217+ /// </summary>
218+ /// <remarks>
219+ /// The comment encoding is determined by the <c>entryNameEncoding</c> parameter of the <see cref="ZipArchive(Stream,ZipArchiveMode,bool,Encoding?)"/> constructor.
220+ /// If the comment byte length is larger than <see cref="ushort.MaxValue"/>, it will be truncated when disposing the archive.
221+ /// </remarks>
222+ [ AllowNull ]
223+ public string Comment
224+ {
225+ get => ( EntryNameAndCommentEncoding ?? Encoding . UTF8 ) . GetString ( _archiveComment ) ;
226+ set => _archiveComment = ZipHelper . GetEncodedTruncatedBytesFromString ( value , EntryNameAndCommentEncoding , ZipEndOfCentralDirectoryBlock . ZipFileCommentMaxLength , out _ ) ;
227+ }
228+
214229 /// <summary>
215230 /// The collection of entries that are currently in the ZipArchive. This may not accurately represent the actual entries that are present in the underlying file or stream.
216231 /// </summary>
@@ -345,9 +360,9 @@ public void Dispose()
345360
346361 internal uint NumberOfThisDisk => _numberOfThisDisk ;
347362
348- internal Encoding ? EntryNameEncoding
363+ internal Encoding ? EntryNameAndCommentEncoding
349364 {
350- get { return _entryNameEncoding ; }
365+ get => _entryNameAndCommentEncoding ;
351366
352367 private set
353368 {
@@ -370,10 +385,10 @@ private set
370385 ( value . Equals ( Encoding . BigEndianUnicode )
371386 || value . Equals ( Encoding . Unicode ) ) )
372387 {
373- throw new ArgumentException ( SR . EntryNameEncodingNotSupported , nameof ( EntryNameEncoding ) ) ;
388+ throw new ArgumentException ( SR . EntryNameAndCommentEncodingNotSupported , nameof ( EntryNameAndCommentEncoding ) ) ;
374389 }
375390
376- _entryNameEncoding = value ;
391+ _entryNameAndCommentEncoding = value ;
377392 }
378393 }
379394
@@ -547,9 +562,7 @@ private void ReadEndOfCentralDirectory()
547562
548563 _expectedNumberOfEntries = eocd . NumberOfEntriesInTheCentralDirectory ;
549564
550- // only bother saving the comment if we are in update mode
551- if ( _mode == ZipArchiveMode . Update )
552- _archiveComment = eocd . ArchiveComment ;
565+ _archiveComment = eocd . ArchiveComment ;
553566
554567 TryReadZip64EndOfCentralDirectory ( eocd , eocdStart ) ;
555568
0 commit comments