diff --git a/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs b/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs
index 71a739600..0391b8e0e 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_.NameTransform = null; // all required transforms handled by us
if (password_ != null)
{
diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipNameTransform.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipNameTransform.cs
index 1b5e01a68..9569018bd 100644
--- a/src/ICSharpCode.SharpZipLib/Zip/ZipNameTransform.cs
+++ b/src/ICSharpCode.SharpZipLib/Zip/ZipNameTransform.cs
@@ -247,4 +247,76 @@ public static bool IsValidName(string name)
#endregion Class Fields
}
+
+ ///
+ /// An implementation of INameTransform that transforms entry paths as per the Zip file naming convention.
+ /// Strips path roots and puts directory separators in the correct format ('/')
+ ///
+ public class PathTransformer : INameTransform
+ {
+ ///
+ /// Initialize a new instance of
+ ///
+ public PathTransformer()
+ {
+ }
+
+ ///
+ /// Transform a windows directory name according to the Zip file naming conventions.
+ ///
+ /// The directory name to transform.
+ /// The transformed name.
+ public string TransformDirectory(string name)
+ {
+ name = TransformFile(name);
+
+ if (name.Length > 0)
+ {
+ if (!name.EndsWith("/", StringComparison.Ordinal))
+ {
+ name += "/";
+ }
+ }
+ else
+ {
+ throw new ZipException("Cannot have an empty directory name");
+ }
+
+ return name;
+ }
+
+ ///
+ /// Transform a windows file name according to the Zip file naming conventions.
+ ///
+ /// The file name to transform.
+ /// The transformed name.
+ public string TransformFile(string name)
+ {
+ if (name != null)
+ {
+ // Put separators in the expected format.
+ name = name.Replace(@"\", "/");
+
+ // Remove the path root.
+ name = WindowsPathUtils.DropPathRoot(name);
+
+ // Drop any leading and trailing slashes.
+ name = name.Trim('/');
+
+ // Convert consecutive // characters to /
+ int index = name.IndexOf("//", StringComparison.Ordinal);
+ while (index >= 0)
+ {
+ name = name.Remove(index, 1);
+ index = name.IndexOf("//", StringComparison.Ordinal);
+ }
+ }
+ else
+ {
+ name = string.Empty;
+ }
+
+ return name;
+ }
+ }
}
diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
index bfd308daa..004985323 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,12 @@ public UseZip64 UseZip64
set { useZip64_ = value; }
}
+ ///
+ /// Used for transforming the names of entries added by .
+ /// Defaults to , set to null to disable transforms and use names as supplied.
+ ///
+ public INameTransform NameTransform { get; set; } = new PathTransformer();
+
///
/// Write an unsigned short in little endian byte order.
///
@@ -182,6 +189,34 @@ private void WriteLeLong(long value)
}
}
+ // Apply any configured transforms/cleaning to the name of the supplied entry.
+ private string TransformEntryName(ZipEntry entry)
+ {
+ string transformedName = entry.Name;
+
+ if (this.NameTransform != null)
+ {
+ if (entry.IsDirectory)
+ {
+ transformedName = this.NameTransform.TransformDirectory(entry.Name);
+ }
+ else
+ {
+ transformedName = this.NameTransform.TransformFile(entry.Name);
+ }
+ }
+
+ 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 +402,7 @@ public void PutNextEntry(ZipEntry entry)
}
}
- byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);
+ byte[] name = TransformEntryNameToArray(entry);
if (name.Length > 0xFFFF)
{
@@ -787,7 +822,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)
{