forked from dotnet/linker
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port .NET Native type name parser (dotnet#1472)
* Add type parser * PR feedback * Fix mono build * Move corert code to external * Match filepaths
- Loading branch information
Showing
22 changed files
with
1,601 additions
and
250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The code in this folder was adapted from dotnet/corert commit c8bfca5f4554badfb89b80d2319769f83512bf62 |
156 changes: 156 additions & 0 deletions
156
external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.IO; | ||
using System.Text; | ||
using System.Globalization; | ||
using System.Collections.Generic; | ||
|
||
namespace System.Reflection | ||
{ | ||
internal static class AssemblyNameFormatter | ||
{ | ||
public static string ComputeDisplayName(RuntimeAssemblyName a) | ||
{ | ||
const int PUBLIC_KEY_TOKEN_LEN = 8; | ||
|
||
if (a.Name == string.Empty) | ||
throw new FileLoadException(); | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
if (a.Name != null) | ||
{ | ||
sb.AppendQuoted(a.Name); | ||
} | ||
|
||
if (a.Version != null) | ||
{ | ||
Version canonicalizedVersion = a.Version.CanonicalizeVersion(); | ||
if (canonicalizedVersion.Major != ushort.MaxValue) | ||
{ | ||
sb.Append(", Version="); | ||
sb.Append(canonicalizedVersion.Major); | ||
|
||
if (canonicalizedVersion.Minor != ushort.MaxValue) | ||
{ | ||
sb.Append('.'); | ||
sb.Append(canonicalizedVersion.Minor); | ||
|
||
if (canonicalizedVersion.Build != ushort.MaxValue) | ||
{ | ||
sb.Append('.'); | ||
sb.Append(canonicalizedVersion.Build); | ||
|
||
if (canonicalizedVersion.Revision != ushort.MaxValue) | ||
{ | ||
sb.Append('.'); | ||
sb.Append(canonicalizedVersion.Revision); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
string cultureName = a.CultureName; | ||
if (cultureName != null) | ||
{ | ||
if (cultureName == string.Empty) | ||
cultureName = "neutral"; | ||
sb.Append(", Culture="); | ||
sb.AppendQuoted(cultureName); | ||
} | ||
|
||
byte[] pkt = a.PublicKeyOrToken; | ||
if (pkt != null) | ||
{ | ||
if (pkt.Length > PUBLIC_KEY_TOKEN_LEN) | ||
throw new ArgumentException(); | ||
|
||
sb.Append(", PublicKeyToken="); | ||
if (pkt.Length == 0) | ||
sb.Append("null"); | ||
else | ||
{ | ||
foreach (byte b in pkt) | ||
{ | ||
sb.Append(b.ToString("x2", CultureInfo.InvariantCulture)); | ||
} | ||
} | ||
} | ||
|
||
if (0 != (a.Flags & AssemblyNameFlags.Retargetable)) | ||
sb.Append(", Retargetable=Yes"); | ||
|
||
AssemblyContentType contentType = a.Flags.ExtractAssemblyContentType(); | ||
if (contentType == AssemblyContentType.WindowsRuntime) | ||
sb.Append(", ContentType=WindowsRuntime"); | ||
|
||
// NOTE: By design (desktop compat) AssemblyName.FullName and ToString() do not include ProcessorArchitecture. | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
private static void AppendQuoted(this StringBuilder sb, string s) | ||
{ | ||
bool needsQuoting = false; | ||
const char quoteChar = '\"'; | ||
|
||
// App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthority) picks one | ||
// by some algorithm. Rather than guess at it, we use double quotes consistently. | ||
if (s != s.Trim() || s.Contains("\"") || s.Contains("\'")) | ||
needsQuoting = true; | ||
|
||
if (needsQuoting) | ||
sb.Append(quoteChar); | ||
|
||
for (int i = 0; i < s.Length; i++) | ||
{ | ||
bool addedEscape = false; | ||
foreach (KeyValuePair<char, string> kv in EscapeSequences) | ||
{ | ||
string escapeReplacement = kv.Value; | ||
if (!(s[i] == escapeReplacement[0])) | ||
continue; | ||
if ((s.Length - i) < escapeReplacement.Length) | ||
continue; | ||
if (s.Substring(i, escapeReplacement.Length).Equals(escapeReplacement)) | ||
{ | ||
sb.Append('\\'); | ||
sb.Append(kv.Key); | ||
addedEscape = true; | ||
} | ||
} | ||
|
||
if (!addedEscape) | ||
sb.Append(s[i]); | ||
} | ||
|
||
if (needsQuoting) | ||
sb.Append(quoteChar); | ||
} | ||
|
||
private static Version CanonicalizeVersion(this Version version) | ||
{ | ||
ushort major = (ushort)version.Major; | ||
ushort minor = (ushort)version.Minor; | ||
ushort build = (ushort)version.Build; | ||
ushort revision = (ushort)version.Revision; | ||
|
||
if (major == version.Major && minor == version.Minor && build == version.Build && revision == version.Revision) | ||
return version; | ||
|
||
return new Version(major, minor, build, revision); | ||
} | ||
|
||
public static KeyValuePair<char, string>[] EscapeSequences = | ||
{ | ||
new KeyValuePair<char, string>('\\', "\\"), | ||
new KeyValuePair<char, string>(',', ","), | ||
new KeyValuePair<char, string>('=', "="), | ||
new KeyValuePair<char, string>('\'', "'"), | ||
new KeyValuePair<char, string>('\"', "\""), | ||
new KeyValuePair<char, string>('n', Environment.NewLine), | ||
new KeyValuePair<char, string>('t', "\t"), | ||
}; | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Text; | ||
using System.Collections.Generic; | ||
|
||
namespace System.Reflection | ||
{ | ||
public static partial class AssemblyNameHelpers | ||
{ | ||
|
||
|
||
// | ||
// These helpers convert between the combined flags+contentType+processorArchitecture value and the separated parts. | ||
// | ||
// Since these are only for trusted callers, they do NOT check for out of bound bits. | ||
// | ||
|
||
internal static AssemblyContentType ExtractAssemblyContentType(this AssemblyNameFlags flags) | ||
{ | ||
return (AssemblyContentType)((((int)flags) >> 9) & 0x7); | ||
} | ||
|
||
internal static ProcessorArchitecture ExtractProcessorArchitecture(this AssemblyNameFlags flags) | ||
{ | ||
return (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); | ||
} | ||
|
||
public static AssemblyNameFlags ExtractAssemblyNameFlags(this AssemblyNameFlags combinedFlags) | ||
{ | ||
return combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); | ||
} | ||
|
||
internal static AssemblyNameFlags CombineAssemblyNameFlags(AssemblyNameFlags flags, AssemblyContentType contentType, ProcessorArchitecture processorArchitecture) | ||
{ | ||
return (AssemblyNameFlags)(((int)flags) | (((int)contentType) << 9) | ((int)processorArchitecture << 4)); | ||
} | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameLexer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.IO; | ||
using System.Text; | ||
using System.Collections.Generic; | ||
|
||
namespace System.Reflection | ||
{ | ||
// | ||
// A simple lexer for assembly display names. | ||
// | ||
internal struct AssemblyNameLexer | ||
{ | ||
internal AssemblyNameLexer(string s) | ||
{ | ||
// Convert string to char[] with NUL terminator. (An actual NUL terminator in the input string will be treated | ||
// as an actual end of string: this is compatible with desktop behavior.) | ||
char[] chars = new char[s.Length + 1]; | ||
s.CopyTo(0, chars, 0, s.Length); | ||
_chars = chars; | ||
_index = 0; | ||
} | ||
|
||
// | ||
// Return the next token in assembly name. If you expect the result to be DisplayNameToken.String, | ||
// use GetNext(out String) instead. | ||
// | ||
internal Token GetNext() | ||
{ | ||
string ignore; | ||
return GetNext(out ignore); | ||
} | ||
|
||
// | ||
// Return the next token in assembly name. If the result is DisplayNameToken.String, | ||
// sets "tokenString" to the tokenized string. | ||
// | ||
internal Token GetNext(out string tokenString) | ||
{ | ||
tokenString = null; | ||
while (char.IsWhiteSpace(_chars[_index])) | ||
_index++; | ||
|
||
char c = _chars[_index++]; | ||
if (c == 0) | ||
return Token.End; | ||
if (c == ',') | ||
return Token.Comma; | ||
if (c == '=') | ||
return Token.Equals; | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
|
||
char quoteChar = (char)0; | ||
if (c == '\'' || c == '\"') | ||
{ | ||
quoteChar = c; | ||
c = _chars[_index++]; | ||
} | ||
|
||
for (; ; ) | ||
{ | ||
if (c == 0) | ||
{ | ||
_index--; | ||
break; // Terminate: End of string (desktop compat: if string was quoted, permitted to terminate without end-quote.) | ||
} | ||
|
||
if (quoteChar != 0 && c == quoteChar) | ||
break; // Terminate: Found closing quote of quoted string. | ||
|
||
if (quoteChar == 0 && (c == ',' || c == '=')) | ||
{ | ||
_index--; | ||
break; // Terminate: Found start of a new ',' or '=' token. | ||
} | ||
|
||
if (quoteChar == 0 && (c == '\'' || c == '\"')) | ||
throw new FileLoadException(); // Desktop compat: Unescaped quote illegal unless entire string is quoted. | ||
|
||
if (c == '\\') | ||
{ | ||
c = _chars[_index++]; | ||
bool matched = false; | ||
foreach (KeyValuePair<char, string> kv in AssemblyNameFormatter.EscapeSequences) | ||
{ | ||
if (c == kv.Key) | ||
{ | ||
matched = true; | ||
sb.Append(kv.Value); | ||
break; | ||
} | ||
} | ||
if (!matched) | ||
throw new FileLoadException(); // Unrecognized escape | ||
} | ||
else | ||
{ | ||
sb.Append(c); | ||
} | ||
|
||
c = _chars[_index++]; | ||
} | ||
|
||
tokenString = sb.ToString(); | ||
if (quoteChar == 0) | ||
tokenString = tokenString.Trim(); // Unless quoted, whitespace at beginning or end doesn't count. | ||
return Token.String; | ||
} | ||
|
||
// Token categories for display name lexer. | ||
internal enum Token | ||
{ | ||
Equals = 1, | ||
Comma = 2, | ||
String = 3, | ||
End = 4, | ||
} | ||
|
||
private readonly char[] _chars; | ||
private int _index; | ||
} | ||
} |
Oops, something went wrong.