{
[LibraryImport(Libraries.Version, EntryPoint = "GetFileVersionInfoExW", StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool GetFileVersionInfoEx(
+ internal static unsafe partial bool GetFileVersionInfoEx(
uint dwFlags,
string lpwstrFilename,
uint dwHandle,
uint dwLen,
- IntPtr lpData);
+ void* lpData);
}
}
{
[LibraryImport(Libraries.Version, EntryPoint = "VerQueryValueW", StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool VerQueryValue(IntPtr pBlock, string lpSubBlock, out IntPtr lplpBuffer, out uint puLen);
+ internal static unsafe partial bool VerQueryValue(void* pBlock, string lpSubBlock, out void* lplpBuffer, out uint puLen);
}
}
{
_fileName = fileName;
- uint handle; // This variable is not used, but we need an out variable.
- uint infoSize = Interop.Version.GetFileVersionInfoSizeEx(
- (uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, out handle);
-
+ uint infoSize = Interop.Version.GetFileVersionInfoSizeEx(Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, out _);
if (infoSize != 0)
{
- byte[] mem = new byte[infoSize];
- fixed (byte* memPtr = &mem[0])
+ void* memPtr = NativeMemory.Alloc(infoSize);
+ try
{
- IntPtr memIntPtr = new IntPtr((void*)memPtr);
if (Interop.Version.GetFileVersionInfoEx(
- (uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED | (uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_NEUTRAL,
- _fileName,
- 0U,
- infoSize,
- memIntPtr))
+ Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED | Interop.Version.FileVersionInfoType.FILE_VER_GET_NEUTRAL,
+ _fileName,
+ 0U,
+ infoSize,
+ memPtr))
{
- uint langid = GetVarEntry(memIntPtr);
- if (!GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(langid)))
- {
- // Some DLLs might not contain correct codepage information. In these cases we will fail during lookup.
- // Explorer will take a few shots in dark by trying several specific lang-codepages
- // (Explorer also randomly guesses 041D04B0=Swedish+CP_UNICODE and 040704B0=German+CP_UNICODE sometimes).
- // We will try to simulate similar behavior here.
- foreach (uint id in s_fallbackLanguageCodePages)
- {
- if (id != langid)
- {
- if (GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(id)))
- {
- break;
- }
- }
- }
- }
+ // Some dlls might not contain correct codepage information, in which case the lookup will fail. Explorer will take
+ // a few shots in dark. We'll simulate similar behavior by falling back to the following lang-codepages.
+ uint lcp = GetLanguageAndCodePage(memPtr);
+ _ = GetVersionInfoForCodePage(memPtr, lcp.ToString("X8")) ||
+ (lcp != 0x040904B0 && GetVersionInfoForCodePage(memPtr, "040904B0")) || // US English + CP_UNICODE
+ (lcp != 0x040904E4 && GetVersionInfoForCodePage(memPtr, "040904E4")) || // US English + CP_USASCII
+ (lcp != 0x04090000 && GetVersionInfoForCodePage(memPtr, "04090000")); // US English + unknown codepage
}
}
+ finally
+ {
+ NativeMemory.Free(memPtr);
+ }
}
}
- // Some dlls might not contain correct codepage information,
- // in which case the lookup will fail. Explorer will take
- // a few shots in dark. We'll simulate similar behavior by
- // falling back to the following lang-codepages:
- private static readonly uint[] s_fallbackLanguageCodePages = new uint[]
- {
- 0x040904B0, // US English + CP_UNICODE
- 0x040904E4, // US English + CP_USASCII
- 0x04090000 // US English + unknown codepage
- };
-
- private static string ConvertTo8DigitHex(uint value)
- {
- return value.ToString("X8");
- }
-
- private static unsafe Interop.Version.VS_FIXEDFILEINFO GetFixedFileInfo(IntPtr memPtr)
+ private static unsafe Interop.Version.VS_FIXEDFILEINFO GetFixedFileInfo(void* memPtr)
{
- if (Interop.Version.VerQueryValue(memPtr, "\\", out IntPtr memRef, out _))
+ if (Interop.Version.VerQueryValue(memPtr, "\\", out void* memRef, out _))
{
return *(Interop.Version.VS_FIXEDFILEINFO*)memRef;
}
return default;
}
- private static unsafe string GetFileVersionLanguage(IntPtr memPtr)
+ private static unsafe string GetFileVersionLanguage(void* memPtr)
{
- uint langid = GetVarEntry(memPtr) >> 16;
+ uint langid = GetLanguageAndCodePage(memPtr) >> 16;
const int MaxLength = 256;
char* lang = stackalloc char[MaxLength];
return new string(lang, 0, charsWritten);
}
- private static string GetFileVersionString(IntPtr memPtr, string name)
+ private static unsafe string GetFileVersionString(void* memPtr, string name)
{
- if (Interop.Version.VerQueryValue(memPtr, name, out IntPtr memRef, out _))
+ if (Interop.Version.VerQueryValue(memPtr, name, out void* memRef, out _) &&
+ memRef is not null)
{
- if (memRef != IntPtr.Zero)
- {
- return Marshal.PtrToStringUni(memRef)!;
- }
+ return Marshal.PtrToStringUni((IntPtr)memRef)!;
}
return string.Empty;
}
- private static uint GetVarEntry(IntPtr memPtr)
+ private static unsafe uint GetLanguageAndCodePage(void* memPtr)
{
- if (Interop.Version.VerQueryValue(memPtr, "\\VarFileInfo\\Translation", out IntPtr memRef, out _))
+ if (Interop.Version.VerQueryValue(memPtr, "\\VarFileInfo\\Translation", out void* memRef, out _))
{
- return (uint)((Marshal.ReadInt16(memRef) << 16) + Marshal.ReadInt16((IntPtr)((long)memRef + 2)));
+ return
+ (uint)((*(ushort*)memRef << 16) +
+ *((ushort*)memRef + 1));
}
- return 0x040904E4;
+ return 0x040904E4; // US English + CP_USASCII
}
//
// This function tries to find version information for a specific codepage.
// Returns true when version information is found.
//
- private bool GetVersionInfoForCodePage(IntPtr memIntPtr, string codepage)
+ private unsafe bool GetVersionInfoForCodePage(void* memIntPtr, string codepage)
{
Span<char> stackBuffer = stackalloc char[256];
_productBuild = (int)HIWORD(ffi.dwProductVersionLS);
_productPrivate = (int)LOWORD(ffi.dwProductVersionLS);
- _isDebug = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_DEBUG) != 0;
- _isPatched = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PATCHED) != 0;
- _isPrivateBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRIVATEBUILD) != 0;
- _isPreRelease = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRERELEASE) != 0;
- _isSpecialBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_SPECIALBUILD) != 0;
+ _isDebug = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_DEBUG) != 0;
+ _isPatched = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PATCHED) != 0;
+ _isPrivateBuild = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PRIVATEBUILD) != 0;
+ _isPreRelease = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PRERELEASE) != 0;
+ _isSpecialBuild = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_SPECIALBUILD) != 0;
// fileVersion is chosen based on best guess. Other fields can be used if appropriate.
return (_fileVersion != string.Empty);
}
- private static uint HIWORD(uint dword)
- {
- return (dword >> 16) & 0xffff;
- }
+ private static uint HIWORD(uint dword) => (dword >> 16) & 0xffff;
- private static uint LOWORD(uint dword)
- {
- return dword & 0xffff;
- }
+ private static uint LOWORD(uint dword) => dword & 0xffff;
}
}
/// </summary>
internal struct MultiProxy
{
- private static readonly char[] s_proxyDelimiters = { ';', ' ', '\n', '\r', '\t' };
private readonly FailedProxyCache? _failedProxyCache;
private readonly Uri[]? _uris;
private readonly string? _proxyConfig;
private int _currentIndex;
private Uri? _currentUri;
- public static MultiProxy Empty => new MultiProxy(null, Array.Empty<Uri>());
-
private MultiProxy(FailedProxyCache? failedProxyCache, Uri[] uris)
{
_failedProxyCache = failedProxyCache;
_currentUri = null;
}
+ public static MultiProxy Empty => new MultiProxy(null, Array.Empty<Uri>());
+
/// <summary>
/// Parses a WinHTTP proxy config into a MultiProxy instance.
/// </summary>
{
const int SECURE_FLAG = 1;
const int INSECURE_FLAG = 2;
+ const string ProxyDelimiters = "; \n\r\t";
int wantedFlag = secure ? SECURE_FLAG : INSECURE_FLAG;
int originalLength = proxyString.Length;
{
// Skip any delimiters.
int iter = 0;
- while (iter < proxyString.Length && Array.IndexOf(s_proxyDelimiters, proxyString[iter]) >= 0)
+ while (iter < proxyString.Length && ProxyDelimiters.Contains(proxyString[iter]))
{
++iter;
}
}
// Find the next delimiter, or end of string.
- iter = proxyString.IndexOfAny(s_proxyDelimiters);
+ iter = proxyString.IndexOfAny(ProxyDelimiters);
if (iter < 0)
{
iter = proxyString.Length;
set => EntitySendFormat = value ? EntitySendFormat.Chunked : EntitySendFormat.ContentLength;
}
- // We MUST NOT send message-body when we send responses with these Status codes
- private static readonly int[] s_noResponseBody = { 100, 101, 204, 205, 304 };
- private static bool CanSendResponseBody(int responseCode)
- {
- for (int i = 0; i < s_noResponseBody.Length; i++)
- {
- if (responseCode == s_noResponseBody[i])
- {
- return false;
- }
- }
- return true;
- }
+
+ private static bool CanSendResponseBody(int responseCode) =>
+ // We MUST NOT send message-body when we send responses with these Status codes
+ responseCode is not (100 or 101 or 204 or 205 or 304);
public long ContentLength64
{
_version = HttpVersion.Version10;
}
- private static readonly char[] s_separators = new char[] { ' ' };
-
internal void SetRequestLine(string req)
{
- string[] parts = req.Split(s_separators, 3);
+ string[] parts = req.Split(' ', 3);
if (parts.Length != 3)
{
_context.ErrorMessage = "Invalid request line (parts).";
internal static readonly char[] PortSplitDelimiters = new char[] { ' ', ',', '\"' };
// Space (' ') should be reserved as well per RFCs, but major web browsers support it and some web sites use it - so we support it too
- internal static readonly char[] ReservedToName = new char[] { '\t', '\r', '\n', '=', ';', ',' };
- internal static readonly char[] ReservedToValue = new char[] { ';', ',' };
+ internal const string ReservedToName = "\t\r\n=;,";
private string m_comment = string.Empty; // Do not rename (binary serialization)
private Uri? m_commentUri; // Do not rename (binary serialization)
|| value.StartsWith('$')
|| value.StartsWith(' ')
|| value.EndsWith(' ')
- || value.IndexOfAny(ReservedToName) >= 0)
+ || value.AsSpan().IndexOfAny(ReservedToName) >= 0)
{
m_name = string.Empty;
return false;
m_name.StartsWith('$') ||
m_name.StartsWith(' ') ||
m_name.EndsWith(' ') ||
- m_name.IndexOfAny(ReservedToName) >= 0)
+ m_name.AsSpan().IndexOfAny(ReservedToName) >= 0)
{
if (shouldThrow)
{
// Check the value
if (m_value == null ||
- (!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.IndexOfAny(ReservedToValue) >= 0))
+ (!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.AsSpan().IndexOfAny(';', ',') >= 0))
{
if (shouldThrow)
{
// Check Comment syntax
if (Comment != null && !(Comment.Length > 2 && Comment.StartsWith('\"') && Comment.EndsWith('\"'))
- && (Comment.IndexOfAny(ReservedToValue) >= 0))
+ && (Comment.AsSpan().IndexOfAny(';', ',') >= 0))
{
if (shouldThrow)
{
// Check Path syntax
if (Path != null && !(Path.Length > 2 && Path.StartsWith('\"') && Path.EndsWith('\"'))
- && (Path.IndexOfAny(ReservedToValue) >= 0))
+ && (Path.AsSpan().IndexOfAny(';', ',') != -1))
{
if (shouldThrow)
{
// Need to special case Enum because typecode will be underlying type, e.g. Int32
private static readonly Type EnumType = typeof(Enum);
- internal static readonly char[] base64Table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
- 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '+', '/', '=' };
+ internal const string Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- private const int base64LineBreakPosition = 76;
+ private const int Base64LineBreakPosition = 76;
#if DEBUG
static Convert()
// Convert three bytes at a time to base64 notation. This will consume 4 chars.
int i;
- // get a pointer to the base64Table to avoid unnecessary range checking
- fixed (char* base64 = &base64Table[0])
+ // get a pointer to the Base64Table to avoid unnecessary range checking
+ fixed (char* base64 = Base64Table)
{
for (i = offset; i < calcLength; i += 3)
{
if (insertLineBreaks)
{
- if (charcount == base64LineBreakPosition)
+ if (charcount == Base64LineBreakPosition)
{
outChars[j++] = '\r';
outChars[j++] = '\n';
// Where we left off before
i = calcLength;
- if (insertLineBreaks && (lengthmod3 != 0) && (charcount == base64LineBreakPosition))
+ if (insertLineBreaks && (lengthmod3 != 0) && (charcount == Base64LineBreakPosition))
{
outChars[j++] = '\r';
outChars[j++] = '\n';
if (insertLineBreaks)
{
- (uint newLines, uint remainder) = Math.DivRem(outlen, base64LineBreakPosition);
+ (uint newLines, uint remainder) = Math.DivRem(outlen, Base64LineBreakPosition);
if (remainder == 0)
{
--newLines;
*/
// This class contains only static members and does not require the serializable attribute.
- internal static
- class DateTimeFormat
+ internal static class DateTimeFormat
{
internal const int MaxSecondsFractionDigits = 7;
internal const long NullOffset = long.MinValue;
- internal static char[] allStandardFormats =
- {
- 'd', 'D', 'f', 'F', 'g', 'G',
- 'm', 'M', 'o', 'O', 'r', 'R',
- 's', 't', 'T', 'u', 'U', 'y', 'Y',
- };
+ internal const string AllStandardFormats = "dDfFgGmMoOrRstTuUyY";
internal const string RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
internal const string RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz";
{
List<string> results = new List<string>(DEFAULT_ALL_DATETIMES_SIZE);
- for (int i = 0; i < allStandardFormats.Length; i++)
+ foreach (char standardFormat in AllStandardFormats)
{
- string[] strings = GetAllDateTimes(dateTime, allStandardFormats[i], dtfi);
- for (int j = 0; j < strings.Length; j++)
+ foreach (string dateTimes in GetAllDateTimes(dateTime, standardFormat, dtfi))
{
- results.Add(strings[j]);
+ results.Add(dateTimes);
}
}
{
List<string> results = new List<string>(DEFAULT_ALL_DATETIMES_SIZE);
- for (int i = 0; i < DateTimeFormat.allStandardFormats.Length; i++)
+ foreach (char standardFormat in DateTimeFormat.AllStandardFormats)
{
- string[] strings = GetAllDateTimePatterns(DateTimeFormat.allStandardFormats[i]);
- for (int j = 0; j < strings.Length; j++)
+ foreach (string pattern in GetAllDateTimePatterns(standardFormat))
{
- results.Add(strings[j]);
+ results.Add(pattern);
}
}
+
return results.ToArray();
}
Index + target.Length <= Length &&
m_info.Compare(Value.Slice(Index, target.Length), target, CompareOptions.IgnoreCase) == 0;
- private static readonly char[] WhiteSpaceChecks = new char[] { ' ', '\u00A0' };
-
internal bool MatchSpecifiedWords(string target, bool checkWordBoundary, ref int matchLength)
{
int valueRemaining = Value.Length - Index;
// Check word by word
int targetPosition = 0; // Where we are in the target string
int thisPosition = Index; // Where we are in this string
- int wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition);
+ int wsIndex = target.AsSpan(targetPosition).IndexOfAny(' ', '\u00A0');
if (wsIndex < 0)
{
return false;
}
- do
+ wsIndex += targetPosition;
+
+ while (true)
{
int segmentLength = wsIndex - targetPosition;
if (thisPosition >= Value.Length - segmentLength)
thisPosition++;
matchLength++;
}
- } while ((wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition)) >= 0);
+
+ wsIndex = target.AsSpan(targetPosition).IndexOfAny(' ', '\u00A0');
+ if (wsIndex < 0)
+ {
+ break;
+ }
+ wsIndex += targetPosition;
+ }
+
// now check the last segment;
if (targetPosition < target.Length)
{
private const int c_skew = 38;
private const int c_damp = 700;
- // Legal "dot" separators (i.e: . in www.microsoft.com)
- private static readonly char[] s_dotSeparators = { '.', '\u3002', '\uFF0E', '\uFF61' };
-
private string GetAsciiInvariant(string unicode, int index, int count)
{
if (index > 0 || count < unicode.Length)
// Find the next dot
while (iNextDot < unicode.Length)
{
+ // Legal "dot" separators (i.e: . in www.microsoft.com)
+ const string DotSeparators = ".\u3002\uFF0E\uFF61";
+
// Find end of this segment
- iNextDot = unicode.IndexOfAny(s_dotSeparators, iAfterLastDot);
- Debug.Assert(iNextDot <= unicode.Length, "[IdnMapping.punycode_encode]IndexOfAny is broken");
- if (iNextDot < 0)
- iNextDot = unicode.Length;
+ iNextDot = unicode.AsSpan(iAfterLastDot).IndexOfAny(DotSeparators);
+ iNextDot = iNextDot < 0 ? unicode.Length : iNextDot + iAfterLastDot;
// Only allowed to have empty . section at end (www.microsoft.com.)
if (iNextDot == iAfterLastDot)
{
internal static class FileSystemEnumerableFactory
{
- // These all have special meaning in DOS name matching. '\' is the escaping character (which conveniently
- // is the directory separator and cannot be part of any path segment in Windows). The other three are the
- // special case wildcards that we'll convert some * and ? into. They're also valid as filenames on Unix,
- // which is not true in Windows and as such we'll escape any that occur on the input string.
- private static readonly char[] s_unixEscapeChars = { '\\', '"', '<', '>' };
-
/// <summary>
/// Validates the directory and expression strings to check that they have no invalid characters, any special DOS wildcard characters in Win32 in the expression get replaced with their proper escaped representation, and if the expression string begins with a directory name, the directory name is moved and appended at the end of the directory string.
/// </summary>
}
else
{
- if (Path.DirectorySeparatorChar != '\\' && expression.IndexOfAny(s_unixEscapeChars) >= 0)
+ // These all have special meaning in DOS name matching. '\' is the escaping character (which conveniently
+ // is the directory separator and cannot be part of any path segment in Windows). The other three are the
+ // special case wildcards that we'll convert some * and ? into. They're also valid as filenames on Unix,
+ // which is not true in Windows and as such we'll escape any that occur on the input string.
+ if (Path.DirectorySeparatorChar != '\\' && expression.AsSpan().IndexOfAny(@"\""<>") >= 0)
{
// Backslash isn't the default separator, need to escape (e.g. Unix)
expression = expression.Replace("\\", "\\\\");
/// <summary>Provides methods for matching file system names.</summary>
public static class FileSystemName
{
- // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression
- // https://msdn.microsoft.com/en-us/library/ff469270.aspx
- private static readonly char[] s_wildcardChars =
- {
- '\"', '<', '>', '*', '?'
- };
-
- private static readonly char[] s_simpleWildcardChars =
- {
- '*', '?'
- };
-
/// <summary>Translates the given Win32 expression. Change '*' and '?' to '<', '>' and '"' to match Win32 behavior.</summary>
/// <param name="expression">The expression to translate.</param>
/// <returns>A string with the translated Win32 expression.</returns>
return true;
ReadOnlySpan<char> expressionEnd = expression.Slice(1);
- if (expressionEnd.IndexOfAny(useExtendedWildcards ? s_wildcardChars : s_simpleWildcardChars) < 0)
+
+ // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression
+ // https://msdn.microsoft.com/en-us/library/ff469270.aspx
+ bool hasWildcards = (useExtendedWildcards ?
+ expressionEnd.IndexOfAny("\"<>*?") :
+ expressionEnd.IndexOfAny('*', '?')) >= 0;
+ if (!hasWildcards)
{
// Handle the special case of a single starting *, which essentially means "ends with"
ContentType = 32
}
- private static readonly char[] s_illegalCharactersInSimpleName = { '/', '\\', ':' };
private ReadOnlySpan<char> _input;
private int _index;
if (token != Token.String)
ThrowInvalidAssemblyName();
- if (name == string.Empty || name.IndexOfAny(s_illegalCharactersInSimpleName) != -1)
+ if (string.IsNullOrEmpty(name) || name.AsSpan().IndexOfAny('/', '\\', ':') != -1)
ThrowInvalidAssemblyName();
Version? version = null;
private const int AttributesTypical = 4 * 2; // 4 attributes, times 2 strings per attribute
private const int ChildrenTypical = 1;
- private static readonly char[] s_escapeChars = new char[] { '<', '>', '\"', '\'', '&' };
+ private const string EscapeChars = "<>\"'&";
private static readonly string[] s_escapeStringPairs = new string[]
{
// these must be all once character escape sequences or a new escaping algorithm is needed
StringBuilder? sb = null;
- int strLen = str.Length;
- int index; // Pointer into the string that indicates the location of the current '&' character
- int newIndex = 0; // Pointer into the string that indicates the start index of the "remaining" string (that still needs to be processed).
-
- while (true)
+ ReadOnlySpan<char> span = str;
+ int pos;
+ while ((pos = span.IndexOfAny(EscapeChars)) >= 0)
{
- index = str.IndexOfAny(s_escapeChars, newIndex);
-
- if (index < 0)
- {
- if (sb == null)
- return str;
- else
- {
- sb.Append(str, newIndex, strLen - newIndex);
- return sb.ToString();
- }
- }
- else
- {
- sb ??= new StringBuilder();
-
- sb.Append(str, newIndex, index - newIndex);
- sb.Append(GetEscapeSequence(str[index]));
-
- newIndex = (index + 1);
- }
+ sb ??= new StringBuilder();
+ sb.Append(span.Slice(0, pos)).Append(GetEscapeSequence(span[pos]));
+ span = span.Slice(pos + 1);
}
- // no normal exit is possible
+ return sb == null ? str : sb.Append(span).ToString();
}
private static string GetUnescapeSequence(string str, int index, out int newIndex)
public static readonly UTF8Encoding ValidatingUTF8 = new UTF8Encoding(false, true);
public const string PositiveInf = "INF";
public const string NegativeInf = "-INF";
- public static readonly char[] FloatingPointCharacters = new char[] { '.', 'e', 'E' };
public const string typeString = "type";
public const string nullString = "null";
public const string arrayString = "array";
throw new XmlException(SR.Format(SR.XmlInvalidConversion, value, Globals.TypeOfInt));
}
- if (value.IndexOfAny(JsonGlobals.FloatingPointCharacters) == -1)
+ if (value.AsSpan().IndexOfAny('.', 'e', 'E') < 0)
{
int intValue;
if (int.TryParse(value, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out intValue))
// This means that a host containing Unicode characters can be normalized to contain
// URI reserved characters, changing the meaning of a URI only when certain properties
// such as IdnHost are accessed. To be safe, disallow control characters in normalized hosts.
- private static readonly char[] s_UnsafeForNormalizedHost = { '\\', '/', '?', '@', '#', ':', '[', ']' };
-
- internal static bool ContainsCharactersUnsafeForNormalizedHost(string host)
- {
- return host.IndexOfAny(s_UnsafeForNormalizedHost) != -1;
- }
+ internal static bool ContainsCharactersUnsafeForNormalizedHost(string host) =>
+ host.AsSpan().IndexOfAny(@"\/?@#:[]") >= 0;
}
}
//
// Returns true if a colon is found in the first path segment, false otherwise
//
-
- // Check for anything that may terminate the first regular path segment
- // or an illegal colon
- private static readonly char[] s_pathDelims = { ':', '\\', '/', '?', '#' };
-
private static bool CheckForColonInFirstPathSegment(string uriString)
{
- int index = uriString.IndexOfAny(s_pathDelims);
-
- return (index >= 0 && uriString[index] == ':');
+ // Check for anything that may terminate the first regular path segment
+ // or an illegal colon
+ int index = uriString.AsSpan().IndexOfAny(@":\/?#");
+ return (uint)index < (uint)uriString.Length && uriString[index] == ':';
}
internal static string InternalEscapeString(string rawString) =>
{
internal sealed class XNodeReader : XmlReader, IXmlLineInfo
{
- private static readonly char[] s_WhitespaceChars = new char[] { ' ', '\t', '\n', '\r' };
-
// The reader position is encoded by the tuple (source, parent).
// Lazy text uses (instance, parent element). Attribute value
// uses (instance, parent attribute). End element uses (instance,
XAttribute? a = e.Attribute(name);
if (a != null)
{
- switch (a.Value.Trim(s_WhitespaceChars))
+ switch (a.Value.AsSpan().Trim(" \t\n\r"))
{
case "preserve":
return XmlSpace.Preserve;
}
}
- internal static readonly char[] NodeTypeLetter = new char[] {
- 'R', // Root
- 'E', // Element
- 'A', // Attribute
- 'N', // Namespace
- 'T', // Text
- 'S', // SignificantWhitespace
- 'W', // Whitespace
- 'P', // ProcessingInstruction
- 'C', // Comment
- 'X', // All
- };
-
- internal static readonly char[] UniqueIdTbl = new char[] {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4',
- '5', '6'
- };
+ // (R)oot
+ // (E)lement
+ // (A)ttribute
+ // (N)amespace
+ // (T)ext
+ // (S)ignificantWhitespace
+ // (W)hitespace
+ // (P)rocessingInstruction
+ // (C)omment
+ // (X) All
+ internal const string NodeTypeLetter = "REANTSWPCX";
+
+ internal const string UniqueIdTbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
// Requirements for id:
// 1. must consist of alphanumeric characters only
}
if (idx <= 0x1f)
{
- sb.Append(UniqueIdTbl[idx]);
+ sb.Append(UniqueIdTbl[(int)idx]);
}
else
{
sb.Append('0');
do
{
- sb.Append(UniqueIdTbl[idx & 0x1f]);
+ sb.Append(UniqueIdTbl[(int)(idx & 0x1f)]);
idx >>= 5;
} while (idx != 0);
sb.Append('0');
{
private const string OidTagPrefix = "OID.";
- private static readonly char[] s_quoteNeedingChars =
- {
- ',',
- '+',
- '=',
- '\"',
- '\n',
- // \r is NOT in this list, because it isn't in Windows.
- '<',
- '>',
- '#',
- ';',
- };
-
private static readonly List<char> s_useSemicolonSeparators = new List<char>(1) { ';' };
private static readonly List<char> s_useCommaSeparators = new List<char>(1) { ',' };
private static readonly List<char> s_useNewlineSeparators = new List<char>(2) { '\r', '\n' };
return writer.Encode();
}
- private static bool NeedsQuoting(string rdnValue)
+ private static bool NeedsQuoting(ReadOnlySpan<char> rdnValue)
{
- if (string.IsNullOrEmpty(rdnValue))
+ if (rdnValue.IsEmpty ||
+ IsQuotableWhitespace(rdnValue[0]) ||
+ IsQuotableWhitespace(rdnValue[^1]))
{
return true;
}
- if (IsQuotableWhitespace(rdnValue[0]) ||
- IsQuotableWhitespace(rdnValue[rdnValue.Length - 1]))
- {
- return true;
- }
-
- int index = rdnValue.IndexOfAny(s_quoteNeedingChars);
-
- return index != -1;
+ const string QuoteNeedingChars = ",+=\"\n<>#;"; // \r is NOT in this list, because it isn't in Windows.
+ return rdnValue.IndexOfAny(QuoteNeedingChars) >= 0;
}
private static bool IsQuotableWhitespace(char c)