Skip to content

Commit 612969e

Browse files
authored
feat(zip): better string encoding handling (#592)
This replaces the global static ZipStrings singleton with instances of StringCodec, which will: - Remove encoding configuration from a shared global state - Allow for different defaults for input and output - Explicitly override the encodings used for ZipCrypto and zip archive comments (the one in the Central Directory, not the individual entry comments). - Use "Unicode" for new entries (unless overriden) - Make it much more clear (hopefully) how and why different encodings are used.
1 parent e1e1a91 commit 612969e

13 files changed

+319
-286
lines changed

src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.IO;
44
using System.Security.Cryptography;
5+
using System.Text;
56
using System.Threading;
67
using System.Threading.Tasks;
78

@@ -203,6 +204,9 @@ public bool CanPatchEntries
203204
/// </summary>
204205
protected byte[] AESAuthCode;
205206

207+
/// <inheritdoc cref="StringCodec.ZipCryptoEncoding"/>
208+
public Encoding ZipCryptoEncoding { get; set; } = StringCodec.DefaultZipCryptoEncoding;
209+
206210
/// <summary>
207211
/// Encrypt a block of data
208212
/// </summary>

src/ICSharpCode.SharpZipLib/Zip/FastZip.cs

+29-1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,29 @@ public Deflater.CompressionLevel CompressionLevel
345345
set { compressionLevel_ = value; }
346346
}
347347

348+
/// <summary>
349+
/// Reflects the opposite of the internal <see cref="StringCodec.ForceZipLegacyEncoding"/>, setting it to <c>false</c> overrides the encoding used for reading and writing zip entries
350+
/// </summary>
351+
public bool UseUnicode
352+
{
353+
get => !_stringCodec.ForceZipLegacyEncoding;
354+
set => _stringCodec.ForceZipLegacyEncoding = !value;
355+
}
356+
357+
/// <summary> Gets or sets the code page used for reading/writing zip file entries when unicode is disabled </summary>
358+
public int LegacyCodePage
359+
{
360+
get => _stringCodec.CodePage;
361+
set => _stringCodec.CodePage = value;
362+
}
363+
364+
/// <inheritdoc cref="StringCodec"/>
365+
public StringCodec StringCodec
366+
{
367+
get => _stringCodec;
368+
set => _stringCodec = value;
369+
}
370+
348371
#endregion Properties
349372

350373
#region Delegates
@@ -456,7 +479,7 @@ private void CreateZip(Stream outputStream, string sourceDirectory, bool recurse
456479
NameTransform = new ZipNameTransform(sourceDirectory);
457480
sourceDirectory_ = sourceDirectory;
458481

459-
using (outputStream_ = new ZipOutputStream(outputStream))
482+
using (outputStream_ = new ZipOutputStream(outputStream, _stringCodec))
460483
{
461484
outputStream_.SetLevel((int)CompressionLevel);
462485
outputStream_.IsStreamOwner = !leaveOpen;
@@ -631,6 +654,10 @@ private void ProcessFile(object sender, ScanEventArgs e)
631654
using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read))
632655
{
633656
ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);
657+
if (_stringCodec.ForceZipLegacyEncoding)
658+
{
659+
entry.IsUnicodeText = false;
660+
}
634661

635662
// Set up AES encryption for the entry if required.
636663
ConfigureEntryEncryption(entry);
@@ -967,6 +994,7 @@ private static bool NameIsValid(string name)
967994
private INameTransform extractNameTransform_;
968995
private UseZip64 useZip64_ = UseZip64.Dynamic;
969996
private CompressionLevel compressionLevel_ = CompressionLevel.DEFAULT_COMPRESSION;
997+
private StringCodec _stringCodec = new StringCodec();
970998

971999
private string password_;
9721000

src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs

-43
Original file line numberDiff line numberDiff line change
@@ -471,48 +471,5 @@ public static class ZipConstants
471471
public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
472472

473473
#endregion Header Signatures
474-
475-
/// <summary>
476-
/// Default encoding used for string conversion. 0 gives the default system OEM code page.
477-
/// Using the default code page isnt the full solution necessarily
478-
/// there are many variable factors, codepage 850 is often a good choice for
479-
/// European users, however be careful about compatability.
480-
/// </summary>
481-
[Obsolete("Use ZipStrings instead")]
482-
public static int DefaultCodePage
483-
{
484-
get => ZipStrings.CodePage;
485-
set => ZipStrings.CodePage = value;
486-
}
487-
488-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToString(byte[], int)"/></summary>
489-
[Obsolete("Use ZipStrings.ConvertToString instead")]
490-
public static string ConvertToString(byte[] data, int count)
491-
=> ZipStrings.ConvertToString(data, count);
492-
493-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToString(byte[])"/></summary>
494-
[Obsolete("Use ZipStrings.ConvertToString instead")]
495-
public static string ConvertToString(byte[] data)
496-
=> ZipStrings.ConvertToString(data);
497-
498-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToStringExt(int, byte[], int)"/></summary>
499-
[Obsolete("Use ZipStrings.ConvertToStringExt instead")]
500-
public static string ConvertToStringExt(int flags, byte[] data, int count)
501-
=> ZipStrings.ConvertToStringExt(flags, data, count);
502-
503-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToStringExt(int, byte[])"/></summary>
504-
[Obsolete("Use ZipStrings.ConvertToStringExt instead")]
505-
public static string ConvertToStringExt(int flags, byte[] data)
506-
=> ZipStrings.ConvertToStringExt(flags, data);
507-
508-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToArray(string)"/></summary>
509-
[Obsolete("Use ZipStrings.ConvertToArray instead")]
510-
public static byte[] ConvertToArray(string str)
511-
=> ZipStrings.ConvertToArray(str);
512-
513-
/// <summary> Deprecated wrapper for <see cref="ZipStrings.ConvertToArray(int, string)"/></summary>
514-
[Obsolete("Use ZipStrings.ConvertToArray instead")]
515-
public static byte[] ConvertToArray(int flags, string str)
516-
=> ZipStrings.ConvertToArray(flags, str);
517474
}
518475
}

src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Text;
34

45
namespace ICSharpCode.SharpZipLib.Zip
56
{
@@ -150,7 +151,7 @@ private enum Known : byte
150151
/// The name passed is null
151152
/// </exception>
152153
public ZipEntry(string name)
153-
: this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)
154+
: this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated, true)
154155
{
155156
}
156157

@@ -171,7 +172,7 @@ public ZipEntry(string name)
171172
/// </exception>
172173
internal ZipEntry(string name, int versionRequiredToExtract)
173174
: this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy,
174-
CompressionMethod.Deflated)
175+
CompressionMethod.Deflated, true)
175176
{
176177
}
177178

@@ -182,6 +183,7 @@ internal ZipEntry(string name, int versionRequiredToExtract)
182183
/// <param name="madeByInfo">Version and HostSystem Information</param>
183184
/// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</param>
184185
/// <param name="method">Compression method for this entry.</param>
186+
/// <param name="unicode">Whether the entry uses unicode for name and comment</param>
185187
/// <exception cref="ArgumentNullException">
186188
/// The name passed is null
187189
/// </exception>
@@ -193,7 +195,7 @@ internal ZipEntry(string name, int versionRequiredToExtract)
193195
/// It is not generally useful, use the constructor specifying the name only.
194196
/// </remarks>
195197
internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
196-
CompressionMethod method)
198+
CompressionMethod method, bool unicode)
197199
{
198200
if (name == null)
199201
{
@@ -216,7 +218,7 @@ internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
216218
this.versionToExtract = (ushort)versionRequiredToExtract;
217219
this.method = method;
218220

219-
IsUnicodeText = ZipStrings.UseUnicode;
221+
IsUnicodeText = unicode;
220222
}
221223

222224
/// <summary>

src/ICSharpCode.SharpZipLib/Zip/ZipEntryFactory.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public enum TimeSetting
6868
public ZipEntryFactory()
6969
{
7070
nameTransform_ = new ZipNameTransform();
71-
isUnicodeText_ = ZipStrings.UseUnicode;
71+
isUnicodeText_ = true;
7272
}
7373

7474
/// <summary>
@@ -162,7 +162,7 @@ public int SetAttributes
162162
}
163163

164164
/// <summary>
165-
/// Get set a value indicating whether unidoce text should be set on.
165+
/// Get set a value indicating whether unicode text should be set on.
166166
/// </summary>
167167
public bool IsUnicodeText
168168
{

0 commit comments

Comments
 (0)