| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Collections.Generic; |
| | | 5 | | using System.Diagnostics; |
| | | 6 | | using System.Globalization; |
| | | 7 | | using System.Text; |
| | | 8 | | |
| | | 9 | | namespace System.Reflection |
| | | 10 | | { |
| | | 11 | | internal static class AssemblyNameFormatter |
| | | 12 | | { |
| | | 13 | | public static unsafe string ComputeDisplayName(string name, Version? version, string? cultureName, byte[]? pkt, |
| | 0 | 14 | | { |
| | 0 | 15 | | ValueStringBuilder vsb = new(stackalloc char[256]); |
| | 0 | 16 | | AppendDisplayName(ref vsb, name, version, cultureName, pkt, flags, contentType, pk); |
| | 0 | 17 | | return vsb.ToString(); |
| | 0 | 18 | | } |
| | | 19 | | |
| | | 20 | | public static void AppendDisplayName(ref ValueStringBuilder vsb, string name, Version? version, string? cultureN |
| | 4940 | 21 | | { |
| | | 22 | | const int PUBLIC_KEY_TOKEN_LEN = 8; |
| | 4940 | 23 | | Debug.Assert(name.Length != 0); |
| | | 24 | | |
| | 4940 | 25 | | vsb.AppendQuoted(name); |
| | | 26 | | |
| | 4940 | 27 | | if (version != null) |
| | 368 | 28 | | { |
| | 368 | 29 | | ushort major = (ushort)version.Major; |
| | 368 | 30 | | if (major != ushort.MaxValue) |
| | 368 | 31 | | { |
| | 368 | 32 | | vsb.Append(", Version="); |
| | 368 | 33 | | vsb.AppendSpanFormattable(major); |
| | | 34 | | |
| | 368 | 35 | | ushort minor = (ushort)version.Minor; |
| | 368 | 36 | | if (minor != ushort.MaxValue) |
| | 368 | 37 | | { |
| | 368 | 38 | | vsb.Append('.'); |
| | 368 | 39 | | vsb.AppendSpanFormattable(minor); |
| | | 40 | | |
| | 368 | 41 | | ushort build = (ushort)version.Build; |
| | 368 | 42 | | if (build != ushort.MaxValue) |
| | 208 | 43 | | { |
| | 208 | 44 | | vsb.Append('.'); |
| | 208 | 45 | | vsb.AppendSpanFormattable(build); |
| | | 46 | | |
| | 208 | 47 | | ushort revision = (ushort)version.Revision; |
| | 208 | 48 | | if (revision != ushort.MaxValue) |
| | 120 | 49 | | { |
| | 120 | 50 | | vsb.Append('.'); |
| | 120 | 51 | | vsb.AppendSpanFormattable(revision); |
| | 120 | 52 | | } |
| | 208 | 53 | | } |
| | 368 | 54 | | } |
| | 368 | 55 | | } |
| | 368 | 56 | | } |
| | | 57 | | |
| | 4940 | 58 | | if (cultureName != null) |
| | 0 | 59 | | { |
| | 0 | 60 | | if (cultureName.Length == 0) |
| | 0 | 61 | | cultureName = "neutral"; |
| | 0 | 62 | | vsb.Append(", Culture="); |
| | 0 | 63 | | vsb.AppendQuoted(cultureName); |
| | 0 | 64 | | } |
| | | 65 | | |
| | 4940 | 66 | | byte[]? keyOrToken = pkt ?? pk; |
| | 4940 | 67 | | if (keyOrToken != null) |
| | 744 | 68 | | { |
| | 744 | 69 | | if (pkt != null) |
| | 72 | 70 | | { |
| | 72 | 71 | | if (pkt.Length > PUBLIC_KEY_TOKEN_LEN) |
| | 0 | 72 | | throw new ArgumentException(); |
| | | 73 | | |
| | 72 | 74 | | vsb.Append(", PublicKeyToken="); |
| | 72 | 75 | | } |
| | | 76 | | else |
| | 672 | 77 | | { |
| | 672 | 78 | | vsb.Append(", PublicKey="); |
| | 672 | 79 | | } |
| | | 80 | | |
| | 744 | 81 | | if (keyOrToken.Length == 0) |
| | 52 | 82 | | { |
| | 52 | 83 | | vsb.Append("null"); |
| | 52 | 84 | | } |
| | | 85 | | else |
| | 692 | 86 | | { |
| | 692 | 87 | | HexConverter.EncodeToUtf16(keyOrToken, vsb.AppendSpan(keyOrToken.Length * 2), HexConverter.Casing.Lo |
| | 692 | 88 | | } |
| | 744 | 89 | | } |
| | | 90 | | |
| | 4940 | 91 | | if (0 != (flags & AssemblyNameFlags.Retargetable)) |
| | 16 | 92 | | vsb.Append(", Retargetable=Yes"); |
| | | 93 | | |
| | 4940 | 94 | | if (contentType == AssemblyContentType.WindowsRuntime) |
| | 12 | 95 | | vsb.Append(", ContentType=WindowsRuntime"); |
| | | 96 | | |
| | | 97 | | // NOTE: By design (desktop compat) AssemblyName.FullName and ToString() do not include ProcessorArchitectur |
| | 4940 | 98 | | } |
| | | 99 | | |
| | | 100 | | private static void AppendQuoted(this ref ValueStringBuilder vsb, string s) |
| | 4940 | 101 | | { |
| | 4940 | 102 | | bool needsQuoting = false; |
| | | 103 | | const char quoteChar = '\"'; |
| | | 104 | | |
| | | 105 | | // App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthor |
| | | 106 | | // by some algorithm. Rather than guess at it, we use double quotes consistently. |
| | 4940 | 107 | | ReadOnlySpan<char> span = s.AsSpan(); |
| | 4940 | 108 | | if (s.Length != span.Trim().Length || span.IndexOfAny('\"', '\'') >= 0) |
| | 700 | 109 | | needsQuoting = true; |
| | | 110 | | |
| | 4940 | 111 | | if (needsQuoting) |
| | 700 | 112 | | vsb.Append(quoteChar); |
| | | 113 | | |
| | 789256 | 114 | | for (int i = 0; i < s.Length; i++) |
| | 389688 | 115 | | { |
| | 389688 | 116 | | switch (s[i]) |
| | | 117 | | { |
| | | 118 | | case '\\': |
| | | 119 | | case ',': |
| | | 120 | | case '=': |
| | | 121 | | case '\'': |
| | | 122 | | case '"': |
| | 12948 | 123 | | vsb.Append('\\'); |
| | 12948 | 124 | | break; |
| | | 125 | | case '\t': |
| | 90200 | 126 | | vsb.Append("\\t"); |
| | 90200 | 127 | | continue; |
| | | 128 | | case '\r': |
| | 9236 | 129 | | vsb.Append("\\r"); |
| | 9236 | 130 | | continue; |
| | | 131 | | case '\n': |
| | 4904 | 132 | | vsb.Append("\\n"); |
| | 4904 | 133 | | continue; |
| | | 134 | | } |
| | | 135 | | |
| | 285348 | 136 | | vsb.Append(s[i]); |
| | 285348 | 137 | | } |
| | | 138 | | |
| | 4940 | 139 | | if (needsQuoting) |
| | 700 | 140 | | vsb.Append(quoteChar); |
| | 4940 | 141 | | } |
| | | 142 | | |
| | | 143 | | #if !NET |
| | | 144 | | private static void AppendSpanFormattable(this ref ValueStringBuilder vsb, ushort value) |
| | | 145 | | { |
| | | 146 | | vsb.Append(value.ToString()); |
| | | 147 | | } |
| | | 148 | | #endif |
| | | 149 | | } |
| | | 150 | | } |
| | | 151 | | |