// // IRI normalization for strings containing characters that are not allowed or // escaped characters that should be unescaped in the context of the specified Uri component. // internal static unsafe string EscapeUnescapeIri(char *pInput, int start, int end, UriComponents component) { int size = end - start; ValueStringBuilder dest = size <= 256 ? new ValueStringBuilder(stackalloc char[256]) : new ValueStringBuilder(size); Span <byte> maxUtf8EncodedSpan = stackalloc byte[4]; for (int i = start; i < end; ++i) { char ch = pInput[i]; if (ch == '%') { if (end - i > 2) { ch = UriHelper.DecodeHexChars(pInput[i + 1], pInput[i + 2]); // Do not unescape a reserved char if (ch == Uri.c_DummyChar || ch == '%' || CheckIsReserved(ch, component) || UriHelper.IsNotSafeForUnescape(ch)) { // keep as is dest.Append(pInput[i++]); dest.Append(pInput[i++]); dest.Append(pInput[i]); continue; } else if (ch <= '\x7F') { Debug.Assert(ch < 0xFF, "Expecting ASCII character."); //ASCII dest.Append(ch); i += 2; continue; } else { // possibly utf8 encoded sequence of unicode int charactersRead = PercentEncodingHelper.UnescapePercentEncodedUTF8Sequence( pInput + i, end - i, ref dest, component == UriComponents.Query, iriParsing: true); Debug.Assert(charactersRead > 0); i += charactersRead - 1; // -1 as i will be incremented in the loop } } else { dest.Append(pInput[i]); } } else if (ch > '\x7f') { // unicode bool isInIriUnicodeRange; bool surrogatePair = false; char ch2 = '\0'; if ((char.IsHighSurrogate(ch)) && (i + 1 < end)) { ch2 = pInput[i + 1]; isInIriUnicodeRange = CheckIriUnicodeRange(ch, ch2, out surrogatePair, component == UriComponents.Query); } else { isInIriUnicodeRange = CheckIriUnicodeRange(ch, component == UriComponents.Query); } if (isInIriUnicodeRange) { dest.Append(ch); if (surrogatePair) { dest.Append(ch2); } } else { Rune rune; if (surrogatePair) { rune = new Rune(ch, ch2); } else if (!Rune.TryCreate(ch, out rune)) { rune = Rune.ReplacementChar; } int bytesWritten = rune.EncodeToUtf8(maxUtf8EncodedSpan); Span <byte> encodedBytes = maxUtf8EncodedSpan.Slice(0, bytesWritten); foreach (byte b in encodedBytes) { UriHelper.EscapeAsciiChar(b, ref dest); } } if (surrogatePair) { i++; } } else { // just copy the character dest.Append(pInput[i]); } } return(dest.ToString()); }
/// <summary> /// Replaces all occurrences of the regex in the string with the /// replacement evaluator. /// /// Note that the special case of no matches is handled on its own: /// with no matches, the input string is returned unchanged. /// The right-to-left case is split out because StringBuilder /// doesn't handle right-to-left string building directly very well. /// </summary> private static string Replace(MatchEvaluator evaluator, Regex regex, string input, int count, int startat) { if (evaluator == null) { throw new ArgumentNullException(nameof(evaluator)); } if (count < -1) { throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall); } if (startat < 0 || startat > input.Length) { throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative); } if (count == 0) { return(input); } Match match = regex.Match(input, startat); if (!match.Success) { return(input); } else { Span <char> charInitSpan = stackalloc char[ReplaceBufferSize]; var vsb = new ValueStringBuilder(charInitSpan); if (!regex.RightToLeft) { int prevat = 0; do { if (match.Index != prevat) { vsb.Append(input.AsSpan(prevat, match.Index - prevat)); } prevat = match.Index + match.Length; vsb.Append(evaluator(match) ?? ""); if (--count == 0) { break; } match = match.NextMatch(); } while (match.Success); if (prevat < input.Length) { vsb.Append(input.AsSpan(prevat, input.Length - prevat)); } } else { // In right to left mode append all the inputs in reversed order to avoid an extra dynamic data structure // and to be able to work with Spans. A final reverse of the transformed reversed input string generates // the desired output. Similar to Tower of Hanoi. int prevat = input.Length; do { if (match.Index + match.Length != prevat) { vsb.AppendReversed(input.AsSpan(match.Index + match.Length, prevat - match.Index - match.Length)); } prevat = match.Index; vsb.AppendReversed(evaluator(match)); if (--count == 0) { break; } match = match.NextMatch(); } while (match.Success); if (prevat > 0) { vsb.AppendReversed(input.AsSpan(0, prevat)); } vsb.Reverse(); } return(vsb.ToString()); } }
/// <summary> /// Try to remove relative segments from the given path (without combining with a root). /// </summary> /// <param name="rootLength">The length of the root of the given path</param> internal static string RemoveRelativeSegments(string path, int rootLength) { Debug.Assert(rootLength > 0); bool flippedSeparator = false; int skip = rootLength; // We treat "\.." , "\." and "\\" as a relative segment. We want to collapse the first separator past the root presuming // the root actually ends in a separator. Otherwise the first segment for RemoveRelativeSegments // in cases like "\\?\C:\.\" and "\\?\C:\..\", the first segment after the root will be ".\" and "..\" which is not considered as a relative segment and hence not be removed. if (PathInternal.IsDirectorySeparator(path[skip - 1])) { skip--; } Span <char> initialBuffer = stackalloc char[260 /* PathInternal.MaxShortPath */]; ValueStringBuilder sb = new ValueStringBuilder(initialBuffer); // Remove "//", "/./", and "/../" from the path by copying each character to the output, // except the ones we're removing, such that the builder contains the normalized path // at the end. if (skip > 0) { sb.Append(path.AsSpan(0, skip)); } for (int i = skip; i < path.Length; i++) { char c = path[i]; if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) { // Skip this character if it's a directory separator and if the next character is, too, // e.g. "parent//child" => "parent/child" if (PathInternal.IsDirectorySeparator(path[i + 1])) { continue; } // Skip this character and the next if it's referring to the current directory, // e.g. "parent/./child" => "parent/child" if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && path[i + 1] == '.') { i++; continue; } // Skip this character and the next two if it's referring to the parent directory, // e.g. "parent/child/../grandchild" => "parent/grandchild" if (i + 2 < path.Length && (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && path[i + 1] == '.' && path[i + 2] == '.') { // Unwind back to the last slash (and if there isn't one, clear out everything). int s; for (s = sb.Length - 1; s >= skip; s--) { if (PathInternal.IsDirectorySeparator(sb[s])) { sb.Length = (i + 3 >= path.Length && s == skip) ? s + 1 : s; // to avoid removing the complete "\tmp\" segment in cases like \\?\C:\tmp\..\, C:\tmp\.. break; } } if (s < skip) { sb.Length = skip; } i += 2; continue; } } // Normalize the directory separator if needed if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) { c = PathInternal.DirectorySeparatorChar; flippedSeparator = true; } sb.Append(c); } // If we haven't changed the source path, return the original if (!flippedSeparator && sb.Length == path.Length) { sb.Dispose(); return(path); } return(sb.Length < rootLength?path.Substring(0, rootLength) : sb.ToString()); }
private string GetFieldsDirective() { // 152 is the length of the default fields directive var sb = new ValueStringBuilder(152); sb.Append("#Fields:"); if (_loggingFields.HasFlag(W3CLoggingFields.Date)) { sb.Append(" date"); } if (_loggingFields.HasFlag(W3CLoggingFields.Time)) { sb.Append(" time"); } if (_loggingFields.HasFlag(W3CLoggingFields.ClientIpAddress)) { sb.Append(" c-ip"); } if (_loggingFields.HasFlag(W3CLoggingFields.UserName)) { sb.Append(" cs-username"); } if (_loggingFields.HasFlag(W3CLoggingFields.ServerName)) { sb.Append(" s-computername"); } if (_loggingFields.HasFlag(W3CLoggingFields.ServerIpAddress)) { sb.Append(" s-ip"); } if (_loggingFields.HasFlag(W3CLoggingFields.ServerPort)) { sb.Append(" s-port"); } if (_loggingFields.HasFlag(W3CLoggingFields.Method)) { sb.Append(" cs-method"); } if (_loggingFields.HasFlag(W3CLoggingFields.UriStem)) { sb.Append(" cs-uri-stem"); } if (_loggingFields.HasFlag(W3CLoggingFields.UriQuery)) { sb.Append(" cs-uri-query"); } if (_loggingFields.HasFlag(W3CLoggingFields.ProtocolStatus)) { sb.Append(" sc-status"); } if (_loggingFields.HasFlag(W3CLoggingFields.TimeTaken)) { sb.Append(" time-taken"); } if (_loggingFields.HasFlag(W3CLoggingFields.ProtocolVersion)) { sb.Append(" cs-version"); } if (_loggingFields.HasFlag(W3CLoggingFields.Host)) { sb.Append(" cs-host"); } if (_loggingFields.HasFlag(W3CLoggingFields.UserAgent)) { sb.Append(" cs(User-Agent)"); } if (_loggingFields.HasFlag(W3CLoggingFields.Cookie)) { sb.Append(" cs(Cookie)"); } if (_loggingFields.HasFlag(W3CLoggingFields.Referer)) { sb.Append(" cs(Referer)"); } if (_additionalRequestHeaders != null) { foreach (var header in _additionalRequestHeaders) { sb.Append($" cs({header})"); } } return(sb.ToString()); }
public static string Combine(params string[] paths) { if (paths == null) { throw new ArgumentNullException(nameof(paths)); } int maxSize = 0; int firstComponent = 0; // We have two passes, the first calculates how large a buffer to allocate and does some precondition // checks on the paths passed in. The second actually does the combination. for (int i = 0; i < paths.Length; i++) { if (paths[i] == null) { throw new ArgumentNullException(nameof(paths)); } if (paths[i].Length == 0) { continue; } if (IsPathRooted(paths[i])) { firstComponent = i; maxSize = paths[i].Length; } else { maxSize += paths[i].Length; } char ch = paths[i][paths[i].Length - 1]; if (!PathInternal.IsDirectorySeparator(ch)) { maxSize++; } } Span <char> initialBuffer = stackalloc char[260]; // MaxShortPath on Windows var builder = new ValueStringBuilder(initialBuffer); builder.EnsureCapacity(maxSize); for (int i = firstComponent; i < paths.Length; i++) { if (paths[i].Length == 0) { continue; } if (builder.Length == 0) { builder.Append(paths[i]); } else { char ch = builder[builder.Length - 1]; if (!PathInternal.IsDirectorySeparator(ch)) { builder.Append(PathInternal.DirectorySeparatorChar); } builder.Append(paths[i]); } } return(builder.ToString()); }
// // IRI normalization for strings containing characters that are not allowed or // escaped characters that should be unescaped in the context of the specified Uri component. // internal static unsafe string EscapeUnescapeIri(char *pInput, int start, int end, UriComponents component) { int size = end - start; ValueStringBuilder dest = new ValueStringBuilder(size); byte[]? bytes = null; const int percentEncodingLen = 3; // Escaped UTF-8 will take 3 chars: %AB. int bufferRemaining = 0; int next = start; char ch; bool escape = false; bool surrogatePair = false; for (; next < end; ++next) { escape = false; surrogatePair = false; if ((ch = pInput[next]) == '%') { if (next + 2 < end) { ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]); // Do not unescape a reserved char if (ch == Uri.c_DummyChar || ch == '%' || CheckIsReserved(ch, component) || UriHelper.IsNotSafeForUnescape(ch)) { // keep as is dest.Append(pInput[next++]); dest.Append(pInput[next++]); dest.Append(pInput[next]); continue; } else if (ch <= '\x7F') { Debug.Assert(ch < 0xFF, "Expecting ASCII character."); //ASCII dest.Append(ch); next += 2; continue; } else { // possibly utf8 encoded sequence of unicode // check if safe to unescape according to Iri rules Debug.Assert(ch < 0xFF, "Expecting ASCII character."); int startSeq = next; int byteCount = 1; // lazy initialization of max size, will reuse the array for next sequences if ((object?)bytes == null) { bytes = new byte[end - next]; } bytes[0] = (byte)ch; next += 3; while (next < end) { // Check on exit criterion if ((ch = pInput[next]) != '%' || next + 2 >= end) { break; } // already made sure we have 3 characters in str ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]); //invalid hex sequence ? if (ch == Uri.c_DummyChar) { break; } // character is not part of a UTF-8 sequence ? else if (ch < '\x80') { break; } else { //a UTF-8 sequence bytes[byteCount++] = (byte)ch; next += 3; } Debug.Assert(ch < 0xFF, "Expecting ASCII character."); } next--; // for loop will increment // Using encoder with no replacement fall-back will skip all invalid UTF-8 sequences. Encoding noFallbackCharUTF8 = Encoding.GetEncoding( Encoding.UTF8.CodePage, new EncoderReplacementFallback(""), new DecoderReplacementFallback("")); char[] unescapedChars = new char[bytes.Length]; int charCount = noFallbackCharUTF8.GetChars(bytes, 0, byteCount, unescapedChars, 0); if (charCount != 0) { // If invalid sequences were present in the original escaped string, we need to // copy the escaped versions of those sequences. // Decoded Unicode values will be kept only when they are allowed by the URI/IRI RFC // rules. UriHelper.MatchUTF8Sequence(ref dest, unescapedChars, charCount, bytes, byteCount, component == UriComponents.Query, true); } else { // copy escaped sequence as is for (int i = startSeq; i <= next; ++i) { dest.Append(pInput[i]); } } } } else { dest.Append(pInput[next]); } } else if (ch > '\x7f') { // unicode char ch2; if ((char.IsHighSurrogate(ch)) && (next + 1 < end)) { ch2 = pInput[next + 1]; escape = !CheckIriUnicodeRange(ch, ch2, ref surrogatePair, component == UriComponents.Query); if (!escape) { // copy the two chars dest.Append(pInput[next++]); dest.Append(pInput[next]); } } else { if (CheckIriUnicodeRange(ch, component == UriComponents.Query)) { // copy it dest.Append(pInput[next]); } else { // escape it escape = true; } } } else { // just copy the character dest.Append(pInput[next]); } if (escape) { const int MaxNumberOfBytesEncoded = 4; byte[] encodedBytes = new byte[MaxNumberOfBytesEncoded]; fixed(byte *pEncodedBytes = &encodedBytes[0]) { int encodedBytesCount = Encoding.UTF8.GetBytes(pInput + next, surrogatePair ? 2 : 1, pEncodedBytes, MaxNumberOfBytesEncoded); Debug.Assert(encodedBytesCount <= MaxNumberOfBytesEncoded, "UTF8 encoder should not exceed specified byteCount"); bufferRemaining -= encodedBytesCount * percentEncodingLen; for (int count = 0; count < encodedBytesCount; ++count) { UriHelper.EscapeAsciiChar((char)encodedBytes[count], ref dest); } } } } string result = dest.ToString(); return(result); }
static string GetJoinedStringValueFromArray(string[] values) { // Calculate final length int length = 0; for (int i = 0; i < values.Length; i++) { string value = values[i]; // Skip null and empty values if (value != null && value.Length > 0) { if (length > 0) { // Add seperator length++; } length += value.Length; } } #if NETCOREAPP // Create the new string return(string.Create(length, values, (span, strings) => { int offset = 0; // Skip null and empty values for (int i = 0; i < strings.Length; i++) { string value = strings[i]; if (value != null && value.Length > 0) { if (offset > 0) { // Add seperator span[offset] = ','; offset++; } value.AsSpan().CopyTo(span.Slice(offset)); offset += value.Length; } } })); #else var sb = new ValueStringBuilder(length); bool hasAdded = false; // Skip null and empty values for (int i = 0; i < values.Length; i++) { string value = values[i]; if (value != null && value.Length > 0) { if (hasAdded) { // Add seperator sb.Append(','); } sb.Append(value); hasAdded = true; } } return(sb.ToString()); #endif }
private static string FormatBigIntegerToHex(BigInteger value, char format, int digits, NumberFormatInfo info) { Debug.Assert(format == 'x' || format == 'X'); // Get the bytes that make up the BigInteger. Span <byte> bits = stackalloc byte[64]; // arbitrary limit to switch from stack to heap bits = value.TryWriteBytes(bits, out int bytesWritten) ? bits.Slice(0, bytesWritten) : value.ToByteArray(); Span <char> stackSpace = stackalloc char[128]; // each byte is typically two chars var sb = new ValueStringBuilder(stackSpace); int cur = bits.Length - 1; if (cur > -1) { // [FF..F8] drop the high F as the two's complement negative number remains clear // [F7..08] retain the high bits as the two's complement number is wrong without it // [07..00] drop the high 0 as the two's complement positive number remains clear bool clearHighF = false; byte head = bits[cur]; if (head > 0xF7) { head -= 0xF0; clearHighF = true; } if (head < 0x08 || clearHighF) { // {0xF8-0xFF} print as {8-F} // {0x00-0x07} print as {0-7} sb.Append(head < 10 ? (char)(head + '0') : format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a')); cur--; } } if (cur > -1) { Span <char> chars = sb.AppendSpan((cur + 1) * 2); int charsPos = 0; string hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; while (cur > -1) { byte b = bits[cur--]; chars[charsPos++] = hexValues[b >> 4]; chars[charsPos++] = hexValues[b & 0xF]; } } if (digits > sb.Length) { // Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD" sb.Insert( 0, value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F', digits - sb.Length); } return(sb.ToString()); }
internal static string Normalize(string path) { Span <char> initialBuffer = stackalloc char[PathInternal.MaxShortPath]; var builder = new ValueStringBuilder(initialBuffer); // Get the full path GetFullPathName(path.AsSpan(), ref builder); // If we have the exact same string we were passed in, don't allocate another string. // TryExpandShortName does this input identity check. string result = builder.AsSpan().IndexOf('~') >= 0 ? TryExpandShortFileName(ref builder, originalPath: path) : builder.AsSpan().Equals(path.AsSpan(), StringComparison.Ordinal) ? path : builder.ToString(); // Clear the buffer builder.Dispose(); return(result); }
internal static string NormalizeDirectorySeparators(string path) { if (string.IsNullOrEmpty(path)) { return(path); } char current; // Make a pass to see if we need to normalize so we can potentially skip allocating bool normalized = true; for (int i = 0; i < path.Length; i++) { current = path[i]; if (IsDirectorySeparator(current) && (current != DirectorySeparatorChar // Check for sequential separators past the first position (we need to keep initial two for UNC/extended) || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))) { normalized = false; break; } } if (normalized) { return(path); } Span <char> initialBuffer = stackalloc char[MaxShortPath]; ValueStringBuilder builder = new ValueStringBuilder(initialBuffer); int start = 0; if (IsDirectorySeparator(path[start])) { start++; builder.Append(DirectorySeparatorChar); } for (int i = start; i < path.Length; i++) { current = path[i]; // If we have a separator if (IsDirectorySeparator(current)) { // If the next is a separator, skip adding this if (i + 1 < path.Length && IsDirectorySeparator(path[i + 1])) { continue; } // Ensure it is the primary separator current = DirectorySeparatorChar; } builder.Append(current); } return(builder.ToString()); }
// // IRI normalization for strings containing characters that are not allowed or // escaped characters that should be unescaped in the context of the specified Uri component. // internal static unsafe string EscapeUnescapeIri(char *pInput, int start, int end, UriComponents component) { int size = end - start; ValueStringBuilder dest = new ValueStringBuilder(size); byte[]? bytes = null; int next = start; char ch; for (; next < end; ++next) { if ((ch = pInput[next]) == '%') { if (next + 2 < end) { ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]); // Do not unescape a reserved char if (ch == Uri.c_DummyChar || ch == '%' || CheckIsReserved(ch, component) || UriHelper.IsNotSafeForUnescape(ch)) { // keep as is dest.Append(pInput[next++]); dest.Append(pInput[next++]); dest.Append(pInput[next]); continue; } else if (ch <= '\x7F') { Debug.Assert(ch < 0xFF, "Expecting ASCII character."); //ASCII dest.Append(ch); next += 2; continue; } else { // possibly utf8 encoded sequence of unicode // check if safe to unescape according to Iri rules Debug.Assert(ch < 0xFF, "Expecting ASCII character."); int startSeq = next; int byteCount = 1; // lazy initialization of max size, will reuse the array for next sequences if ((object?)bytes == null) { bytes = new byte[end - next]; } bytes[0] = (byte)ch; next += 3; while (next < end) { // Check on exit criterion if ((ch = pInput[next]) != '%' || next + 2 >= end) { break; } // already made sure we have 3 characters in str ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]); //invalid hex sequence ? if (ch == Uri.c_DummyChar) { break; } // character is not part of a UTF-8 sequence ? else if (ch < '\x80') { break; } else { //a UTF-8 sequence bytes[byteCount++] = (byte)ch; next += 3; } Debug.Assert(ch < 0xFF, "Expecting ASCII character."); } next--; // for loop will increment // Using encoder with no replacement fall-back will skip all invalid UTF-8 sequences. Encoding noFallbackCharUTF8 = Encoding.GetEncoding( Encoding.UTF8.CodePage, new EncoderReplacementFallback(""), new DecoderReplacementFallback("")); char[] unescapedChars = new char[bytes.Length]; int charCount = noFallbackCharUTF8.GetChars(bytes, 0, byteCount, unescapedChars, 0); if (charCount != 0) { // If invalid sequences were present in the original escaped string, we need to // copy the escaped versions of those sequences. // Decoded Unicode values will be kept only when they are allowed by the URI/IRI RFC // rules. UriHelper.MatchUTF8Sequence(ref dest, unescapedChars, charCount, bytes, byteCount, component == UriComponents.Query, true); } else { // copy escaped sequence as is for (int i = startSeq; i <= next; ++i) { dest.Append(pInput[i]); } } } } else { dest.Append(pInput[next]); } } else if (ch > '\x7f') { // unicode bool escape; bool surrogatePair = false; char ch2 = '\0'; if ((char.IsHighSurrogate(ch)) && (next + 1 < end)) { ch2 = pInput[next + 1]; escape = !CheckIriUnicodeRange(ch, ch2, ref surrogatePair, component == UriComponents.Query); } else { escape = !CheckIriUnicodeRange(ch, component == UriComponents.Query); } if (escape) { Span <byte> encodedBytes = stackalloc byte[4]; Rune rune; if (surrogatePair) { rune = new Rune(ch, ch2); } else if (!Rune.TryCreate(ch, out rune)) { rune = Rune.ReplacementChar; } int bytesWritten = rune.EncodeToUtf8(encodedBytes); encodedBytes = encodedBytes.Slice(0, bytesWritten); foreach (byte b in encodedBytes) { UriHelper.EscapeAsciiChar(b, ref dest); } } else { dest.Append(ch); if (surrogatePair) { dest.Append(ch2); } } if (surrogatePair) { next++; } } else { // just copy the character dest.Append(pInput[next]); } } string result = dest.ToString(); return(result); }
private static string?FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span <char> destination, out int charsWritten, out bool spanSuccess) { Debug.Assert(format == 'x' || format == 'X'); // Get the bytes that make up the BigInteger. byte[]? arrayToReturnToPool = null; Span <byte> bits = stackalloc byte[64]; // arbitrary threshold if (!value.TryWriteOrCountBytes(bits, out int bytesWrittenOrNeeded)) { bits = arrayToReturnToPool = ArrayPool <byte> .Shared.Rent(bytesWrittenOrNeeded); bool success = value.TryWriteBytes(bits, out bytesWrittenOrNeeded); Debug.Assert(success); } bits = bits.Slice(0, bytesWrittenOrNeeded); Span <char> stackSpace = stackalloc char[128]; // each byte is typically two chars var sb = new ValueStringBuilder(stackSpace); int cur = bits.Length - 1; if (cur > -1) { // [FF..F8] drop the high F as the two's complement negative number remains clear // [F7..08] retain the high bits as the two's complement number is wrong without it // [07..00] drop the high 0 as the two's complement positive number remains clear bool clearHighF = false; byte head = bits[cur]; if (head > 0xF7) { head -= 0xF0; clearHighF = true; } if (head < 0x08 || clearHighF) { // {0xF8-0xFF} print as {8-F} // {0x00-0x07} print as {0-7} sb.Append(head < 10 ? (char)(head + '0') : format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a')); cur--; } } if (cur > -1) { Span <char> chars = sb.AppendSpan((cur + 1) * 2); int charsPos = 0; string hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; while (cur > -1) { byte b = bits[cur--]; chars[charsPos++] = hexValues[b >> 4]; chars[charsPos++] = hexValues[b & 0xF]; } } if (digits > sb.Length) { // Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD" sb.Insert( 0, value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F', digits - sb.Length); } if (arrayToReturnToPool != null) { ArrayPool <byte> .Shared.Return(arrayToReturnToPool); } if (targetSpan) { spanSuccess = sb.TryCopyTo(destination, out charsWritten); return(null); } else { charsWritten = 0; spanSuccess = false; return(sb.ToString()); } }
public string CreateReagentListString(string separator) { ValueStringBuilder sb = new ValueStringBuilder(); { for (int i = 0; i < Regs.Length; i++) { switch (Regs[i]) { // britanian reagents case Reagents.BlackPearl: sb.Append(ResGeneral.BlackPearl); break; case Reagents.Bloodmoss: sb.Append(ResGeneral.Bloodmoss); break; case Reagents.Garlic: sb.Append(ResGeneral.Garlic); break; case Reagents.Ginseng: sb.Append(ResGeneral.Ginseng); break; case Reagents.MandrakeRoot: sb.Append(ResGeneral.MandrakeRoot); break; case Reagents.Nightshade: sb.Append(ResGeneral.Nightshade); break; case Reagents.SulfurousAsh: sb.Append(ResGeneral.SulfurousAsh); break; case Reagents.SpidersSilk: sb.Append(ResGeneral.SpidersSilk); break; // pagan reagents case Reagents.BatWing: sb.Append(ResGeneral.BatWing); break; case Reagents.GraveDust: sb.Append(ResGeneral.GraveDust); break; case Reagents.DaemonBlood: sb.Append(ResGeneral.DaemonBlood); break; case Reagents.NoxCrystal: sb.Append(ResGeneral.NoxCrystal); break; case Reagents.PigIron: sb.Append(ResGeneral.PigIron); break; default: if (Regs[i] < Reagents.None) { sb.Append(StringHelper.AddSpaceBeforeCapital(Regs[i].ToString())); } break; } if (i < Regs.Length - 1) { sb.Append(separator); } } string ss = sb.ToString(); sb.Dispose(); return(ss); } }
private static void LogPacket(byte[] buffer, int length, bool toServer) { if (_logFile == null) { _logFile = new LogFile(FileSystemHelper.CreateFolderIfNotExists(CUOEnviroment.ExecutablePath, "Logs", "Network"), "packets.log"); } Span <char> span = stackalloc char[256]; ValueStringBuilder output = new ValueStringBuilder(span); { int off = sizeof(ulong) + 2; output.Append(' ', off); output.Append(string.Format("Ticks: {0} | {1} | ID: {2:X2} Length: {3}\n", Time.Ticks, (toServer ? "Client -> Server" : "Server -> Client"), buffer[0], length)); if (buffer[0] == 0x80 || buffer[0] == 0x91) { output.Append(' ', off); output.Append("[ACCOUNT CREDENTIALS HIDDEN]\n"); } else { output.Append(' ', off); output.Append("0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); output.Append(' ', off); output.Append("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n"); ulong address = 0; for (int i = 0; i < length; i += 16, address += 16) { output.Append($"{address:X8}"); for (int j = 0; j < 16; ++j) { if ((j % 8) == 0) { output.Append(" "); } if (i + j < length) { output.Append($" {buffer[i + j]:X2}"); } else { output.Append(" "); } } output.Append(" "); for (int j = 0; j < 16 && i + j < length; ++j) { byte c = buffer[i + j]; if (c >= 0x20 && c < 0x80) { output.Append((char)c); } else { output.Append('.'); } } output.Append('\n'); } } output.Append('\n'); output.Append('\n'); _logFile.Write(output.ToString()); output.Dispose(); } }
public override object?ConvertTo(ITypeDescriptorContext?context, CultureInfo?culture, object?value, Type destinationType) { if (value is Font font) { if (destinationType == typeof(string)) { if (culture == null) { culture = CultureInfo.CurrentCulture; } ValueStringBuilder sb = default; sb.Append(font.Name); sb.Append(culture.TextInfo.ListSeparator[0]); sb.Append(" "); sb.Append(font.Size.ToString(culture.NumberFormat)); switch (font.Unit) { // MS throws ArgumentException, if unit is set // to GraphicsUnit.Display // Don't know what to append for GraphicsUnit.Display case GraphicsUnit.Display: sb.Append("display"); break; case GraphicsUnit.Document: sb.Append("doc"); break; case GraphicsUnit.Point: sb.Append("pt"); break; case GraphicsUnit.Inch: sb.Append("in"); break; case GraphicsUnit.Millimeter: sb.Append("mm"); break; case GraphicsUnit.Pixel: sb.Append("px"); break; case GraphicsUnit.World: sb.Append("world"); break; } if (font.Style != FontStyle.Regular) { sb.Append(culture.TextInfo.ListSeparator[0]); sb.Append(" style="); sb.Append(font.Style.ToString()); } return(sb.ToString()); } if (destinationType == typeof(InstanceDescriptor)) { ConstructorInfo?met = typeof(Font).GetConstructor(new Type[] { typeof(string), typeof(float), typeof(FontStyle), typeof(GraphicsUnit) }); object[] args = new object[4]; args[0] = font.Name; args[1] = font.Size; args[2] = font.Style; args[3] = font.Unit; return(new InstanceDescriptor(met, args)); } } return(base.ConvertTo(context, culture, value, destinationType)); }
public void TestStringBuilders() { { Span <char> buf = stackalloc char[128]; var bdr = new FixedStringBuilder(buf); bdr.AppendLine("Hello World"); bdr.Append("Hello"); bdr.Append(' '); bdr.Append(12); bdr.Append(' '); bdr.AppendLine("Worlds"); int numReplaced = bdr.Replace('e', 'u'); Assert.AreEqual(2, numReplaced); var expected = "Hullo World" + Environment.NewLine + "Hullo 12 Worlds" + Environment.NewLine; Assert.AreEqual(expected.Length, bdr.Length); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); numReplaced = bdr.Replace("Hullo", "Hi"); Assert.AreEqual(2, numReplaced); expected = expected.Replace("Hullo", "Hi"); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); numReplaced = bdr.Replace("Hi", ""); Assert.AreEqual(2, numReplaced); expected = expected.Replace("Hi", ""); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); bdr.Replace("World", "World"); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); bdr.Replace("Florka", "--"); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); bdr.Replace("Florka", "Florka"); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual(expected)); bdr.Clear(); Assert.AreEqual(0, bdr.Length); Assert.AreEqual("", bdr.ToString()); bdr.Append("Koko"); bdr.Append('s'); Assert.AreEqual("Kokos".Length, bdr.Length); Assert.IsTrue(bdr.ReadOnlySpan.SequenceEqual("Kokos")); } { var sbdr = new ValueStringBuilder(8); sbdr.AppendLine("Hello World"); sbdr.Append("Hello"); sbdr.Append(' '); sbdr.Append(12u); sbdr.Append(' '); sbdr.AppendLine("Worlds"); var numReplaced = sbdr.Replace('e', 'u'); Assert.AreEqual(2, numReplaced); var expected = "Hullo World" + Environment.NewLine + "Hullo 12 Worlds" + Environment.NewLine; Assert.AreEqual(expected.Length, sbdr.Length); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); numReplaced = sbdr.Replace("Hullo", "Hi"); Assert.AreEqual(2, numReplaced); expected = expected.Replace("Hullo", "Hi"); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); numReplaced = sbdr.Replace("Hi", ""); Assert.AreEqual(2, numReplaced); expected = expected.Replace("Hi", ""); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); sbdr.Replace("World", "World"); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); sbdr.Replace("Florka", "--"); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); sbdr.Replace("Florka", "Florka"); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual(expected)); sbdr.Clear(); Assert.AreEqual(0, sbdr.Length); Assert.AreEqual("", sbdr.ToString()); sbdr.Append("Koko"); sbdr.Append('s'); Assert.AreEqual("Kokos".Length, sbdr.Length); Assert.IsTrue(sbdr.ReadOnlySpan.SequenceEqual("Kokos")); } }
private readonly int[] _rules; // negative -> group #, positive -> string # /// <summary> /// Since RegexReplacement shares the same parser as Regex, /// the constructor takes a RegexNode which is a concatenation /// of constant strings and backreferences. /// </summary> public RegexReplacement(string rep, RegexNode concat, Hashtable _caps) { if (concat.Type != RegexNode.Concatenate) { throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } Span <char> vsbStack = stackalloc char[256]; var vsb = new ValueStringBuilder(vsbStack); FourStackStrings stackStrings = default; var strings = new ValueListBuilder <string>(MemoryMarshal.CreateSpan(ref stackStrings.Item1 !, 4)); var rules = new ValueListBuilder <int>(stackalloc int[64]); int childCount = concat.ChildCount(); for (int i = 0; i < childCount; i++) { RegexNode child = concat.Child(i); switch (child.Type) { case RegexNode.Multi: vsb.Append(child.Str !); break; case RegexNode.One: vsb.Append(child.Ch); break; case RegexNode.Ref: if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); vsb = new ValueStringBuilder(vsbStack); } int slot = child.M; if (_caps != null && slot >= 0) { slot = (int)_caps[slot] !; } rules.Append(-Specials - 1 - slot); break; default: throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } } if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); } Pattern = rep; _strings = strings.AsSpan().ToArray(); _rules = rules.AsSpan().ToArray(); rules.Dispose(); }
public static void HandleMessage ( Entity parent, string text, string name, ushort hue, MessageType type, byte font, TextType textType, bool unicode = false, string lang = null ) { if (string.IsNullOrEmpty(text)) { return; } Profile currentProfile = ProfileManager.CurrentProfile; if (currentProfile != null && currentProfile.OverrideAllFonts) { font = currentProfile.ChatFont; unicode = currentProfile.OverrideAllFontsIsUnicode; } switch (type) { case MessageType.Command: case MessageType.Encoded: case MessageType.System: case MessageType.Party: break; case MessageType.Guild: if (currentProfile.IgnoreGuildMessages) { return; } break; case MessageType.Alliance: if (currentProfile.IgnoreAllianceMessages) { return; } break; case MessageType.Spell: { //server hue color per default if (!string.IsNullOrEmpty(text) && SpellDefinition.WordToTargettype.TryGetValue(text, out SpellDefinition spell)) { if (currentProfile != null && currentProfile.EnabledSpellFormat && !string.IsNullOrWhiteSpace(currentProfile.SpellDisplayFormat)) { ValueStringBuilder sb = new ValueStringBuilder(currentProfile.SpellDisplayFormat.AsSpan()); { sb.Replace("{power}".AsSpan(), spell.PowerWords.AsSpan()); sb.Replace("{spell}".AsSpan(), spell.Name.AsSpan()); text = sb.ToString().Trim(); } sb.Dispose(); } //server hue color per default if not enabled if (currentProfile != null && currentProfile.EnabledSpellHue) { if (spell.TargetType == TargetType.Beneficial) { hue = currentProfile.BeneficHue; } else if (spell.TargetType == TargetType.Harmful) { hue = currentProfile.HarmfulHue; } else { hue = currentProfile.NeutralHue; } } } goto case MessageType.Label; } default: case MessageType.Focus: case MessageType.Whisper: case MessageType.Yell: case MessageType.Regular: case MessageType.Label: case MessageType.Limit3Spell: if (parent == null) { break; } TextObject msg = CreateMessage ( text, hue, font, unicode, type, textType ); msg.Owner = parent; if (parent is Item it && !it.OnGround) { msg.X = DelayedObjectClickManager.X; msg.Y = DelayedObjectClickManager.Y; msg.IsTextGump = true; bool found = false; for (LinkedListNode <Gump> gump = UIManager.Gumps.Last; gump != null; gump = gump.Previous) { Control g = gump.Value; if (!g.IsDisposed) { switch (g) { case PaperDollGump paperDoll when g.LocalSerial == it.Container: paperDoll.AddText(msg); found = true; break; case ContainerGump container when g.LocalSerial == it.Container: container.AddText(msg); found = true; break; case TradingGump trade when trade.ID1 == it.Container || trade.ID2 == it.Container: trade.AddText(msg); found = true; break; } } if (found) { break; } } } parent.AddMessage(msg); break; } MessageReceived.Raise ( new MessageEventArgs ( parent, text, name, hue, type, font, textType, unicode, lang ), parent ); }