Summary

Class:ICSharpCode.SharpZipLib.Zip.ZipNameTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipNameTransform.cs
Covered lines:66
Uncovered lines:11
Coverable lines:77
Total lines:220
Line coverage:85.7%
Branch coverage:67.6%

Metrics

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)1100100
.cctor()1100100
TransformDirectory(...)385.7160
TransformFile(...)977.7870.59
MakeValidName(...)584.6288.89
IsValidName(...)485.7160
IsValidName(...)3100100

File(s)

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipNameTransform.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4using ICSharpCode.SharpZipLib.Core;
 5
 6namespace ICSharpCode.SharpZipLib.Zip
 7{
 8  /// <summary>
 9  /// ZipNameTransform transforms names as per the Zip file naming convention.
 10  /// </summary>
 11  /// <remarks>The use of absolute names is supported although its use is not valid
 12  /// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>
 13  public class ZipNameTransform : INameTransform
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Initialize a new instance of <see cref="ZipNameTransform"></see>
 18    /// </summary>
 10119    public ZipNameTransform()
 20    {
 10121    }
 22
 23    /// <summary>
 24    /// Initialize a new instance of <see cref="ZipNameTransform"></see>
 25    /// </summary>
 26    /// <param name="trimPrefix">The string to trim from the front of paths if found.</param>
 527    public ZipNameTransform(string trimPrefix)
 28    {
 529      TrimPrefix = trimPrefix;
 530    }
 31    #endregion
 32
 33    /// <summary>
 34    /// Static constructor.
 35    /// </summary>
 36    static ZipNameTransform()
 37    {
 38      char[] invalidPathChars;
 139      invalidPathChars = Path.GetInvalidPathChars();
 140      int howMany = invalidPathChars.Length + 2;
 41
 142      InvalidEntryCharsRelaxed = new char[howMany];
 143      Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length);
 144      InvalidEntryCharsRelaxed[howMany - 1] = '*';
 145      InvalidEntryCharsRelaxed[howMany - 2] = '?';
 46
 147      howMany = invalidPathChars.Length + 4;
 148      InvalidEntryChars = new char[howMany];
 149      Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
 150      InvalidEntryChars[howMany - 1] = ':';
 151      InvalidEntryChars[howMany - 2] = '\\';
 152      InvalidEntryChars[howMany - 3] = '*';
 153      InvalidEntryChars[howMany - 4] = '?';
 154    }
 55
 56    /// <summary>
 57    /// Transform a windows directory name according to the Zip file naming conventions.
 58    /// </summary>
 59    /// <param name="name">The directory name to transform.</param>
 60    /// <returns>The transformed name.</returns>
 61    public string TransformDirectory(string name)
 62    {
 563      name = TransformFile(name);
 464       if (name.Length > 0) {
 465         if (!name.EndsWith("/", StringComparison.Ordinal)) {
 466          name += "/";
 67        }
 468      } else {
 069        throw new ZipException("Cannot have an empty directory name");
 70      }
 471      return name;
 72    }
 73
 74    /// <summary>
 75    /// Transform a windows file name according to the Zip file naming conventions.
 76    /// </summary>
 77    /// <param name="name">The file name to transform.</param>
 78    /// <returns>The transformed name.</returns>
 79    public string TransformFile(string name)
 80    {
 6592781       if (name != null) {
 6592782        string lowerName = name.ToLower();
 6592783         if ((trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_, StringComparison.Ordinal) == 0)) {
 784          name = name.Substring(trimPrefix_.Length);
 85        }
 86
 6592787        name = name.Replace(@"\", "/");
 6592788        name = WindowsPathUtils.DropPathRoot(name);
 89
 90        // Drop any leading slashes.
 6593291         while ((name.Length > 0) && (name[0] == '/')) {
 592          name = name.Remove(0, 1);
 93        }
 94
 95        // Drop any trailing slashes.
 6592796         while ((name.Length > 0) && (name[name.Length - 1] == '/')) {
 097          name = name.Remove(name.Length - 1, 1);
 98        }
 99
 100        // Convert consecutive // characters to /
 65927101        int index = name.IndexOf("//", StringComparison.Ordinal);
 65927102         while (index >= 0) {
 0103          name = name.Remove(index, 1);
 0104          index = name.IndexOf("//", StringComparison.Ordinal);
 105        }
 106
 65927107        name = MakeValidName(name, '_');
 65926108      } else {
 0109        name = string.Empty;
 110      }
 65926111      return name;
 112    }
 113
 114    /// <summary>
 115    /// Get/set the path prefix to be trimmed from paths if present.
 116    /// </summary>
 117    /// <remarks>The prefix is trimmed before any conversion from
 118    /// a windows path is done.</remarks>
 119    public string TrimPrefix {
 0120      get { return trimPrefix_; }
 121      set {
 5122        trimPrefix_ = value;
 5123         if (trimPrefix_ != null) {
 5124          trimPrefix_ = trimPrefix_.ToLower();
 125        }
 5126      }
 127    }
 128
 129    /// <summary>
 130    /// Force a name to be valid by replacing invalid characters with a fixed value
 131    /// </summary>
 132    /// <param name="name">The name to force valid</param>
 133    /// <param name="replacement">The replacement character to use.</param>
 134    /// <returns>Returns a valid name</returns>
 135    static string MakeValidName(string name, char replacement)
 136    {
 65927137      int index = name.IndexOfAny(InvalidEntryChars);
 65927138       if (index >= 0) {
 2139        var builder = new StringBuilder(name);
 140
 5141         while (index >= 0) {
 3142          builder[index] = replacement;
 143
 3144           if (index >= name.Length) {
 0145            index = -1;
 0146          } else {
 3147            index = name.IndexOfAny(InvalidEntryChars, index + 1);
 148          }
 149        }
 2150        name = builder.ToString();
 151      }
 152
 65927153       if (name.Length > 0xffff) {
 1154        throw new PathTooLongException();
 155      }
 156
 65926157      return name;
 158    }
 159
 160    /// <summary>
 161    /// Test a name to see if it is a valid name for a zip entry.
 162    /// </summary>
 163    /// <param name="name">The name to test.</param>
 164    /// <param name="relaxed">If true checking is relaxed about windows file names and absolute paths.</param>
 165    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
 166    /// <remarks>Zip path names are actually in Unix format, and should only contain relative paths.
 167    /// This means that any path stored should not contain a drive or
 168    /// device letter, or a leading slash.  All slashes should forward slashes '/'.
 169    /// An empty name is valid for a file where the input comes from standard input.
 170    /// A null name is not considered valid.
 171    /// </remarks>
 172    public static bool IsValidName(string name, bool relaxed)
 173    {
 65916174      bool result = (name != null);
 175
 65916176       if (result) {
 65916177         if (relaxed) {
 65916178          result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0;
 65916179        } else {
 0180          result =
 0181            (name.IndexOfAny(InvalidEntryChars) < 0) &&
 0182            (name.IndexOf('/') != 0);
 183        }
 184      }
 185
 65916186      return result;
 187    }
 188
 189    /// <summary>
 190    /// Test a name to see if it is a valid name for a zip entry.
 191    /// </summary>
 192    /// <param name="name">The name to test.</param>
 193    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
 194    /// <remarks>Zip path names are actually in unix format,
 195    /// and should only contain relative paths if a path is present.
 196    /// This means that the path stored should not contain a drive or
 197    /// device letter, or a leading slash.  All slashes should forward slashes '/'.
 198    /// An empty name is valid where the input comes from standard input.
 199    /// A null name is not considered valid.
 200    /// </remarks>
 201    public static bool IsValidName(string name)
 202    {
 2203      bool result =
 2204        (name != null) &&
 2205        (name.IndexOfAny(InvalidEntryChars) < 0) &&
 2206        (name.IndexOf('/') != 0)
 2207        ;
 1208      return result;
 209    }
 210
 211    #region Instance Fields
 212    string trimPrefix_;
 213    #endregion
 214
 215    #region Class Fields
 216    static readonly char[] InvalidEntryChars;
 217    static readonly char[] InvalidEntryCharsRelaxed;
 218    #endregion
 219  }
 220}