From 36236f5aa9e73f257a0627c451ea89b73cdf14d3 Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Wed, 5 Aug 2020 22:05:06 +0100 Subject: [PATCH] In ZipOutputStream, optionally transform the names of added entries with a simple fixed transform function. --- src/ICSharpCode.SharpZipLib/Zip/FastZip.cs | 1 + .../Zip/ZipOutputStream.cs | 49 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) 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) {