// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace Microsoft.DotNet.Tools.Test.Utilities { /// /// Implements a few file name utilities that are needed by the compiler. /// In general the compiler is not supposed to understand the format of the paths. /// In rare cases it needs to check if a string is a valid file name or change the extension /// (embedded resources, netmodules, output name). /// The APIs are intentionally limited to cover just these rare cases. Do not add more APIs. /// internal static class FileNameUtilities { private const string DirectorySeparatorStr = "\\"; internal const char DirectorySeparatorChar = '\\'; internal const char AltDirectorySeparatorChar = '/'; internal const char VolumeSeparatorChar = ':'; /// /// Returns true if the string represents an unqualified file name. /// The name may contain any characters but directory and volume separators. /// /// Path. /// /// True if is a simple file name, false if it is null or includes a directory specification. /// internal static bool IsFileName(string path) { return IndexOfFileName(path) == 0; } /// /// Returns the offset in where the dot that starts an extension is, or -1 if the path doesn't have an extension. /// /// /// Returns 0 for path ".foo". /// Returns -1 for path "foo.". /// private static int IndexOfExtension(string path) { if (path == null) { return -1; } int length = path.Length; int i = length; while (--i >= 0) { char c = path[i]; if (c == '.') { if (i != length - 1) { return i; } return -1; } if (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar || c == VolumeSeparatorChar) { break; } } return -1; } /// /// Returns an extension of the specified path string. /// /// /// The same functionality as but doesn't throw an exception /// if there are invalid characters in the path. /// internal static string GetExtension(string path) { if (path == null) { return null; } int index = IndexOfExtension(path); return (index >= 0) ? path.Substring(index) : string.Empty; } /// /// Removes extension from path. /// /// /// Returns "foo" for path "foo.". /// Returns "foo.." for path "foo...". /// private static string RemoveExtension(string path) { if (path == null) { return null; } int index = IndexOfExtension(path); if (index >= 0) { return path.Substring(0, index); } // trim last ".", if present if (path.Length > 0 && path[path.Length - 1] == '.') { return path.Substring(0, path.Length - 1); } return path; } /// /// Returns path with the extension changed to . /// /// /// Equivalent of /// /// If is null, returns null. /// If path does not end with an extension, the new extension is appended to the path. /// If extension is null, equivalent to . /// internal static string ChangeExtension(string path, string extension) { if (path == null) { return null; } var pathWithoutExtension = RemoveExtension(path); if (extension == null || path.Length == 0) { return pathWithoutExtension; } if (extension.Length == 0 || extension[0] != '.') { return pathWithoutExtension + "." + extension; } return pathWithoutExtension + extension; } /// /// Returns the position in given path where the file name starts. /// /// -1 if path is null. internal static int IndexOfFileName(string path) { if (path == null) { return -1; } for (int i = path.Length - 1; i >= 0; i--) { char ch = path[i]; if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar || ch == VolumeSeparatorChar) { return i + 1; } } return 0; } /// /// Get file name from path. /// /// Unlike doesn't check for invalid path characters. internal static string GetFileName(string path) { int fileNameStart = IndexOfFileName(path); return (fileNameStart <= 0) ? path : path.Substring(fileNameStart); } } }