summaryrefslogtreecommitdiff
path: root/src/mscorlib
diff options
context:
space:
mode:
authorRahul Kumar <rahku@microsoft.com>2016-11-13 09:34:58 -0800
committerJan Kotas <jkotas@microsoft.com>2016-11-13 09:34:58 -0800
commitb28f557ee79d70a83e299d6c83a2c803139edba2 (patch)
treef37685dbbe8ed256a5ff5862553db540b895d48e /src/mscorlib
parentdfd0e4b4e20d00a02fdd412251f6146a639ae33c (diff)
downloadcoreclr-b28f557ee79d70a83e299d6c83a2c803139edba2.tar.gz
coreclr-b28f557ee79d70a83e299d6c83a2c803139edba2.tar.bz2
coreclr-b28f557ee79d70a83e299d6c83a2c803139edba2.zip
Add implementation for AssemblyName::EscapedCodeBase (#8072)
Diffstat (limited to 'src/mscorlib')
-rw-r--r--src/mscorlib/model.xml4
-rw-r--r--src/mscorlib/ref/mscorlib.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/AssemblyName.cs226
3 files changed, 230 insertions, 2 deletions
diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml
index 393a4bb26b..d43dd574d1 100644
--- a/src/mscorlib/model.xml
+++ b/src/mscorlib/model.xml
@@ -3958,6 +3958,7 @@
<Member Name="get_IsFullyTrusted" />
<Member Name="get_IsDynamic" />
<Member Name="get_CodeBase" />
+ <Member Name="get_EscapedCodeBase" />
<Member Name="get_Location" />
<Member Name="get_ManifestModule" />
<Member Name="get_CustomAttributes" />
@@ -4019,6 +4020,7 @@
<Member MemberType="Property" Name="GlobalAssemblyCache" />
<Member MemberType="Property" Name="HostContext" />
<Member MemberType="Property" Name="CodeBase" />
+ <Member MemberType="Property" Name="EscapedCodeBase" />
<Member MemberType="Property" Name="ImageRuntimeVersion" />
<Member MemberType="Property" Name="IsFullyTrusted" />
<Member MemberType="Property" Name="Location" />
@@ -4158,6 +4160,7 @@
<Member Name="get_CultureInfo" />
<Member Name="get_CultureName" />
<Member Name="get_CodeBase" />
+ <Member Name="get_EscapedCodeBase" />
<Member Name="get_ContentType" />
<Member Name="get_Flags" />
<Member Name="get_FullName" />
@@ -4191,6 +4194,7 @@
<Member MemberType="Property" Name="CultureInfo" />
<Member MemberType="Property" Name="CultureName" />
<Member MemberType="Property" Name="ContentType" />
+ <Member MemberType="Property" Name="EscapedCodeBase" />
<Member MemberType="Property" Name="Flags" />
<Member MemberType="Property" Name="FullName" />
<Member MemberType="Property" Name="HashAlgorithm" />
diff --git a/src/mscorlib/ref/mscorlib.cs b/src/mscorlib/ref/mscorlib.cs
index 4c364ada18..f63433e0b4 100644
--- a/src/mscorlib/ref/mscorlib.cs
+++ b/src/mscorlib/ref/mscorlib.cs
@@ -7230,6 +7230,7 @@ namespace System.Reflection
public virtual System.Collections.Generic.IEnumerable<System.Reflection.CustomAttributeData> CustomAttributes { get { throw null; } }
public virtual System.Collections.Generic.IEnumerable<System.Reflection.TypeInfo> DefinedTypes { get { throw null; } }
public virtual System.Reflection.MethodInfo EntryPoint { get { throw null; } }
+ public virtual string EscapedCodeBase { [System.Security.SecurityCriticalAttribute]get { throw null; } }
public virtual System.Collections.Generic.IEnumerable<System.Type> ExportedTypes { get { throw null; } }
public virtual string FullName { get { throw null; } }
public virtual bool GlobalAssemblyCache { get { throw null; } }
@@ -7436,6 +7437,7 @@ namespace System.Reflection
public System.Globalization.CultureInfo CultureInfo { get { throw null; } set { } }
public string CultureName { [System.Security.SecurityCriticalAttribute]get { throw null; } [System.Security.SecurityCriticalAttribute]set { } }
public string CodeBase { get { throw null; } set { } }
+ public string EscapedCodeBase { get { throw null; } }
public System.Reflection.AssemblyNameFlags Flags { get { throw null; } set { } }
public string FullName { [System.Security.SecuritySafeCriticalAttribute]get { throw null; } }
public System.Configuration.Assemblies.AssemblyHashAlgorithm HashAlgorithm { get { throw null; } set { } }
diff --git a/src/mscorlib/src/System/Reflection/AssemblyName.cs b/src/mscorlib/src/System/Reflection/AssemblyName.cs
index 4c3d5aa6d6..c45a4619ea 100644
--- a/src/mscorlib/src/System/Reflection/AssemblyName.cs
+++ b/src/mscorlib/src/System/Reflection/AssemblyName.cs
@@ -24,6 +24,7 @@ namespace System.Reflection {
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
+ using System.Text;
[Serializable]
[ClassInterface(ClassInterfaceType.None)]
@@ -533,7 +534,228 @@ namespace System.Reflection {
private extern byte[] nGetPublicKeyToken();
[System.Security.SecurityCritical] // auto-generated
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static internal extern String EscapeCodeBase(String codeBase);
+ static internal String EscapeCodeBase(String codebase)
+ {
+ if (codebase == null)
+ return string.Empty;
+
+ int position = 0;
+ char[] dest = EscapeString(codebase, 0, codebase.Length, null, ref position, true, c_DummyChar, c_DummyChar, c_DummyChar);
+ if (dest == null)
+ return codebase;
+
+ return new string(dest, 0, position);
+ }
+
+ // This implementation of EscapeString has been copied from System.Private.Uri from corefx repo
+ // - forceX characters are always escaped if found
+ // - rsvd character will remain unescaped
+ //
+ // start - starting offset from input
+ // end - the exclusive ending offset in input
+ // destPos - starting offset in dest for output, on return this will be an exclusive "end" in the output.
+ //
+ // In case "dest" has lack of space it will be reallocated by preserving the _whole_ content up to current destPos
+ //
+ // Returns null if nothing has to be escaped AND passed dest was null, otherwise the resulting array with the updated destPos
+ //
+ internal unsafe static char[] EscapeString(string input, int start, int end, char[] dest, ref int destPos,
+ bool isUriString, char force1, char force2, char rsvd)
+ {
+ int i = start;
+ int prevInputPos = start;
+ byte* bytes = stackalloc byte[c_MaxUnicodeCharsReallocate * c_MaxUTF_8BytesPerUnicodeChar]; // 40*4=160
+
+ fixed (char* pStr = input)
+ {
+ for (; i < end; ++i)
+ {
+ char ch = pStr[i];
+
+ // a Unicode ?
+ if (ch > '\x7F')
+ {
+ short maxSize = (short)Math.Min(end - i, (int)c_MaxUnicodeCharsReallocate - 1);
+
+ short count = 1;
+ for (; count < maxSize && pStr[i + count] > '\x7f'; ++count)
+ ;
+
+ // Is the last a high surrogate?
+ if (pStr[i + count - 1] >= 0xD800 && pStr[i + count - 1] <= 0xDBFF)
+ {
+ // Should be a rare case where the app tries to feed an invalid Unicode surrogates pair
+ if (count == 1 || count == end - i)
+ throw new FormatException(Environment.GetResourceString("Arg_FormatException"));
+ // need to grab one more char as a Surrogate except when it's a bogus input
+ ++count;
+ }
+
+ dest = EnsureDestinationSize(pStr, dest, i,
+ (short)(count * c_MaxUTF_8BytesPerUnicodeChar * c_EncodedCharsPerByte),
+ c_MaxUnicodeCharsReallocate * c_MaxUTF_8BytesPerUnicodeChar * c_EncodedCharsPerByte,
+ ref destPos, prevInputPos);
+
+ short numberOfBytes = (short)Encoding.UTF8.GetBytes(pStr + i, count, bytes,
+ c_MaxUnicodeCharsReallocate * c_MaxUTF_8BytesPerUnicodeChar);
+
+ // This is the only exception that built in UriParser can throw after a Uri ctor.
+ // Should not happen unless the app tries to feed an invalid Unicode String
+ if (numberOfBytes == 0)
+ throw new FormatException(Environment.GetResourceString("Arg_FormatException"));
+
+ i += (count - 1);
+
+ for (count = 0; count < numberOfBytes; ++count)
+ EscapeAsciiChar((char)bytes[count], dest, ref destPos);
+
+ prevInputPos = i + 1;
+ }
+ else if (ch == '%' && rsvd == '%')
+ {
+ // Means we don't reEncode '%' but check for the possible escaped sequence
+ dest = EnsureDestinationSize(pStr, dest, i, c_EncodedCharsPerByte,
+ c_MaxAsciiCharsReallocate * c_EncodedCharsPerByte, ref destPos, prevInputPos);
+ if (i + 2 < end && EscapedAscii(pStr[i + 1], pStr[i + 2]) != c_DummyChar)
+ {
+ // leave it escaped
+ dest[destPos++] = '%';
+ dest[destPos++] = pStr[i + 1];
+ dest[destPos++] = pStr[i + 2];
+ i += 2;
+ }
+ else
+ {
+ EscapeAsciiChar('%', dest, ref destPos);
+ }
+ prevInputPos = i + 1;
+ }
+ else if (ch == force1 || ch == force2)
+ {
+ dest = EnsureDestinationSize(pStr, dest, i, c_EncodedCharsPerByte,
+ c_MaxAsciiCharsReallocate * c_EncodedCharsPerByte, ref destPos, prevInputPos);
+ EscapeAsciiChar(ch, dest, ref destPos);
+ prevInputPos = i + 1;
+ }
+ else if (ch != rsvd && (isUriString ? !IsReservedUnreservedOrHash(ch) : !IsUnreserved(ch)))
+ {
+ dest = EnsureDestinationSize(pStr, dest, i, c_EncodedCharsPerByte,
+ c_MaxAsciiCharsReallocate * c_EncodedCharsPerByte, ref destPos, prevInputPos);
+ EscapeAsciiChar(ch, dest, ref destPos);
+ prevInputPos = i + 1;
+ }
+ }
+
+ if (prevInputPos != i)
+ {
+ // need to fill up the dest array ?
+ if (prevInputPos != start || dest != null)
+ dest = EnsureDestinationSize(pStr, dest, i, 0, 0, ref destPos, prevInputPos);
+ }
+ }
+
+ return dest;
+ }
+
+ //
+ // ensure destination array has enough space and contains all the needed input stuff
+ //
+ private unsafe static char[] EnsureDestinationSize(char* pStr, char[] dest, int currentInputPos,
+ short charsToAdd, short minReallocateChars, ref int destPos, int prevInputPos)
+ {
+ if ((object)dest == null || dest.Length < destPos + (currentInputPos - prevInputPos) + charsToAdd)
+ {
+ // allocating or reallocating array by ensuring enough space based on maxCharsToAdd.
+ char[] newresult = new char[destPos + (currentInputPos - prevInputPos) + minReallocateChars];
+
+ if ((object)dest != null && destPos != 0)
+ Buffer.BlockCopy(dest, 0, newresult, 0, destPos << 1);
+ dest = newresult;
+ }
+
+ // ensuring we copied everything form the input string left before last escaping
+ while (prevInputPos != currentInputPos)
+ dest[destPos++] = pStr[prevInputPos++];
+ return dest;
+ }
+
+ internal static void EscapeAsciiChar(char ch, char[] to, ref int pos)
+ {
+ to[pos++] = '%';
+ to[pos++] = s_hexUpperChars[(ch & 0xf0) >> 4];
+ to[pos++] = s_hexUpperChars[ch & 0xf];
+ }
+
+ internal static char EscapedAscii(char digit, char next)
+ {
+ if (!(((digit >= '0') && (digit <= '9'))
+ || ((digit >= 'A') && (digit <= 'F'))
+ || ((digit >= 'a') && (digit <= 'f'))))
+ {
+ return c_DummyChar;
+ }
+
+ int res = (digit <= '9')
+ ? ((int)digit - (int)'0')
+ : (((digit <= 'F')
+ ? ((int)digit - (int)'A')
+ : ((int)digit - (int)'a'))
+ + 10);
+
+ if (!(((next >= '0') && (next <= '9'))
+ || ((next >= 'A') && (next <= 'F'))
+ || ((next >= 'a') && (next <= 'f'))))
+ {
+ return c_DummyChar;
+ }
+
+ return (char)((res << 4) + ((next <= '9')
+ ? ((int)next - (int)'0')
+ : (((next <= 'F')
+ ? ((int)next - (int)'A')
+ : ((int)next - (int)'a'))
+ + 10)));
+ }
+
+ private static unsafe bool IsReservedUnreservedOrHash(char c)
+ {
+ if (IsUnreserved(c))
+ {
+ return true;
+ }
+ return (RFC3986ReservedMarks.IndexOf(c) >= 0);
+ }
+
+ internal static unsafe bool IsUnreserved(char c)
+ {
+ if (IsAsciiLetterOrDigit(c))
+ {
+ return true;
+ }
+ return (RFC3986UnreservedMarks.IndexOf(c) >= 0);
+ }
+
+ //Only consider ASCII characters
+ internal static bool IsAsciiLetter(char character)
+ {
+ return (character >= 'a' && character <= 'z') ||
+ (character >= 'A' && character <= 'Z');
+ }
+
+ internal static bool IsAsciiLetterOrDigit(char character)
+ {
+ return IsAsciiLetter(character) || (character >= '0' && character <= '9');
+ }
+
+ private static readonly char[] s_hexUpperChars = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ internal const char c_DummyChar = (char)0xFFFF; //An Invalid Unicode character used as a dummy char passed into the parameter
+ private const short c_MaxAsciiCharsReallocate = 40;
+ private const short c_MaxUnicodeCharsReallocate = 40;
+ private const short c_MaxUTF_8BytesPerUnicodeChar = 4;
+ private const short c_EncodedCharsPerByte = 3;
+ private const string RFC3986ReservedMarks = @":/?#[]@!$&'()*+,;=";
+ private const string RFC3986UnreservedMarks = @"-._~";
}
}