# ICSharpCode.SharpZipLib.Zip.WindowsNameTransform - Coverage Report

# Summary

Class: | ICSharpCode.SharpZipLib.Zip.WindowsNameTransform
Assembly: | ICSharpCode.SharpZipLib
File(s): | C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\WindowsNameTransform.cs
Covered lines: | 42
Uncovered lines: | 35
Coverable lines: | 77
Total lines: | 226
Line coverage: | 54.5%
Branch coverage: | 42.8%

# Metrics

Method | Cyclomatic Complexity | Sequence Coverage | Branch Coverage
--- | --- | --- | ---
.ctor(...) | 2 | 83.33 | 66.67
.ctor() | 1 | 100 | 100
TransformDirectory(...) | 3 | 71.43 | 60
TransformFile(...) | 4 | 77.78 | 71.43
IsValidName(...) | 3 | 0 | 0
.cctor() | 1 | 100 | 100
MakeValidName(...) | 11 | 50 | 52.38

# File(s)

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

| # | Line |  | Line coverage
--- | --- | --- | --- | ---
|  | `1` |  | `using System;`
|  | `2` |  | `using System.IO;`
|  | `3` |  | `using System.Text;`
|  | `4` |  | `using ICSharpCode.SharpZipLib.Core;`
|  | `5` |  | ``
|  | `6` |  | `namespace ICSharpCode.SharpZipLib.Zip`
|  | `7` |  | `{`
|  | `8` |  | `/// <summary>`
|  | `9` |  | `/// WindowsNameTransform transforms <see cref="ZipFile"/> names to windows compatible ones.`
|  | `10` |  | `/// </summary>`
|  | `11` |  | `public class WindowsNameTransform : INameTransform`
|  | `12` |  | `{`
|  | `13` |  | `/// <summary>`
|  | `14` |  | `/// Initialises a new instance of <see cref="WindowsNameTransform"/>`
|  | `15` |  | `/// </summary>`
|  | `16` |  | `/// <param name="baseDirectory"></param>`
| 1 | `17` |  | `public WindowsNameTransform(string baseDirectory)`
|  | `18` |  | `{`
| 1 | `19` |  | `if (baseDirectory == null) {`
| 0 | `20` |  | `throw new ArgumentNullException(nameof(baseDirectory), "Directory name is invalid");`
|  | `21` |  | `}`
|  | `22` |  | ``
| 1 | `23` |  | `BaseDirectory = baseDirectory;`
| 1 | `24` |  | `}`
|  | `25` |  | ``
|  | `26` |  | `/// <summary>`
|  | `27` |  | `/// Initialise a default instance of <see cref="WindowsNameTransform"/>`
|  | `28` |  | `/// </summary>`
| 2 | `29` |  | `public WindowsNameTransform()`
|  | `30` |  | `{`
|  | `31` |  | `// Do nothing.`
| 2 | `32` |  | `}`
|  | `33` |  | ``
|  | `34` |  | `/// <summary>`
|  | `35` |  | `/// Gets or sets a value containing the target directory to prefix values with.`
|  | `36` |  | `/// </summary>`
|  | `37` |  | `public string BaseDirectory {`
| 0 | `38` |  | `get { return _baseDirectory; }`
|  | `39` |  | `set {`
| 1 | `40` |  | `if (value == null) {`
| 0 | `41` |  | `throw new ArgumentNullException(nameof(value));`
|  | `42` |  | `}`
|  | `43` |  | ``
| 1 | `44` |  | `_baseDirectory = Path.GetFullPath(value);`
| 1 | `45` |  | `}`
|  | `46` |  | `}`
|  | `47` |  | ``
|  | `48` |  | `/// <summary>`
|  | `49` |  | `/// Gets or sets a value indicating wether paths on incoming values should be removed.`
|  | `50` |  | `/// </summary>`
|  | `51` |  | `public bool TrimIncomingPaths {`
| 0 | `52` |  | `get { return _trimIncomingPaths; }`
| 0 | `53` |  | `set { _trimIncomingPaths = value; }`
|  | `54` |  | `}`
|  | `55` |  | ``
|  | `56` |  | `/// <summary>`
|  | `57` |  | `/// Transform a Zip directory name to a windows directory name.`
|  | `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` |  | `{`
| 3 | `63` |  | `name = TransformFile(name);`
| 2 | `64` |  | `if (name.Length > 0) {`
| 2 | `65` |  | `while (name.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) {`
| 0 | `66` |  | `name = name.Remove(name.Length - 1, 1);`
|  | `67` |  | `}`
| 2 | `68` |  | `} else {`
| 0 | `69` |  | `throw new ZipException("Cannot have an empty directory name");`
|  | `70` |  | `}`
| 2 | `71` |  | `return name;`
|  | `72` |  | `}`
|  | `73` |  | ``
|  | `74` |  | `/// <summary>`
|  | `75` |  | `/// Transform a Zip format file name to a windows style one.`
|  | `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` |  | `{`
| 3 | `81` |  | `if (name != null) {`
| 3 | `82` |  | `name = MakeValidName(name, _replacementChar);`
|  | `83` |  | ``
| 2 | `84` |  | `if (_trimIncomingPaths) {`
| 0 | `85` |  | `name = Path.GetFileName(name);`
|  | `86` |  | `}`
|  | `87` |  | ``
|  | `88` |  | `// This may exceed windows length restrictions.`
|  | `89` |  | `// Combine will throw a PathTooLongException in that case.`
| 2 | `90` |  | `if (_baseDirectory != null) {`
| 1 | `91` |  | `name = Path.Combine(_baseDirectory, name);`
|  | `92` |  | `}`
| 1 | `93` |  | `} else {`
| 0 | `94` |  | `name = string.Empty;`
|  | `95` |  | `}`
| 2 | `96` |  | `return name;`
|  | `97` |  | `}`
|  | `98` |  | ``
|  | `99` |  | `/// <summary>`
|  | `100` |  | `/// Test a name to see if it is a valid name for a windows filename as extracted from a Zip archive.`
|  | `101` |  | `/// </summary>`
|  | `102` |  | `/// <param name="name">The name to test.</param>`
|  | `103` |  | `/// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>`
|  | `104` |  | `/// <remarks>The filename isnt a true windows path in some fundamental ways like no absolute paths, no rooted paths`
|  | `105` |  | `public static bool IsValidName(string name)`
|  | `106` |  | `{`
| 0 | `107` |  | `bool result =`
| 0 | `108` |  | `(name != null) &&`
| 0 | `109` |  | `(name.Length <= MaxPath) &&`
| 0 | `110` |  | `(string.Compare(name, MakeValidName(name, '_'), StringComparison.Ordinal) == 0)`
| 0 | `111` |  | `;`
|  | `112` |  | ``
| 0 | `113` |  | `return result;`
|  | `114` |  | `}`
|  | `115` |  | ``
|  | `116` |  | `/// <summary>`
|  | `117` |  | `/// Initialise static class information.`
|  | `118` |  | `/// </summary>`
|  | `119` |  | `static WindowsNameTransform()`
|  | `120` |  | `{`
|  | `121` |  | `char[] invalidPathChars;`
|  | `122` |  | ``
| 1 | `123` |  | `invalidPathChars = Path.GetInvalidPathChars();`
| 1 | `124` |  | `int howMany = invalidPathChars.Length + 3;`
|  | `125` |  | ``
| 1 | `126` |  | `InvalidEntryChars = new char[howMany];`
| 1 | `127` |  | `Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);`
| 1 | `128` |  | `InvalidEntryChars[howMany - 1] = '*';`
| 1 | `129` |  | `InvalidEntryChars[howMany - 2] = '?';`
| 1 | `130` |  | `InvalidEntryChars[howMany - 3] = ':';`
| 1 | `131` |  | `}`
|  | `132` |  | ``
|  | `133` |  | `/// <summary>`
|  | `134` |  | `/// Force a name to be valid by replacing invalid characters with a fixed value`
|  | `135` |  | `/// </summary>`
|  | `136` |  | `/// <param name="name">The name to make valid</param>`
|  | `137` |  | `/// <param name="replacement">The replacement character to use for any invalid characters.</param>`
|  | `138` |  | `/// <returns>Returns a valid name</returns>`
|  | `139` |  | `public static string MakeValidName(string name, char replacement)`
|  | `140` |  | `{`
| 3 | `141` |  | `if (name == null) {`
| 0 | `142` |  | `throw new ArgumentNullException(nameof(name));`
|  | `143` |  | `}`
|  | `144` |  | ``
| 3 | `145` |  | `name = WindowsPathUtils.DropPathRoot(name.Replace("/", Path.DirectorySeparatorChar.ToString()));`
|  | `146` |  | ``
|  | `147` |  | `// Drop any leading slashes.`
| 3 | `148` |  | `while ((name.Length > 0) && (name[0] == Path.DirectorySeparatorChar)) {`
| 0 | `149` |  | `name = name.Remove(0, 1);`
|  | `150` |  | `}`
|  | `151` |  | ``
|  | `152` |  | `// Drop any trailing slashes.`
| 4 | `153` |  | `while ((name.Length > 0) && (name[name.Length - 1] == Path.DirectorySeparatorChar)) {`
| 1 | `154` |  | `name = name.Remove(name.Length - 1, 1);`
|  | `155` |  | `}`
|  | `156` |  | ``
|  | `157` |  | `// Convert consecutive \\ characters to \`
| 3 | `158` |  | `int index = name.IndexOf(string.Format("{0}{0}", Path.DirectorySeparatorChar), StringComparison.Ordinal);`
| 3 | `159` |  | `while (index >= 0) {`
| 0 | `160` |  | `name = name.Remove(index, 1);`
| 0 | `161` |  | `index = name.IndexOf(Path.DirectorySeparatorChar);`
|  | `162` |  | `}`
|  | `163` |  | ``
|  | `164` |  | `// Convert any invalid characters using the replacement one.`
| 3 | `165` |  | `index = name.IndexOfAny(InvalidEntryChars);`
| 3 | `166` |  | `if (index >= 0) {`
| 0 | `167` |  | `var builder = new StringBuilder(name);`
|  | `168` |  | ``
| 0 | `169` |  | `while (index >= 0) {`
| 0 | `170` |  | `builder[index] = replacement;`
|  | `171` |  | ``
| 0 | `172` |  | `if (index >= name.Length) {`
| 0 | `173` |  | `index = -1;`
| 0 | `174` |  | `} else {`
| 0 | `175` |  | `index = name.IndexOfAny(InvalidEntryChars, index + 1);`
|  | `176` |  | `}`
|  | `177` |  | `}`
| 0 | `178` |  | `name = builder.ToString();`
|  | `179` |  | `}`
|  | `180` |  | ``
|  | `181` |  | `// Check for names greater than MaxPath characters.`
|  | `182` |  | `// TODO: Were is CLR version of MaxPath defined? Can't find it in Environment.`
| 3 | `183` |  | `if (name.Length > MaxPath) {`
| 1 | `184` |  | `throw new PathTooLongException();`
|  | `185` |  | `}`
|  | `186` |  | ``
| 2 | `187` |  | `return name;`
|  | `188` |  | `}`
|  | `189` |  | ``
|  | `190` |  | `/// <summary>`
|  | `191` |  | `/// Gets or set the character to replace invalid characters during transformations.`
|  | `192` |  | `/// </summary>`
|  | `193` |  | `public char Replacement {`
| 0 | `194` |  | `get { return _replacementChar; }`
|  | `195` |  | `set {`
| 0 | `196` |  | `for (int i = 0; i < InvalidEntryChars.Length; ++i) {`
| 0 | `197` |  | `if (InvalidEntryChars[i] == value) {`
| 0 | `198` |  | `throw new ArgumentException("invalid path character");`
|  | `199` |  | `}`
|  | `200` |  | `}`
|  | `201` |  | ``
| 0 | `202` |  | `if ((value == Path.DirectorySeparatorChar) || (value == Path.AltDirectorySeparatorChar)) {`
| 0 | `203` |  | `throw new ArgumentException("invalid replacement character");`
|  | `204` |  | `}`
|  | `205` |  | ``
| 0 | `206` |  | `_replacementChar = value;`
| 0 | `207` |  | `}`
|  | `208` |  | `}`
|  | `209` |  | ``
|  | `210` |  | `/// <summary>`
|  | `211` |  | `/// The maximum windows path name permitted.`
|  | `212` |  | `/// </summary>`
|  | `213` |  | `/// <remarks>This may not valid for all windows systems - CE?, etc but I cant find the equivalent in the CLR.</remar`
|  | `214` |  | `const int MaxPath = 260;`
|  | `215` |  | ``
|  | `216` |  | `#region Instance Fields`
|  | `217` |  | `string _baseDirectory;`
|  | `218` |  | `bool _trimIncomingPaths;`
| 3 | `219` |  | `char _replacementChar = '_';`
|  | `220` |  | `#endregion`
|  | `221` |  | ``
|  | `222` |  | `#region Class Fields`
|  | `223` |  | `static readonly char[] InvalidEntryChars;`
|  | `224` |  | `#endregion`
|  | `225` |  | `}`
|  | `226` |  | `}`