| File: FileUtilitiesRegex.cs | Web Access |
| Project: src\msbuild\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; namespace Microsoft.Build.Shared { /// <summary> /// This class contains utility methods for file IO. /// Separate from FileUtilities because some assemblies may only need the patterns. /// PERF\COVERAGE NOTE: Try to keep classes in 'shared' as granular as possible. All the methods in /// each class get pulled into the resulting assembly. /// </summary> internal static class FileUtilitiesRegex { private const char _backSlash = '\\'; private const char _forwardSlash = '/'; /// <summary> /// Indicates whether the specified string follows the pattern drive pattern (for example "C:", "D:"). /// </summary> /// <param name="pattern">Input to check for drive pattern.</param> /// <returns>true if follows the drive pattern, false otherwise.</returns> internal static bool IsDrivePattern(string pattern) { // Format must be two characters long: "<drive letter>:" return pattern.Length == 2 && StartsWithDrivePattern(pattern); } /// <summary> /// Indicates whether the specified string follows the pattern drive pattern (for example "C:/" or "C:\"). /// </summary> /// <param name="pattern">Input to check for drive pattern with slash.</param> /// <returns>true if follows the drive pattern with slash, false otherwise.</returns> internal static bool IsDrivePatternWithSlash(string pattern) { return pattern.Length == 3 && StartsWithDrivePatternWithSlash(pattern); } /// <summary> /// Indicates whether the specified string starts with the drive pattern (for example "C:"). /// </summary> /// <param name="pattern">Input to check for drive pattern.</param> /// <returns>true if starts with drive pattern, false otherwise.</returns> internal static bool StartsWithDrivePattern(string pattern) { // Format dictates a length of at least 2, // first character must be a letter, // second character must be a ":" return pattern.Length >= 2 && #if NET char.IsAsciiLetter(pattern[0]) && #else ((pattern[0] >= 'A' && pattern[0] <= 'Z') || (pattern[0] >= 'a' && pattern[0] <= 'z')) && #endif pattern[1] == ':'; } /// <summary> /// Indicates whether the specified string starts with the drive pattern (for example "C:/" or "C:\"). /// </summary> /// <param name="pattern">Input to check for drive pattern.</param> /// <returns>true if starts with drive pattern with slash, false otherwise.</returns> internal static bool StartsWithDrivePatternWithSlash(string pattern) { // Format dictates a length of at least 3, // first character must be a letter, // second character must be a ":" // third character must be a slash. return pattern.Length >= 3 && StartsWithDrivePattern(pattern) && (pattern[2] == _backSlash || pattern[2] == _forwardSlash); } /// <summary> /// Indicates whether the specified file-spec comprises exactly "\\server\share" (with no trailing characters). /// </summary> /// <param name="pattern">Input to check for UNC pattern.</param> /// <returns>true if comprises UNC pattern.</returns> internal static bool IsUncPattern(string pattern) { // Return value == pattern.length means: // meets minimum unc requirements // pattern does not end in a '/' or '\' // if a subfolder were found the value returned would be length up to that subfolder, therefore no subfolder exists return StartsWithUncPatternMatchLength(pattern) == pattern.Length; } /// <summary> /// Indicates whether the specified file-spec begins with "\\server\share". /// </summary> /// <param name="pattern">Input to check for UNC pattern.</param> /// <returns>true if starts with UNC pattern.</returns> internal static bool StartsWithUncPattern(string pattern) { // Any non -1 value returned means there was a match, therefore is begins with the pattern. return StartsWithUncPatternMatchLength(pattern) != -1; } /// <summary> /// Indicates whether the file-spec begins with a UNC pattern and how long the match is. /// </summary> /// <param name="pattern">Input to check for UNC pattern.</param> /// <returns>length of the match, -1 if no match.</returns> internal static int StartsWithUncPatternMatchLength(string pattern) { if (!MeetsUncPatternMinimumRequirements(pattern)) { return -1; } bool prevCharWasSlash = true; bool hasShare = false; for (int i = 2; i < pattern.Length; i++) { // Real UNC paths should only contain backslashes. However, the previous // regex pattern accepted both so functionality will be retained. if (pattern[i] == _backSlash || pattern[i] == _forwardSlash) { if (prevCharWasSlash) { // We get here in the case of an extra slash. return -1; } else if (hasShare) { return i; } hasShare = true; prevCharWasSlash = true; } else { prevCharWasSlash = false; } } if (!hasShare) { // no subfolder means no unc pattern. string is something like "\\abc" in this case return -1; } return pattern.Length; } /// <summary> /// Indicates whether or not the file-spec meets the minimum requirements of a UNC pattern. /// </summary> /// <param name="pattern">Input to check for UNC pattern minimum requirements.</param> /// <returns>true if the UNC pattern is a minimum length of 5 and the first two characters are be a slash, false otherwise.</returns> [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool MeetsUncPatternMinimumRequirements(string pattern) { return pattern.Length >= 5 && (pattern[0] == _backSlash || pattern[0] == _forwardSlash) && (pattern[1] == _backSlash || pattern[1] == _forwardSlash); } } }