You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

368 lines
16 KiB

  1. /* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. using System;
  22. using System.Diagnostics.CodeAnalysis;
  23. using System.Security;
  24. namespace Alphaleonis.Win32.Filesystem
  25. {
  26. public static partial class Path
  27. {
  28. #region ChangeExtension (.NET)
  29. /// <summary>Changes the extension of a path string.</summary>
  30. /// <returns>The modified path information.</returns>
  31. /// <exception cref="ArgumentException"/>
  32. /// <param name="path">The path information to modify. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  33. /// <param name="extension">The new extension (with or without a leading period). Specify <see langword="null"/> to remove an existing extension from path.</param>
  34. [SecurityCritical]
  35. public static string ChangeExtension(string path, string extension)
  36. {
  37. return System.IO.Path.ChangeExtension(path, extension);
  38. }
  39. #endregion // ChangeExtension (.NET)
  40. #region GetDirectoryName
  41. #region .NET
  42. /// <summary>Returns the directory information for the specified path string.</summary>
  43. /// <returns>
  44. /// <para>Directory information for <paramref name="path"/>, or <see langword="null"/> if <paramref name="path"/> denotes a root directory or is
  45. /// <see langword="null"/>.</para>
  46. /// <para>Returns <see cref="string.Empty"/> if <paramref name="path"/> does not contain directory information.</para>
  47. /// </returns>
  48. /// <exception cref="ArgumentException"/>
  49. /// <param name="path">The path of a file or directory.</param>
  50. [SecurityCritical]
  51. public static string GetDirectoryName(string path)
  52. {
  53. return GetDirectoryName(path, true);
  54. }
  55. #endregion // .NET
  56. #region AlphaFS
  57. /// <summary>[AlphaFS] Returns the directory information for the specified path string.</summary>
  58. /// <returns>
  59. /// Directory information for <paramref name="path"/>, or <see langword="null"/> if <paramref name="path"/> denotes a root directory or is
  60. /// <see langword="null"/>. Returns <see cref="string.Empty"/> if <paramref name="path"/> does not contain directory information.
  61. /// </returns>
  62. /// <exception cref="ArgumentException"/>
  63. /// <param name="path">The path of a file or directory.</param>
  64. /// <param name="checkInvalidPathChars"><see langword="true"/> will check <paramref name="path"/> for invalid path characters.</param>
  65. [SecurityCritical]
  66. public static string GetDirectoryName(string path, bool checkInvalidPathChars)
  67. {
  68. if (path != null)
  69. {
  70. int rootLength = GetRootLength(path, checkInvalidPathChars);
  71. if (path.Length > rootLength)
  72. {
  73. int length = path.Length;
  74. if (length == rootLength)
  75. return null;
  76. while (length > rootLength && path[--length] != DirectorySeparatorChar && path[length] != AltDirectorySeparatorChar) { }
  77. return path.Substring(0, length).Replace(AltDirectorySeparatorChar, DirectorySeparatorChar);
  78. }
  79. }
  80. return null;
  81. }
  82. #endregion // AlphaFS
  83. #endregion // GetDirectoryName
  84. #region GetDirectoryNameWithoutRoot
  85. #region AlphaFS
  86. /// <summary>[AlphaFS] Returns the directory information for the specified path string without the root information, for example: "C:\Windows\system32" returns: "Windows".</summary>
  87. /// <returns>The <paramref name="path"/>without the file name part and without the root information (if any), or <see langword="null"/> if <paramref name="path"/> is <see langword="null"/> or if <paramref name="path"/> denotes a root (such as "\", "C:", or * "\\server\share").</returns>
  88. /// <param name="path">The path.</param>
  89. [SecurityCritical]
  90. public static string GetDirectoryNameWithoutRoot(string path)
  91. {
  92. return GetDirectoryNameWithoutRootTransacted(null, path);
  93. }
  94. /// <summary>[AlphaFS] Returns the directory information for the specified path string without the root information, for example: "C:\Windows\system32" returns: "Windows".</summary>
  95. /// <returns>The <paramref name="path"/>without the file name part and without the root information (if any), or <see langword="null"/> if <paramref name="path"/> is <see langword="null"/> or if <paramref name="path"/> denotes a root (such as "\", "C:", or * "\\server\share").</returns>
  96. /// <param name="transaction">The transaction.</param>
  97. /// <param name="path">The path.</param>
  98. [SecurityCritical]
  99. public static string GetDirectoryNameWithoutRootTransacted(KernelTransaction transaction, string path)
  100. {
  101. if (path == null)
  102. return null;
  103. DirectoryInfo di = Directory.GetParentCore(transaction, path, PathFormat.RelativePath);
  104. return di != null && di.Parent != null ? di.Name : null;
  105. }
  106. #endregion // AlphaFS
  107. #endregion // GetDirectoryNameWithoutRoot
  108. #region GetExtension
  109. #region .NET
  110. /// <summary>Returns the extension of the specified path string.</summary>
  111. /// <returns>
  112. /// <para>The extension of the specified path (including the period "."), or null, or <see cref="string.Empty"/>.</para>
  113. /// <para>If <paramref name="path"/> is null, this method returns null.</para>
  114. /// <para>If <paramref name="path"/> does not have extension information,
  115. /// this method returns <see cref="string.Empty"/>.</para>
  116. /// </returns>
  117. /// <exception cref="ArgumentException"/>
  118. /// <exception cref="ArgumentNullException"/>
  119. /// <param name="path">The path string from which to get the extension. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  120. [SecurityCritical]
  121. public static string GetExtension(string path)
  122. {
  123. return GetExtension(path, !Utils.IsNullOrWhiteSpace(path));
  124. }
  125. #endregion // .NET
  126. #region AlphaFS
  127. /// <summary>Returns the extension of the specified path string.</summary>
  128. /// <returns>
  129. /// <para>The extension of the specified path (including the period "."), or null, or <see cref="string.Empty"/>.</para>
  130. /// <para>If <paramref name="path"/> is null, this method returns null.</para>
  131. /// <para>If <paramref name="path"/> does not have extension information,
  132. /// this method returns <see cref="string.Empty"/>.</para>
  133. /// </returns>
  134. /// <exception cref="ArgumentException"/>
  135. /// <param name="path">The path string from which to get the extension. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  136. /// <param name="checkInvalidPathChars"><see langword="true"/> will check <paramref name="path"/> for invalid path characters.</param>
  137. [SecurityCritical]
  138. public static string GetExtension(string path, bool checkInvalidPathChars)
  139. {
  140. if (path == null)
  141. return null;
  142. if (checkInvalidPathChars)
  143. CheckInvalidPathChars(path, false, true);
  144. int length = path.Length;
  145. int index = length;
  146. while (--index >= 0)
  147. {
  148. char ch = path[index];
  149. if (ch == ExtensionSeparatorChar)
  150. return index != length - 1 ? path.Substring(index, length - index) : string.Empty;
  151. if (IsDVsc(ch, null))
  152. break;
  153. }
  154. return string.Empty;
  155. }
  156. #endregion // AlphaFS
  157. #endregion // GetExtension
  158. #region GetFileName
  159. #region .NET
  160. /// <summary>Returns the file name and extension of the specified path string.</summary>
  161. /// <returns>
  162. /// The characters after the last directory character in <paramref name="path"/>. If the last character of <paramref name="path"/> is a
  163. /// directory or volume separator character, this method returns <c>string.Empty</c>. If path is null, this method returns null.
  164. /// </returns>
  165. /// <exception cref="ArgumentException"/>
  166. /// <param name="path">The path string from which to obtain the file name and extension. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  167. [SecurityCritical]
  168. public static string GetFileName(string path)
  169. {
  170. return GetFileName(path, true);
  171. }
  172. #endregion // .NET
  173. #region AlphaFS
  174. /// <summary>[AlphaFS] Returns the file name and extension of the specified path string.</summary>
  175. /// <returns>
  176. /// The characters after the last directory character in <paramref name="path"/>. If the last character of <paramref name="path"/> is a
  177. /// directory or volume separator character, this method returns <c>string.Empty</c>. If path is null, this method returns null.
  178. /// </returns>
  179. /// <exception cref="ArgumentException"/>
  180. /// <param name="path">The path string from which to obtain the file name and extension.</param>
  181. /// <param name="checkInvalidPathChars"><see langword="true"/> will check <paramref name="path"/> for invalid path characters.</param>
  182. [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
  183. public static string GetFileName(string path, bool checkInvalidPathChars)
  184. {
  185. if (Utils.IsNullOrWhiteSpace(path))
  186. return path;
  187. if (checkInvalidPathChars)
  188. CheckInvalidPathChars(path, false, true);
  189. int length = path.Length;
  190. int index = length;
  191. while (--index >= 0)
  192. {
  193. char ch = path[index];
  194. if (IsDVsc(ch, null))
  195. return path.Substring(index + 1, length - index - 1);
  196. }
  197. return path;
  198. }
  199. #endregion // AlphaFS
  200. #endregion // GetFileName
  201. #region GetFileNameWithoutExtension
  202. #region .NET
  203. /// <summary>Returns the file name of the specified path string without the extension.</summary>
  204. /// <returns>The string returned by GetFileName, minus the last period (.) and all characters following it.</returns>
  205. /// <exception cref="ArgumentException"/>
  206. /// <param name="path">The path of the file. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  207. [SecurityCritical]
  208. public static string GetFileNameWithoutExtension(string path)
  209. {
  210. return GetFileNameWithoutExtension(path, true);
  211. }
  212. #endregion // .NET
  213. #region AlphaFS
  214. /// <summary>[AlphaFS] Returns the file name of the specified path string without the extension.</summary>
  215. /// <returns>The string returned by GetFileName, minus the last period (.) and all characters following it.</returns>
  216. /// <exception cref="ArgumentException"/>
  217. /// <param name="path">The path of the file. The path cannot contain any of the characters defined in <see cref="GetInvalidPathChars"/>.</param>
  218. /// <param name="checkInvalidPathChars"><see langword="true"/> will check <paramref name="path"/> for invalid path characters.</param>
  219. [SecurityCritical]
  220. public static string GetFileNameWithoutExtension(string path, bool checkInvalidPathChars)
  221. {
  222. path = GetFileName(path, checkInvalidPathChars);
  223. if (path != null)
  224. {
  225. int i;
  226. return (i = path.LastIndexOf('.')) == -1 ? path : path.Substring(0, i);
  227. }
  228. return null;
  229. }
  230. #endregion // AlphaFS
  231. #endregion // GetFileNameWithoutExtension
  232. #region GetInvalidFileNameChars (.NET)
  233. /// <summary>Gets an array containing the characters that are not allowed in file names.</summary>
  234. /// <returns>An array containing the characters that are not allowed in file names.</returns>
  235. [SecurityCritical]
  236. public static char[] GetInvalidFileNameChars()
  237. {
  238. return System.IO.Path.GetInvalidFileNameChars();
  239. }
  240. #endregion // GetInvalidFileNameChars (.NET)
  241. #region GetInvalidPathChars (.NET)
  242. /// <summary>Gets an array containing the characters that are not allowed in path names.</summary>
  243. /// <returns>An array containing the characters that are not allowed in path names.</returns>
  244. [SecurityCritical]
  245. public static char[] GetInvalidPathChars()
  246. {
  247. return System.IO.Path.GetInvalidPathChars();
  248. }
  249. #endregion // GetInvalidPathChars (.NET)
  250. #region GetPathRoot
  251. #region .NET
  252. /// <summary>Gets the root directory information of the specified path.</summary>
  253. /// <returns>
  254. /// Returns the root directory of <paramref name="path"/>, such as "C:\",
  255. /// or <see langword="null"/> if <paramref name="path"/> is <see langword="null"/>,
  256. /// or an empty string if <paramref name="path"/> does not contain root directory information.
  257. /// </returns>
  258. /// <exception cref="ArgumentException"/>
  259. /// <param name="path">The path from which to obtain root directory information.</param>
  260. [SecurityCritical]
  261. public static string GetPathRoot(string path)
  262. {
  263. return GetPathRoot(path, true);
  264. }
  265. #endregion // .NET
  266. /// <summary>[AlphaFS] Gets the root directory information of the specified path.</summary>
  267. /// <returns>
  268. /// Returns the root directory of <paramref name="path"/>, such as "C:\",
  269. /// or <see langword="null"/> if <paramref name="path"/> is <see langword="null"/>,
  270. /// or an empty string if <paramref name="path"/> does not contain root directory information.
  271. /// </returns>
  272. /// <exception cref="ArgumentException"/>
  273. /// <param name="path">The path from which to obtain root directory information.</param>
  274. /// <param name="checkInvalidPathChars"><see langword="true"/> will check <paramref name="path"/> for invalid path characters.</param>
  275. [SecurityCritical]
  276. public static string GetPathRoot(string path, bool checkInvalidPathChars)
  277. {
  278. if (path == null)
  279. return null;
  280. if (path.Trim().Length == 0)
  281. throw new ArgumentException(Resources.Path_Is_Zero_Length_Or_Only_White_Space, "path");
  282. string pathRp = GetRegularPathCore(path, checkInvalidPathChars ? GetFullPathOptions.CheckInvalidPathChars : GetFullPathOptions.None, false);
  283. var rootLengthPath = GetRootLength(path, false);
  284. var rootLengthPathRp = GetRootLength(pathRp, false);
  285. // Check if pathRp is an empty string.
  286. if (rootLengthPathRp == 0)
  287. if (path.StartsWith(LongPathPrefix, StringComparison.OrdinalIgnoreCase))
  288. return GetLongPathCore(path.Substring(0, rootLengthPath), GetFullPathOptions.None);
  289. return path.StartsWith(LongPathUncPrefix, StringComparison.OrdinalIgnoreCase)
  290. ? GetLongPathCore(pathRp.Substring(0, rootLengthPathRp), GetFullPathOptions.None)
  291. : path.Substring(0, rootLengthPath);
  292. }
  293. #endregion // GetPathRoot
  294. }
  295. }