# ICSharpCode.SharpZipLib.Zip.ZipNameTransform - Coverage Report

# 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

Method | Cyclomatic Complexity | Sequence Coverage | Branch Coverage
--- | --- | --- | ---
.ctor() | 1 | 100 | 100
.ctor(...) | 1 | 100 | 100
.cctor() | 1 | 100 | 100
TransformDirectory(...) | 3 | 85.71 | 60
TransformFile(...) | 9 | 77.78 | 70.59
MakeValidName(...) | 5 | 84.62 | 88.89
IsValidName(...) | 4 | 85.71 | 60
IsValidName(...) | 3 | 100 | 100

# File(s)

## C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipNameTransform.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` |  | `/// 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>`
| 101 | `19` |  | `public ZipNameTransform()`
|  | `20` |  | `{`
| 101 | `21` |  | `}`
|  | `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>`
| 5 | `27` |  | `public ZipNameTransform(string trimPrefix)`
|  | `28` |  | `{`
| 5 | `29` |  | `TrimPrefix = trimPrefix;`
| 5 | `30` |  | `}`
|  | `31` |  | `#endregion`
|  | `32` |  | ``
|  | `33` |  | `/// <summary>`
|  | `34` |  | `/// Static constructor.`
|  | `35` |  | `/// </summary>`
|  | `36` |  | `static ZipNameTransform()`
|  | `37` |  | `{`
|  | `38` |  | `char[] invalidPathChars;`
| 1 | `39` |  | `invalidPathChars = Path.GetInvalidPathChars();`
| 1 | `40` |  | `int howMany = invalidPathChars.Length + 2;`
|  | `41` |  | ``
| 1 | `42` |  | `InvalidEntryCharsRelaxed = new char[howMany];`
| 1 | `43` |  | `Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length);`
| 1 | `44` |  | `InvalidEntryCharsRelaxed[howMany - 1] = '*';`
| 1 | `45` |  | `InvalidEntryCharsRelaxed[howMany - 2] = '?';`
|  | `46` |  | ``
| 1 | `47` |  | `howMany = invalidPathChars.Length + 4;`
| 1 | `48` |  | `InvalidEntryChars = new char[howMany];`
| 1 | `49` |  | `Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);`
| 1 | `50` |  | `InvalidEntryChars[howMany - 1] = ':';`
| 1 | `51` |  | `InvalidEntryChars[howMany - 2] = '\\';`
| 1 | `52` |  | `InvalidEntryChars[howMany - 3] = '*';`
| 1 | `53` |  | `InvalidEntryChars[howMany - 4] = '?';`
| 1 | `54` |  | `}`
|  | `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` |  | `{`
| 5 | `63` |  | `name = TransformFile(name);`
| 4 | `64` |  | `if (name.Length > 0) {`
| 4 | `65` |  | `if (!name.EndsWith("/", StringComparison.Ordinal)) {`
| 4 | `66` |  | `name += "/";`
|  | `67` |  | `}`
| 4 | `68` |  | `} else {`
| 0 | `69` |  | `throw new ZipException("Cannot have an empty directory name");`
|  | `70` |  | `}`
| 4 | `71` |  | `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` |  | `{`
| 65927 | `81` |  | `if (name != null) {`
| 65927 | `82` |  | `string lowerName = name.ToLower();`
| 65927 | `83` |  | `if ((trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_, StringComparison.Ordinal) == 0)) {`
| 7 | `84` |  | `name = name.Substring(trimPrefix_.Length);`
|  | `85` |  | `}`
|  | `86` |  | ``
| 65927 | `87` |  | `name = name.Replace(@"\", "/");`
| 65927 | `88` |  | `name = WindowsPathUtils.DropPathRoot(name);`
|  | `89` |  | ``
|  | `90` |  | `// Drop any leading slashes.`
| 65932 | `91` |  | `while ((name.Length > 0) && (name[0] == '/')) {`
| 5 | `92` |  | `name = name.Remove(0, 1);`
|  | `93` |  | `}`
|  | `94` |  | ``
|  | `95` |  | `// Drop any trailing slashes.`
| 65927 | `96` |  | `while ((name.Length > 0) && (name[name.Length - 1] == '/')) {`
| 0 | `97` |  | `name = name.Remove(name.Length - 1, 1);`
|  | `98` |  | `}`
|  | `99` |  | ``
|  | `100` |  | `// Convert consecutive // characters to /`
| 65927 | `101` |  | `int index = name.IndexOf("//", StringComparison.Ordinal);`
| 65927 | `102` |  | `while (index >= 0) {`
| 0 | `103` |  | `name = name.Remove(index, 1);`
| 0 | `104` |  | `index = name.IndexOf("//", StringComparison.Ordinal);`
|  | `105` |  | `}`
|  | `106` |  | ``
| 65927 | `107` |  | `name = MakeValidName(name, '_');`
| 65926 | `108` |  | `} else {`
| 0 | `109` |  | `name = string.Empty;`
|  | `110` |  | `}`
| 65926 | `111` |  | `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 {`
| 0 | `120` |  | `get { return trimPrefix_; }`
|  | `121` |  | `set {`
| 5 | `122` |  | `trimPrefix_ = value;`
| 5 | `123` |  | `if (trimPrefix_ != null) {`
| 5 | `124` |  | `trimPrefix_ = trimPrefix_.ToLower();`
|  | `125` |  | `}`
| 5 | `126` |  | `}`
|  | `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` |  | `{`
| 65927 | `137` |  | `int index = name.IndexOfAny(InvalidEntryChars);`
| 65927 | `138` |  | `if (index >= 0) {`
| 2 | `139` |  | `var builder = new StringBuilder(name);`
|  | `140` |  | ``
| 5 | `141` |  | `while (index >= 0) {`
| 3 | `142` |  | `builder[index] = replacement;`
|  | `143` |  | ``
| 3 | `144` |  | `if (index >= name.Length) {`
| 0 | `145` |  | `index = -1;`
| 0 | `146` |  | `} else {`
| 3 | `147` |  | `index = name.IndexOfAny(InvalidEntryChars, index + 1);`
|  | `148` |  | `}`
|  | `149` |  | `}`
| 2 | `150` |  | `name = builder.ToString();`
|  | `151` |  | `}`
|  | `152` |  | ``
| 65927 | `153` |  | `if (name.Length > 0xffff) {`
| 1 | `154` |  | `throw new PathTooLongException();`
|  | `155` |  | `}`
|  | `156` |  | ``
| 65926 | `157` |  | `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` |  | `{`
| 65916 | `174` |  | `bool result = (name != null);`
|  | `175` |  | ``
| 65916 | `176` |  | `if (result) {`
| 65916 | `177` |  | `if (relaxed) {`
| 65916 | `178` |  | `result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0;`
| 65916 | `179` |  | `} else {`
| 0 | `180` |  | `result =`
| 0 | `181` |  | `(name.IndexOfAny(InvalidEntryChars) < 0) &&`
| 0 | `182` |  | `(name.IndexOf('/') != 0);`
|  | `183` |  | `}`
|  | `184` |  | `}`
|  | `185` |  | ``
| 65916 | `186` |  | `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` |  | `{`
| 2 | `203` |  | `bool result =`
| 2 | `204` |  | `(name != null) &&`
| 2 | `205` |  | `(name.IndexOfAny(InvalidEntryChars) < 0) &&`
| 2 | `206` |  | `(name.IndexOf('/') != 0)`
| 2 | `207` |  | `;`
| 1 | `208` |  | `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` |  | `}`