Skip to content

Commit

Permalink
PR #497: Transform new entry names using an INameTranform in ZipOutpu…
Browse files Browse the repository at this point in the history
…tStream
  • Loading branch information
Numpsy authored Aug 9, 2020
1 parent 3491abb commit 1a47326
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/ICSharpCode.SharpZipLib/Zip/FastZip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ private void CreateZip(Stream outputStream, string sourceDirectory, bool recurse
{
outputStream_.SetLevel((int)CompressionLevel);
outputStream_.IsStreamOwner = !leaveOpen;
outputStream_.NameTransform = null; // all required transforms handled by us

if (password_ != null)
{
Expand Down
5 changes: 5 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,11 @@ public string Name
{
return name;
}

internal set
{
name = value;
}
}

/// <summary>
Expand Down
72 changes: 72 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipNameTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,76 @@ public static bool IsValidName(string name)

#endregion Class Fields
}

/// <summary>
/// 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 ('/')
/// </summary>
public class PathTransformer : INameTransform
{
/// <summary>
/// Initialize a new instance of <see cref="PathTransformer"></see>
/// </summary>
public PathTransformer()
{
}

/// <summary>
/// Transform a windows directory name according to the Zip file naming conventions.
/// </summary>
/// <param name="name">The directory name to transform.</param>
/// <returns>The transformed name.</returns>
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;
}

/// <summary>
/// Transform a windows file name according to the Zip file naming conventions.
/// </summary>
/// <param name="name">The file name to transform.</param>
/// <returns>The transformed name.</returns>
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;
}
}
}
25 changes: 25 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -146,6 +147,12 @@ public UseZip64 UseZip64
set { useZip64_ = value; }
}

/// <summary>
/// Used for transforming the names of entries added by <see cref="PutNextEntry(ZipEntry)"/>.
/// Defaults to <see cref="PathTransformer"/>, set to null to disable transforms and use names as supplied.
/// </summary>
public INameTransform NameTransform { get; set; } = new PathTransformer();

/// <summary>
/// Write an unsigned short in little endian byte order.
/// </summary>
Expand Down Expand Up @@ -182,6 +189,22 @@ private void WriteLeLong(long value)
}
}

// Apply any configured transforms/cleaning to the name of the supplied entry.
private void TransformEntryName(ZipEntry entry)
{
if (this.NameTransform != null)
{
if (entry.IsDirectory)
{
entry.Name = this.NameTransform.TransformDirectory(entry.Name);
}
else
{
entry.Name = this.NameTransform.TransformFile(entry.Name);
}
}
}

/// <summary>
/// Starts a new Zip entry. It automatically closes the previous
/// entry if present.
Expand Down Expand Up @@ -367,6 +390,8 @@ public void PutNextEntry(ZipEntry entry)
}
}

// Apply any required transforms to the entry name, and then convert to byte array format.
TransformEntryName(entry);
byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);

if (name.Length > 0xFFFF)
Expand Down

0 comments on commit 1a47326

Please sign in to comment.