/// <summary> /// Returns a C# string literal with the given value. /// </summary> /// <param name="value">The value that the resulting string literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A string literal with the given value.</returns> /// <remarks> /// Escapes non-printable characters. /// </remarks> public static string FormatLiteral(string value, ObjectDisplayOptions options) { ValidateOptions(options); if (value == null) { throw new ArgumentNullException(nameof(value)); } var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); var quote = useQuotes ? '"' : '\0'; if (!useQuotes && !ReplaceAny(value, quote)) { return(value); } var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; if (useQuotes) { builder.Append(quote); } foreach (var c in value) { FormatStringChar(builder, c, quote); } if (useQuotes) { builder.Append(quote); } return(pooledBuilder.ToStringAndFree()); }
/// <summary> /// Contains a list of buckets, each of which contains a number of flags, a slot ID, and a name. /// TODO: comment when the structure is understood. /// </summary> /// <remarks> /// Appears when there are dynamic locals. /// </remarks> private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.DynamicLocals); writer.WriteStartElement("dynamicLocals"); var buckets = CDI.DecodeDynamicLocalsRecord(record.Data); foreach (DynamicLocalBucket bucket in buckets) { ulong flags = bucket.Flags; int flagCount = bucket.FlagCount; PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); StringBuilder flagsBuilder = pooled.Builder; for (int f = 0; f < flagCount; f++) { flagsBuilder.Append((flags >> f) & 1UL); } writer.WriteStartElement("bucket"); writer.WriteAttributeString("flagCount", flagCount.ToString()); writer.WriteAttributeString("flags", pooled.ToStringAndFree()); writer.WriteAttributeString("slotId", bucket.SlotId.ToString()); writer.WriteAttributeString("localName", bucket.Name); writer.WriteEndElement(); //bucket } writer.WriteEndElement(); //dynamicLocals }
/// <summary> /// Returns a C# string literal with the given value. /// </summary> /// <param name="value">The value that the resulting string literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A string literal with the given value.</returns> /// <remarks> /// Escapes non-printable characters. /// </remarks> public static string FormatLiteral(string value, ObjectDisplayOptions options) { ValidateOptions(options); if (value == null) { throw new ArgumentNullException("value"); } var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); var quote = useQuotes ? '"' : '\0'; PooledStringBuilder pooledBuilder = null; StringBuilder builder = null; if (useQuotes) { pooledBuilder = PooledStringBuilder.GetInstance(); builder = pooledBuilder.Builder; builder.Append(quote); } for (int i = 0; i < value.Length; i++) { FormatStringChar(ref pooledBuilder, value, i, value[i], quote, useLanguageSpecificEscapes: true, useUnicodeEscapes: true); } if (useQuotes) { builder.Append(quote); } return((pooledBuilder == null) ? value : pooledBuilder.ToStringAndFree()); }
/// <summary> /// Returns a C# string literal with the given value. /// </summary> /// <param name="value">The value that the resulting string literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A string literal with the given value.</returns> /// <remarks> /// Optionally escapes non-printable characters. /// </remarks> public static string FormatLiteral(string value, ObjectDisplayOptions options) { if (value == null) { throw new ArgumentNullException(nameof(value)); } const char quote = '"'; var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); var escapeNonPrintable = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableCharacters); var isVerbatim = useQuotes && !escapeNonPrintable && ContainsNewLine(value); if (useQuotes) { if (isVerbatim) { builder.Append('@'); } builder.Append(quote); } foreach (var c in value) { string replaceWith; if (escapeNonPrintable && TryReplaceChar(c, out replaceWith)) { builder.Append(replaceWith); } else if (useQuotes && c == quote) { if (isVerbatim) { builder.Append(quote); builder.Append(quote); } else { builder.Append('\\'); builder.Append(quote); } } else { builder.Append(c); } } if (useQuotes) { builder.Append(quote); } return(pooledBuilder.ToStringAndFree()); }
internal static string ToHexString(byte[] input) { PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); StringBuilder sb = pooled.Builder; foreach (byte b in input) { sb.AppendFormat("{0:X2}", b); } return(pooled.ToStringAndFree()); }
/// <summary> /// If the custom debug info is in a format that we don't understand, then we will /// just print a standard record header followed by the rest of the record as a /// single hex string. /// </summary> private void WriteUnknownCustomDebugInfo(CustomDebugInfoRecord record) { writer.WriteStartElement("unknown"); writer.WriteAttributeString("kind", record.Kind.ToString()); writer.WriteAttributeString("version", record.Version.ToString()); PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); StringBuilder builder = pooled.Builder; foreach (byte b in record.Data) { builder.AppendFormat("{0:X2}", b); } writer.WriteAttributeString("payload", pooled.ToStringAndFree()); writer.WriteEndElement(); //unknown }
/// <summary> /// Returns a C# character literal with the given value. /// </summary> /// <param name="c">The value that the resulting character literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A character literal with the given value.</returns> internal static string FormatLiteral(char c, ObjectDisplayOptions options) { const char quote = '\''; var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; if (options.IncludesOption(ObjectDisplayOptions.IncludeCodePoints)) { builder.Append(options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) ? "0x" + ((int)c).ToString("x4") : ((int)c).ToString()); builder.Append(" "); } var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); var escapeNonPrintable = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableCharacters); if (useQuotes) { builder.Append(quote); } string replaceWith; if (escapeNonPrintable && TryReplaceChar(c, out replaceWith)) { builder.Append(replaceWith); } else if (useQuotes && c == quote) { builder.Append('\\'); builder.Append(quote); } else { builder.Append(c); } if (useQuotes) { builder.Append(quote); } return(pooledBuilder.ToStringAndFree()); }
internal static string FormatString(string str, bool useQuotes) { if (!useQuotes) { return(str); } var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; const char quote = '"'; builder.Append(quote); foreach (var c in str) { FormatStringChar(builder, c, quote); } builder.Append(quote); return(pooledBuilder.ToStringAndFree()); }
internal static string FormatString(string str, bool useQuotes) { if (!useQuotes) { return(str); } var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; const char quote = '"'; builder.Append(quote); for (int i = 0; i < str.Length; i++) { FormatStringChar(ref pooledBuilder, str, i, str[i], quote, useLanguageSpecificEscapes: useQuotes, useUnicodeEscapes: false); } builder.Append(quote); return(pooledBuilder.ToStringAndFree()); }
internal static string FormatLiteral(ulong value, ObjectDisplayOptions options, CultureInfo cultureInfo = null) { var pooledBuilder = PooledStringBuilder.GetInstance(); var sb = pooledBuilder.Builder; if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) { sb.Append("0x"); sb.Append(value.ToString("x16")); } else { sb.Append(value.ToString(GetFormatCulture(cultureInfo))); } if (options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) { sb.Append("UL"); } return(pooledBuilder.ToStringAndFree()); }
internal static string FormatLiteral(uint value, ObjectDisplayOptions options) { var pooledBuilder = PooledStringBuilder.GetInstance(); var sb = pooledBuilder.Builder; if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) { sb.Append("0x"); sb.Append(value.ToString("x8")); } else { sb.Append(value.ToString(CultureInfo.InvariantCulture)); } if (options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) { sb.Append('U'); } return(pooledBuilder.ToStringAndFree()); }
/// <summary> /// Returns a C# character literal with the given value. /// </summary> /// <param name="c">The value that the resulting character literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A character literal with the given value.</returns> internal static string FormatLiteral(char c, ObjectDisplayOptions options) { var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; if (options.IncludesOption(ObjectDisplayOptions.IncludeCodePoints)) { builder.Append(options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) ? "0x" + ((int)c).ToString("x4") : ((int)c).ToString()); builder.Append(" "); } if (options.IncludesOption(ObjectDisplayOptions.UseQuotes)) { const char quote = '\''; builder.Append(quote); FormatStringChar(builder, c, quote); builder.Append(quote); } else { builder.Append(c); } return(pooledBuilder.ToStringAndFree()); }
/// <summary> /// Returns a C# character literal with the given value. /// </summary> /// <param name="c">The value that the resulting character literal should have.</param> /// <param name="options">Options used to customize formatting of an object value.</param> /// <returns>A character literal with the given value.</returns> internal static string FormatLiteral(char c, ObjectDisplayOptions options) { var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); var quote = useQuotes ? '\'' : '\0'; var includeCodePoints = options.IncludesOption(ObjectDisplayOptions.IncludeCodePoints); var pooledBuilder = PooledStringBuilder.GetInstance(); var builder = pooledBuilder.Builder; if (includeCodePoints) { builder.Append(options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) ? "0x" + ((int)c).ToString("x4") : ((int)c).ToString()); builder.Append(" "); } if (useQuotes) { builder.Append(quote); } FormatStringChar(ref pooledBuilder, str: null, index: 0, c: c, quote: quote, useLanguageSpecificEscapes: useQuotes, useUnicodeEscapes: !includeCodePoints); if (useQuotes) { builder.Append(quote); } return(pooledBuilder.ToStringAndFree()); }
private void WriteLocalsHelper(ISymUnmanagedScope scope, Dictionary <int, ImmutableArray <string> > slotNames, bool includeChildScopes) { foreach (ISymUnmanagedVariable l in scope.GetLocals()) { writer.WriteStartElement("local"); { writer.WriteAttributeString("name", l.GetName()); // Each local maps to a "IL Index" or "slot" number. // The index is not necessarily unique. Several locals may refer to the same slot. // It just means that the same local is known under different names inside the same or different scopes. // This index is what you pass to ICorDebugILFrame::GetLocalVariable() to get // a specific local variable. // NOTE: VB emits "fake" locals for resumable locals which are actually backed by fields. // These locals always map to the slot #0 which is just a valid number that is // not used. Only scoping information is used by EE in this case. int slot = l.GetSlot(); writer.WriteAttributeString("il_index", CultureInvariantToString(slot)); bool reusingSlot = false; // collect slot names so that we can verify ISymUnmanagedReader APIs if (slotNames != null) { ImmutableArray <string> existingNames; if (slotNames.TryGetValue(slot, out existingNames)) { slotNames[slot] = existingNames.Add(l.GetName()); reusingSlot = true; } else { slotNames.Add(slot, ImmutableArray.Create(l.GetName())); } } // Provide scope range writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset())); writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset())); writer.WriteAttributeString("attributes", l.GetAttributes().ToString()); if (reusingSlot) { writer.WriteAttributeString("reusingslot", reusingSlot.ToString(CultureInfo.InvariantCulture)); } } writer.WriteEndElement(); // </local> } foreach (ISymUnmanagedConstant c in scope.GetConstants()) { // Note: We can retrieve constant tokens by saving it into signature blob // in our implementation of IMetadataImport.GetSigFromToken. writer.WriteStartElement("constant"); { writer.WriteAttributeString("name", c.GetName()); object value = c.GetValue(); string typeName = value.GetType().Name; // certain Unicode characters will give Xml writers fits...in order to avoid this, we'll replace // problematic characters/sequences with their hexadecimal equivalents, like U+0000, etc... var chars = value as string; if (chars != null) { PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); var valueWithPlaceholders = pooled.Builder; foreach (var ch in chars) { // if we end up with more, we can add them here if (0 == (int)ch) { valueWithPlaceholders.AppendFormat("U+{0:X4}", (int)ch); } else { valueWithPlaceholders.Append(ch); } } if (valueWithPlaceholders.Length > chars.Length) { value = valueWithPlaceholders.ToString(); } pooled.Free(); } writer.WriteAttributeString("value", value.ToString()); writer.WriteAttributeString("type", typeName); } writer.WriteEndElement(); // </constant> } if (includeChildScopes) { foreach (ISymUnmanagedScope childScope in scope.GetScopes()) { WriteLocalsHelper(childScope, slotNames, includeChildScopes); } } }
internal static string FormatString(string str, char quote, bool escapeNonPrintable) { PooledStringBuilder pooledBuilder = null; StringBuilder sb = null; int lastEscape = -1; for (int i = 0; i < str.Length; i++) { char c = str[i]; char replaceWith = '\0'; bool unicodeEscape = false; switch (c) { case '\\': replaceWith = c; break; case '\0': replaceWith = '0'; break; case '\r': replaceWith = 'r'; break; case '\n': replaceWith = 'n'; break; case '\t': replaceWith = 't'; break; case '\b': replaceWith = 'b'; break; case '\v': replaceWith = 'v'; break; default: if (quote == c) { replaceWith = c; break; } if (escapeNonPrintable) { switch (CharUnicodeInfo.GetUnicodeCategory(c)) { case UnicodeCategory.OtherNotAssigned: case UnicodeCategory.ParagraphSeparator: case UnicodeCategory.Control: unicodeEscape = true; break; } } break; } if (unicodeEscape || replaceWith != '\0') { if (pooledBuilder == null) { pooledBuilder = PooledStringBuilder.GetInstance(); sb = pooledBuilder.Builder; if (quote != 0) { sb.Append(quote); } } sb.Append(str, lastEscape + 1, i - (lastEscape + 1)); sb.Append('\\'); if (unicodeEscape) { sb.Append('u'); sb.Append(((int)c).ToString("x4")); } else { sb.Append(replaceWith); } lastEscape = i; } } if (sb != null) { sb.Append(str, lastEscape + 1, str.Length - (lastEscape + 1)); if (quote != 0) { sb.Append(quote); } return(pooledBuilder.ToStringAndFree()); } switch (quote) { case '"': return(String.Concat("\"", str, "\"")); case '\'': return(String.Concat("'", str, "'")); case '\0': return(str); } throw ExceptionUtilities.Unreachable; }
private static void FormatStringChar( ref PooledStringBuilder pooledBuilder, string str, int index, char c, char quote, bool useLanguageSpecificEscapes, bool useUnicodeEscapes) { Debug.Assert(quote == '\0' || quote == '"' || quote == '\''); string replaceWith = null; if (useLanguageSpecificEscapes) { switch (c) { case '\\': replaceWith = "\\\\"; break; case '"': if (quote == c) { replaceWith = "\\\""; } break; case '\'': if (quote == c) { replaceWith = "\\'"; } break; case '\0': replaceWith = "\\0"; break; case '\a': replaceWith = "\\a"; break; case '\b': replaceWith = "\\b"; break; case '\f': replaceWith = "\\f"; break; case '\n': replaceWith = "\\n"; break; case '\r': replaceWith = "\\r"; break; case '\t': replaceWith = "\\t"; break; case '\v': replaceWith = "\\v"; break; } } bool unicodeEscape = false; if ((replaceWith == null) && useUnicodeEscapes) { switch (CharUnicodeInfo.GetUnicodeCategory(c)) { case UnicodeCategory.Control: case UnicodeCategory.OtherNotAssigned: case UnicodeCategory.ParagraphSeparator: unicodeEscape = true; break; } } if ((replaceWith != null) || unicodeEscape) { if (pooledBuilder == null) { pooledBuilder = PooledStringBuilder.GetInstance(); if (index > 0) { pooledBuilder.Builder.Append(str, 0, index); } } var builder = pooledBuilder.Builder; if (replaceWith != null) { builder.Append(replaceWith); } else { builder.Append("\\u"); builder.Append(((int)c).ToString("x4")); } } else if (pooledBuilder != null) { var builder = pooledBuilder.Builder; builder.Append(c); } }