diff --git a/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs b/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs
index 71a739600..0a07a5bf0 100644
--- a/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs
+++ b/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs
@@ -368,6 +368,7 @@ public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse,
using (outputStream_ = new ZipOutputStream(outputStream))
{
outputStream_.SetLevel((int)CompressionLevel);
+ outputStream_.TransformEntryNames = false; // all required transforms handled by us
if (password_ != null)
{
diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
index bfd308daa..f9b182933 100644
--- a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
+++ b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
@@ -1,4 +1,5 @@
using ICSharpCode.SharpZipLib.Checksum;
+using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System;
@@ -146,6 +147,11 @@ public UseZip64 UseZip64
set { useZip64_ = value; }
}
+ ///
+ /// Controls whether to transform the names of entries added by into Zip format, or to leave them as they are.
+ ///
+ public bool TransformEntryNames { get; set; } = true;
+
///
/// Write an unsigned short in little endian byte order.
///
@@ -182,6 +188,45 @@ private void WriteLeLong(long value)
}
}
+ // Transform entry names into zip format by fixing up separators and removing path roots.
+ private string TransformEntryName(ZipEntry entry)
+ {
+ string transformedName = entry.Name;
+
+ if (this.TransformEntryNames)
+ {
+ transformedName = transformedName.Replace(@"\", "/");
+ transformedName = WindowsPathUtils.DropPathRoot(transformedName);
+
+ // Drop any leading and trailing slashes.
+ transformedName = transformedName.Trim('/');
+
+ // Convert consecutive // characters to /
+ int index = transformedName.IndexOf("//", StringComparison.Ordinal);
+ while (index >= 0)
+ {
+ transformedName = transformedName.Remove(index, 1);
+ index = transformedName.IndexOf("//", StringComparison.Ordinal);
+ }
+
+ // Directory entries need just a single / on the end
+ if (entry.IsDirectory)
+ {
+ transformedName += "/";
+ }
+ }
+
+ return transformedName;
+ }
+
+ // Convert an entry name to a byte array, and apply any transforms
+ private byte[] TransformEntryNameToArray(ZipEntry entry)
+ {
+ string transformedName = TransformEntryName(entry);
+ byte[] name = ZipStrings.ConvertToArray(entry.Flags, transformedName);
+ return name;
+ }
+
///
/// Starts a new Zip entry. It automatically closes the previous
/// entry if present.
@@ -367,7 +412,7 @@ public void PutNextEntry(ZipEntry entry)
}
}
- byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);
+ byte[] name = TransformEntryNameToArray(entry);
if (name.Length > 0xFFFF)
{
@@ -787,7 +832,7 @@ public override void Finish()
WriteLeInt((int)entry.Size);
}
- byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);
+ byte[] name = TransformEntryNameToArray(entry);
if (name.Length > 0xffff)
{