diff --git a/SigningService.Tests/.config/test/KeyVaultSettings.json b/SigningService.Tests/.config/test/KeyVaultSettings.json index c62bc89..83909b8 100644 --- a/SigningService.Tests/.config/test/KeyVaultSettings.json +++ b/SigningService.Tests/.config/test/KeyVaultSettings.json @@ -1,4 +1,5 @@ { - "KeyId": "https://puszkipkeyvault.vault.azure.net/keys/FirstKey/fa220215edd84347bc9af7bafdaf1b5a", - "Algorithm" : "RS256" + "Vault" : "https://puszkipkeyvault.vault.azure.net", + "KeyId": "https://puszkipkeyvault.vault.azure.net:443/keys/KrzyszekKey", + "Algorithm": "RS256" } \ No newline at end of file diff --git a/SigningService.Tests/Agents/KeyVaultAgentSpecs.cs b/SigningService.Tests/Agents/KeyVaultAgentSpecs.cs new file mode 100644 index 0000000..00fe438 --- /dev/null +++ b/SigningService.Tests/Agents/KeyVaultAgentSpecs.cs @@ -0,0 +1,56 @@ +using Its.Configuration; +using SigningService.Agents; +using SigningService.Models; +using SigningService.Signers.StrongName; +using SigningService.Tests.Utils; +using System.IO; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; +using FluentAssertions; +using SigningService.Services.Configuration; + +namespace SigningService.Tests +{ + public class KeyVaultAgentSpecs + { + private readonly ITestOutputHelper output; + + public KeyVaultAgentSpecs(ITestOutputHelper output) + { + this.output = output; + } + + public async Task GetKeyVaultKeyId(Stream peImage) + { + string keyId = null; + using (peImage) + { + StrongNameSignerHelper sns = new StrongNameSignerHelper(peImage); + + var keyVaultAgent = new KeyVaultAgent(); + PublicKey publicKey = sns.SignaturePublicKeyBlob.PublicKey; + keyId = await keyVaultAgent.GetRsaKeyIdAsync(publicKey.Exponent, publicKey.Modulus); + output.WriteLine("KeyVault KeyId = {0}", keyId ?? ""); + output.WriteLine(sns.ToString()); + } + return keyId; + } + + [Fact] + public async void Test() + { + TestAssembly sha256 = new TestAssembly("TestLib.sha256.dll", null); + TestAssembly sha384 = new TestAssembly("TestLib.sha384.dll", null); + TestAssembly ppsha256delay = new TestAssembly("TestLib.delay.dll", null); + TestAssembly jscript = new TestAssembly("Microsoft.JScript.dll", null); + + Settings.Precedence = new string [] { "test" }; + + (await GetKeyVaultKeyId(sha256.GetWritablePEImage())).Should().BeNull(); + (await GetKeyVaultKeyId(sha384.GetWritablePEImage())).Should().BeNull(); + (await GetKeyVaultKeyId(ppsha256delay.GetWritablePEImage())).Should().NotBeNull(); + (await GetKeyVaultKeyId(jscript.GetWritablePEImage())).Should().BeNull(); + } + } +} diff --git a/SigningService.Tests/KeyVaultAgentSpecs.cs b/SigningService.Tests/KeyVaultAgentSpecs.cs deleted file mode 100644 index 6a5064c..0000000 --- a/SigningService.Tests/KeyVaultAgentSpecs.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Linq; -using FluentAssertions; -using Its.Configuration; -using Microsoft.Its.Recipes; -using SigningService.Agents; -using Xunit; - -namespace SigningService.Tests -{ - public class KeyVaultAgentSpecs - { - [Fact] - public async void When_digest_has_32_bytes_the_response_has_256_bytes() - { - Settings.Precedence = new[] {"test"}; - - var keyVaultAgent = new KeyVaultAgent(); - - var response = await keyVaultAgent.Sign(Any.Sequence(x => Any.Byte(), 32).ToArray()); - - response - .Should().HaveCount(256, "Because that is the length of an RSA256 signed digest"); - } - - [Fact] - public async void When_digest_has_more_or_less_than_32_bytes_Then_it_fails_with_a_useful_message() - { - var keyVaultAgent = new KeyVaultAgent(); - - var byteCount = Any.Int(0, 1024); - if (byteCount == 32) byteCount += Any.Int(1, 1024); - - Action sign = () => { keyVaultAgent.Sign(new byte[byteCount]).Wait(); }; - - sign - .ShouldThrow("Because only 32 bit digests are accepted by RSA256") - .WithMessage("The value must have 32 bytes\r\nParameter name: digest"); - } - - [Fact] - public async void When_digest_is_null_Then_it_fails_with_a_useful_message() - { - var keyVaultAgent = new KeyVaultAgent(); - - Action sign = () => keyVaultAgent.Sign(null).Wait(); - - sign - .ShouldThrow("Because a digest must be provided.") - .WithMessage("Value cannot be null.\r\nParameter name: digest"); - } - } -} diff --git a/SigningService.Tests/Resources/Microsoft.JScript.dll b/SigningService.Tests/Resources/Microsoft.JScript.dll new file mode 100644 index 0000000..f02a50b Binary files /dev/null and b/SigningService.Tests/Resources/Microsoft.JScript.dll differ diff --git a/SigningService.Tests/Resources/TestLib.delay.dll b/SigningService.Tests/Resources/TestLib.delay.dll new file mode 100644 index 0000000..2b329c0 Binary files /dev/null and b/SigningService.Tests/Resources/TestLib.delay.dll differ diff --git a/SigningService.Tests/Resources/TestLib.sha256.dll b/SigningService.Tests/Resources/TestLib.sha256.dll new file mode 100644 index 0000000..fad2017 Binary files /dev/null and b/SigningService.Tests/Resources/TestLib.sha256.dll differ diff --git a/SigningService.Tests/Resources/TestLib.sha384.dll b/SigningService.Tests/Resources/TestLib.sha384.dll new file mode 100644 index 0000000..3585ebb Binary files /dev/null and b/SigningService.Tests/Resources/TestLib.sha384.dll differ diff --git a/SigningService.Tests/SigningService.Tests.csproj b/SigningService.Tests/SigningService.Tests.csproj index 62a75a5..94d6255 100644 --- a/SigningService.Tests/SigningService.Tests.csproj +++ b/SigningService.Tests/SigningService.Tests.csproj @@ -44,6 +44,10 @@ ..\packages\FluentAssertions.3.3.0\lib\net45\FluentAssertions.Core.dll True + + False + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + ..\packages\Its.Configuration.1.0.0-beta\lib\net40\Its.Configuration.dll @@ -51,6 +55,17 @@ ..\packages\Its.Log.2.8.3\lib\net40\Its.Log.dll True + + False + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + + + False + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll @@ -72,7 +87,20 @@ ..\packages\Microsoft.Owin.MockSrevice.0.1.0.0\lib\net45\Microsoft.Owin.MockService.dll True + + False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + ..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll True @@ -86,7 +114,15 @@ + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + + @@ -110,7 +146,7 @@ - + @@ -118,6 +154,11 @@ True Resources.resx + + + + + @@ -129,6 +170,18 @@ Always + + Microsoft.JScript.dll + + + TestLib.sha256.dll + + + TestLib.sha384.dll + + + TestLib.delay.dll + Always @@ -152,6 +205,11 @@ + + + + + strings are unequal if current char and current byte are unequal + if (currentChar != currentByte) + { + return FastComparisonResult.Unequal; + } + } + else if (currentChar <= 0x7F) + { + // current byte is not in ascii range, but current char is. + // --> strings are unequal. + return FastComparisonResult.Unequal; + } + else + { + // uncommon non-ascii case --> fall back to slow allocating comparison. + return FastComparisonResult.Inconclusive; + } + } + + if (currentIndex != text.Length) + { + return FastComparisonResult.Unequal; + } + + if (currentPointer != endPointer && *currentPointer != 0 && *currentPointer != terminator) + { + return FastComparisonResult.IsPrefix; + } + + return FastComparisonResult.Equal; + } + + // comparison stops at null terminator, terminator parameter, or end-of-block -- whichever comes first. + internal bool Utf8NullTerminatedStringStartsWithAsciiPrefix(int offset, string asciiPrefix) + { + // Assumes stringAscii only contains ASCII characters and no nil characters. + + CheckBounds(offset, 0); + + // Make sure that we won't read beyond the block even if the block doesn't end with 0 byte. + if (asciiPrefix.Length > Length - offset) + { + return false; + } + + byte* p = Pointer + offset; + + for (int i = 0; i < asciiPrefix.Length; i++) + { + Debug.Assert((int)asciiPrefix[i] > 0 && (int)asciiPrefix[i] <= 0x7f); + + if (asciiPrefix[i] != *p) + { + return false; + } + + p++; + } + + return true; + } + + internal int CompareUtf8NullTerminatedStringWithAsciiString(int offset, string asciiString) + { + // Assumes stringAscii only contains ASCII characters and no nil characters. + + CheckBounds(offset, 0); + + byte* p = Pointer + offset; + int limit = Length - offset; + + for (int i = 0; i < asciiString.Length; i++) + { + Debug.Assert((int)asciiString[i] > 0 && (int)asciiString[i] <= 0x7f); + + if (i > limit) + { + // Heap value is shorter. + return -1; + } + + if (*p != asciiString[i]) + { + // If we hit the end of the heap value (*p == 0) + // the heap value is shorter than the string, so we return negative value. + return *p - asciiString[i]; + } + + p++; + } + + // Either the heap value name matches exactly the given string or + // it is longer so it is considered "greater". + return (*p == 0) ? 0 : +1; + } + + internal byte[] PeekBytes(int offset, int byteCount) + { + CheckBounds(offset, byteCount); + + if (byteCount == 0) + { + return EmptyArray.Instance; + } + + byte[] result = new byte[byteCount]; + Marshal.Copy((IntPtr)(Pointer + offset), result, 0, byteCount); + return result; + } + + internal int IndexOf(byte b, int start) + { + CheckBounds(start, 0); + + byte* p = Pointer + start; + byte* end = Pointer + Length; + while (p < end) + { + if (*p == b) + { + return (int)(p - Pointer); + } + + p++; + } + + return -1; + } + + // same as Array.BinarySearch, but without using IComparer + internal int BinarySearch(string[] asciiKeys, int offset) + { + var low = 0; + var high = asciiKeys.Length - 1; + + while (low <= high) + { + var middle = low + ((high - low) >> 1); + var midValue = asciiKeys[middle]; + + int comparison = CompareUtf8NullTerminatedStringWithAsciiString(offset, midValue); + if (comparison == 0) + { + return middle; + } + + if (comparison < 0) + { + high = middle - 1; + } + else + { + low = middle + 1; + } + } + + return ~low; + } + + // Returns row number [0..RowCount) or -1 if not found. + internal int BinarySearchForSlot( + uint rowCount, + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall) + { + int startRowNumber = 0; + int endRowNumber = (int)rowCount - 1; + uint startValue = PeekReference(startRowNumber * rowSize + referenceOffset, isReferenceSmall); + uint endValue = PeekReference(endRowNumber * rowSize + referenceOffset, isReferenceSmall); + if (endRowNumber == 1) + { + if (referenceValue >= endValue) + { + return endRowNumber; + } + + return startRowNumber; + } + + while ((endRowNumber - startRowNumber) > 1) + { + if (referenceValue <= startValue) + { + return referenceValue == startValue ? startRowNumber : startRowNumber - 1; + } + else if (referenceValue >= endValue) + { + return referenceValue == endValue ? endRowNumber : endRowNumber + 1; + } + + int midRowNumber = (startRowNumber + endRowNumber) / 2; + uint midReferenceValue = PeekReference(midRowNumber * rowSize + referenceOffset, isReferenceSmall); + if (referenceValue > midReferenceValue) + { + startRowNumber = midRowNumber; + startValue = midReferenceValue; + } + else if (referenceValue < midReferenceValue) + { + endRowNumber = midRowNumber; + endValue = midReferenceValue; + } + else + { + return midRowNumber; + } + } + + return startRowNumber; + } + + // Returns row number [0..RowCount) or -1 if not found. + internal int BinarySearchReference( + uint rowCount, + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall) + { + int startRowNumber = 0; + int endRowNumber = (int)rowCount - 1; + while (startRowNumber <= endRowNumber) + { + int midRowNumber = (startRowNumber + endRowNumber) / 2; + uint midReferenceValue = PeekReference(midRowNumber * rowSize + referenceOffset, isReferenceSmall); + if (referenceValue > midReferenceValue) + { + startRowNumber = midRowNumber + 1; + } + else if (referenceValue < midReferenceValue) + { + endRowNumber = midRowNumber - 1; + } + else + { + return midRowNumber; + } + } + + return -1; + } + + // Row number [0, ptrTable.Length) or -1 if not found. + internal int BinarySearchReference( + uint[] ptrTable, + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall) + { + int startRowNumber = 0; + int endRowNumber = ptrTable.Length - 1; + while (startRowNumber <= endRowNumber) + { + int midRowNumber = (startRowNumber + endRowNumber) / 2; + uint midReferenceValue = PeekReference(((int)ptrTable[midRowNumber] - 1) * rowSize + referenceOffset, isReferenceSmall); + if (referenceValue > midReferenceValue) + { + startRowNumber = midRowNumber + 1; + } + else if (referenceValue < midReferenceValue) + { + endRowNumber = midRowNumber - 1; + } + else + { + return midRowNumber; + } + } + + return -1; + } + + /// + /// Calculates a range of rows that have specified value in the specified column in a table that is sorted by that column. + /// + internal void BinarySearchReferenceRange( + uint rowCount, + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall, + out int startRowNumber, // [0, rowCount) or -1 + out int endRowNumber) // [0, rowCount) or -1 + { + int foundRowNumber = BinarySearchReference( + rowCount, + rowSize, + referenceOffset, + referenceValue, + isReferenceSmall + ); + + if (foundRowNumber == -1) + { + startRowNumber = -1; + endRowNumber = -1; + return; + } + + startRowNumber = foundRowNumber; + while (startRowNumber > 0 && + PeekReference((startRowNumber - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue) + { + startRowNumber--; + } + + endRowNumber = foundRowNumber; + while (endRowNumber + 1 < rowCount && + PeekReference((endRowNumber + 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue) + { + endRowNumber++; + } + } + + /// + /// Calculates a range of rows that have specified value in the specified column in a table that is sorted by that column. + /// + internal void BinarySearchReferenceRange( + uint[] ptrTable, + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall, + out int startRowNumber, // [0, ptrTable.Length) or -1 + out int endRowNumber) // [0, ptrTable.Length) or -1 + { + int foundRowNumber = BinarySearchReference( + ptrTable, + rowSize, + referenceOffset, + referenceValue, + isReferenceSmall + ); + + if (foundRowNumber == -1) + { + startRowNumber = -1; + endRowNumber = -1; + return; + } + + startRowNumber = foundRowNumber; + while (startRowNumber > 0 && + PeekReference(((int)ptrTable[startRowNumber - 1] - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue) + { + startRowNumber--; + } + + endRowNumber = foundRowNumber; + while (endRowNumber + 1 < ptrTable.Length && + PeekReference(((int)ptrTable[endRowNumber + 1] - 1) * rowSize + referenceOffset, isReferenceSmall) == referenceValue) + { + endRowNumber++; + } + } + + // Always RowNumber.... + internal int LinearSearchReference( + int rowSize, + int referenceOffset, + uint referenceValue, + bool isReferenceSmall) + { + int currOffset = referenceOffset; + int totalSize = this.Length; + while (currOffset < totalSize) + { + uint currReference = PeekReference(currOffset, isReferenceSmall); + if (currReference == referenceValue) + { + return currOffset / rowSize; + } + + currOffset += rowSize; + } + + return -1; + } + + internal bool IsOrderedByReferenceAscending( + int rowSize, + int referenceOffset, + bool isReferenceSmall) + { + int offset = referenceOffset; + int totalSize = this.Length; + + uint previous = 0; + while (offset < totalSize) + { + uint current = PeekReference(offset, isReferenceSmall); + if (current < previous) + { + return false; + } + + previous = current; + offset += rowSize; + } + + return true; + } + + internal uint[] BuildPtrTable( + int numberOfRows, + int rowSize, + int referenceOffset, + bool isReferenceSmall) + { + uint[] ptrTable = new uint[numberOfRows]; + uint[] unsortedReferences = new uint[numberOfRows]; + + for (int i = 0; i < ptrTable.Length; i++) + { + ptrTable[i] = (uint)(i + 1); + } + + ReadColumn(unsortedReferences, rowSize, referenceOffset, isReferenceSmall); + Array.Sort(ptrTable, (uint a, uint b) => { return unsortedReferences[a - 1].CompareTo(unsortedReferences[b - 1]); }); + return ptrTable; + } + + private void ReadColumn( + uint[] result, + int rowSize, + int referenceOffset, + bool isReferenceSmall) + { + int offset = referenceOffset; + int totalSize = this.Length; + + int i = 0; + while (offset < totalSize) + { + result[i] = PeekTaggedReference(offset, isReferenceSmall); + offset += rowSize; + i++; + } + + Debug.Assert(i == result.Length); + } + + internal bool PeekHeapValueOffsetAndSize(int index, out int offset, out int size) + { + int bytesRead; + int numberOfBytes = PeekCompressedInteger(index, out bytesRead); + if (numberOfBytes == BlobReader.InvalidCompressedInteger) + { + offset = 0; + size = 0; + return false; + } + + offset = index + bytesRead; + size = numberOfBytes; + return true; + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/MemoryMapLightUp.cs b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/MemoryMapLightUp.cs new file mode 100644 index 0000000..2f4f848 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/MemoryMapLightUp.cs @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace System.Reflection.Internal +{ + internal static class MemoryMapLightUp + { + private static Type s_lazyMemoryMappedFileType; + private static Type s_lazyMemoryMappedViewAccessorType; + private static Type s_lazyMemoryMappedFileAccessType; + private static Type s_lazyMemoryMappedFileSecurityType; + private static Type s_lazyHandleInheritabilityType; + private static MethodInfo s_lazyCreateFromFile; + private static MethodInfo s_lazyCreateFromFileClassic; + private static MethodInfo s_lazyCreateViewAccessor; + private static PropertyInfo s_lazySafeMemoryMappedViewHandle; + private static PropertyInfo s_lazyPointerOffset; + private static FieldInfo s_lazyInternalViewField; + private static PropertyInfo s_lazyInternalPointerOffset; + + private static readonly object s_MemoryMappedFileAccess_Read = 1; + private static readonly object s_HandleInheritability_None = 0; + private static readonly object s_LongZero = (long)0; + private static readonly object s_True = true; + + private static bool? s_lazyIsAvailable; + + internal static bool IsAvailable + { + get + { + if (!s_lazyIsAvailable.HasValue) + { + s_lazyIsAvailable = TryLoadTypes(); + } + + return s_lazyIsAvailable.Value; + } + } + + private static bool TryLoadType(string typeName, string modernAssembly, string classicAssembly, out Type type) + { + type = LightUpHelper.GetType(typeName, modernAssembly, classicAssembly); + return type != null; + } + + private static bool TryLoadTypes() + { + const string systemIOMemoryMappedFiles = "System.IO.MemoryMappedFiles, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; + const string systemRuntimeHandles = "System.Runtime.Handles, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; + const string systemCore = "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + + TryLoadType("System.IO.MemoryMappedFiles.MemoryMappedFileSecurity", systemIOMemoryMappedFiles, systemCore, out s_lazyMemoryMappedFileSecurityType); + + return FileStreamReadLightUp.FileStreamType.Value != null + && TryLoadType("System.IO.MemoryMappedFiles.MemoryMappedFile", systemIOMemoryMappedFiles, systemCore, out s_lazyMemoryMappedFileType) + && TryLoadType("System.IO.MemoryMappedFiles.MemoryMappedViewAccessor", systemIOMemoryMappedFiles, systemCore, out s_lazyMemoryMappedViewAccessorType) + && TryLoadType("System.IO.MemoryMappedFiles.MemoryMappedFileAccess", systemIOMemoryMappedFiles, systemCore, out s_lazyMemoryMappedFileAccessType) + && TryLoadType("System.IO.HandleInheritability", systemRuntimeHandles, systemCore, out s_lazyHandleInheritabilityType) + && TryLoadMembers(); + } + + private static bool TryLoadMembers() + { + // .NET Core, .NET 4.6+ + s_lazyCreateFromFile = LightUpHelper.GetMethod( + s_lazyMemoryMappedFileType, + "CreateFromFile", + FileStreamReadLightUp.FileStreamType.Value, + typeof(string), + typeof(long), + s_lazyMemoryMappedFileAccessType, + s_lazyHandleInheritabilityType, + typeof(bool) + ); + + // .NET < 4.6 + if (s_lazyCreateFromFile == null) + { + if (s_lazyMemoryMappedFileSecurityType != null) + { + s_lazyCreateFromFileClassic = LightUpHelper.GetMethod( + s_lazyMemoryMappedFileType, + "CreateFromFile", + FileStreamReadLightUp.FileStreamType.Value, + typeof(string), + typeof(long), + s_lazyMemoryMappedFileAccessType, + s_lazyMemoryMappedFileSecurityType, + s_lazyHandleInheritabilityType, + typeof(bool)); + } + + if (s_lazyCreateFromFileClassic == null) + { + return false; + } + } + + s_lazyCreateViewAccessor = LightUpHelper.GetMethod( + s_lazyMemoryMappedFileType, + "CreateViewAccessor", + typeof(long), + typeof(long), + s_lazyMemoryMappedFileAccessType); + + if (s_lazyCreateViewAccessor == null) + { + return false; + } + + s_lazySafeMemoryMappedViewHandle = s_lazyMemoryMappedViewAccessorType.GetTypeInfo().GetDeclaredProperty("SafeMemoryMappedViewHandle"); + if (s_lazySafeMemoryMappedViewHandle == null) + { + return false; + } + + // .NET Core, .NET 4.5.1+ + s_lazyPointerOffset = s_lazyMemoryMappedViewAccessorType.GetTypeInfo().GetDeclaredProperty("PointerOffset"); + + // .NET < 4.5.1 + if (s_lazyPointerOffset == null) + { + s_lazyInternalViewField = s_lazyMemoryMappedViewAccessorType.GetTypeInfo().GetDeclaredField("m_view"); + if (s_lazyInternalViewField == null) + { + return false; + } + + s_lazyInternalPointerOffset = s_lazyInternalViewField.FieldType.GetTypeInfo().GetDeclaredProperty("PointerOffset"); + if (s_lazyInternalPointerOffset == null) + { + return false; + } + } + + return true; + } + + internal static IDisposable CreateMemoryMap(Stream stream) + { + Debug.Assert(s_lazyIsAvailable.GetValueOrDefault()); + + try + { + if (s_lazyCreateFromFile != null) + { + return (IDisposable)s_lazyCreateFromFile.Invoke(null, new object[6] + { + stream, // fileStream + null, // mapName + s_LongZero, // capacity + s_MemoryMappedFileAccess_Read, // access + s_HandleInheritability_None, // inheritability + s_True, // leaveOpen + }); + } + else + { + Debug.Assert(s_lazyCreateFromFileClassic != null); + return (IDisposable)s_lazyCreateFromFileClassic.Invoke(null, new object[7] + { + stream, // fileStream + null, // mapName + s_LongZero, // capacity + s_MemoryMappedFileAccess_Read, // access + null, // memoryMappedFileSecurity + s_HandleInheritability_None, // inheritability + s_True, // leaveOpen + }); + } + } + catch (MemberAccessException) + { + s_lazyIsAvailable = false; + return null; + } + catch (TargetInvocationException ex) + { + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + throw; + } + } + + internal static IDisposable CreateViewAccessor(object memoryMap, long start, int size) + { + Debug.Assert(s_lazyIsAvailable.GetValueOrDefault()); + try + { + return (IDisposable)s_lazyCreateViewAccessor.Invoke(memoryMap, new object[3] + { + start, // start + (long)size, // size + s_MemoryMappedFileAccess_Read, // access + }); + } + catch (MemberAccessException) + { + s_lazyIsAvailable = false; + return null; + } + catch (TargetInvocationException ex) + { + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + throw; + } + } + + internal unsafe static byte* AcquirePointer(object accessor, out SafeBuffer safeBuffer) + { + Debug.Assert(s_lazyIsAvailable.GetValueOrDefault()); + + safeBuffer = (SafeBuffer)s_lazySafeMemoryMappedViewHandle.GetValue(accessor); + + byte* ptr = null; + safeBuffer.AcquirePointer(ref ptr); + + long offset; + if (s_lazyPointerOffset != null) + { + offset = (long)s_lazyPointerOffset.GetValue(accessor); + } + else + { + object internalView = s_lazyInternalViewField.GetValue(accessor); + offset = (long)s_lazyInternalPointerOffset.GetValue(internalView); + } + + return ptr + offset; + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ObjectPool`1.cs b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ObjectPool`1.cs new file mode 100644 index 0000000..8fd87a4 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ObjectPool`1.cs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; + +namespace System.Reflection.Internal +{ + /// + /// Generic implementation of object pooling pattern with predefined pool size limit. The main + /// purpose is that limited number of frequently used objects can be kept in the pool for + /// further recycling. + /// + /// Notes: + /// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there + /// is no space in the pool, extra returned objects will be dropped. + /// + /// 2) it is implied that if object was obtained from a pool, the caller will return it back in + /// a relatively short time. Keeping checked out objects for long durations is ok, but + /// reduces usefulness of pooling. Just new up your own. + /// + /// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice. + /// Rationale: + /// If there is no intent for reusing the object, do not use pool - just use "new". + /// + internal sealed class ObjectPool where T : class + { + private struct Element + { + internal T Value; + } + + // storage for the pool objects. + private readonly Element[] _items; + + // factory is stored for the lifetime of the pool. We will call this only when pool needs to + // expand. compared to "new T()", Func gives more flexibility to implementers and faster + // than "new T()". + private readonly Func _factory; + + + internal ObjectPool(Func factory) + : this(factory, Environment.ProcessorCount * 2) + { } + + internal ObjectPool(Func factory, int size) + { + _factory = factory; + _items = new Element[size]; + } + + private T CreateInstance() + { + var inst = _factory(); + return inst; + } + + /// + /// Produces an instance. + /// + /// + /// Search strategy is a simple linear probing which is chosen for it cache-friendliness. + /// Note that Free will try to store recycled objects close to the start thus statistically + /// reducing how far we will typically search. + /// + internal T Allocate() + { + var items = _items; + T inst; + + for (int i = 0; i < items.Length; i++) + { + // Note that the read is optimistically not synchronized. That is intentional. + // We will interlock only when we have a candidate. in a worst case we may miss some + // recently returned objects. Not a big deal. + inst = items[i].Value; + if (inst != null) + { + if (inst == Interlocked.CompareExchange(ref items[i].Value, null, inst)) + { + goto gotInstance; + } + } + } + + inst = CreateInstance(); + gotInstance: + + return inst; + } + + /// + /// Returns objects to the pool. + /// + /// + /// Search strategy is a simple linear probing which is chosen for it cache-friendliness. + /// Note that Free will try to store recycled objects close to the start thus statistically + /// reducing how far we will typically search in Allocate. + /// + internal void Free(T obj) + { + var items = _items; + for (int i = 0; i < items.Length; i++) + { + if (items[i].Value == null) + { + // Intentionally not using interlocked here. + // In a worst case scenario two objects may be stored into same slot. + // It is very unlikely to happen and will only mean that one of the objects will get collected. + items[i].Value = obj; + break; + } + } + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ReadOnlyUnmanagedMemoryStream.cs b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ReadOnlyUnmanagedMemoryStream.cs new file mode 100644 index 0000000..ec5b7e3 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/ReadOnlyUnmanagedMemoryStream.cs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Runtime.InteropServices; + +namespace System.Reflection.Internal +{ + internal unsafe sealed class ReadOnlyUnmanagedMemoryStream : Stream + { + private readonly byte* _data; + private readonly int _length; + private int _position; + + public ReadOnlyUnmanagedMemoryStream(byte* data, int length) + { + _data = data; + _length = length; + } + + public unsafe override int ReadByte() + { + if (_position == _length) + { + return -1; + } + + return _data[_position++]; + } + + public override int Read(byte[] buffer, int offset, int count) + { + int bytesRead = Math.Min(count, _length - _position); + Marshal.Copy((IntPtr)(_data + _position), buffer, offset, bytesRead); + _position += bytesRead; + return bytesRead; + } + + public override void Flush() + { + } + + public override bool CanRead + { + get + { + return true; + } + } + + public override bool CanSeek + { + get + { + return true; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override long Length + { + get + { + return _length; + } + } + + public override long Position + { + get + { + return _position; + } + + set + { + Seek(value, SeekOrigin.Begin); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + long target; + try + { + switch (origin) + { + case SeekOrigin.Begin: + target = offset; + break; + + case SeekOrigin.Current: + target = checked(offset + _position); + break; + + case SeekOrigin.End: + target = checked(offset + _length); + break; + + default: + throw new ArgumentOutOfRangeException("origin"); + } + } + catch (OverflowException) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (target < 0 || target >= _length) + { + throw new ArgumentOutOfRangeException("offset"); + } + + _position = (int)target; + return target; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/StreamExtensions.cs b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/StreamExtensions.cs new file mode 100644 index 0000000..9dd3ad0 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Internal/Utilities/StreamExtensions.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Reflection.Metadata; +using System.Runtime.InteropServices; + +namespace System.Reflection.Internal +{ + internal static class StreamExtensions + { + // From System.IO.Stream.CopyTo: + // We pick a value that is the largest multiple of 4096 that is still smaller than the large object heap threshold (85K). + // The CopyTo/CopyToAsync buffer is short-lived and is likely to be collected at Gen0, and it offers a significant + // improvement in Copy performance. + internal const int StreamCopyBufferSize = 81920; + + /// + /// Copies specified amount of data from given stream to a target memory pointer. + /// + /// unexpected stream end. + internal static unsafe void CopyTo(this Stream source, byte* destination, int size) + { + byte[] buffer = new byte[Math.Min(StreamCopyBufferSize, size)]; + while (size > 0) + { + int readSize = Math.Min(size, buffer.Length); + int bytesRead = source.Read(buffer, 0, readSize); + + if (bytesRead <= 0 || bytesRead > readSize) + { + throw new IOException(MetadataResources.UnexpectedStreamEnd); + } + + Marshal.Copy(buffer, 0, (IntPtr)destination, bytesRead); + + destination += bytesRead; + size -= bytesRead; + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyDefinition.cs new file mode 100644 index 0000000..4ad0ea8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyDefinition.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct AssemblyDefinition + { + private readonly MetadataReader _reader; + + internal AssemblyDefinition(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + } + + private Handle Handle + { + get + { + return Handle.AssemblyDefinition; + } + } + + public AssemblyHashAlgorithm HashAlgorithm + { + get + { + return _reader.AssemblyTable.GetHashAlgorithm(); + } + } + + public Version Version + { + get + { + return _reader.AssemblyTable.GetVersion(); + } + } + + public AssemblyFlags Flags + { + get + { + return _reader.AssemblyTable.GetFlags(); + } + } + + public StringHandle Name + { + get + { + return _reader.AssemblyTable.GetName(); + } + } + + public StringHandle Culture + { + get + { + return _reader.AssemblyTable.GetCulture(); + } + } + + public BlobHandle PublicKey + { + get + { + return _reader.AssemblyTable.GetPublicKey(); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + public DeclarativeSecurityAttributeHandleCollection GetDeclarativeSecurityAttributes() + { + return new DeclarativeSecurityAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyFile.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyFile.cs new file mode 100644 index 0000000..5d51f06 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyFile.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct AssemblyFile + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal AssemblyFile(MetadataReader reader, AssemblyFileHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private AssemblyFileHandle Handle + { + get { return AssemblyFileHandle.FromRowId(_rowId); } + } + + /// + /// True if the file contains metadata. + /// + /// + /// Corresponds to Flags field of File table in ECMA-335 Standard. + /// + public bool ContainsMetadata + { + get { return _reader.FileTable.GetFlags(Handle) == 0; } + } + + /// + /// File name with extension. + /// + /// + /// Corresponds to Name field of File table in ECMA-335 Standard. + /// + public StringHandle Name + { + get { return _reader.FileTable.GetName(Handle); } + } + + /// + /// Hash value of the file content calculated using . + /// + /// + /// Corresponds to HashValue field of File table in ECMA-335 Standard. + /// + public BlobHandle HashValue + { + get { return _reader.FileTable.GetHashValue(Handle); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyReference.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyReference.cs new file mode 100644 index 0000000..9d89319 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/AssemblyReference.cs @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct AssemblyReference + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use raw uint. + private readonly uint _treatmentAndRowId; + + private static readonly Version s_version_4_0_0_0 = new Version(4, 0, 0, 0); + + internal AssemblyReference(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + // only virtual bit can be set in highest byte: + Debug.Assert((treatmentAndRowId & ~(TokenTypeIds.VirtualTokenMask | TokenTypeIds.RIDMask)) == 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private bool IsVirtual + { + get { return (_treatmentAndRowId & TokenTypeIds.VirtualTokenMask) != 0; } + } + + public Version Version + { + get + { + if (IsVirtual) + { + return GetVirtualVersion(); + } + + // change mscorlib version: + if (RowId == _reader.WinMDMscorlibRef) + { + return s_version_4_0_0_0; + } + + return _reader.AssemblyRefTable.GetVersion(RowId); + } + } + + public AssemblyFlags Flags + { + get + { + if (IsVirtual) + { + return GetVirtualFlags(); + } + + return _reader.AssemblyRefTable.GetFlags(RowId); + } + } + + public StringHandle Name + { + get + { + if (IsVirtual) + { + return GetVirtualName(); + } + + return _reader.AssemblyRefTable.GetName(RowId); + } + } + + public StringHandle Culture + { + get + { + if (IsVirtual) + { + return GetVirtualCulture(); + } + + return _reader.AssemblyRefTable.GetCulture(RowId); + } + } + + public BlobHandle PublicKeyOrToken + { + get + { + if (IsVirtual) + { + return GetVirtualPublicKeyOrToken(); + } + + return _reader.AssemblyRefTable.GetPublicKeyOrToken(RowId); + } + } + + public BlobHandle HashValue + { + get + { + if (IsVirtual) + { + return GetVirtualHashValue(); + } + + return _reader.AssemblyRefTable.GetHashValue(RowId); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + if (IsVirtual) + { + return GetVirtualCustomAttributes(); + } + + return new CustomAttributeHandleCollection(_reader, AssemblyReferenceHandle.FromRowId(RowId)); + } + + #region Virtual Rows + private Version GetVirtualVersion() + { + // currently all projected assembly references have version 4.0.0.0 + return s_version_4_0_0_0; + } + + private AssemblyFlags GetVirtualFlags() + { + // use flags from mscorlib ref (specifically PublicKey flag): + return _reader.AssemblyRefTable.GetFlags(_reader.WinMDMscorlibRef); + } + + private StringHandle GetVirtualName() + { + return StringHandle.FromVirtualIndex(GetVirtualNameIndex((AssemblyReferenceHandle.VirtualIndex)RowId)); + } + + private StringHandle.VirtualIndex GetVirtualNameIndex(AssemblyReferenceHandle.VirtualIndex index) + { + switch (index) + { + case AssemblyReferenceHandle.VirtualIndex.System_ObjectModel: + return StringHandle.VirtualIndex.System_ObjectModel; + + case AssemblyReferenceHandle.VirtualIndex.System_Runtime: + return StringHandle.VirtualIndex.System_Runtime; + + case AssemblyReferenceHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime: + return StringHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime; + + case AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime: + return StringHandle.VirtualIndex.System_Runtime_WindowsRuntime; + + case AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml: + return StringHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml; + + case AssemblyReferenceHandle.VirtualIndex.System_Numerics_Vectors: + return StringHandle.VirtualIndex.System_Numerics_Vectors; + } + + Debug.Assert(false, "Unexpected virtual index value"); + return 0; + } + + private StringHandle GetVirtualCulture() + { + return default(StringHandle); + } + + private BlobHandle GetVirtualPublicKeyOrToken() + { + switch ((AssemblyReferenceHandle.VirtualIndex)RowId) + { + case AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime: + case AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml: + // use key or token from mscorlib ref: + return _reader.AssemblyRefTable.GetPublicKeyOrToken(_reader.WinMDMscorlibRef); + + default: + // use contract assembly key or token: + var hasFullKey = (_reader.AssemblyRefTable.GetFlags(_reader.WinMDMscorlibRef) & AssemblyFlags.PublicKey) != 0; + return BlobHandle.FromVirtualIndex(hasFullKey ? BlobHandle.VirtualIndex.ContractPublicKey : BlobHandle.VirtualIndex.ContractPublicKeyToken, 0); + } + } + + private BlobHandle GetVirtualHashValue() + { + return default(BlobHandle); + } + + private CustomAttributeHandleCollection GetVirtualCustomAttributes() + { + // return custom attributes applied on mscorlib ref + return new CustomAttributeHandleCollection(_reader, AssemblyReferenceHandle.FromRowId(_reader.WinMDMscorlibRef)); + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/BlobReader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/BlobReader.cs new file mode 100644 index 0000000..f1573b8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/BlobReader.cs @@ -0,0 +1,519 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Internal; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata +{ + [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] + public unsafe struct BlobReader + { + /// An array containing the '\0' character. + private static readonly char[] _nullCharArray = new char[1] { '\0' }; + + internal const int InvalidCompressedInteger = Int32.MaxValue; + + private readonly MemoryBlock _block; + + // Points right behind the last byte of the block. + private readonly byte* _endPointer; + + private byte* _currentPointer; + + public unsafe BlobReader(byte* buffer, int length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (buffer == null && length != 0) + { + throw new ArgumentNullException("buffer"); + } + + // the reader performs little-endian specific operations + if (!BitConverter.IsLittleEndian) + { + throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); + } + + this = new BlobReader(new MemoryBlock(buffer, length)); + } + + internal BlobReader(MemoryBlock block) + { + Debug.Assert(BitConverter.IsLittleEndian && block.Length >= 0 && (block.Pointer != null || block.Length == 0)); + _block = block; + _currentPointer = block.Pointer; + _endPointer = block.Pointer + block.Length; + } + + private string GetDebuggerDisplay() + { + if (_block.Pointer == null) + { + return ""; + } + + int displayedBytes; + string display = _block.GetDebuggerDisplay(out displayedBytes); + if (this.Offset < displayedBytes) + { + display = display.Insert(this.Offset * 3, "*"); + } + else if (displayedBytes == _block.Length) + { + display += "*"; + } + else + { + display += "*..."; + } + + return display; + } + + #region Offset, Skipping, Marking, Alignment, Bounds Checking + + public int Length + { + get + { + return _block.Length; + } + } + + public int Offset + { + get + { + return (int)(_currentPointer - _block.Pointer); + } + } + + public int RemainingBytes + { + get + { + return (int)(_endPointer - _currentPointer); + } + } + + public void Reset() + { + _currentPointer = _block.Pointer; + } + + internal bool SeekOffset(int offset) + { + if (unchecked((uint)offset) >= (uint)_block.Length) + { + return false; + } + + _currentPointer = _block.Pointer + offset; + return true; + } + + internal void SkipBytes(int count) + { + GetCurrentPointerAndAdvance(count); + } + + internal void Align(byte alignment) + { + if (!TryAlign(alignment)) + { + ThrowOutOfBounds(); + } + } + + internal bool TryAlign(byte alignment) + { + int remainder = this.Offset & (alignment - 1); + + Debug.Assert((alignment & (alignment - 1)) == 0, "Alignment must be a power of two."); + Debug.Assert(remainder >= 0 && remainder < alignment); + + if (remainder != 0) + { + int bytesToSkip = alignment - remainder; + if (bytesToSkip > RemainingBytes) + { + return false; + } + _currentPointer += bytesToSkip; + } + return true; + } + + internal MemoryBlock GetMemoryBlockAt(int offset, int length) + { + CheckBounds(offset, length); + return new MemoryBlock(_currentPointer + offset, length); + } + #endregion + + #region Bounds Checking + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowOutOfBounds() + { + throw new BadImageFormatException(MetadataResources.OutOfBoundsRead); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CheckBounds(int offset, int byteCount) + { + if (unchecked((ulong)(uint)offset + (uint)byteCount) > (ulong)(_endPointer - _currentPointer)) + { + ThrowOutOfBounds(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CheckBounds(int byteCount) + { + if (unchecked((uint)byteCount) > (_endPointer - _currentPointer)) + { + ThrowOutOfBounds(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte* GetCurrentPointerAndAdvance(int length) + { + byte* p = _currentPointer; + + if (unchecked((uint)length) > (uint)(_endPointer - p)) + { + ThrowOutOfBounds(); + } + + _currentPointer = p + length; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte* GetCurrentPointerAndAdvance1() + { + byte* p = _currentPointer; + + if (p == _endPointer) + { + ThrowOutOfBounds(); + } + + _currentPointer = p + 1; + return p; + } + + #endregion + + #region Read Methods + + public bool ReadBoolean() + { + return ReadByte() == 1; + } + + public SByte ReadSByte() + { + return *(SByte*)GetCurrentPointerAndAdvance1(); + } + + public Byte ReadByte() + { + return *(Byte*)GetCurrentPointerAndAdvance1(); + } + + public Char ReadChar() + { + return *(Char*)GetCurrentPointerAndAdvance(sizeof(Char)); + } + + public Int16 ReadInt16() + { + return *(Int16*)GetCurrentPointerAndAdvance(sizeof(Int16)); + } + + public UInt16 ReadUInt16() + { + return *(UInt16*)GetCurrentPointerAndAdvance(sizeof(UInt16)); + } + + public Int32 ReadInt32() + { + return *(Int32*)GetCurrentPointerAndAdvance(sizeof(Int32)); + } + + public UInt32 ReadUInt32() + { + return *(UInt32*)GetCurrentPointerAndAdvance(sizeof(UInt32)); + } + + public Int64 ReadInt64() + { + return *(Int64*)GetCurrentPointerAndAdvance(sizeof(Int64)); + } + + public UInt64 ReadUInt64() + { + return *(UInt64*)GetCurrentPointerAndAdvance(sizeof(UInt64)); + } + + public Single ReadSingle() + { + return *(Single*)GetCurrentPointerAndAdvance(sizeof(Single)); + } + + public Double ReadDouble() + { + return *(Double*)GetCurrentPointerAndAdvance(sizeof(UInt64)); + } + + public SignatureHeader ReadSignatureHeader() + { + return new SignatureHeader(ReadByte()); + } + + /// + /// Reads UTF8 encoded string starting at the current position. + /// + /// The number of bytes to read. + /// The string. + /// bytes not available. + public string ReadUTF8(int byteCount) + { + string s = _block.PeekUtf8(this.Offset, byteCount); + _currentPointer += byteCount; + return s; + } + + /// + /// Reads UTF16 (little-endian) encoded string starting at the current position. + /// + /// The number of bytes to read. + /// The string. + /// bytes not available. + public string ReadUTF16(int byteCount) + { + string s = _block.PeekUtf16(this.Offset, byteCount); + _currentPointer += byteCount; + return s; + } + + /// + /// Reads bytes starting at the current position. + /// + /// The number of bytes to read. + /// The byte array. + /// bytes not available. + public byte[] ReadBytes(int byteCount) + { + byte[] bytes = _block.PeekBytes(this.Offset, byteCount); + _currentPointer += byteCount; + return bytes; + } + + internal string ReadUtf8NullTerminated() + { + int bytesRead; + string value = _block.PeekUtf8NullTerminated(this.Offset, null, MetadataStringDecoder.DefaultUTF8, out bytesRead, '\0'); + _currentPointer += bytesRead; + return value; + } + + private int ReadCompressedIntegerOrInvalid() + { + int bytesRead; + int value = _block.PeekCompressedInteger(this.Offset, out bytesRead); + _currentPointer += bytesRead; + return value; + } + + /// + /// Reads an unsigned compressed integer value. + /// See Metadata Specification section II.23.2: Blobs and signatures. + /// + /// The value of the compressed integer that was read. + /// true if the value was read successfully. false if the data at the current position was not a valid compressed integer. + public bool TryReadCompressedInteger(out int value) + { + value = ReadCompressedIntegerOrInvalid(); + return value != InvalidCompressedInteger; + } + + /// + /// Reads an unsigned compressed integer value. + /// See Metadata Specification section II.23.2: Blobs and signatures. + /// + /// The value of the compressed integer that was read. + /// The data at the current position was not a valid compressed integer. + public int ReadCompressedInteger() + { + int value; + if (!TryReadCompressedInteger(out value)) + { + ThrowInvalidCompressedInteger(); + } + return value; + } + + /// + /// Reads a signed compressed integer value. + /// See Metadata Specification section II.23.2: Blobs and signatures. + /// + /// The value of the compressed integer that was read. + /// true if the value was read successfully. false if the data at the current position was not a valid compressed integer. + public bool TryReadCompressedSignedInteger(out int value) + { + int bytesRead; + value = _block.PeekCompressedInteger(this.Offset, out bytesRead); + + if (value == InvalidCompressedInteger) + { + return false; + } + + bool signExtend = (value & 0x1) != 0; + value >>= 1; + + if (signExtend) + { + switch (bytesRead) + { + case 1: + value |= unchecked((int)0xffffffc0); + break; + case 2: + value |= unchecked((int)0xffffe000); + break; + default: + Debug.Assert(bytesRead == 4); + value |= unchecked((int)0xf0000000); + break; + } + } + + _currentPointer += bytesRead; + return true; + } + + /// + /// Reads a signed compressed integer value. + /// See Metadata Specification section II.23.2: Blobs and signatures. + /// + /// The value of the compressed integer that was read. + /// The data at the current position was not a valid compressed integer. + public int ReadCompressedSignedInteger() + { + int value; + if (!TryReadCompressedSignedInteger(out value)) + { + ThrowInvalidCompressedInteger(); + } + return value; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowInvalidCompressedInteger() + { + throw new BadImageFormatException(MetadataResources.InvalidCompressedInteger); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowInvalidSerializedString() + { + throw new BadImageFormatException(MetadataResources.InvalidSerializedString); + } + + /// + /// Reads type code encoded in a serialized custom attribute value. + /// + /// if the encoding is invalid. + public SerializationTypeCode ReadSerializationTypeCode() + { + int value = ReadCompressedIntegerOrInvalid(); + if (value > byte.MaxValue) + { + return SerializationTypeCode.Invalid; + } + + return unchecked((SerializationTypeCode)value); + } + + /// + /// Reads type code encoded in a signature. + /// + /// if the encoding is invalid. + public SignatureTypeCode ReadSignatureTypeCode() + { + int value = ReadCompressedIntegerOrInvalid(); + + switch (value) + { + case (int)CorElementType.ELEMENT_TYPE_CLASS: + case (int)CorElementType.ELEMENT_TYPE_VALUETYPE: + return SignatureTypeCode.TypeHandle; + + default: + if (value > byte.MaxValue) + { + return SignatureTypeCode.Invalid; + } + + return unchecked((SignatureTypeCode)value); + } + } + + /// + /// Reads a string encoded as a compressed integer containing its length followed by + /// its contents in UTF8. Null strings are encoded as a single 0xFF byte. + /// + /// Defined as a 'SerString' in the Ecma CLI specification. + /// String value or null. + /// If the encoding is invalid. + public string ReadSerializedString() + { + int length; + if (TryReadCompressedInteger(out length)) + { + // Removal of trailing '\0' is a departure from the spec, but required + // for compatibility with legacy compilers. + return ReadUTF8(length).TrimEnd(_nullCharArray); + } + + if (ReadByte() != 0xFF) + { + ThrowInvalidSerializedString(); + } + + return null; + } + + /// + /// Reads a type handle encoded in a signature as TypeDefOrRefOrSpecEncoded (see ECMA-335 II.23.2.8). + /// + /// The handle or nil if the encoding is invalid. + public Handle ReadTypeHandle() + { + uint value = (uint)ReadCompressedIntegerOrInvalid(); + uint tokenType = s_corEncodeTokenArray[value & 0x3]; + + if (value == InvalidCompressedInteger || tokenType == 0) + { + return default(Handle); + } + + return new Handle(tokenType | (value >> 2)); + } + + private static readonly uint[] s_corEncodeTokenArray = new uint[] { TokenTypeIds.TypeDef, TokenTypeIds.TypeRef, TokenTypeIds.TypeSpec, 0 }; + #endregion + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Constant.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Constant.cs new file mode 100644 index 0000000..d5a2349 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Constant.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct Constant + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal Constant(MetadataReader reader, uint rowId) + { + Debug.Assert(reader != null); + Debug.Assert(rowId != 0); + + _reader = reader; + _rowId = rowId; + } + + private ConstantHandle Handle + { + get + { + return ConstantHandle.FromRowId(_rowId); + } + } + + /// + /// The type of the constant value. + /// + /// + /// Corresponds to Type field of Constant table in ECMA-335 Standard. + /// + public ConstantTypeCode TypeCode + { + get + { + return _reader.ConstantTable.GetType(Handle); + } + } + + /// + /// The constant value. + /// + /// + /// Corresponds to Value field of Constant table in ECMA-335 Standard. + /// + public BlobHandle Value + { + get + { + return _reader.ConstantTable.GetValue(Handle); + } + } + + /// + /// The parent handle (, , or ). + /// + /// + /// Corresponds to Parent field of Constant table in ECMA-335 Standard. + /// + public Handle Parent + { + get + { + return _reader.ConstantTable.GetParent(Handle); + } + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ConstantTypeCode.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ConstantTypeCode.cs new file mode 100644 index 0000000..86dfbf7 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ConstantTypeCode.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public enum ConstantTypeCode : byte + { + // II.22.9 Constant : 0x0B + // Type shall be exactly one of: ELEMENT_TYPE_BOOLEAN, ELEMENT_TYPE_CHAR, + // ELEMENT_TYPE_I1, ELEMENT_TYPE_U1, ELEMENT_TYPE_I2, ELEMENT_TYPE_U2, + // ELEMENT_TYPE_I4, ELEMENT_TYPE_U4, ELEMENT_TYPE_I8, ELEMENT_TYPE_U8, + // ELEMENT_TYPE_R4, ELEMENT_TYPE_R8, or ELEMENT_TYPE_STRING; or + // ELEMENT_TYPE_CLASS with a Value of zero (Section II.23.1.16) + Invalid = 0, + + Boolean = CorElementType.ELEMENT_TYPE_BOOLEAN, + Char = CorElementType.ELEMENT_TYPE_CHAR, + SByte = CorElementType.ELEMENT_TYPE_I1, + Byte = CorElementType.ELEMENT_TYPE_U1, + Int16 = CorElementType.ELEMENT_TYPE_I2, + UInt16 = CorElementType.ELEMENT_TYPE_U2, + Int32 = CorElementType.ELEMENT_TYPE_I4, + UInt32 = CorElementType.ELEMENT_TYPE_U4, + Int64 = CorElementType.ELEMENT_TYPE_I8, + UInt64 = CorElementType.ELEMENT_TYPE_U8, + Single = CorElementType.ELEMENT_TYPE_R4, + Double = CorElementType.ELEMENT_TYPE_R8, + String = CorElementType.ELEMENT_TYPE_STRING, + NullReference = CorElementType.ELEMENT_TYPE_CLASS, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttribute.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttribute.cs new file mode 100644 index 0000000..efe430d --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttribute.cs @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct CustomAttribute + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal CustomAttribute(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private CustomAttributeHandle Handle + { + get { return CustomAttributeHandle.FromRowId(RowId); } + } + + private MethodDefTreatment Treatment + { + get { return (MethodDefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + /// + /// The constructor ( or ) of the custom attribute type. + /// + /// + /// Corresponds to Type field of CustomAttribute table in ECMA-335 Standard. + /// + public Handle Constructor + { + get + { + return _reader.CustomAttributeTable.GetConstructor(Handle); + } + } + + /// + /// The handle of the metadata entity the attribute is applied to. + /// + /// + /// Corresponds to Parent field of CustomAttribute table in ECMA-335 Standard. + /// + public Handle Parent + { + get + { + return _reader.CustomAttributeTable.GetParent(Handle); + } + } + + /// + /// The value of the attribute. + /// + /// + /// Corresponds to Value field of CustomAttribute table in ECMA-335 Standard. + /// + public BlobHandle Value + { + get + { + if (Treatment == 0) + { + return _reader.CustomAttributeTable.GetValue(Handle); + } + + return GetProjectedValue(); + } + } + + #region Projections + + private BlobHandle GetProjectedValue() + { + // The usual pattern for accessing custom attributes differs from pattern for accessing e.g. TypeDef row fields. + // The value blob is only accessed when the consumer is about to decode it (which is a nontrivial process), + // while the Constructor and Parent fields are often accessed when searching for a particular attribute. + // + // The current WinMD projections only affect the blob and not the Constructor and Parent values. + // It is thus more efficient to calculate the treatment here (and make GetValue more expensive) and + // avoid calculating the treatment when the CustomAttributeHandle is looked up and CustomAttribute struct + // is initialized. + + CustomAttributeValueTreatment treatment = _reader.CalculateCustomAttributeValueTreatment(Handle); + if (treatment == 0) + { + return _reader.CustomAttributeTable.GetValue(Handle); + } + + return GetProjectedValue(treatment); + } + + private BlobHandle GetProjectedValue(CustomAttributeValueTreatment treatment) + { + BlobHandle.VirtualIndex virtualIndex; + bool isVersionOrDeprecated; + switch (treatment) + { + case CustomAttributeValueTreatment.AttributeUsageVersionAttribute: + case CustomAttributeValueTreatment.AttributeUsageDeprecatedAttribute: + virtualIndex = BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple; + isVersionOrDeprecated = true; + break; + + case CustomAttributeValueTreatment.AttributeUsageAllowMultiple: + virtualIndex = BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple; + isVersionOrDeprecated = false; + break; + + case CustomAttributeValueTreatment.AttributeUsageAllowSingle: + virtualIndex = BlobHandle.VirtualIndex.AttributeUsage_AllowSingle; + isVersionOrDeprecated = false; + break; + + default: + Debug.Assert(false); + return default(BlobHandle); + } + + // Raw blob format: + // 01 00 - Fixed prolog for CA's + // xx xx xx xx - The Windows.Foundation.Metadata.AttributeTarget value + // 00 00 - Indicates 0 name/value pairs following. + var rawBlob = _reader.CustomAttributeTable.GetValue(Handle); + var rawBlobReader = _reader.GetBlobReader(rawBlob); + if (rawBlobReader.Length != 8) + { + return rawBlob; + } + + if (rawBlobReader.ReadInt16() != 1) + { + return rawBlob; + } + + AttributeTargets projectedValue = ProjectAttributeTargetValue(rawBlobReader.ReadUInt32()); + if (isVersionOrDeprecated) + { + projectedValue |= AttributeTargets.Constructor | AttributeTargets.Property; + } + + return BlobHandle.FromVirtualIndex(virtualIndex, (ushort)projectedValue); + } + + private static AttributeTargets ProjectAttributeTargetValue(uint rawValue) + { + // Windows.Foundation.Metadata.AttributeTargets.All + if (rawValue == 0xffffffff) + { + return AttributeTargets.All; + } + + AttributeTargets result = 0; + + if ((rawValue & 0x00000001) != 0) result |= AttributeTargets.Delegate; + if ((rawValue & 0x00000002) != 0) result |= AttributeTargets.Enum; + if ((rawValue & 0x00000004) != 0) result |= AttributeTargets.Event; + if ((rawValue & 0x00000008) != 0) result |= AttributeTargets.Field; + if ((rawValue & 0x00000010) != 0) result |= AttributeTargets.Interface; + // InterfaceGroup (no equivalent in CLR) + if ((rawValue & 0x00000040) != 0) result |= AttributeTargets.Method; + if ((rawValue & 0x00000080) != 0) result |= AttributeTargets.Parameter; + if ((rawValue & 0x00000100) != 0) result |= AttributeTargets.Property; + if ((rawValue & 0x00000200) != 0) result |= AttributeTargets.Class; + if ((rawValue & 0x00000400) != 0) result |= AttributeTargets.Struct; + // InterfaceImpl (no equivalent in CLR) + + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttributeNamedArgumentKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttributeNamedArgumentKind.cs new file mode 100644 index 0000000..9839c8f --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/CustomAttributeNamedArgumentKind.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public enum CustomAttributeNamedArgumentKind : byte + { + Field = 0x53, + Property = 0x54, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/DeclarativeSecurityAttribute.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/DeclarativeSecurityAttribute.cs new file mode 100644 index 0000000..a1b4a60 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/DeclarativeSecurityAttribute.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct DeclarativeSecurityAttribute + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal DeclarativeSecurityAttribute(MetadataReader reader, uint rowId) + { + Debug.Assert(reader != null); + Debug.Assert(rowId != 0); + + _reader = reader; + _rowId = rowId; + } + + private uint RowId + { + get { return _rowId & TokenTypeIds.RIDMask; } + } + + private DeclarativeSecurityAttributeHandle Handle + { + get { return DeclarativeSecurityAttributeHandle.FromRowId(RowId); } + } + + private MethodDefTreatment Treatment + { + get { return (MethodDefTreatment)(_rowId >> TokenTypeIds.RowIdBitCount); } + } + + public DeclarativeSecurityAction Action + { + get + { + return _reader.DeclSecurityTable.GetAction(_rowId); + } + } + + public Handle Parent + { + get + { + return _reader.DeclSecurityTable.GetParent(_rowId); + } + } + + public BlobHandle PermissionSet + { + get + { + return _reader.DeclSecurityTable.GetPermissionSet(_rowId); + } + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueLogEntry.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueLogEntry.cs new file mode 100644 index 0000000..143a64c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueLogEntry.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + public struct EditAndContinueLogEntry : IEquatable + { + public readonly Handle Handle; + public readonly EditAndContinueOperation Operation; + + public EditAndContinueLogEntry(Handle handle, EditAndContinueOperation operation) + { + this.Handle = handle; + this.Operation = operation; + } + + public override bool Equals(object obj) + { + return obj is EditAndContinueLogEntry && Equals((EditAndContinueLogEntry)obj); + } + + public bool Equals(EditAndContinueLogEntry other) + { + return this.Operation == other.Operation && + this.Handle == other.Handle; + } + + public override int GetHashCode() + { + return (int)Operation ^ Handle.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueOperation.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueOperation.cs new file mode 100644 index 0000000..748124b --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/EditAndContinueOperation.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + public enum EditAndContinueOperation + { + Default = 0, + AddMethod = 1, + AddField = 2, + AddParameter = 3, + AddProperty = 4, + AddEvent = 5, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/ExportedTypeExtensions.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/ExportedTypeExtensions.cs new file mode 100644 index 0000000..d3c1a06 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/ExportedTypeExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + /// + /// Provides an extension method to access the TypeDefinitionId column of the ExportedType table. + /// + public static class ExportedTypeExtensions + { + /// + /// Gets a hint at the likely row number of the target type in the TypeDef table of its module. + /// If the namespaces and names do not match, resolution falls back to a full search of the + /// target TypeDef table. Ignored and should be zero if is + /// true. + /// + public static int GetTypeDefinitionId(this ExportedType exportedType) + { + return (int)exportedType.reader.ExportedTypeTable.GetTypeDefId(exportedType.rowId); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/HeapIndex.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/HeapIndex.cs new file mode 100644 index 0000000..d6e3721 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/HeapIndex.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + public enum HeapIndex + { + UserString, + String, + Blob, + Guid + } + + internal static class HeapIndexExtensions + { + internal const int Count = (int)HeapIndex.Guid + 1; + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataReaderExtensions.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataReaderExtensions.cs new file mode 100644 index 0000000..3ac3f15 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataReaderExtensions.cs @@ -0,0 +1,348 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Internal; + +namespace System.Reflection.Metadata.Ecma335 +{ + /// + /// Provides extension methods for working with certain raw elements of the Ecma 335 metadata tables and heaps. + /// + public static class MetadataReaderExtensions + { + /// + /// Returns the number of rows in the specified table. + /// + /// is null. + /// is not a valid table index. + public static int GetTableRowCount(this MetadataReader reader, TableIndex tableIndex) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + if ((int)tableIndex >= TableIndexExtensions.Count) + { + throw new ArgumentOutOfRangeException("tableIndex"); + } + + return (int)reader.TableRowCounts[(int)tableIndex]; + } + + /// + /// Returns the size of a row in the specified table. + /// + /// is null. + /// is not a valid table index. + public static int GetTableRowSize(this MetadataReader reader, TableIndex tableIndex) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + switch (tableIndex) + { + case TableIndex.Module: return reader.ModuleTable.RowSize; + case TableIndex.TypeRef: return reader.TypeRefTable.RowSize; + case TableIndex.TypeDef: return reader.TypeDefTable.RowSize; + case TableIndex.FieldPtr: return reader.FieldPtrTable.RowSize; + case TableIndex.Field: return reader.FieldTable.RowSize; + case TableIndex.MethodPtr: return reader.MethodPtrTable.RowSize; + case TableIndex.MethodDef: return reader.MethodDefTable.RowSize; + case TableIndex.ParamPtr: return reader.ParamPtrTable.RowSize; + case TableIndex.Param: return reader.ParamTable.RowSize; + case TableIndex.InterfaceImpl: return reader.InterfaceImplTable.RowSize; + case TableIndex.MemberRef: return reader.MemberRefTable.RowSize; + case TableIndex.Constant: return reader.ConstantTable.RowSize; + case TableIndex.CustomAttribute: return reader.CustomAttributeTable.RowSize; + case TableIndex.FieldMarshal: return reader.FieldMarshalTable.RowSize; + case TableIndex.DeclSecurity: return reader.DeclSecurityTable.RowSize; + case TableIndex.ClassLayout: return reader.ClassLayoutTable.RowSize; + case TableIndex.FieldLayout: return reader.FieldLayoutTable.RowSize; + case TableIndex.StandAloneSig: return reader.StandAloneSigTable.RowSize; + case TableIndex.EventMap: return reader.EventMapTable.RowSize; + case TableIndex.EventPtr: return reader.EventPtrTable.RowSize; + case TableIndex.Event: return reader.EventTable.RowSize; + case TableIndex.PropertyMap: return reader.PropertyMapTable.RowSize; + case TableIndex.PropertyPtr: return reader.PropertyPtrTable.RowSize; + case TableIndex.Property: return reader.PropertyTable.RowSize; + case TableIndex.MethodSemantics: return reader.MethodSemanticsTable.RowSize; + case TableIndex.MethodImpl: return reader.MethodImplTable.RowSize; + case TableIndex.ModuleRef: return reader.ModuleRefTable.RowSize; + case TableIndex.TypeSpec: return reader.TypeSpecTable.RowSize; + case TableIndex.ImplMap: return reader.ImplMapTable.RowSize; + case TableIndex.FieldRva: return reader.FieldRvaTable.RowSize; + case TableIndex.EncLog: return reader.EncLogTable.RowSize; + case TableIndex.EncMap: return reader.EncMapTable.RowSize; + case TableIndex.Assembly: return reader.AssemblyTable.RowSize; + case TableIndex.AssemblyProcessor: return reader.AssemblyProcessorTable.RowSize; + case TableIndex.AssemblyOS: return reader.AssemblyOSTable.RowSize; + case TableIndex.AssemblyRef: return reader.AssemblyRefTable.RowSize; + case TableIndex.AssemblyRefProcessor: return reader.AssemblyRefProcessorTable.RowSize; + case TableIndex.AssemblyRefOS: return reader.AssemblyRefOSTable.RowSize; + case TableIndex.File: return reader.FileTable.RowSize; + case TableIndex.ExportedType: return reader.ExportedTypeTable.RowSize; + case TableIndex.ManifestResource: return reader.ManifestResourceTable.RowSize; + case TableIndex.NestedClass: return reader.NestedClassTable.RowSize; + case TableIndex.GenericParam: return reader.GenericParamTable.RowSize; + case TableIndex.MethodSpec: return reader.MethodSpecTable.RowSize; + case TableIndex.GenericParamConstraint: return reader.GenericParamConstraintTable.RowSize; + + default: + throw new ArgumentOutOfRangeException("tableIndex"); + } + } + + /// + /// Returns the offset from the start of metadata to the specified table. + /// + /// is null. + /// is not a valid table index. + public static unsafe int GetTableMetadataOffset(this MetadataReader reader, TableIndex tableIndex) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return (int)(reader.GetTableMetadataBlock(tableIndex).Pointer - reader.Block.Pointer); + } + + private static MemoryBlock GetTableMetadataBlock(this MetadataReader reader, TableIndex tableIndex) + { + Debug.Assert(reader != null); + + switch (tableIndex) + { + case TableIndex.Module: return reader.ModuleTable.Block; + case TableIndex.TypeRef: return reader.TypeRefTable.Block; + case TableIndex.TypeDef: return reader.TypeDefTable.Block; + case TableIndex.FieldPtr: return reader.FieldPtrTable.Block; + case TableIndex.Field: return reader.FieldTable.Block; + case TableIndex.MethodPtr: return reader.MethodPtrTable.Block; + case TableIndex.MethodDef: return reader.MethodDefTable.Block; + case TableIndex.ParamPtr: return reader.ParamPtrTable.Block; + case TableIndex.Param: return reader.ParamTable.Block; + case TableIndex.InterfaceImpl: return reader.InterfaceImplTable.Block; + case TableIndex.MemberRef: return reader.MemberRefTable.Block; + case TableIndex.Constant: return reader.ConstantTable.Block; + case TableIndex.CustomAttribute: return reader.CustomAttributeTable.Block; + case TableIndex.FieldMarshal: return reader.FieldMarshalTable.Block; + case TableIndex.DeclSecurity: return reader.DeclSecurityTable.Block; + case TableIndex.ClassLayout: return reader.ClassLayoutTable.Block; + case TableIndex.FieldLayout: return reader.FieldLayoutTable.Block; + case TableIndex.StandAloneSig: return reader.StandAloneSigTable.Block; + case TableIndex.EventMap: return reader.EventMapTable.Block; + case TableIndex.EventPtr: return reader.EventPtrTable.Block; + case TableIndex.Event: return reader.EventTable.Block; + case TableIndex.PropertyMap: return reader.PropertyMapTable.Block; + case TableIndex.PropertyPtr: return reader.PropertyPtrTable.Block; + case TableIndex.Property: return reader.PropertyTable.Block; + case TableIndex.MethodSemantics: return reader.MethodSemanticsTable.Block; + case TableIndex.MethodImpl: return reader.MethodImplTable.Block; + case TableIndex.ModuleRef: return reader.ModuleRefTable.Block; + case TableIndex.TypeSpec: return reader.TypeSpecTable.Block; + case TableIndex.ImplMap: return reader.ImplMapTable.Block; + case TableIndex.FieldRva: return reader.FieldRvaTable.Block; + case TableIndex.EncLog: return reader.EncLogTable.Block; + case TableIndex.EncMap: return reader.EncMapTable.Block; + case TableIndex.Assembly: return reader.AssemblyTable.Block; + case TableIndex.AssemblyProcessor: return reader.AssemblyProcessorTable.Block; + case TableIndex.AssemblyOS: return reader.AssemblyOSTable.Block; + case TableIndex.AssemblyRef: return reader.AssemblyRefTable.Block; + case TableIndex.AssemblyRefProcessor: return reader.AssemblyRefProcessorTable.Block; + case TableIndex.AssemblyRefOS: return reader.AssemblyRefOSTable.Block; + case TableIndex.File: return reader.FileTable.Block; + case TableIndex.ExportedType: return reader.ExportedTypeTable.Block; + case TableIndex.ManifestResource: return reader.ManifestResourceTable.Block; + case TableIndex.NestedClass: return reader.NestedClassTable.Block; + case TableIndex.GenericParam: return reader.GenericParamTable.Block; + case TableIndex.MethodSpec: return reader.MethodSpecTable.Block; + case TableIndex.GenericParamConstraint: return reader.GenericParamConstraintTable.Block; + + default: + throw new ArgumentOutOfRangeException("tableIndex"); + } + } + + /// + /// Returns the size of the specified heap. + /// + /// is null. + /// is not a valid heap index. + public static int GetHeapSize(this MetadataReader reader, HeapIndex heapIndex) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return reader.GetMetadataBlock(heapIndex).Length; + } + + /// + /// Returns the offset from the start of metadata to the specified heap. + /// + /// is null. + /// is not a valid heap index. + public static unsafe int GetHeapMetadataOffset(this MetadataReader reader, HeapIndex heapIndex) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return (int)(reader.GetMetadataBlock(heapIndex).Pointer - reader.Block.Pointer); + } + + /// + /// Returns the size of the specified heap. + /// + /// is null. + /// is not a valid heap index. + private static MemoryBlock GetMetadataBlock(this MetadataReader reader, HeapIndex heapIndex) + { + Debug.Assert(reader != null); + + switch (heapIndex) + { + case HeapIndex.UserString: + return reader.UserStringStream.Block; + + case HeapIndex.String: + return reader.StringStream.Block; + + case HeapIndex.Blob: + return reader.BlobStream.Block; + + case HeapIndex.Guid: + return reader.GuidStream.Block; + + default: + throw new ArgumentOutOfRangeException("heapIndex"); + } + } + + /// + /// Returns the a handle to the UserString that follows the given one in the UserString heap or a nil handle if it is the last one. + /// + /// is null. + public static UserStringHandle GetNextHandle(this MetadataReader reader, UserStringHandle handle) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return reader.UserStringStream.GetNextHandle(handle); + } + + /// + /// Returns the a handle to the Blob that follows the given one in the Blob heap or a nil handle if it is the last one. + /// + /// is null. + public static BlobHandle GetNextHandle(this MetadataReader reader, BlobHandle handle) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return reader.BlobStream.GetNextHandle(handle); + } + + /// + /// Returns the a handle to the String that follows the given one in the String heap or a nil handle if it is the last one. + /// + /// is null. + public static StringHandle GetNextHandle(this MetadataReader reader, StringHandle handle) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + return reader.StringStream.GetNextHandle(handle); + } + + /// + /// Enumerates entries of EnC log. + /// + /// is null. + public static IEnumerable GetEditAndContinueLogEntries(this MetadataReader reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + for (uint rid = 1; rid <= reader.EncLogTable.NumberOfRows; rid++) + { + yield return new EditAndContinueLogEntry( + new Handle(reader.EncLogTable.GetToken(rid)), + reader.EncLogTable.GetFuncCode(rid)); + } + } + + /// + /// Enumerates entries of EnC map. + /// + /// is null. + public static IEnumerable GetEditAndContinueMapEntries(this MetadataReader reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + for (uint rid = 1; rid <= reader.EncMapTable.NumberOfRows; rid++) + { + yield return new Handle(reader.EncMapTable.GetToken(rid)); + } + } + + /// + /// Enumerate types that define one or more properties. + /// + /// + /// The resulting sequence corresponds exactly to entries in PropertyMap table, + /// i.e. n-th returned is stored in n-th row of PropertyMap. + /// + public static IEnumerable GetTypesWithProperties(this MetadataReader reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + for (uint rid = 1; rid <= reader.PropertyMapTable.NumberOfRows; rid++) + { + yield return reader.PropertyMapTable.GetParentType(rid); + } + } + + /// + /// Enumerate types that define one or more events. + /// + /// + /// The resulting sequence corresponds exactly to entries in EventMap table, + /// i.e. n-th returned is stored in n-th row of EventMap. + /// + public static IEnumerable GetTypesWithEvents(this MetadataReader reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + for (uint rid = 1; rid <= reader.EventMapTable.NumberOfRows; rid++) + { + yield return reader.EventMapTable.GetParentType(rid); + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataTokens.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataTokens.cs new file mode 100644 index 0000000..f289cb7 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/MetadataTokens.cs @@ -0,0 +1,426 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + public static class MetadataTokens + { + /// + /// Maximum number of tables that can be present in Ecma335 metadata. + /// + public static readonly int TableCount = TableIndexExtensions.Count; + + /// + /// Maximum number of tables that can be present in Ecma335 metadata. + /// + public static readonly int HeapCount = HeapIndexExtensions.Count; + + /// + /// Returns the row number of a metadata table entry that corresponds + /// to the specified in the context of . + /// + /// One based row number. + /// The is not a valid metadata table handle. + public static int GetRowNumber(this MetadataReader reader, Handle handle) + { + if (handle.IsHeapHandle) + { + ThrowTableHandleRequired(); + } + + if (handle.IsVirtual) + { + return MapVirtualHandleRowId(reader, handle); + } + + return (int)handle.RowId; + } + + /// + /// Returns the offset of metadata heap data that corresponds + /// to the specified in the context of . + /// + /// Zero based offset, or -1 if isn't a metadata heap handle. + /// The operation is not supported for the specified . + /// The is invalid. + public static int GetHeapOffset(this MetadataReader reader, Handle handle) + { + if (!handle.IsHeapHandle) + { + ThrowHeapHandleRequired(); + } + + if (handle.IsVirtual) + { + return MapVirtualHandleRowId(reader, handle); + } + + return (int)handle.RowId; + } + + /// + /// Returns the metadata token of the specified in the context of . + /// + /// Metadata token. + /// + /// Handle represents a metadata entity that doesn't have a token. + /// A token can only be retrieved for a metadata table handle or a heap handle of type . + /// + public static int GetToken(this MetadataReader reader, Handle handle) + { + if (!TokenTypeIds.IsEcmaToken(handle.value)) + { + ThrowTableHandleOrUserStringRequired(); + } + + if (handle.IsVirtual) + { + return MapVirtualHandleRowId(reader, handle) | (int)(handle.value & TokenTypeIds.TokenTypeMask); + } + + return (int)handle.value; + } + + private static int MapVirtualHandleRowId(MetadataReader reader, Handle handle) + { + switch (handle.Kind) + { + case HandleKind.AssemblyReference: + // pretend that virtual rows immediately follow real rows: + return (int)(reader.AssemblyRefTable.NumberOfNonVirtualRows + 1 + handle.RowId); + + case HandleKind.String: + case HandleKind.Blob: + // We could precalculate offsets for virtual strings and blobs as we are creating them + // if we wanted to implement this. + throw new NotSupportedException(MetadataResources.CantGetOffsetForVirtualHeapHandle); + + default: + throw new ArgumentException(MetadataResources.InvalidHandle, "handle"); + } + } + + /// + /// Returns the row number of a metadata table entry that corresponds + /// to the specified . + /// + /// + /// One based row number, or -1 if can only be interpreted in a context of a specific . + /// See . + /// + public static int GetRowNumber(Handle handle) + { + if (handle.IsHeapHandle) + { + ThrowTableHandleRequired(); + } + + if (handle.IsVirtual) + { + return -1; + } + + return (int)handle.RowId; + } + + /// + /// Returns the offset of metadata heap data that corresponds + /// to the specified . + /// + /// + /// Zero based offset, or -1 if can only be interpreted in a context of a specific . + /// See . + /// + public static int GetHeapOffset(Handle handle) + { + if (!handle.IsHeapHandle) + { + ThrowHeapHandleRequired(); + } + + if (handle.IsVirtual) + { + return -1; + } + + return (int)handle.RowId; + } + + /// + /// Returns the metadata token of the specified . + /// + /// + /// Metadata token, or 0 if can only be interpreted in a context of a specific . + /// See . + /// + /// + /// Handle represents a metadata entity that doesn't have a token. + /// A token can only be retrieved for a metadata table handle or a heap handle of type . + /// + public static int GetToken(Handle handle) + { + if (!TokenTypeIds.IsEcmaToken(handle.value)) + { + ThrowTableHandleOrUserStringRequired(); + } + + if (handle.IsVirtual) + { + return 0; + } + + return (int)handle.value; + } + + /// + /// Gets the of the table corresponding to the specified . + /// + /// Handle type. + /// Table index. + /// True if the handle type corresponds to an Ecma335 table, false otherwise. + public static bool TryGetTableIndex(HandleKind type, out TableIndex index) + { + if ((int)type < TableIndexExtensions.Count) + { + index = (TableIndex)type; + return true; + } + + index = 0; + return false; + } + + /// + /// Gets the of the heap corresponding to the specified . + /// + /// Handle type. + /// Heap index. + /// True if the handle type corresponds to an Ecma335 heap, false otherwise. + public static bool TryGetHeapIndex(HandleKind type, out HeapIndex index) + { + switch (type) + { + case HandleKind.UserString: + index = HeapIndex.UserString; + return true; + + case HandleKind.String: + case HandleKind.NamespaceDefinition: + index = HeapIndex.String; + return true; + + case HandleKind.Blob: + index = HeapIndex.Blob; + return true; + + case HandleKind.Guid: + index = HeapIndex.Guid; + return true; + + default: + index = 0; + return false; + } + } + + #region Handle Factories + + /// + /// Creates a handle from a token value. + /// + /// + /// is not a valid metadata token. + /// It must encode a metadata table entity or an offset in heap. + /// + public static Handle Handle(int token) + { + if (!TokenTypeIds.IsEcmaToken(unchecked((uint)token))) + { + ThrowInvalidToken(); + } + + return new Handle((uint)token); + } + + /// + /// Creates a handle from a token value. + /// + /// + /// is not a valid table index. + public static Handle Handle(TableIndex tableIndex, int rowNumber) + { + int token = ((int)tableIndex << TokenTypeIds.RowIdBitCount) | rowNumber; + + if (!TokenTypeIds.IsEcmaToken(unchecked((uint)token))) + { + ThrowInvalidTableIndex(); + } + + return new Handle((uint)token); + } + + public static MethodDefinitionHandle MethodDefinitionHandle(int rowNumber) + { + return Metadata.MethodDefinitionHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static MethodImplementationHandle MethodImplementationHandle(int rowNumber) + { + return Metadata.MethodImplementationHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static MethodSpecificationHandle MethodSpecificationHandle(int rowNumber) + { + return Metadata.MethodSpecificationHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static TypeDefinitionHandle TypeDefinitionHandle(int rowNumber) + { + return Metadata.TypeDefinitionHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static ExportedTypeHandle ExportedTypeHandle(int rowNumber) + { + return Metadata.ExportedTypeHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static TypeReferenceHandle TypeReferenceHandle(int rowNumber) + { + return Metadata.TypeReferenceHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static TypeSpecificationHandle TypeSpecificationHandle(int rowNumber) + { + return Metadata.TypeSpecificationHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static MemberReferenceHandle MemberReferenceHandle(int rowNumber) + { + return Metadata.MemberReferenceHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static FieldDefinitionHandle FieldDefinitionHandle(int rowNumber) + { + return Metadata.FieldDefinitionHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static EventDefinitionHandle EventDefinitionHandle(int rowNumber) + { + return Metadata.EventDefinitionHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static PropertyDefinitionHandle PropertyDefinitionHandle(int rowNumber) + { + return Metadata.PropertyDefinitionHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static StandaloneSignatureHandle StandaloneSignatureHandle(int rowNumber) + { + return Metadata.StandaloneSignatureHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static ParameterHandle ParameterHandle(int rowNumber) + { + return Metadata.ParameterHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static GenericParameterHandle GenericParameterHandle(int rowNumber) + { + return Metadata.GenericParameterHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static GenericParameterConstraintHandle GenericParameterConstraintHandle(int rowNumber) + { + return Metadata.GenericParameterConstraintHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static ModuleReferenceHandle ModuleReferenceHandle(int rowNumber) + { + return Metadata.ModuleReferenceHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static AssemblyReferenceHandle AssemblyReferenceHandle(int rowNumber) + { + return Metadata.AssemblyReferenceHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static CustomAttributeHandle CustomAttributeHandle(int rowNumber) + { + return Metadata.CustomAttributeHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static DeclarativeSecurityAttributeHandle DeclarativeSecurityAttributeHandle(int rowNumber) + { + return Metadata.DeclarativeSecurityAttributeHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static ConstantHandle ConstantHandle(int rowNumber) + { + return Metadata.ConstantHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static ManifestResourceHandle ManifestResourceHandle(int rowNumber) + { + return Metadata.ManifestResourceHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static AssemblyFileHandle AssemblyFileHandle(int rowNumber) + { + return Metadata.AssemblyFileHandle.FromRowId((uint)(rowNumber & TokenTypeIds.RIDMask)); + } + + public static UserStringHandle UserStringHandle(int offset) + { + return Metadata.UserStringHandle.FromIndex((uint)(offset & TokenTypeIds.RIDMask)); + } + + public static StringHandle StringHandle(int offset) + { + return Metadata.StringHandle.FromIndex((uint)(offset & TokenTypeIds.RIDMask)); + } + + public static BlobHandle BlobHandle(int offset) + { + return Metadata.BlobHandle.FromIndex((uint)(offset & TokenTypeIds.RIDMask)); + } + + public static GuidHandle GuidHandle(int offset) + { + return Metadata.GuidHandle.FromIndex((uint)(offset & TokenTypeIds.RIDMask)); + } + + #endregion + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowTableHandleRequired() + { + throw new ArgumentException(MetadataResources.NotMetadataTableHandle, "handle"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowHeapHandleRequired() + { + throw new ArgumentException(MetadataResources.NotMetadataHeapHandle, "handle"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowTableHandleOrUserStringRequired() + { + throw new ArgumentException(MetadataResources.NotMetadataTableOrUserStringHandle, "handle"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowInvalidToken() + { + throw new ArgumentException(MetadataResources.InvalidToken, "token"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowInvalidTableIndex() + { + throw new ArgumentOutOfRangeException("tableIndex"); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/TableIndex.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/TableIndex.cs new file mode 100644 index 0000000..99d1694 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Ecma335/TableIndex.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + public enum TableIndex : byte + { + Module = 0x00, + TypeRef = 0x01, + TypeDef = 0x02, + FieldPtr = 0x03, + Field = 0x04, + MethodPtr = 0x05, + MethodDef = 0x06, + ParamPtr = 0x07, + Param = 0x08, + InterfaceImpl = 0x09, + MemberRef = 0x0A, + Constant = 0x0B, + CustomAttribute = 0x0C, + FieldMarshal = 0x0D, + DeclSecurity = 0x0E, + ClassLayout = 0x0F, + FieldLayout = 0x10, + StandAloneSig = 0x11, + EventMap = 0x12, + EventPtr = 0x13, + Event = 0x14, + PropertyMap = 0x15, + PropertyPtr = 0x16, + Property = 0x17, + MethodSemantics = 0x18, + MethodImpl = 0x19, + ModuleRef = 0x1A, + TypeSpec = 0x1B, + ImplMap = 0x1C, + FieldRva = 0x1D, + EncLog = 0x1E, + EncMap = 0x1F, + Assembly = 0x20, + AssemblyProcessor = 0x21, + AssemblyOS = 0x22, + AssemblyRef = 0x23, + AssemblyRefProcessor = 0x24, + AssemblyRefOS = 0x25, + File = 0x26, + ExportedType = 0x27, + ManifestResource = 0x28, + NestedClass = 0x29, + GenericParam = 0x2A, + MethodSpec = 0x2B, + GenericParamConstraint = 0x2C, + } + + internal static class TableIndexExtensions + { + internal const int Count = (int)TableIndex.GenericParamConstraint + 1; + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/EventDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/EventDefinition.cs new file mode 100644 index 0000000..4f6075b --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/EventDefinition.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct EventDefinition + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal EventDefinition(MetadataReader reader, EventDefinitionHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private EventDefinitionHandle Handle + { + get { return EventDefinitionHandle.FromRowId(_rowId); } + } + + public StringHandle Name + { + get + { + return _reader.EventTable.GetName(Handle); + } + } + + public EventAttributes Attributes + { + get + { + return _reader.EventTable.GetFlags(Handle); + } + } + + public Handle Type + { + get + { + return _reader.EventTable.GetEventType(Handle); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + public EventAccessors GetAccessors() + { + uint adder = 0; + uint remover = 0; + uint fire = 0; + + ushort methodCount; + var firstRowId = _reader.MethodSemanticsTable.FindSemanticMethodsForEvent(Handle, out methodCount); + for (ushort i = 0; i < methodCount; i++) + { + uint rowId = firstRowId + i; + switch (_reader.MethodSemanticsTable.GetSemantics(rowId)) + { + case MethodSemanticsAttributes.Adder: + adder = _reader.MethodSemanticsTable.GetMethod(rowId).RowId; + break; + + case MethodSemanticsAttributes.Remover: + remover = _reader.MethodSemanticsTable.GetMethod(rowId).RowId; + break; + + case MethodSemanticsAttributes.Raiser: + fire = _reader.MethodSemanticsTable.GetMethod(rowId).RowId; + break; + // TODO: expose 'Other' collection on EventAccessors for completeness. + } + } + + return new EventAccessors(adder, remover, fire); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegion.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegion.cs new file mode 100644 index 0000000..ac486ce --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegion.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public struct ExceptionRegion + { + private readonly ExceptionRegionKind _kind; + private readonly int _tryOffset; + private readonly int _tryLength; + private readonly int _handlerOffset; + private readonly int _handlerLength; + private readonly int _classTokenOrFilterOffset; + + internal ExceptionRegion( + ExceptionRegionKind kind, + int tryOffset, + int tryLength, + int handlerOffset, + int handlerLength, + int classTokenOrFilterOffset) + { + _kind = kind; + _tryOffset = tryOffset; + _tryLength = tryLength; + _handlerOffset = handlerOffset; + _handlerLength = handlerLength; + _classTokenOrFilterOffset = classTokenOrFilterOffset; + } + + public ExceptionRegionKind Kind + { + get { return _kind; } + } + + /// + /// Start IL offset of the try block. + /// + public int TryOffset + { + get { return _tryOffset; } + } + + /// + /// Length in bytes of try block. + /// + public int TryLength + { + get { return _tryLength; } + } + + /// + /// Start IL offset of the exception handler. + /// + public int HandlerOffset + { + get { return _handlerOffset; } + } + + /// + /// Length in bytes of the exception handler. + /// + public int HandlerLength + { + get { return _handlerLength; } + } + + /// + /// IL offset of the start of the filter block, or -1 if the region is not a filter. + /// + public int FilterOffset + { + get { return (Kind == ExceptionRegionKind.Filter) ? _classTokenOrFilterOffset : -1; } + } + + /// + /// Returns a TypeRef, TypeDef, or TypeSpec handle if the region represents a catch, nil token otherwise. + /// + public Handle CatchType + { + get { return (Kind == ExceptionRegionKind.Catch) ? new Handle((uint)_classTokenOrFilterOffset) : default(Handle); } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegionKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegionKind.cs new file mode 100644 index 0000000..ede48df --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExceptionRegionKind.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public enum ExceptionRegionKind : ushort + { + Catch = 0, + Filter = 1, + Finally = 2, + Fault = 4, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ExportedType.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExportedType.cs new file mode 100644 index 0000000..dfbc3f0 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ExportedType.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct ExportedType + { + internal readonly MetadataReader reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + internal readonly uint rowId; + + internal ExportedType(MetadataReader reader, uint rowId) + { + Debug.Assert(reader != null); + Debug.Assert(rowId != 0); + + this.reader = reader; + this.rowId = rowId; + } + + private ExportedTypeHandle Handle + { + get { return ExportedTypeHandle.FromRowId(rowId); } + } + + public TypeAttributes Attributes + { + get { return reader.ExportedTypeTable.GetFlags(rowId); } + } + + public bool IsForwarder + { + get { return Attributes.IsForwarder() && Implementation.Kind == HandleKind.AssemblyReference; } + } + + public StringHandle Name + { + get { return reader.ExportedTypeTable.GetTypeName(rowId); } + } + + public NamespaceDefinitionHandle Namespace + { + get + { + // NOTE: NamespaceDefinitionHandle currently relies on never having virtual values. If this ever gets projected + // to a virtual namespace name, then that assumption will need to be removed. + return reader.ExportedTypeTable.GetTypeNamespace(rowId); + } + } + + /// + /// Handle to resolve the implementation of the target type. + /// + /// + /// + /// representing another module in the assembly. + /// representing another assembly if is true. + /// representing the declaring exported type in which this was is nested. + /// + /// + public Handle Implementation + { + get + { + return reader.ExportedTypeTable.GetImplementation(rowId); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/FieldDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/FieldDefinition.cs new file mode 100644 index 0000000..26e331c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/FieldDefinition.cs @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct FieldDefinition + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal FieldDefinition(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private FieldDefTreatment Treatment + { + get { return (FieldDefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + private FieldDefinitionHandle Handle + { + get { return FieldDefinitionHandle.FromRowId(RowId); } + } + + public StringHandle Name + { + get + { + if (Treatment == 0) + { + return _reader.FieldTable.GetName(Handle); + } + + return GetProjectedName(); + } + } + + public FieldAttributes Attributes + { + get + { + if (Treatment == 0) + { + return _reader.FieldTable.GetFlags(Handle); + } + + return GetProjectedFlags(); + } + } + + public BlobHandle Signature + { + get + { + if (Treatment == 0) + { + return _reader.FieldTable.GetSignature(Handle); + } + + return GetProjectedSignature(); + } + } + + public TypeDefinitionHandle GetDeclaringType() + { + return _reader.GetDeclaringType(Handle); + } + + public ConstantHandle GetDefaultValue() + { + return _reader.ConstantTable.FindConstant(Handle); + } + + public int GetRelativeVirtualAddress() + { + uint fieldRvaRowId = _reader.FieldRvaTable.FindFieldRVARowId(Handle.RowId); + if (fieldRvaRowId == 0) + { + return 0; + } + + return _reader.FieldRvaTable.GetRVA(fieldRvaRowId); + } + + /// + /// Returns field layout offset, or -1 if not available. + /// + public int GetOffset() + { + uint layoutRowId = _reader.FieldLayoutTable.FindFieldLayoutRowId(Handle); + if (layoutRowId == 0) + { + return -1; + } + + uint offset = _reader.FieldLayoutTable.GetOffset(layoutRowId); + if (offset > int.MaxValue) + { + // CLI spec says: + // "Offset (a 4-byte constant)" + // "Offset shall be zero or more" + // + // Peverify fails with "Type load failed" error if offset is greater than Int32.MaxValue. + return -1; + } + + return (int)offset; + } + + public BlobHandle GetMarshallingDescriptor() + { + uint marshalRowId = _reader.FieldMarshalTable.FindFieldMarshalRowId(Handle); + if (marshalRowId == 0) + { + return default(BlobHandle); + } + + return _reader.FieldMarshalTable.GetNativeType(marshalRowId); + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + #region Projections + + private StringHandle GetProjectedName() + { + // no change: + return _reader.FieldTable.GetName(Handle); + } + + private FieldAttributes GetProjectedFlags() + { + var flags = _reader.FieldTable.GetFlags(Handle); + + if (Treatment == FieldDefTreatment.EnumValue) + { + return (flags & ~FieldAttributes.FieldAccessMask) | FieldAttributes.Public; + } + + return flags; + } + + private BlobHandle GetProjectedSignature() + { + return _reader.FieldTable.GetSignature(Handle); + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameter.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameter.cs new file mode 100644 index 0000000..6f6839b --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameter.cs @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct GenericParameter + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal GenericParameter(MetadataReader reader, GenericParameterHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private GenericParameterHandle Handle + { + get { return GenericParameterHandle.FromRowId(_rowId); } + } + + /// + /// or . + /// + /// + /// Corresponds to Owner field of GenericParam table in ECMA-335 Standard. + /// + public Handle Parent + { + get + { + return _reader.GenericParamTable.GetOwner(Handle); + } + } + + /// + /// Attributes specifying variance and constraints. + /// + /// + /// Corresponds to Flags field of GenericParam table in ECMA-335 Standard. + /// + public GenericParameterAttributes Attributes + { + get + { + return _reader.GenericParamTable.GetFlags(Handle); + } + } + + /// + /// Zero-based index of the parameter within the declaring generic type or method declaration. + /// + /// + /// Corresponds to Number field of GenericParam table in ECMA-335 Standard. + /// + public int Index + { + get + { + return _reader.GenericParamTable.GetNumber(Handle); + } + } + + /// + /// The name of the generic parameter. + /// + /// + /// Corresponds to Name field of GenericParam table in ECMA-335 Standard. + /// + public StringHandle Name + { + get + { + return _reader.GenericParamTable.GetName(Handle); + } + } + + public GenericParameterConstraintHandleCollection GetConstraints() + { + return _reader.GenericParamConstraintTable.FindConstraintsForGenericParam(Handle); + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameterConstraint.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameterConstraint.cs new file mode 100644 index 0000000..fe479b6 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/GenericParameterConstraint.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct GenericParameterConstraint + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal GenericParameterConstraint(MetadataReader reader, GenericParameterConstraintHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private GenericParameterConstraintHandle Handle + { + get { return GenericParameterConstraintHandle.FromRowId(_rowId); } + } + + /// + /// The constrained . + /// + /// + /// Corresponds to Owner field of GenericParamConstraint table in ECMA-335 Standard. + /// + public GenericParameterHandle Parameter + { + get { return _reader.GenericParamConstraintTable.GetOwner(Handle); } + } + + /// + /// Handle (, , or ) + /// specifying from which type this generic parameter is constrained to derive, + /// or which interface this generic parameter is constrained to implement. + /// + /// + /// Corresponds to Constraint field of GenericParamConstraint table in ECMA-335 Standard. + /// + public Handle Type + { + get { return _reader.GenericParamConstraintTable.GetConstraint(Handle); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleCollections.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleCollections.cs new file mode 100644 index 0000000..1f3d214 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleCollections.cs @@ -0,0 +1,1948 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata +{ + /// + /// Represents generic type parameters of a method or type. + /// + public struct GenericParameterHandleCollection : IReadOnlyList + { + private readonly int _firstRowId; + private readonly ushort _count; + + internal GenericParameterHandleCollection(int firstRowId, ushort count) + { + _firstRowId = firstRowId; + _count = count; + } + + public int Count + { + get + { + return _count; + } + } + + public GenericParameterHandle this[int index] + { + get + { + if (index < 0 || index >= _count) + { + ThrowIndexOutOfRange(); + } + + return GenericParameterHandle.FromRowId((uint)(_firstRowId + index)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowIndexOutOfRange() + { + throw new ArgumentOutOfRangeException("index"); + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_firstRowId, _firstRowId + _count - 1); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; // inclusive + + // first parameter rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int firstRowId, int lastRowId) + { + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public GenericParameterHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + return GenericParameterHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents constraints of a generic type parameter. + /// + public struct GenericParameterConstraintHandleCollection : IReadOnlyList + { + private readonly int _firstRowId; + private readonly ushort _count; + + internal GenericParameterConstraintHandleCollection(int firstRowId, ushort count) + { + _firstRowId = firstRowId; + _count = count; + } + + public int Count + { + get + { + return _count; + } + } + + public GenericParameterConstraintHandle this[int index] + { + get + { + if (index < 0 || index >= _count) + { + ThrowIndexOutOfRange(); + } + + return GenericParameterConstraintHandle.FromRowId((uint)(_firstRowId + index)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowIndexOutOfRange() + { + throw new ArgumentOutOfRangeException("index"); + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_firstRowId, _firstRowId + _count - 1); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; // inclusive + + // first parameter rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int firstRowId, int lastRowId) + { + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public GenericParameterConstraintHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + return GenericParameterConstraintHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct CustomAttributeHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal CustomAttributeHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.CustomAttributeTable.NumberOfRows; + } + + internal CustomAttributeHandleCollection(MetadataReader reader, Handle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + reader.CustomAttributeTable.GetAttributeRange(handle, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first custom attribute rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public CustomAttributeHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.CustomAttributeTable.PtrTable != null) + { + return GetCurrentCustomAttributeIndirect(); + } + else + { + return CustomAttributeHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private CustomAttributeHandle GetCurrentCustomAttributeIndirect() + { + return CustomAttributeHandle.FromRowId( + _reader.CustomAttributeTable.PtrTable[(_currentRowId & (int)TokenTypeIds.RIDMask) - 1]); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct DeclarativeSecurityAttributeHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal DeclarativeSecurityAttributeHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.DeclSecurityTable.NumberOfRows; + } + + internal DeclarativeSecurityAttributeHandleCollection(MetadataReader reader, Handle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + reader.DeclSecurityTable.GetAttributeRange(handle, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first custom attribute rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public DeclarativeSecurityAttributeHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + return DeclarativeSecurityAttributeHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct MethodDefinitionHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal MethodDefinitionHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.MethodDefTable.NumberOfRows; + } + + internal MethodDefinitionHandleCollection(MetadataReader reader, TypeDefinitionHandle containingType) + { + Debug.Assert(reader != null); + Debug.Assert(!containingType.IsNil); + + _reader = reader; + reader.GetMethodRange(containingType, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first method rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public MethodDefinitionHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.UseMethodPtrTable) + { + return GetCurrentMethodIndirect(); + } + else + { + return MethodDefinitionHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private MethodDefinitionHandle GetCurrentMethodIndirect() + { + return _reader.MethodPtrTable.GetMethodFor(_currentRowId & (int)TokenTypeIds.RIDMask); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct FieldDefinitionHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal FieldDefinitionHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.FieldTable.NumberOfRows; + } + + internal FieldDefinitionHandleCollection(MetadataReader reader, TypeDefinitionHandle containingType) + { + Debug.Assert(reader != null); + Debug.Assert(!containingType.IsNil); + + _reader = reader; + reader.GetFieldRange(containingType, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first field rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public FieldDefinitionHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.UseFieldPtrTable) + { + return GetCurrentFieldIndirect(); + } + else + { + return FieldDefinitionHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private FieldDefinitionHandle GetCurrentFieldIndirect() + { + return _reader.FieldPtrTable.GetFieldFor(_currentRowId & (int)TokenTypeIds.RIDMask); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct PropertyDefinitionHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal PropertyDefinitionHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.PropertyTable.NumberOfRows; + } + + internal PropertyDefinitionHandleCollection(MetadataReader reader, TypeDefinitionHandle containingType) + { + Debug.Assert(reader != null); + Debug.Assert(!containingType.IsNil); + + _reader = reader; + reader.GetPropertyRange(containingType, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first Property rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public PropertyDefinitionHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.UsePropertyPtrTable) + { + return GetCurrentPropertyIndirect(); + } + else + { + return PropertyDefinitionHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private PropertyDefinitionHandle GetCurrentPropertyIndirect() + { + return _reader.PropertyPtrTable.GetPropertyFor(_currentRowId & (int)TokenTypeIds.RIDMask); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct EventDefinitionHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal EventDefinitionHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + _firstRowId = 1; + _lastRowId = (int)reader.EventTable.NumberOfRows; + } + + internal EventDefinitionHandleCollection(MetadataReader reader, TypeDefinitionHandle containingType) + { + Debug.Assert(reader != null); + Debug.Assert(!containingType.IsNil); + + _reader = reader; + reader.GetEventRange(containingType, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; + + // first rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public EventDefinitionHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.UseEventPtrTable) + { + return GetCurrentEventIndirect(); + } + else + { + return EventDefinitionHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private EventDefinitionHandle GetCurrentEventIndirect() + { + return _reader.EventPtrTable.GetEventFor(_currentRowId & (int)TokenTypeIds.RIDMask); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct MethodImplementationHandleCollection : IReadOnlyCollection + { + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal MethodImplementationHandleCollection(MetadataReader reader, TypeDefinitionHandle containingType) + { + Debug.Assert(reader != null); + + if (containingType.IsNil) + { + _firstRowId = 1; + _lastRowId = (int)reader.MethodImplTable.NumberOfRows; + } + else + { + reader.MethodImplTable.GetMethodImplRange(containingType, out _firstRowId, out _lastRowId); + } + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; // inclusive + + // first impl rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int firstRowId, int lastRowId) + { + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public MethodImplementationHandle Current + { + get + { + return MethodImplementationHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Collection of parameters of a specified method. + /// + public struct ParameterHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal ParameterHandleCollection(MetadataReader reader, MethodDefinitionHandle containingMethod) + { + Debug.Assert(reader != null); + Debug.Assert(!containingMethod.IsNil); + _reader = reader; + + reader.GetParameterRange(containingMethod, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first Parameter rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _lastRowId = lastRowId; + _currentRowId = firstRowId - 1; + } + + public ParameterHandle Current + { + get + { + // PERF: keep this code small to enable inlining. + + if (_reader.UseParamPtrTable) + { + return GetCurrentParameterIndirect(); + } + else + { + return ParameterHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + private ParameterHandle GetCurrentParameterIndirect() + { + return _reader.ParamPtrTable.GetParamFor(_currentRowId & (int)TokenTypeIds.RIDMask); + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct InterfaceImplementationHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + private readonly int _firstRowId; + private readonly int _lastRowId; + + internal InterfaceImplementationHandleCollection(MetadataReader reader, TypeDefinitionHandle implementingType) + { + Debug.Assert(reader != null); + Debug.Assert(!implementingType.IsNil); + _reader = reader; + + reader.InterfaceImplTable.GetInterfaceImplRange(implementingType, out _firstRowId, out _lastRowId); + } + + public int Count + { + get + { + return _lastRowId - _firstRowId + 1; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader, _firstRowId, _lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + private readonly int _lastRowId; // inclusive + + // first rid - 1: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(MetadataReader reader, int firstRowId, int lastRowId) + { + _reader = reader; + _currentRowId = firstRowId - 1; + _lastRowId = lastRowId; + } + + public InterfaceImplementationHandle Current + { + get + { + return InterfaceImplementationHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this code small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct TypeDefinitionHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire TypeDef table. + internal TypeDefinitionHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public TypeDefinitionHandle Current + { + get + { + return TypeDefinitionHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct TypeReferenceHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire TypeRef table. + internal TypeReferenceHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public TypeReferenceHandle Current + { + get + { + return TypeReferenceHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct ExportedTypeHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire TypeRef table. + internal ExportedTypeHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public ExportedTypeHandle Current + { + get + { + return ExportedTypeHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct MemberReferenceHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire TypeRef table. + internal MemberReferenceHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public MemberReferenceHandle Current + { + get + { + return MemberReferenceHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + public struct PropertyAccessors + { + // Workaround: JIT doesn't generate good code for nested structures, so use uints. + + private readonly uint _getterRowId; + private readonly uint _setterRowId; + + public MethodDefinitionHandle Getter { get { return MethodDefinitionHandle.FromRowId(_getterRowId); } } + public MethodDefinitionHandle Setter { get { return MethodDefinitionHandle.FromRowId(_setterRowId); } } + + internal PropertyAccessors(uint getterRowId, uint setterRowId) + { + _getterRowId = getterRowId; + _setterRowId = setterRowId; + } + } + + public struct EventAccessors + { + // Workaround: JIT doesn't generate good code for nested structures, so use uints. + + private readonly uint _adderRowId; + private readonly uint _removerRowId; + private readonly uint _raiserRowId; + + public MethodDefinitionHandle Adder { get { return MethodDefinitionHandle.FromRowId(_adderRowId); } } + public MethodDefinitionHandle Remover { get { return MethodDefinitionHandle.FromRowId(_removerRowId); } } + public MethodDefinitionHandle Raiser { get { return MethodDefinitionHandle.FromRowId(_raiserRowId); } } + + internal EventAccessors(uint adderRowId, uint removerRowId, uint raiserRowId) + { + _adderRowId = adderRowId; + _removerRowId = removerRowId; + _raiserRowId = raiserRowId; + } + } + + /// + /// Collection of assembly references. + /// + public struct AssemblyReferenceHandleCollection : IReadOnlyCollection + { + private readonly MetadataReader _reader; + + internal AssemblyReferenceHandleCollection(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + } + + public int Count + { + get + { + return _reader.AssemblyRefTable.NumberOfNonVirtualRows + _reader.AssemblyRefTable.NumberOfVirtualRows; + } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_reader); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly MetadataReader _reader; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + private int _virtualRowId; + + internal Enumerator(MetadataReader reader) + { + _reader = reader; + _currentRowId = 0; + _virtualRowId = -1; + } + + public AssemblyReferenceHandle Current + { + get + { + if (_virtualRowId >= 0) + { + if (_virtualRowId == EnumEnded) + { + return default(AssemblyReferenceHandle); + } + + return AssemblyReferenceHandle.FromVirtualIndex((AssemblyReferenceHandle.VirtualIndex)((uint)_virtualRowId)); + } + else + { + return AssemblyReferenceHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + } + + public bool MoveNext() + { + if (_currentRowId < _reader.AssemblyRefTable.NumberOfNonVirtualRows) + { + _currentRowId++; + return true; + } + + if (_virtualRowId < _reader.AssemblyRefTable.NumberOfVirtualRows - 1) + { + _virtualRowId++; + return true; + } + + _currentRowId = EnumEnded; + _virtualRowId = EnumEnded; + return false; + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct ManifestResourceHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire ManifestResource table. + internal ManifestResourceHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public ManifestResourceHandle Current + { + get + { + return ManifestResourceHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } + + /// + /// Represents a collection of . + /// + public struct AssemblyFileHandleCollection : IReadOnlyCollection + { + private readonly int _lastRowId; + + // Creates collection that represents the entire AssemblyFile table. + internal AssemblyFileHandleCollection(int lastRowId) + { + _lastRowId = lastRowId; + } + + public int Count + { + get { return _lastRowId; } + } + + public Enumerator GetEnumerator() + { + return new Enumerator(_lastRowId); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly int _lastRowId; + + // 0: initial state + // EnumEnded: enumeration ended + private int _currentRowId; + + // greater than any RowId and with last 24 bits clear, so that Current returns nil token + private const int EnumEnded = (int)TokenTypeIds.RIDMask + 1; + + internal Enumerator(int lastRowId) + { + _lastRowId = lastRowId; + _currentRowId = 0; + } + + public AssemblyFileHandle Current + { + get + { + return AssemblyFileHandle.FromRowId((uint)_currentRowId & TokenTypeIds.RIDMask); + } + } + + public bool MoveNext() + { + // PERF: keep this method small to enable inlining. + + if (_currentRowId >= _lastRowId) + { + _currentRowId = EnumEnded; + return false; + } + else + { + _currentRowId++; + return true; + } + } + + object IEnumerator.Current + { + get { return Current; } + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + void IDisposable.Dispose() + { + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleComparer.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleComparer.cs new file mode 100644 index 0000000..5f064d9 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleComparer.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public sealed class HandleComparer : IEqualityComparer, IComparer + { + private static readonly HandleComparer _default = new HandleComparer(); + + private HandleComparer() + { + } + + public static HandleComparer Default + { + get { return _default; } + } + + public bool Equals(Handle x, Handle y) + { + return x == y; + } + + public int GetHashCode(Handle obj) + { + return obj.GetHashCode(); + } + + public int Compare(Handle x, Handle y) + { + return TokenTypeIds.CompareTokens(x.value, y.value); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleKind.cs new file mode 100644 index 0000000..c586b5e --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/HandleKind.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public enum HandleKind : byte + { + ModuleDefinition = (byte)(TokenTypeIds.Module >> TokenTypeIds.RowIdBitCount), + TypeReference = (byte)(TokenTypeIds.TypeRef >> TokenTypeIds.RowIdBitCount), + TypeDefinition = (byte)(TokenTypeIds.TypeDef >> TokenTypeIds.RowIdBitCount), + FieldDefinition = (byte)(TokenTypeIds.FieldDef >> TokenTypeIds.RowIdBitCount), + MethodDefinition = (byte)(TokenTypeIds.MethodDef >> TokenTypeIds.RowIdBitCount), + Parameter = (byte)(TokenTypeIds.ParamDef >> TokenTypeIds.RowIdBitCount), + InterfaceImplementation = (byte)(TokenTypeIds.InterfaceImpl >> TokenTypeIds.RowIdBitCount), + MemberReference = (byte)(TokenTypeIds.MemberRef >> TokenTypeIds.RowIdBitCount), + Constant = (byte)(TokenTypeIds.Constant >> TokenTypeIds.RowIdBitCount), + CustomAttribute = (byte)(TokenTypeIds.CustomAttribute >> TokenTypeIds.RowIdBitCount), + DeclarativeSecurityAttribute = (byte)(TokenTypeIds.DeclSecurity >> TokenTypeIds.RowIdBitCount), + StandaloneSignature = (byte)(TokenTypeIds.Signature >> TokenTypeIds.RowIdBitCount), + EventDefinition = (byte)(TokenTypeIds.Event >> TokenTypeIds.RowIdBitCount), + PropertyDefinition = (byte)(TokenTypeIds.Property >> TokenTypeIds.RowIdBitCount), + MethodImplementation = (byte)(TokenTypeIds.MethodImpl >> TokenTypeIds.RowIdBitCount), + ModuleReference = (byte)(TokenTypeIds.ModuleRef >> TokenTypeIds.RowIdBitCount), + TypeSpecification = (byte)(TokenTypeIds.TypeSpec >> TokenTypeIds.RowIdBitCount), + AssemblyDefinition = (byte)(TokenTypeIds.Assembly >> TokenTypeIds.RowIdBitCount), + AssemblyFile = (byte)(TokenTypeIds.File >> TokenTypeIds.RowIdBitCount), + AssemblyReference = (byte)(TokenTypeIds.AssemblyRef >> TokenTypeIds.RowIdBitCount), + ExportedType = (byte)(TokenTypeIds.ExportedType >> TokenTypeIds.RowIdBitCount), + GenericParameter = (byte)(TokenTypeIds.GenericParam >> TokenTypeIds.RowIdBitCount), + MethodSpecification = (byte)(TokenTypeIds.MethodSpec >> TokenTypeIds.RowIdBitCount), + GenericParameterConstraint = (byte)(TokenTypeIds.GenericParamConstraint >> TokenTypeIds.RowIdBitCount), + ManifestResource = (byte)(TokenTypeIds.ManifestResource >> TokenTypeIds.RowIdBitCount), + + NamespaceDefinition = (byte)(TokenTypeIds.Namespace >> TokenTypeIds.RowIdBitCount), + UserString = (byte)(TokenTypeIds.UserString >> TokenTypeIds.RowIdBitCount), + String = (byte)(TokenTypeIds.String >> TokenTypeIds.RowIdBitCount), + Blob = (byte)(TokenTypeIds.Blob >> TokenTypeIds.RowIdBitCount), + Guid = (byte)(TokenTypeIds.Guid >> TokenTypeIds.RowIdBitCount), + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Handles.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Handles.cs new file mode 100644 index 0000000..9dba5a6 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Handles.cs @@ -0,0 +1,2420 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata +{ + public struct Handle : IEquatable + { + internal readonly uint value; + + internal Handle(uint value) + { + this.value = value; + } + + internal uint RowId { get { return value & TokenTypeIds.RIDMask; } } + internal uint TokenType { get { return value & TokenTypeIds.TokenTypeMask; } } + + internal bool IsVirtual + { + get { return (value & TokenTypeIds.VirtualTokenMask) != 0; } + } + + internal bool IsHeapHandle + { + get { return (value & TokenTypeIds.HeapMask) == TokenTypeIds.HeapMask; } + } + + public HandleKind Kind + { + get + { + uint tokenType = TokenType; + + // Do not surface special string and namespace token sub-types (e.g. dot terminated, winrt prefixed, synthetic) + // in public-facing handle type. + if (tokenType > TokenTypeIds.String) + { + tokenType &= ~TokenTypeIds.StringOrNamespaceKindMask; + Debug.Assert(tokenType == TokenTypeIds.String || tokenType == TokenTypeIds.Namespace); + } + + return (HandleKind)(tokenType >> TokenTypeIds.RowIdBitCount); + } + } + + public bool IsNil + { + get + { + return (value & TokenTypeIds.VirtualBitAndRowIdMask) == 0; + } + } + + public static bool operator ==(Handle left, Handle right) + { + return left.value == right.value; + } + + public override bool Equals(object obj) + { + return obj is Handle && ((Handle)obj).value == this.value; + } + + public bool Equals(Handle other) + { + return this.value == other.value; + } + + public override int GetHashCode() + { + return this.value.GetHashCode(); + } + + public static bool operator !=(Handle left, Handle right) + { + return left.value != right.value; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ThrowInvalidCast() + { + throw new InvalidCastException(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ThrowInvalidCodedIndex() + { + throw new BadImageFormatException(MetadataResources.InvalidCodedIndex); + } + + public static readonly ModuleDefinitionHandle ModuleDefinition = new ModuleDefinitionHandle(1); + public static readonly AssemblyDefinitionHandle AssemblyDefinition = new AssemblyDefinitionHandle(1); + } + + public struct ModuleDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Module; + private readonly uint _rowId; + + internal ModuleDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ModuleDefinitionHandle FromRowId(uint rowId) + { + return new ModuleDefinitionHandle(rowId); + } + + public static implicit operator Handle(ModuleDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ModuleDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ModuleDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ModuleDefinitionHandle left, ModuleDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ModuleDefinitionHandle && ((ModuleDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(ModuleDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ModuleDefinitionHandle left, ModuleDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct AssemblyDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Assembly; + private readonly uint _rowId; + + internal AssemblyDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static AssemblyDefinitionHandle FromRowId(uint rowId) + { + return new AssemblyDefinitionHandle(rowId); + } + + public static implicit operator Handle(AssemblyDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator AssemblyDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new AssemblyDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(AssemblyDefinitionHandle left, AssemblyDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is AssemblyDefinitionHandle && ((AssemblyDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(AssemblyDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(AssemblyDefinitionHandle left, AssemblyDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct InterfaceImplementationHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.InterfaceImpl; + private readonly uint _rowId; + + internal InterfaceImplementationHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static InterfaceImplementationHandle FromRowId(uint rowId) + { + return new InterfaceImplementationHandle(rowId); + } + + public static implicit operator Handle(InterfaceImplementationHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator InterfaceImplementationHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new InterfaceImplementationHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(InterfaceImplementationHandle left, InterfaceImplementationHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is InterfaceImplementationHandle && ((InterfaceImplementationHandle)obj)._rowId == _rowId; + } + + public bool Equals(InterfaceImplementationHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(InterfaceImplementationHandle left, InterfaceImplementationHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct MethodDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.MethodDef; + private readonly uint _rowId; + + private MethodDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static MethodDefinitionHandle FromRowId(uint rowId) + { + return new MethodDefinitionHandle(rowId); + } + + public static implicit operator Handle(MethodDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator MethodDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new MethodDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(MethodDefinitionHandle left, MethodDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is MethodDefinitionHandle && ((MethodDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(MethodDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(MethodDefinitionHandle left, MethodDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct MethodImplementationHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.MethodImpl; + private readonly uint _rowId; + + private MethodImplementationHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static MethodImplementationHandle FromRowId(uint rowId) + { + return new MethodImplementationHandle(rowId); + } + + public static implicit operator Handle(MethodImplementationHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator MethodImplementationHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new MethodImplementationHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(MethodImplementationHandle left, MethodImplementationHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is MethodImplementationHandle && ((MethodImplementationHandle)obj)._rowId == _rowId; + } + + public bool Equals(MethodImplementationHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(MethodImplementationHandle left, MethodImplementationHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct MethodSpecificationHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.MethodSpec; + private readonly uint _rowId; + + private MethodSpecificationHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static MethodSpecificationHandle FromRowId(uint rowId) + { + return new MethodSpecificationHandle(rowId); + } + + public static implicit operator Handle(MethodSpecificationHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator MethodSpecificationHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new MethodSpecificationHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(MethodSpecificationHandle left, MethodSpecificationHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is MethodSpecificationHandle && ((MethodSpecificationHandle)obj)._rowId == _rowId; + } + + public bool Equals(MethodSpecificationHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(MethodSpecificationHandle left, MethodSpecificationHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct TypeDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.TypeDef; + private readonly uint _rowId; + + private TypeDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static TypeDefinitionHandle FromRowId(uint rowId) + { + return new TypeDefinitionHandle(rowId); + } + + public static implicit operator Handle(TypeDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator TypeDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new TypeDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(TypeDefinitionHandle left, TypeDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is TypeDefinitionHandle && ((TypeDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(TypeDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(TypeDefinitionHandle left, TypeDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct ExportedTypeHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.ExportedType; + private readonly uint _rowId; + + private ExportedTypeHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ExportedTypeHandle FromRowId(uint rowId) + { + return new ExportedTypeHandle(rowId); + } + + public static implicit operator Handle(ExportedTypeHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ExportedTypeHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ExportedTypeHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ExportedTypeHandle left, ExportedTypeHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ExportedTypeHandle && ((ExportedTypeHandle)obj)._rowId == _rowId; + } + + public bool Equals(ExportedTypeHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ExportedTypeHandle left, ExportedTypeHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct TypeReferenceHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.TypeRef; + private readonly uint _rowId; + + private TypeReferenceHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static TypeReferenceHandle FromRowId(uint rowId) + { + return new TypeReferenceHandle(rowId); + } + + public static implicit operator Handle(TypeReferenceHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator TypeReferenceHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new TypeReferenceHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(TypeReferenceHandle left, TypeReferenceHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is TypeReferenceHandle && ((TypeReferenceHandle)obj)._rowId == _rowId; + } + + public bool Equals(TypeReferenceHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(TypeReferenceHandle left, TypeReferenceHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct TypeSpecificationHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.TypeSpec; + private readonly uint _rowId; + + private TypeSpecificationHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static TypeSpecificationHandle FromRowId(uint rowId) + { + return new TypeSpecificationHandle(rowId); + } + + public static implicit operator Handle(TypeSpecificationHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator TypeSpecificationHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new TypeSpecificationHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(TypeSpecificationHandle left, TypeSpecificationHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is TypeSpecificationHandle && ((TypeSpecificationHandle)obj)._rowId == _rowId; + } + + public bool Equals(TypeSpecificationHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(TypeSpecificationHandle left, TypeSpecificationHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct MemberReferenceHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.MemberRef; + private readonly uint _rowId; + + private MemberReferenceHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static MemberReferenceHandle FromRowId(uint rowId) + { + return new MemberReferenceHandle(rowId); + } + + public static implicit operator Handle(MemberReferenceHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator MemberReferenceHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new MemberReferenceHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(MemberReferenceHandle left, MemberReferenceHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is MemberReferenceHandle && ((MemberReferenceHandle)obj)._rowId == _rowId; + } + + public bool Equals(MemberReferenceHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(MemberReferenceHandle left, MemberReferenceHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct FieldDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.FieldDef; + private readonly uint _rowId; + + private FieldDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static FieldDefinitionHandle FromRowId(uint rowId) + { + return new FieldDefinitionHandle(rowId); + } + + public static implicit operator Handle(FieldDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator FieldDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new FieldDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(FieldDefinitionHandle left, FieldDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is FieldDefinitionHandle && ((FieldDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(FieldDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(FieldDefinitionHandle left, FieldDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct EventDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Event; + private readonly uint _rowId; + + private EventDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static EventDefinitionHandle FromRowId(uint rowId) + { + return new EventDefinitionHandle(rowId); + } + + public static implicit operator Handle(EventDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator EventDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new EventDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(EventDefinitionHandle left, EventDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is EventDefinitionHandle && ((EventDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(EventDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(EventDefinitionHandle left, EventDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct PropertyDefinitionHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Property; + private readonly uint _rowId; + + private PropertyDefinitionHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static PropertyDefinitionHandle FromRowId(uint rowId) + { + return new PropertyDefinitionHandle(rowId); + } + + public static implicit operator Handle(PropertyDefinitionHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator PropertyDefinitionHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new PropertyDefinitionHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(PropertyDefinitionHandle left, PropertyDefinitionHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is PropertyDefinitionHandle && ((PropertyDefinitionHandle)obj)._rowId == _rowId; + } + + public bool Equals(PropertyDefinitionHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(PropertyDefinitionHandle left, PropertyDefinitionHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct StandaloneSignatureHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Signature; + private readonly uint _rowId; + + private StandaloneSignatureHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static StandaloneSignatureHandle FromRowId(uint rowId) + { + return new StandaloneSignatureHandle(rowId); + } + + public static implicit operator Handle(StandaloneSignatureHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator StandaloneSignatureHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new StandaloneSignatureHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(StandaloneSignatureHandle left, StandaloneSignatureHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is StandaloneSignatureHandle && ((StandaloneSignatureHandle)obj)._rowId == _rowId; + } + + public bool Equals(StandaloneSignatureHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(StandaloneSignatureHandle left, StandaloneSignatureHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct ParameterHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.ParamDef; + private readonly uint _rowId; + + private ParameterHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ParameterHandle FromRowId(uint rowId) + { + return new ParameterHandle(rowId); + } + + public static implicit operator Handle(ParameterHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ParameterHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ParameterHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ParameterHandle left, ParameterHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ParameterHandle && ((ParameterHandle)obj)._rowId == _rowId; + } + + public bool Equals(ParameterHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ParameterHandle left, ParameterHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct GenericParameterHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.GenericParam; + private readonly uint _rowId; + + private GenericParameterHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static GenericParameterHandle FromRowId(uint rowId) + { + return new GenericParameterHandle(rowId); + } + + public static implicit operator Handle(GenericParameterHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator GenericParameterHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new GenericParameterHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(GenericParameterHandle left, GenericParameterHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is GenericParameterHandle && ((GenericParameterHandle)obj)._rowId == _rowId; + } + + public bool Equals(GenericParameterHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(GenericParameterHandle left, GenericParameterHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct GenericParameterConstraintHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.GenericParamConstraint; + private readonly uint _rowId; + + private GenericParameterConstraintHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static GenericParameterConstraintHandle FromRowId(uint rowId) + { + return new GenericParameterConstraintHandle(rowId); + } + + public static implicit operator Handle(GenericParameterConstraintHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator GenericParameterConstraintHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new GenericParameterConstraintHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(GenericParameterConstraintHandle left, GenericParameterConstraintHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is GenericParameterConstraintHandle && ((GenericParameterConstraintHandle)obj)._rowId == _rowId; + } + + public bool Equals(GenericParameterConstraintHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(GenericParameterConstraintHandle left, GenericParameterConstraintHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct ModuleReferenceHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.ModuleRef; + private readonly uint _rowId; + + private ModuleReferenceHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ModuleReferenceHandle FromRowId(uint rowId) + { + return new ModuleReferenceHandle(rowId); + } + + public static implicit operator Handle(ModuleReferenceHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ModuleReferenceHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ModuleReferenceHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ModuleReferenceHandle left, ModuleReferenceHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ModuleReferenceHandle && ((ModuleReferenceHandle)obj)._rowId == _rowId; + } + + public bool Equals(ModuleReferenceHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ModuleReferenceHandle left, ModuleReferenceHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct AssemblyReferenceHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.AssemblyRef; + + // bits: + // 0..24: Heap index or Virtual index + // 25..30: TokenTypeId: AssemblyRef + // 31: IsVirtual + private readonly uint _token; + + internal enum VirtualIndex + { + System_Runtime, + System_Runtime_InteropServices_WindowsRuntime, + System_ObjectModel, + System_Runtime_WindowsRuntime, + System_Runtime_WindowsRuntime_UI_Xaml, + System_Numerics_Vectors, + + Count + } + + private AssemblyReferenceHandle(uint token) + { + _token = token; + } + + internal static AssemblyReferenceHandle FromRowId(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + return new AssemblyReferenceHandle(tokenType | rowId); + } + + internal static AssemblyReferenceHandle FromVirtualIndex(VirtualIndex virtualIndex) + { + Debug.Assert(virtualIndex < VirtualIndex.Count); + return new AssemblyReferenceHandle(TokenTypeIds.VirtualTokenMask | tokenType | (uint)virtualIndex); + } + + public static implicit operator Handle(AssemblyReferenceHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator AssemblyReferenceHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new AssemblyReferenceHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & TokenTypeIds.VirtualBitAndRowIdMask) == 0; + } + } + + internal bool IsVirtual + { + get { return (_token & TokenTypeIds.VirtualTokenMask) != 0; } + } + + internal uint Token { get { return _token; } } + + internal uint RowId { get { return _token & TokenTypeIds.RIDMask; } } + + public static bool operator ==(AssemblyReferenceHandle left, AssemblyReferenceHandle right) + { + return left._token == right._token; + } + + public override bool Equals(object obj) + { + return obj is AssemblyReferenceHandle && ((AssemblyReferenceHandle)obj)._token == _token; + } + + public bool Equals(AssemblyReferenceHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(AssemblyReferenceHandle left, AssemblyReferenceHandle right) + { + return left._token != right._token; + } + } + + public struct CustomAttributeHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.CustomAttribute; + private readonly uint _rowId; + + private CustomAttributeHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static CustomAttributeHandle FromRowId(uint rowId) + { + return new CustomAttributeHandle(rowId); + } + + public static implicit operator Handle(CustomAttributeHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator CustomAttributeHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new CustomAttributeHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return _rowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(CustomAttributeHandle left, CustomAttributeHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is CustomAttributeHandle && ((CustomAttributeHandle)obj)._rowId == _rowId; + } + + public bool Equals(CustomAttributeHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(CustomAttributeHandle left, CustomAttributeHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct DeclarativeSecurityAttributeHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.DeclSecurity; + private readonly uint _rowId; + + private DeclarativeSecurityAttributeHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static DeclarativeSecurityAttributeHandle FromRowId(uint rowId) + { + return new DeclarativeSecurityAttributeHandle(rowId); + } + + public static implicit operator Handle(DeclarativeSecurityAttributeHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator DeclarativeSecurityAttributeHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new DeclarativeSecurityAttributeHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return _rowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(DeclarativeSecurityAttributeHandle left, DeclarativeSecurityAttributeHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is DeclarativeSecurityAttributeHandle && ((DeclarativeSecurityAttributeHandle)obj)._rowId == _rowId; + } + + public bool Equals(DeclarativeSecurityAttributeHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(DeclarativeSecurityAttributeHandle left, DeclarativeSecurityAttributeHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct ConstantHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Constant; + private readonly uint _rowId; + + private ConstantHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ConstantHandle FromRowId(uint rowId) + { + return new ConstantHandle(rowId); + } + + public static implicit operator Handle(ConstantHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ConstantHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ConstantHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ConstantHandle left, ConstantHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ConstantHandle && ((ConstantHandle)obj)._rowId == _rowId; + } + + public bool Equals(ConstantHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ConstantHandle left, ConstantHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct ManifestResourceHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.ManifestResource; + private readonly uint _rowId; + + private ManifestResourceHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static ManifestResourceHandle FromRowId(uint rowId) + { + return new ManifestResourceHandle(rowId); + } + + public static implicit operator Handle(ManifestResourceHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator ManifestResourceHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new ManifestResourceHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(ManifestResourceHandle left, ManifestResourceHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is ManifestResourceHandle && ((ManifestResourceHandle)obj)._rowId == _rowId; + } + + public bool Equals(ManifestResourceHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(ManifestResourceHandle left, ManifestResourceHandle right) + { + return left._rowId != right._rowId; + } + } + + public struct AssemblyFileHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.File; + private readonly uint _rowId; + + private AssemblyFileHandle(uint rowId) + { + Debug.Assert(TokenTypeIds.IsValidRowId(rowId)); + _rowId = rowId; + } + + internal static AssemblyFileHandle FromRowId(uint rowId) + { + return new AssemblyFileHandle(rowId); + } + + public static implicit operator Handle(AssemblyFileHandle handle) + { + return new Handle(handle._rowId | tokenType); + } + + public static explicit operator AssemblyFileHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new AssemblyFileHandle(handle.RowId); + } + + public bool IsNil + { + get + { + return RowId == 0; + } + } + + internal uint RowId { get { return _rowId; } } + + public static bool operator ==(AssemblyFileHandle left, AssemblyFileHandle right) + { + return left._rowId == right._rowId; + } + + public override bool Equals(object obj) + { + return obj is AssemblyFileHandle && ((AssemblyFileHandle)obj)._rowId == _rowId; + } + + public bool Equals(AssemblyFileHandle other) + { + return _rowId == other._rowId; + } + + public override int GetHashCode() + { + return _rowId.GetHashCode(); + } + + public static bool operator !=(AssemblyFileHandle left, AssemblyFileHandle right) + { + return left._rowId != right._rowId; + } + } + + // #UserString heap handle + public struct UserStringHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.UserString; + private readonly uint _token; + + private UserStringHandle(uint token) + { + Debug.Assert((token & TokenTypeIds.TokenTypeMask) == tokenType); + _token = token; + } + + internal static UserStringHandle FromIndex(uint heapIndex) + { + return new UserStringHandle(heapIndex | tokenType); + } + + public static implicit operator Handle(UserStringHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator UserStringHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new UserStringHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & TokenTypeIds.RIDMask) == 0; + } + } + + internal int Index + { + get + { + return (int)(_token & TokenTypeIds.RIDMask); + } + } + + public static bool operator ==(UserStringHandle left, UserStringHandle right) + { + return left._token == right._token; + } + + public override bool Equals(object obj) + { + return obj is UserStringHandle && ((UserStringHandle)obj)._token == _token; + } + + public bool Equals(UserStringHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(UserStringHandle left, UserStringHandle right) + { + return left._token != right._token; + } + } + + // #String heap handle + public struct StringHandle : IEquatable + { + // bits: + // 0..24: Heap index or Virtual index + // 25..30: TokenTypeId: String, WinRTPrefixedString + // 31: IsVirtual + private readonly uint _token; + + internal enum VirtualIndex + { + System_Runtime_WindowsRuntime, + System_Runtime, + System_ObjectModel, + System_Runtime_WindowsRuntime_UI_Xaml, + System_Runtime_InteropServices_WindowsRuntime, + System_Numerics_Vectors, + + Dispose, + + AttributeTargets, + AttributeUsageAttribute, + Color, + CornerRadius, + DateTimeOffset, + Duration, + DurationType, + EventHandler1, + EventRegistrationToken, + Exception, + GeneratorPosition, + GridLength, + GridUnitType, + ICommand, + IDictionary2, + IDisposable, + IEnumerable, + IEnumerable1, + IList, + IList1, + INotifyCollectionChanged, + INotifyPropertyChanged, + IReadOnlyDictionary2, + IReadOnlyList1, + KeyTime, + KeyValuePair2, + Matrix, + Matrix3D, + Matrix3x2, + Matrix4x4, + NotifyCollectionChangedAction, + NotifyCollectionChangedEventArgs, + NotifyCollectionChangedEventHandler, + Nullable1, + Plane, + Point, + PropertyChangedEventArgs, + PropertyChangedEventHandler, + Quaternion, + Rect, + RepeatBehavior, + RepeatBehaviorType, + Size, + System, + System_Collections, + System_Collections_Generic, + System_Collections_Specialized, + System_ComponentModel, + System_Numerics, + System_Windows_Input, + Thickness, + TimeSpan, + Type, + Uri, + Vector2, + Vector3, + Vector4, + Windows_Foundation, + Windows_UI, + Windows_UI_Xaml, + Windows_UI_Xaml_Controls_Primitives, + Windows_UI_Xaml_Media, + Windows_UI_Xaml_Media_Animation, + Windows_UI_Xaml_Media_Media3D, + + Count + } + + private StringHandle(uint token) + { + Debug.Assert((token & TokenTypeIds.TokenTypeMask) == TokenTypeIds.String || + (token & TokenTypeIds.TokenTypeMask) == TokenTypeIds.WinRTPrefixedString || + (token & TokenTypeIds.TokenTypeMask) == TokenTypeIds.DotTerminatedString); + _token = token; + } + + internal static StringHandle FromIndex(uint heapIndex) + { + Debug.Assert(TokenTypeIds.IsValidRowId(heapIndex)); + return new StringHandle(TokenTypeIds.String | heapIndex); + } + + internal static StringHandle FromVirtualIndex(VirtualIndex virtualIndex) + { + Debug.Assert(virtualIndex < VirtualIndex.Count); + return new StringHandle(TokenTypeIds.VirtualTokenMask | TokenTypeIds.String | (uint)virtualIndex); + } + + internal StringHandle WithWinRTPrefix() + { + Debug.Assert(!IsVirtual); + return new StringHandle(TokenTypeIds.VirtualTokenMask | TokenTypeIds.WinRTPrefixedString | (uint)Index); + } + + internal StringHandle WithDotTermination() + { + Debug.Assert(!IsVirtual); + return new StringHandle(TokenTypeIds.DotTerminatedString | (uint)Index); + } + + internal StringHandle SuffixRaw(int prefixByteLength) + { + Debug.Assert(!IsVirtual); + return new StringHandle(TokenTypeIds.String | (uint)(Index + prefixByteLength)); + } + + public static implicit operator Handle(StringHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator StringHandle(Handle handle) + { + if (handle.TokenType < TokenTypeIds.String || handle.TokenType > TokenTypeIds.MaxString) + { + Handle.ThrowInvalidCast(); + } + + return new StringHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & (TokenTypeIds.VirtualTokenMask | TokenTypeIds.RIDMask)) == 0; + } + } + + internal bool IsVirtual + { + get { return (_token & TokenTypeIds.VirtualTokenMask) != 0; } + } + + internal int Index + { + get + { + return (int)(_token & TokenTypeIds.RIDMask); + } + } + + internal StringKind StringKind + { + get + { + return (StringKind)((_token & TokenTypeIds.StringOrNamespaceKindMask) >> TokenTypeIds.RowIdBitCount); + } + } + + public static bool operator ==(StringHandle left, StringHandle right) + { + return left._token == right._token; + } + + public override bool Equals(object obj) + { + return obj is StringHandle && ((StringHandle)obj)._token == _token; + } + + public bool Equals(StringHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(StringHandle left, StringHandle right) + { + return left._token != right._token; + } + } + + /// + /// A handle that represents a namespace definition. + /// + public struct NamespaceDefinitionHandle : IEquatable + { + // + // bits: + // 0..24: Heap index or Virtual index + // 25..30: TokenTypeId: Namespace or SyntheticNamespace + // 31: IsVirtual + // + // At this time, IsVirtual is always false because namespace names come from type definitions + // and type forwarders only, which never get their namespaces projected. + // + // For standard Namespace TokenTypeId, the index is to the null-terminated full name of the + // namespace in the string heap. + // + // For SyntheticNamespace, the index points to the dot-terminated simple name of the namespace + // in the string heap. This is used to represent namespaces that are parents of other namespaces + // but no type definitions or forwarders of their own. + // + private readonly uint _token; + + private NamespaceDefinitionHandle(uint token) + { + Debug.Assert((token & TokenTypeIds.TokenTypeMask) == TokenTypeIds.Namespace || + (token & TokenTypeIds.TokenTypeMask) == TokenTypeIds.SyntheticNamespace); + + _token = token; + } + + internal static NamespaceDefinitionHandle FromIndexOfFullName(uint stringHeapIndex) + { + Debug.Assert(TokenTypeIds.IsValidRowId(stringHeapIndex)); + return new NamespaceDefinitionHandle(TokenTypeIds.Namespace | stringHeapIndex); + } + + internal static NamespaceDefinitionHandle FromIndexOfSimpleName(uint stringHeapIndex) + { + Debug.Assert(TokenTypeIds.IsValidRowId(stringHeapIndex)); + return new NamespaceDefinitionHandle(TokenTypeIds.SyntheticNamespace | stringHeapIndex); + } + + public static implicit operator Handle(NamespaceDefinitionHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator NamespaceDefinitionHandle(Handle handle) + { + if (handle.TokenType < TokenTypeIds.Namespace || handle.TokenType > TokenTypeIds.MaxNamespace) + { + Handle.ThrowInvalidCast(); + } + + return new NamespaceDefinitionHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & (TokenTypeIds.VirtualTokenMask | TokenTypeIds.RIDMask)) == 0; + } + } + + internal int Index + { + get + { + return (int)(_token & TokenTypeIds.RIDMask); + } + } + + internal bool IsVirtual + { + get + { + return (_token & TokenTypeIds.VirtualTokenMask) != 0; + } + } + + internal NamespaceKind NamespaceKind + { + get + { + return (NamespaceKind)((_token & TokenTypeIds.StringOrNamespaceKindMask) >> TokenTypeIds.RowIdBitCount); + } + } + + internal bool HasFullName + { + get + { + return (_token & (TokenTypeIds.TokenTypeMask)) != TokenTypeIds.SyntheticNamespace; + } + } + + internal StringHandle GetFullName() + { + Debug.Assert(!IsVirtual); + Debug.Assert(HasFullName); + return StringHandle.FromIndex((uint)Index); + } + + public static bool operator ==(NamespaceDefinitionHandle left, NamespaceDefinitionHandle right) + { + return left._token == right._token; + } + + public int CompareTo(NamespaceDefinitionHandle other) + { + return TokenTypeIds.CompareTokens(_token, other._token); + } + + public override bool Equals(object obj) + { + return obj is NamespaceDefinitionHandle && ((NamespaceDefinitionHandle)obj)._token == _token; + } + + public bool Equals(NamespaceDefinitionHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(NamespaceDefinitionHandle left, NamespaceDefinitionHandle right) + { + return left._token != right._token; + } + } + + // #Blob heap handle + public struct BlobHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Blob; + + // bits: + // 0..24: Heap index or Virtual Value (16 bits) + Virtual Index (8 bits) + // 25..30: TokenTypeId: Blob + // 31: IsVirtual + private readonly uint _token; + + internal enum VirtualIndex : byte + { + Nil, + + // B0 3F 5F 7F 11 D5 0A 3A + ContractPublicKeyToken, + + // 00, 24, 00, 00, 04, ... + ContractPublicKey, + + // Template for projected AttributeUsage attribute blob + AttributeUsage_AllowSingle, + + // Template for projected AttributeUsage attribute blob with AllowMultiple=true + AttributeUsage_AllowMultiple, + + Count + } + + private BlobHandle(uint token) + { + Debug.Assert((token & TokenTypeIds.TokenTypeMask) == tokenType); + _token = token; + } + + internal static BlobHandle FromIndex(uint heapIndex) + { + Debug.Assert(TokenTypeIds.IsValidRowId(heapIndex)); + return new BlobHandle(heapIndex | tokenType); + } + + internal static BlobHandle FromVirtualIndex(VirtualIndex virtualIndex, ushort virtualValue) + { + Debug.Assert(virtualIndex < VirtualIndex.Count); + return new BlobHandle(TokenTypeIds.VirtualTokenMask | tokenType | (uint)(virtualValue << 8) | (uint)virtualIndex); + } + + internal const int TemplateParameterOffset_AttributeUsageTarget = 2; + + internal unsafe void SubstituteTemplateParameters(byte[] blob) + { + Debug.Assert(blob.Length >= TemplateParameterOffset_AttributeUsageTarget + 4); + + fixed (byte* ptr = &blob[TemplateParameterOffset_AttributeUsageTarget]) + { + *((uint*)ptr) = VirtualValue; + } + } + + public static implicit operator Handle(BlobHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator BlobHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new BlobHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & (TokenTypeIds.VirtualTokenMask | TokenTypeIds.RIDMask)) == 0; + } + } + + internal int Index + { + get + { + Debug.Assert(!IsVirtual); + return (int)(_token & TokenTypeIds.RIDMask); + } + } + + internal bool IsVirtual + { + get + { + return (_token & TokenTypeIds.VirtualTokenMask) != 0; + } + } + + internal VirtualIndex GetVirtualIndex() + { + Debug.Assert(IsVirtual); + return (VirtualIndex)(_token & 0xff); + } + + private ushort VirtualValue + { + get { return unchecked((ushort)(_token >> 8)); } + } + + public static bool operator ==(BlobHandle left, BlobHandle right) + { + return left._token == right._token; + } + + public override bool Equals(object obj) + { + return obj is BlobHandle && ((BlobHandle)obj)._token == _token; + } + + public bool Equals(BlobHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(BlobHandle left, BlobHandle right) + { + return left._token != right._token; + } + } + + // #Guid heap handle + public struct GuidHandle : IEquatable + { + private const uint tokenType = TokenTypeIds.Guid; + private readonly uint _token; + + private GuidHandle(uint token) + { + Debug.Assert((token & TokenTypeIds.TokenTypeMask) == tokenType); + _token = token; + } + + internal static GuidHandle FromIndex(uint heapIndex) + { + return new GuidHandle(heapIndex | tokenType); + } + + public static implicit operator Handle(GuidHandle handle) + { + return new Handle(handle._token); + } + + public static explicit operator GuidHandle(Handle handle) + { + if (handle.TokenType != tokenType) + { + Handle.ThrowInvalidCast(); + } + + return new GuidHandle(handle.value); + } + + public bool IsNil + { + get + { + return (_token & (TokenTypeIds.VirtualTokenMask | TokenTypeIds.RIDMask)) == 0; + } + } + + internal int Index + { + get + { + return (int)(_token & TokenTypeIds.RIDMask); + } + } + + public static bool operator ==(GuidHandle left, GuidHandle right) + { + return left._token == right._token; + } + + public override bool Equals(object obj) + { + return obj is GuidHandle && ((GuidHandle)obj)._token == _token; + } + + public bool Equals(GuidHandle other) + { + return _token == other._token; + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + public static bool operator !=(GuidHandle left, GuidHandle right) + { + return left._token != right._token; + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/InterfaceImplementation.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/InterfaceImplementation.cs new file mode 100644 index 0000000..3daecf8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/InterfaceImplementation.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct InterfaceImplementation + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal InterfaceImplementation(MetadataReader reader, InterfaceImplementationHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private InterfaceImplementationHandle Handle + { + get { return InterfaceImplementationHandle.FromRowId(_rowId); } + } + + + /// + /// The interface that is implemented + /// , , or + /// + public Handle Interface + { + get { return _reader.InterfaceImplTable.GetInterface(_rowId); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/COR20Constants.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/COR20Constants.cs new file mode 100644 index 0000000..f588230 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/COR20Constants.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class COR20Constants + { + internal const int SizeOfCorHeader = 72; + internal const uint COR20MetadataSignature = 0x424A5342; + internal const int MinimumSizeofMetadataHeader = 16; + internal const int SizeofStorageHeader = 4; + internal const int MinimumSizeofStreamHeader = 8; + internal const string StringStreamName = "#Strings"; + internal const string BlobStreamName = "#Blob"; + internal const string GUIDStreamName = "#GUID"; + internal const string UserStringStreamName = "#US"; + internal const string CompressedMetadataTableStreamName = "#~"; + internal const string UncompressedMetadataTableStreamName = "#-"; + internal const string MinimalDeltaMetadataTableStreamName = "#JTD"; + internal const int LargeStreamHeapSize = 0x0001000; + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CorElementType.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CorElementType.cs new file mode 100644 index 0000000..e0bcb63 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CorElementType.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal enum CorElementType : byte + { + Invalid = 0x0, + + ELEMENT_TYPE_VOID = 0x1, + ELEMENT_TYPE_BOOLEAN = 0x2, + ELEMENT_TYPE_CHAR = 0x3, + ELEMENT_TYPE_I1 = 0x4, + ELEMENT_TYPE_U1 = 0x5, // Byte + ELEMENT_TYPE_I2 = 0x6, // Short, int16 + ELEMENT_TYPE_U2 = 0x7, // UShort + ELEMENT_TYPE_I4 = 0x8, // Integer, int32 + ELEMENT_TYPE_U4 = 0x9, // Uinteger + ELEMENT_TYPE_I8 = 0xA, // Long, int64 + ELEMENT_TYPE_U8 = 0xB, // ULong + ELEMENT_TYPE_R4 = 0xC, // Single + ELEMENT_TYPE_R8 = 0xD, // Double + ELEMENT_TYPE_STRING = 0xE, + + // every type above PTR will be simple type + ELEMENT_TYPE_PTR = 0xF, // PTR + ELEMENT_TYPE_BYREF = 0x10, // BYREF + + // Please use ELEMENT_TYPE_VALUETYPE. ELEMENT_TYPE_VALUECLASS is deprecated. + ELEMENT_TYPE_VALUETYPE = 0x11, // VALUETYPE + ELEMENT_TYPE_CLASS = 0x12, // CLASS + ELEMENT_TYPE_VAR = 0x13, // a class type variable VAR + ELEMENT_TYPE_ARRAY = 0x14, // MDARRAY ... ... + ELEMENT_TYPE_GENERICINST = 0x15, // GENERICINST ... + ELEMENT_TYPE_TYPEDBYREF = 0x16, // TYPEDREF (it takes no args) a typed reference to some other type + + ELEMENT_TYPE_I = 0x18, // native integer size + ELEMENT_TYPE_U = 0x19, // native unsigned integer size + + ELEMENT_TYPE_FNPTR = 0x1B, // FNPTR + ELEMENT_TYPE_OBJECT = 0x1C, // Shortcut for System.Object + ELEMENT_TYPE_SZARRAY = 0x1D, // Shortcut for single dimension zero lower bound array + // SZARRAY + ELEMENT_TYPE_MVAR = 0x1E, // a method type variable MVAR + + // This is only for binding + ELEMENT_TYPE_CMOD_REQD = 0x1F, // required C modifier : E_T_CMOD_REQD + ELEMENT_TYPE_CMOD_OPT = 0x20, // optional C modifier : E_T_CMOD_OPT + + ELEMENT_TYPE_HANDLE = 0x40, + ELEMENT_TYPE_SENTINEL = 0x41, // sentinel for varargs + ELEMENT_TYPE_PINNED = 0x45, + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CustomAttributeTypeTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CustomAttributeTypeTag.cs new file mode 100644 index 0000000..b18f7c8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/CustomAttributeTypeTag.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class CustomAttributeTypeTag + { + internal const int NumberOfBits = 3; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint MethodDef = 0x00000002; + internal const uint MemberRef = 0x00000003; + internal const uint TagMask = 0x0000007; + internal const ulong TagToTokenTypeByteVector = TokenTypeIds.MethodDef >> 8 | TokenTypeIds.MemberRef; + internal const TableMask TablesReferenced = + TableMask.MethodDef + | TableMask.MemberRef; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint customAttributeType) + { + uint tokenType = unchecked((uint)(TagToTokenTypeByteVector >> ((int)(customAttributeType & TagMask) << 3)) << TokenTypeIds.RowIdBitCount); + uint rowId = (customAttributeType >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasConstantTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasConstantTag.cs new file mode 100644 index 0000000..d9fd78c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasConstantTag.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class HasConstantTag + { + internal const int NumberOfBits = 2; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint Field = 0x00000000; + internal const uint Param = 0x00000001; + internal const uint Property = 0x00000002; + internal const uint TagMask = 0x00000003; + internal const TableMask TablesReferenced = + TableMask.Field + | TableMask.Param + | TableMask.Property; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.FieldDef >> 24 | TokenTypeIds.ParamDef >> 16 | TokenTypeIds.Property >> 8; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint hasConstant) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(hasConstant & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (hasConstant >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertToTag(Handle token) + { + HandleKind tokenKind = token.Kind; + uint rowId = token.RowId; + if (tokenKind == HandleKind.FieldDefinition) + { + return rowId << NumberOfBits | Field; + } + else if (tokenKind == HandleKind.Parameter) + { + return rowId << NumberOfBits | Param; + } + else if (tokenKind == HandleKind.PropertyDefinition) + { + return rowId << NumberOfBits | Property; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasCustomAttributeTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasCustomAttributeTag.cs new file mode 100644 index 0000000..2481308 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasCustomAttributeTag.cs @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class HasCustomAttributeTag + { + internal const int NumberOfBits = 5; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint MethodDef = 0x00000000; + internal const uint Field = 0x00000001; + internal const uint TypeRef = 0x00000002; + internal const uint TypeDef = 0x00000003; + internal const uint Param = 0x00000004; + internal const uint InterfaceImpl = 0x00000005; + internal const uint MemberRef = 0x00000006; + internal const uint Module = 0x00000007; + internal const uint DeclSecurity = 0x00000008; + internal const uint Property = 0x00000009; + internal const uint Event = 0x0000000A; + internal const uint StandAloneSig = 0x0000000B; + internal const uint ModuleRef = 0x0000000C; + internal const uint TypeSpec = 0x0000000D; + internal const uint Assembly = 0x0000000E; + internal const uint AssemblyRef = 0x0000000F; + internal const uint File = 0x00000010; + internal const uint ExportedType = 0x00000011; + internal const uint ManifestResource = 0x00000012; + internal const uint GenericParam = 0x00000013; + internal const uint GenericParamConstraint = 0x00000014; + internal const uint MethodSpec = 0x00000015; + internal const uint TagMask = 0x0000001F; + + // Arbitrary value not equal to any of the token types in the array. This includes 0 which is TokenTypeIds.Module. + internal const uint InvalidTokenType = uint.MaxValue; + + internal static uint[] TagToTokenTypeArray = + { + TokenTypeIds.MethodDef, + TokenTypeIds.FieldDef, + TokenTypeIds.TypeRef, + TokenTypeIds.TypeDef, + TokenTypeIds.ParamDef, + TokenTypeIds.InterfaceImpl, + TokenTypeIds.MemberRef, + TokenTypeIds.Module, + TokenTypeIds.DeclSecurity, + TokenTypeIds.Property, + TokenTypeIds.Event, + TokenTypeIds.Signature, + TokenTypeIds.ModuleRef, + TokenTypeIds.TypeSpec, + TokenTypeIds.Assembly, + TokenTypeIds.AssemblyRef, + TokenTypeIds.File, + TokenTypeIds.ExportedType, + TokenTypeIds.ManifestResource, + TokenTypeIds.GenericParam, + TokenTypeIds.GenericParamConstraint, + TokenTypeIds.MethodSpec, + + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType, + InvalidTokenType + }; + + internal const TableMask TablesReferenced = + TableMask.MethodDef + | TableMask.Field + | TableMask.TypeRef + | TableMask.TypeDef + | TableMask.Param + | TableMask.InterfaceImpl + | TableMask.MemberRef + | TableMask.Module + | TableMask.DeclSecurity + | TableMask.Property + | TableMask.Event + | TableMask.StandAloneSig + | TableMask.ModuleRef + | TableMask.TypeSpec + | TableMask.Assembly + | TableMask.AssemblyRef + | TableMask.File + | TableMask.ExportedType + | TableMask.ManifestResource + | TableMask.GenericParam + | TableMask.GenericParamConstraint + | TableMask.MethodSpec; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint hasCustomAttribute) + { + uint tokenType = TagToTokenTypeArray[hasCustomAttribute & TagMask]; + uint rowId = (hasCustomAttribute >> NumberOfBits); + + if (tokenType == InvalidTokenType || ((rowId & ~TokenTypeIds.RIDMask) != 0)) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertToTag(Handle handle) + { + uint tokenType = handle.TokenType; + uint rowId = handle.RowId; + switch (tokenType >> TokenTypeIds.RowIdBitCount) + { + case TokenTypeIds.MethodDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | MethodDef; + case TokenTypeIds.FieldDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Field; + case TokenTypeIds.TypeRef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | TypeRef; + case TokenTypeIds.TypeDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | TypeDef; + case TokenTypeIds.ParamDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Param; + case TokenTypeIds.InterfaceImpl >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | InterfaceImpl; + case TokenTypeIds.MemberRef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | MemberRef; + case TokenTypeIds.Module >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Module; + case TokenTypeIds.DeclSecurity >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | DeclSecurity; + case TokenTypeIds.Property >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Property; + case TokenTypeIds.Event >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Event; + case TokenTypeIds.Signature >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | StandAloneSig; + case TokenTypeIds.ModuleRef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | ModuleRef; + case TokenTypeIds.TypeSpec >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | TypeSpec; + case TokenTypeIds.Assembly >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Assembly; + case TokenTypeIds.AssemblyRef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | AssemblyRef; + case TokenTypeIds.File >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | File; + case TokenTypeIds.ExportedType >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | ExportedType; + case TokenTypeIds.ManifestResource >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | ManifestResource; + case TokenTypeIds.GenericParam >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | GenericParam; + case TokenTypeIds.GenericParamConstraint >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | GenericParamConstraint; + case TokenTypeIds.MethodSpec >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | MethodSpec; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasDeclSecurityTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasDeclSecurityTag.cs new file mode 100644 index 0000000..201d2fd --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasDeclSecurityTag.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class HasDeclSecurityTag + { + internal const int NumberOfBits = 2; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint TypeDef = 0x00000000; + internal const uint MethodDef = 0x00000001; + internal const uint Assembly = 0x00000002; + internal const uint TagMask = 0x00000003; + internal const TableMask TablesReferenced = + TableMask.TypeDef + | TableMask.MethodDef + | TableMask.Assembly; + internal const uint TagToTokenTypeByteVector = (TokenTypeIds.TypeDef >> 24) | (TokenTypeIds.MethodDef >> 16) | (TokenTypeIds.Assembly >> 8); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint hasDeclSecurity) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(hasDeclSecurity & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (hasDeclSecurity >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertToTag(Handle handle) + { + uint tokenType = handle.TokenType; + uint rowId = handle.RowId; + switch (tokenType >> TokenTypeIds.RowIdBitCount) + { + case TokenTypeIds.TypeDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | TypeDef; + + case TokenTypeIds.MethodDef >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | MethodDef; + + case TokenTypeIds.Assembly >> TokenTypeIds.RowIdBitCount: + return rowId << NumberOfBits | Assembly; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasFieldMarshalTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasFieldMarshalTag.cs new file mode 100644 index 0000000..b0fdacf --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasFieldMarshalTag.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class HasFieldMarshalTag + { + internal const int NumberOfBits = 1; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint Field = 0x00000000; + internal const uint Param = 0x00000001; + internal const uint TagMask = 0x00000001; + internal const TableMask TablesReferenced = + TableMask.Field + | TableMask.Param; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.FieldDef >> 24 | TokenTypeIds.ParamDef >> 16; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint hasFieldMarshal) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(hasFieldMarshal & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (hasFieldMarshal >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertToTag(Handle handle) + { + if (handle.TokenType == TokenTypeIds.FieldDef) + { + return handle.RowId << NumberOfBits | Field; + } + else if (handle.TokenType == TokenTypeIds.ParamDef) + { + return handle.RowId << NumberOfBits | Param; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasSemanticsTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasSemanticsTag.cs new file mode 100644 index 0000000..7047d4c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/HasSemanticsTag.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class HasSemanticsTag + { + internal const int NumberOfBits = 1; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint Event = 0x00000000; + internal const uint Property = 0x00000001; + internal const uint TagMask = 0x00000001; + internal const TableMask TablesReferenced = + TableMask.Event + | TableMask.Property; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.Event >> 24 | TokenTypeIds.Property >> 16; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint hasSemantic) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(hasSemantic & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (hasSemantic >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertEventHandleToTag(EventDefinitionHandle eventDef) + { + return eventDef.RowId << NumberOfBits | Event; + } + + internal static uint ConvertPropertyHandleToTag(PropertyDefinitionHandle propertyDef) + { + return propertyDef.RowId << NumberOfBits | Property; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Heaps.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Heaps.cs new file mode 100644 index 0000000..09b6add --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Heaps.cs @@ -0,0 +1,550 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Reflection.Internal; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal struct StringStreamReader + { + private static string[] s_virtualValues; + + internal readonly MemoryBlock Block; + + internal StringStreamReader(MemoryBlock block, MetadataKind metadataKind) + { + if (s_virtualValues == null && metadataKind != MetadataKind.Ecma335) + { + // Note: + // Virtual values shall not contain surrogates, otherwise StartsWith might be inconsistent + // when comparing to a text that ends with a high surrogate. + + var values = new string[(int)StringHandle.VirtualIndex.Count]; + values[(int)StringHandle.VirtualIndex.System_Runtime_WindowsRuntime] = "System.Runtime.WindowsRuntime"; + values[(int)StringHandle.VirtualIndex.System_Runtime] = "System.Runtime"; + values[(int)StringHandle.VirtualIndex.System_ObjectModel] = "System.ObjectModel"; + values[(int)StringHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml] = "System.Runtime.WindowsRuntime.UI.Xaml"; + values[(int)StringHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime] = "System.Runtime.InteropServices.WindowsRuntime"; + values[(int)StringHandle.VirtualIndex.System_Numerics_Vectors] = "System.Numerics.Vectors"; + + values[(int)StringHandle.VirtualIndex.Dispose] = "Dispose"; + + values[(int)StringHandle.VirtualIndex.AttributeTargets] = "AttributeTargets"; + values[(int)StringHandle.VirtualIndex.AttributeUsageAttribute] = "AttributeUsageAttribute"; + values[(int)StringHandle.VirtualIndex.Color] = "Color"; + values[(int)StringHandle.VirtualIndex.CornerRadius] = "CornerRadius"; + values[(int)StringHandle.VirtualIndex.DateTimeOffset] = "DateTimeOffset"; + values[(int)StringHandle.VirtualIndex.Duration] = "Duration"; + values[(int)StringHandle.VirtualIndex.DurationType] = "DurationType"; + values[(int)StringHandle.VirtualIndex.EventHandler1] = "EventHandler`1"; + values[(int)StringHandle.VirtualIndex.EventRegistrationToken] = "EventRegistrationToken"; + values[(int)StringHandle.VirtualIndex.Exception] = "Exception"; + values[(int)StringHandle.VirtualIndex.GeneratorPosition] = "GeneratorPosition"; + values[(int)StringHandle.VirtualIndex.GridLength] = "GridLength"; + values[(int)StringHandle.VirtualIndex.GridUnitType] = "GridUnitType"; + values[(int)StringHandle.VirtualIndex.ICommand] = "ICommand"; + values[(int)StringHandle.VirtualIndex.IDictionary2] = "IDictionary`2"; + values[(int)StringHandle.VirtualIndex.IDisposable] = "IDisposable"; + values[(int)StringHandle.VirtualIndex.IEnumerable] = "IEnumerable"; + values[(int)StringHandle.VirtualIndex.IEnumerable1] = "IEnumerable`1"; + values[(int)StringHandle.VirtualIndex.IList] = "IList"; + values[(int)StringHandle.VirtualIndex.IList1] = "IList`1"; + values[(int)StringHandle.VirtualIndex.INotifyCollectionChanged] = "INotifyCollectionChanged"; + values[(int)StringHandle.VirtualIndex.INotifyPropertyChanged] = "INotifyPropertyChanged"; + values[(int)StringHandle.VirtualIndex.IReadOnlyDictionary2] = "IReadOnlyDictionary`2"; + values[(int)StringHandle.VirtualIndex.IReadOnlyList1] = "IReadOnlyList`1"; + values[(int)StringHandle.VirtualIndex.KeyTime] = "KeyTime"; + values[(int)StringHandle.VirtualIndex.KeyValuePair2] = "KeyValuePair`2"; + values[(int)StringHandle.VirtualIndex.Matrix] = "Matrix"; + values[(int)StringHandle.VirtualIndex.Matrix3D] = "Matrix3D"; + values[(int)StringHandle.VirtualIndex.Matrix3x2] = "Matrix3x2"; + values[(int)StringHandle.VirtualIndex.Matrix4x4] = "Matrix4x4"; + values[(int)StringHandle.VirtualIndex.NotifyCollectionChangedAction] = "NotifyCollectionChangedAction"; + values[(int)StringHandle.VirtualIndex.NotifyCollectionChangedEventArgs] = "NotifyCollectionChangedEventArgs"; + values[(int)StringHandle.VirtualIndex.NotifyCollectionChangedEventHandler] = "NotifyCollectionChangedEventHandler"; + values[(int)StringHandle.VirtualIndex.Nullable1] = "Nullable`1"; + values[(int)StringHandle.VirtualIndex.Plane] = "Plane"; + values[(int)StringHandle.VirtualIndex.Point] = "Point"; + values[(int)StringHandle.VirtualIndex.PropertyChangedEventArgs] = "PropertyChangedEventArgs"; + values[(int)StringHandle.VirtualIndex.PropertyChangedEventHandler] = "PropertyChangedEventHandler"; + values[(int)StringHandle.VirtualIndex.Quaternion] = "Quaternion"; + values[(int)StringHandle.VirtualIndex.Rect] = "Rect"; + values[(int)StringHandle.VirtualIndex.RepeatBehavior] = "RepeatBehavior"; + values[(int)StringHandle.VirtualIndex.RepeatBehaviorType] = "RepeatBehaviorType"; + values[(int)StringHandle.VirtualIndex.Size] = "Size"; + values[(int)StringHandle.VirtualIndex.System] = "System"; + values[(int)StringHandle.VirtualIndex.System_Collections] = "System.Collections"; + values[(int)StringHandle.VirtualIndex.System_Collections_Generic] = "System.Collections.Generic"; + values[(int)StringHandle.VirtualIndex.System_Collections_Specialized] = "System.Collections.Specialized"; + values[(int)StringHandle.VirtualIndex.System_ComponentModel] = "System.ComponentModel"; + values[(int)StringHandle.VirtualIndex.System_Numerics] = "System.Numerics"; + values[(int)StringHandle.VirtualIndex.System_Windows_Input] = "System.Windows.Input"; + values[(int)StringHandle.VirtualIndex.Thickness] = "Thickness"; + values[(int)StringHandle.VirtualIndex.TimeSpan] = "TimeSpan"; + values[(int)StringHandle.VirtualIndex.Type] = "Type"; + values[(int)StringHandle.VirtualIndex.Uri] = "Uri"; + values[(int)StringHandle.VirtualIndex.Vector2] = "Vector2"; + values[(int)StringHandle.VirtualIndex.Vector3] = "Vector3"; + values[(int)StringHandle.VirtualIndex.Vector4] = "Vector4"; + values[(int)StringHandle.VirtualIndex.Windows_Foundation] = "Windows.Foundation"; + values[(int)StringHandle.VirtualIndex.Windows_UI] = "Windows.UI"; + values[(int)StringHandle.VirtualIndex.Windows_UI_Xaml] = "Windows.UI.Xaml"; + values[(int)StringHandle.VirtualIndex.Windows_UI_Xaml_Controls_Primitives] = "Windows.UI.Xaml.Controls.Primitives"; + values[(int)StringHandle.VirtualIndex.Windows_UI_Xaml_Media] = "Windows.UI.Xaml.Media"; + values[(int)StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation] = "Windows.UI.Xaml.Media.Animation"; + values[(int)StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Media3D] = "Windows.UI.Xaml.Media.Media3D"; + + s_virtualValues = values; + AssertFilled(); + } + + this.Block = TrimEnd(block); + } + + [Conditional("DEBUG")] + private static void AssertFilled() + { + for (int i = 0; i < s_virtualValues.Length; i++) + { + Debug.Assert(s_virtualValues[i] != null, "Missing virtual value for StringHandle.VirtualIndex." + (StringHandle.VirtualIndex)i); + } + } + + // Trims the alignment padding of the heap. + // See StgStringPool::InitOnMem in ndp\clr\src\Utilcode\StgPool.cpp. + + // This is especially important for EnC. + private static MemoryBlock TrimEnd(MemoryBlock block) + { + if (block.Length == 0) + { + return block; + } + + int i = block.Length - 1; + while (i >= 0 && block.PeekByte(i) == 0) + { + i--; + } + + // this shouldn't happen in valid metadata: + if (i == block.Length - 1) + { + return block; + } + + // +1 for terminating \0 + return block.GetMemoryBlockAt(0, i + 2); + } + + + internal string GetVirtualValue(StringHandle.VirtualIndex index) + { + return s_virtualValues[(int)index]; + } + + internal string GetString(StringHandle handle, MetadataStringDecoder utf8Decoder) + { + int index = handle.Index; + byte[] prefix; + + if (handle.IsVirtual) + { + switch (handle.StringKind) + { + case StringKind.Plain: + return s_virtualValues[index]; + + case StringKind.WinRTPrefixed: + prefix = MetadataReader.WinRTPrefix; + break; + + default: + Debug.Assert(false, "We should not get here"); + return null; + } + } + else + { + prefix = null; + } + + int bytesRead; + char otherTerminator = handle.StringKind == StringKind.DotTerminated ? '.' : '\0'; + return this.Block.PeekUtf8NullTerminated(index, prefix, utf8Decoder, out bytesRead, otherTerminator); + } + + internal StringHandle GetNextHandle(StringHandle handle) + { + if (handle.IsVirtual) + { + return default(StringHandle); + } + + int terminator = this.Block.IndexOf(0, handle.Index); + if (terminator == -1 || terminator == Block.Length - 1) + { + return default(StringHandle); + } + + return StringHandle.FromIndex((uint)(terminator + 1)); + } + + internal bool Equals(StringHandle handle, string value, MetadataStringDecoder utf8Decoder) + { + Debug.Assert(value != null); + + if (handle.IsVirtual) + { + // TODO:This can allocate unnecessarily for prefixed handles. + return GetString(handle, utf8Decoder) == value; + } + + if (handle.IsNil) + { + return value.Length == 0; + } + + char otherTerminator = handle.StringKind == StringKind.DotTerminated ? '.' : '\0'; + return this.Block.Utf8NullTerminatedEquals(handle.Index, value, utf8Decoder, otherTerminator); + } + + internal bool StartsWith(StringHandle handle, string value, MetadataStringDecoder utf8Decoder) + { + Debug.Assert(value != null); + + if (handle.IsVirtual) + { + // TODO:This can allocate unnecessarily for prefixed handles. + return GetString(handle, utf8Decoder).StartsWith(value, StringComparison.Ordinal); + } + + if (handle.IsNil) + { + return value.Length == 0; + } + + char otherTerminator = handle.StringKind == StringKind.DotTerminated ? '.' : '\0'; + return this.Block.Utf8NullTerminatedStartsWith(handle.Index, value, utf8Decoder, otherTerminator); + } + + /// + /// Returns true if the given raw (non-virtual) handle represents the same string as given ASCII string. + /// + internal bool EqualsRaw(StringHandle rawHandle, string asciiString) + { + Debug.Assert(!rawHandle.IsVirtual); + Debug.Assert(rawHandle.StringKind != StringKind.DotTerminated, "Not supported"); + return this.Block.CompareUtf8NullTerminatedStringWithAsciiString(rawHandle.Index, asciiString) == 0; + } + + /// + /// Returns the heap index of the given ASCII character or -1 if not found prior null terminator or end of heap. + /// + internal int IndexOfRaw(int startIndex, char asciiChar) + { + Debug.Assert(asciiChar != 0 && asciiChar <= 0x7f); + return this.Block.Utf8NullTerminatedOffsetOfAsciiChar(startIndex, asciiChar); + } + + /// + /// Returns true if the given raw (non-virtual) handle represents a string that starts with given ASCII prefix. + /// + internal bool StartsWithRaw(StringHandle rawHandle, string asciiPrefix) + { + Debug.Assert(!rawHandle.IsVirtual); + Debug.Assert(rawHandle.StringKind != StringKind.DotTerminated, "Not supported"); + return this.Block.Utf8NullTerminatedStringStartsWithAsciiPrefix(rawHandle.Index, asciiPrefix); + } + + /// + /// Equivalent to Array.BinarySearch, searches for given raw (non-virtual) handle in given array of ASCII strings. + /// + internal int BinarySearchRaw(string[] asciiKeys, StringHandle rawHandle) + { + Debug.Assert(!rawHandle.IsVirtual); + Debug.Assert(rawHandle.StringKind != StringKind.DotTerminated, "Not supported"); + return this.Block.BinarySearch(asciiKeys, rawHandle.Index); + } + } + + internal unsafe struct BlobStreamReader + { + private struct VirtualHeapBlob + { + public readonly GCHandle Pinned; + public readonly byte[] Array; + + public VirtualHeapBlob(byte[] array) + { + Pinned = GCHandle.Alloc(array, GCHandleType.Pinned); + Array = array; + } + } + + // Container for virtual heap blobs that unpins handles on finalization. + // This is not handled via dispose because the only resource is managed memory. + private sealed class VirtualHeapBlobTable + { + public readonly Dictionary Table; + + public VirtualHeapBlobTable() + { + Table = new Dictionary(); + } + + ~VirtualHeapBlobTable() + { + if (Table != null) + { + foreach (var blob in Table.Values) + { + blob.Pinned.Free(); + } + } + } + } + + // Since the number of virtual blobs we need is small (the number of attribute classes in .winmd files) + // we can create a pinned handle for each of them. + // If we needed many more blobs we could create and pin a single byte[] and allocate blobs there. + private VirtualHeapBlobTable _lazyVirtualHeapBlobs; + private static byte[][] s_virtualHeapBlobs; + + internal readonly MemoryBlock Block; + + internal BlobStreamReader(MemoryBlock block, MetadataKind metadataKind) + { + _lazyVirtualHeapBlobs = null; + this.Block = block; + + if (s_virtualHeapBlobs == null && metadataKind != MetadataKind.Ecma335) + { + var blobs = new byte[(int)BlobHandle.VirtualIndex.Count][]; + + blobs[(int)BlobHandle.VirtualIndex.ContractPublicKeyToken] = new byte[] + { + 0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A + }; + + blobs[(int)BlobHandle.VirtualIndex.ContractPublicKey] = new byte[] + { + 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x07, 0xD1, 0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D, + 0xE9, 0xE8, 0xFD, 0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E, + 0xB2, 0x3B, 0xE7, 0x9A, 0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90, + 0x0B, 0x72, 0x3C, 0xF9, 0x80, 0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F, + 0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA, 0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1, + 0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB, 0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D, + 0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5, 0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D, + 0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D, 0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93 + }; + + blobs[(int)BlobHandle.VirtualIndex.AttributeUsage_AllowSingle] = new byte[] + { + // preamble: + 0x01, 0x00, + // target (template parameter): + 0x00, 0x00, 0x00, 0x00, + // named arg count: + 0x01, 0x00, + // SERIALIZATION_TYPE_PROPERTY + 0x54, + // ELEMENT_TYPE_BOOLEAN + 0x02, + // "AllowMultiple".Length + 0x0D, + // "AllowMultiple" + 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65, + // false + 0x00 + }; + + blobs[(int)BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple] = new byte[] + { + // preamble: + 0x01, 0x00, + // target (template parameter): + 0x00, 0x00, 0x00, 0x00, + // named arg count: + 0x01, 0x00, + // SERIALIZATION_TYPE_PROPERTY + 0x54, + // ELEMENT_TYPE_BOOLEAN + 0x02, + // "AllowMultiple".Length + 0x0D, + // "AllowMultiple" + 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65, + // true + 0x01 + }; + + s_virtualHeapBlobs = blobs; + } + } + + internal byte[] GetBytes(BlobHandle handle) + { + if (handle.IsVirtual) + { + // consider: if we returned an ImmutableArray we wouldn't need to copy + return GetVirtualBlobArray(handle, unique: true); + } + + int offset = handle.Index; + int bytesRead; + int numberOfBytes = this.Block.PeekCompressedInteger(offset, out bytesRead); + if (numberOfBytes == BlobReader.InvalidCompressedInteger) + { + return EmptyArray.Instance; + } + + return this.Block.PeekBytes(offset + bytesRead, numberOfBytes); + } + + internal BlobReader GetBlobReader(BlobHandle handle) + { + if (handle.IsVirtual) + { + if (_lazyVirtualHeapBlobs == null) + { + Interlocked.CompareExchange(ref _lazyVirtualHeapBlobs, new VirtualHeapBlobTable(), null); + } + + int index = (int)handle.GetVirtualIndex(); + int length = s_virtualHeapBlobs[index].Length; + + VirtualHeapBlob virtualBlob; + lock (_lazyVirtualHeapBlobs) + { + if (!_lazyVirtualHeapBlobs.Table.TryGetValue(handle, out virtualBlob)) + { + virtualBlob = new VirtualHeapBlob(GetVirtualBlobArray(handle, unique: false)); + _lazyVirtualHeapBlobs.Table.Add(handle, virtualBlob); + } + } + + return new BlobReader(new MemoryBlock((byte*)virtualBlob.Pinned.AddrOfPinnedObject(), length)); + } + + int offset, size; + Block.PeekHeapValueOffsetAndSize(handle.Index, out offset, out size); + return new BlobReader(this.Block.GetMemoryBlockAt(offset, size)); + } + + internal BlobHandle GetNextHandle(BlobHandle handle) + { + if (handle.IsVirtual) + { + return default(BlobHandle); + } + + int offset, size; + if (!Block.PeekHeapValueOffsetAndSize(handle.Index, out offset, out size)) + { + return default(BlobHandle); + } + + int nextIndex = offset + size; + if (nextIndex >= Block.Length) + { + return default(BlobHandle); + } + + return BlobHandle.FromIndex((uint)nextIndex); + } + + internal byte[] GetVirtualBlobArray(BlobHandle handle, bool unique) + { + BlobHandle.VirtualIndex index = handle.GetVirtualIndex(); + byte[] result = s_virtualHeapBlobs[(int)index]; + + switch (index) + { + case BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple: + case BlobHandle.VirtualIndex.AttributeUsage_AllowSingle: + result = (byte[])result.Clone(); + handle.SubstituteTemplateParameters(result); + break; + + default: + if (unique) + { + result = (byte[])result.Clone(); + } + break; + } + + return result; + } + } + + internal struct GuidStreamReader + { + internal readonly MemoryBlock Block; + internal const int GuidSize = 16; + + public GuidStreamReader(MemoryBlock block) + { + this.Block = block; + } + + internal Guid GetGuid(GuidHandle handle) + { + if (handle.IsNil) + { + return default(Guid); + } + + // Metadata Spec: The Guid heap is an array of GUIDs, each 16 bytes wide. + // Its first element is numbered 1, its second 2, and so on. + return this.Block.PeekGuid((handle.Index - 1) * GuidSize); + } + } + + internal struct UserStringStreamReader + { + internal readonly MemoryBlock Block; + + public UserStringStreamReader(MemoryBlock block) + { + this.Block = block; + } + + internal string GetString(UserStringHandle handle) + { + int offset, size; + if (!Block.PeekHeapValueOffsetAndSize(handle.Index, out offset, out size)) + { + return string.Empty; + } + + // Spec: Furthermore, there is an additional terminal byte (so all byte counts are odd, not even). + // The size in the blob header is the length of the string in bytes + 1. + return this.Block.PeekUtf16(offset, size & ~1); + } + + internal UserStringHandle GetNextHandle(UserStringHandle handle) + { + int offset, size; + if (!Block.PeekHeapValueOffsetAndSize(handle.Index, out offset, out size)) + { + return default(UserStringHandle); + } + + int nextIndex = offset + size; + if (nextIndex >= Block.Length) + { + return default(UserStringHandle); + } + + return UserStringHandle.FromIndex((uint)nextIndex); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ImplementationTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ImplementationTag.cs new file mode 100644 index 0000000..2f9be4c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ImplementationTag.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class ImplementationTag + { + internal const int NumberOfBits = 2; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint File = 0x00000000; + internal const uint AssemblyRef = 0x00000001; + internal const uint ExportedType = 0x00000002; + internal const uint TagMask = 0x00000003; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.File >> 24 | TokenTypeIds.AssemblyRef >> 16 | TokenTypeIds.ExportedType >> 8; + internal const TableMask TablesReferenced = + TableMask.File + | TableMask.AssemblyRef + | TableMask.ExportedType; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint implementation) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(implementation & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (implementation >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberForwardedTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberForwardedTag.cs new file mode 100644 index 0000000..8cd453b --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberForwardedTag.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class MemberForwardedTag + { + internal const int NumberOfBits = 1; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint Field = 0x00000000; + internal const uint MethodDef = 0x00000001; + internal const uint TagMask = 0x00000001; + internal const TableMask TablesReferenced = + TableMask.Field + | TableMask.MethodDef; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.FieldDef >> 24 | TokenTypeIds.MethodDef >> 16; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint memberForwarded) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(memberForwarded & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (memberForwarded >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertMethodDefToTag(MethodDefinitionHandle methodDef) + { + return methodDef.RowId << NumberOfBits | MethodDef; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberRefParentTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberRefParentTag.cs new file mode 100644 index 0000000..10b1b3c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MemberRefParentTag.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class MemberRefParentTag + { + internal const int NumberOfBits = 3; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint TypeDef = 0x00000000; + internal const uint TypeRef = 0x00000001; + internal const uint ModuleRef = 0x00000002; + internal const uint MethodDef = 0x00000003; + internal const uint TypeSpec = 0x00000004; + internal const uint TagMask = 0x00000007; + internal const TableMask TablesReferenced = + TableMask.TypeDef + | TableMask.TypeRef + | TableMask.ModuleRef + | TableMask.MethodDef + | TableMask.TypeSpec; + internal const ulong TagToTokenTypeByteVector = + (ulong)TokenTypeIds.TypeDef >> 24 + | (ulong)TokenTypeIds.TypeRef >> 16 + | (ulong)TokenTypeIds.ModuleRef >> 8 + | (ulong)TokenTypeIds.MethodDef + | (ulong)TokenTypeIds.TypeSpec << 8; + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint memberRef) + { + uint tokenType = unchecked((uint)((TagToTokenTypeByteVector >> ((int)(memberRef & TagMask) << 3)) << TokenTypeIds.RowIdBitCount)); + uint rowId = (memberRef >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataFlags.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataFlags.cs new file mode 100644 index 0000000..2f7e9d8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataFlags.cs @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal enum MetadataStreamKind + { + Illegal, + Compressed, + Uncompressed, + } + + [Flags] + internal enum TableMask : ulong + { + Module = 1UL << TableIndex.Module, + TypeRef = 1UL << TableIndex.TypeRef, + TypeDef = 1UL << TableIndex.TypeDef, + FieldPtr = 1UL << TableIndex.FieldPtr, + Field = 1UL << TableIndex.Field, + MethodPtr = 1UL << TableIndex.MethodPtr, + MethodDef = 1UL << TableIndex.MethodDef, + ParamPtr = 1UL << TableIndex.ParamPtr, + Param = 1UL << TableIndex.Param, + InterfaceImpl = 1UL << TableIndex.InterfaceImpl, + MemberRef = 1UL << TableIndex.MemberRef, + Constant = 1UL << TableIndex.Constant, + CustomAttribute = 1UL << TableIndex.CustomAttribute, + FieldMarshal = 1UL << TableIndex.FieldMarshal, + DeclSecurity = 1UL << TableIndex.DeclSecurity, + ClassLayout = 1UL << TableIndex.ClassLayout, + FieldLayout = 1UL << TableIndex.FieldLayout, + StandAloneSig = 1UL << TableIndex.StandAloneSig, + EventMap = 1UL << TableIndex.EventMap, + EventPtr = 1UL << TableIndex.EventPtr, + Event = 1UL << TableIndex.Event, + PropertyMap = 1UL << TableIndex.PropertyMap, + PropertyPtr = 1UL << TableIndex.PropertyPtr, + Property = 1UL << TableIndex.Property, + MethodSemantics = 1UL << TableIndex.MethodSemantics, + MethodImpl = 1UL << TableIndex.MethodImpl, + ModuleRef = 1UL << TableIndex.ModuleRef, + TypeSpec = 1UL << TableIndex.TypeSpec, + ImplMap = 1UL << TableIndex.ImplMap, + FieldRva = 1UL << TableIndex.FieldRva, + EnCLog = 1UL << TableIndex.EncLog, + EnCMap = 1UL << TableIndex.EncMap, + Assembly = 1UL << TableIndex.Assembly, + // AssemblyProcessor = 1UL << TableIndices.AssemblyProcessor, + // AssemblyOS = 1UL << TableIndices.AssemblyOS, + AssemblyRef = 1UL << TableIndex.AssemblyRef, + // AssemblyRefProcessor = 1UL << TableIndices.AssemblyRefProcessor, + // AssemblyRefOS = 1UL << TableIndices.AssemblyRefOS, + File = 1UL << TableIndex.File, + ExportedType = 1UL << TableIndex.ExportedType, + ManifestResource = 1UL << TableIndex.ManifestResource, + NestedClass = 1UL << TableIndex.NestedClass, + GenericParam = 1UL << TableIndex.GenericParam, + MethodSpec = 1UL << TableIndex.MethodSpec, + GenericParamConstraint = 1UL << TableIndex.GenericParamConstraint, + + PtrTables = + FieldPtr + | MethodPtr + | ParamPtr + | EventPtr + | PropertyPtr, + V2_0_TablesMask = + Module + | TypeRef + | TypeDef + | FieldPtr + | Field + | MethodPtr + | MethodDef + | ParamPtr + | Param + | InterfaceImpl + | MemberRef + | Constant + | CustomAttribute + | FieldMarshal + | DeclSecurity + | ClassLayout + | FieldLayout + | StandAloneSig + | EventMap + | EventPtr + | Event + | PropertyMap + | PropertyPtr + | Property + | MethodSemantics + | MethodImpl + | ModuleRef + | TypeSpec + | ImplMap + | FieldRva + | EnCLog + | EnCMap + | Assembly + | AssemblyRef + | File + | ExportedType + | ManifestResource + | NestedClass + | GenericParam + | MethodSpec + | GenericParamConstraint, + } + + internal enum HeapSizeFlag : byte + { + StringHeapLarge = 0x01, // 4 byte uint indexes used for string heap offsets + GuidHeapLarge = 0x02, // 4 byte uint indexes used for GUID heap offsets + BlobHeapLarge = 0x04, // 4 byte uint indexes used for Blob heap offsets + EnCDeltas = 0x20, // Indicates only EnC Deltas are present + DeletedMarks = 0x80, // Indicates metadata might contain items marked deleted + } + + internal enum StringKind : byte + { + Plain = 0, + WinRTPrefixed = 1, + DotTerminated = 2, + } + + internal enum NamespaceKind : byte + { + Plain = 0, + Synthetic = 1, + } + + internal static class TokenTypeIds + { + internal const uint Module = 0x00000000; + internal const uint TypeRef = 0x01000000; + internal const uint TypeDef = 0x02000000; + internal const uint FieldDef = 0x04000000; + internal const uint MethodDef = 0x06000000; + internal const uint ParamDef = 0x08000000; + internal const uint InterfaceImpl = 0x09000000; + internal const uint MemberRef = 0x0a000000; + internal const uint Constant = 0x0b000000; + internal const uint CustomAttribute = 0x0c000000; + internal const uint DeclSecurity = 0x0e000000; + internal const uint Signature = 0x11000000; + internal const uint EventMap = 0x12000000; + internal const uint Event = 0x14000000; + internal const uint PropertyMap = 0x15000000; + internal const uint Property = 0x17000000; + internal const uint MethodSemantics = 0x18000000; + internal const uint MethodImpl = 0x19000000; + internal const uint ModuleRef = 0x1a000000; + internal const uint TypeSpec = 0x1b000000; + internal const uint Assembly = 0x20000000; + internal const uint AssemblyRef = 0x23000000; + internal const uint File = 0x26000000; + internal const uint ExportedType = 0x27000000; + internal const uint ManifestResource = 0x28000000; + internal const uint NestedClass = 0x29000000; + internal const uint GenericParam = 0x2a000000; + internal const uint MethodSpec = 0x2b000000; + internal const uint GenericParamConstraint = 0x2c000000; + + internal const uint UserString = 0x70000000; // #UserString heap + + // The following values never appear in a token stored in metadata, + // they are just helper values to identify the type of a handle. + + internal const uint Blob = 0x71000000; // #Blob heap + internal const uint Guid = 0x72000000; // #Guid heap + + // #String heap and its modifications + internal const uint String = 0x78000000; // #String heap + internal const uint WinRTPrefixedString = 0x79000000; // #String heap with prefix + internal const uint DotTerminatedString = 0x7a000000; // #String heap that treats '.' as a string terminator in addition to '\0' + // internal const uint ReservedString = 0x7b000000; // [reserved] can only be used for a new string kind. + internal const uint MaxString = DotTerminatedString; + + internal const uint Namespace = 0x7c000000; // Namespace handle for namespace with types of its own + internal const uint SyntheticNamespace = 0x7d000000; // Namespace handle for namespace with child namespaces but no types of its own + // internal const uint Reserved1Namespace = 0x7e000000; // [reserved] can only be used for a new namespace kind + // internal const uint Reserved2Namespace = 0x7f000000; // [reserved] can only be used for a new namespace kind + internal const uint MaxNamespace = SyntheticNamespace; + + internal const uint StringOrNamespaceKindMask = 0x03000000; + + internal const uint HeapMask = 0x70000000; + internal const uint RIDMask = 0x00FFFFFF; + internal const uint TableTokenTypeMask = 0x5F000000; + internal const uint TokenTypeMask = 0x7F000000; + + /// + /// Use the highest bit to mark tokens that are virtual (synthesized). + /// We create virtual tokens to represent projected WinMD entities. + /// + internal const uint VirtualTokenMask = 1U << 31; + + internal const uint VirtualBitAndRowIdMask = VirtualTokenMask | RIDMask; + + internal const int RowIdBitCount = 24; + + /// + /// Returns true if the token value can escape the metadata reader. + /// We don't allow virtual tokens and heap tokens other than UserString to escape + /// since the token type ids are internal to the reader and not specified by ECMA spec. + /// + /// Spec (Partition III, 1.9 Metadata tokens): + /// Many CIL instructions are followed by a "metadata token". This is a 4-byte value, that specifies a row in a + /// metadata table, or a starting byte offset in the User String heap. + /// + /// For example, a value of 0x02 specifies the TypeDef table; a value of 0x70 specifies the User + /// String heap.The value corresponds to the number assigned to that metadata table (see Partition II for the full + /// list of tables) or to 0x70 for the User String heap.The least-significant 3 bytes specify the target row within that + /// metadata table, or starting byte offset within the User String heap. + /// + internal static bool IsEcmaToken(uint value) + { + return (value & TokenTypeMask) <= UserString; + } + + internal static bool IsValidRowId(uint rowId) + { + return (rowId & ~RIDMask) == 0; + } + + internal static int CompareTokens(uint t1, uint t2) + { + // all virtual tokens will be sorted after non-virtual tokens + return (int)((t1 & RIDMask) | ((t1 & VirtualTokenMask) >> 3)) - + (int)((t2 & RIDMask) | ((t2 & VirtualTokenMask) >> 3)); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataHeader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataHeader.cs new file mode 100644 index 0000000..bd41b0a --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataHeader.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal struct MetadataHeader + { + internal uint Signature; + internal ushort MajorVersion; + internal ushort MinorVersion; + internal uint ExtraData; + internal int VersionStringSize; + internal string VersionString; + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataStreamConstants.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataStreamConstants.cs new file mode 100644 index 0000000..c75605f --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataStreamConstants.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class MetadataStreamConstants + { + internal const int SizeOfMetadataTableHeader = 24; + internal const uint LargeTableRowCount = 0x00010000; + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataTableHeader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataTableHeader.cs new file mode 100644 index 0000000..a10a12e --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MetadataTableHeader.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection.Internal; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal struct MetadataTableHeader + { + internal uint Reserved; + internal byte MajorVersion; + internal byte MinorVersion; + internal HeapSizeFlag HeapSizeFlags; + internal byte RowId; + internal TableMask ValidTables; + internal TableMask SortedTables; + + // Helper methods + internal int GetNumberOfTablesPresent() + { + return BitArithmetic.CountBits((ulong)this.ValidTables); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MethodDefOrRefTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MethodDefOrRefTag.cs new file mode 100644 index 0000000..445edb8 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/MethodDefOrRefTag.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class MethodDefOrRefTag + { + internal const int NumberOfBits = 1; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint MethodDef = 0x00000000; + internal const uint MemberRef = 0x00000001; + internal const uint TagMask = 0x00000001; + internal const TableMask TablesReferenced = + TableMask.MethodDef + | TableMask.MemberRef; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.MethodDef >> 24 | TokenTypeIds.MemberRef >> 16; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint methodDefOrRef) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(methodDefOrRef & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (methodDefOrRef >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceCache.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceCache.cs new file mode 100644 index 0000000..1ee3edc --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceCache.cs @@ -0,0 +1,513 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal class NamespaceCache + { + private readonly MetadataReader _metadataReader; + private readonly object _namespaceTableAndListLock = new object(); + private Dictionary _namespaceTable; + private NamespaceData _rootNamespace; + private ImmutableArray _namespaceList; + + internal NamespaceCache(MetadataReader reader) + { + Debug.Assert(reader != null); + _metadataReader = reader; + } + + /// + /// Returns whether the namespaceTable has been created. If it hasn't, calling a GetXXX method + /// on this will probably have a very high amount of overhead. + /// + internal bool CacheIsRealized + { + get { return _namespaceTable != null; } + } + + internal string GetFullName(NamespaceDefinitionHandle handle) + { + Debug.Assert(!handle.HasFullName); // we should not hit the cache in this case. + NamespaceData data = GetNamespaceData(handle); + return data.FullName; + } + + internal NamespaceData GetRootNamespace() + { + EnsureNamespaceTableIsPopulated(); + Debug.Assert(_rootNamespace != null); + return _rootNamespace; + } + + internal NamespaceData GetNamespaceData(NamespaceDefinitionHandle handle) + { + EnsureNamespaceTableIsPopulated(); + NamespaceData result; + if (!_namespaceTable.TryGetValue(handle, out result)) + { + ThrowInvalidHandle(); + } + return result; + } + + // TODO: move throw helpers to common place. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + private static void ThrowInvalidHandle() + { + throw new BadImageFormatException(MetadataResources.InvalidHandle); + } + + /// + /// This will return a StringHandle for the simple name of a namespace name at the given segment index. + /// If no segment index is passed explicitly or the "segment" index is greater than or equal to the number + /// of segments, then the last segment is used. "Segment" in this context refers to part of a namespace + /// name between dots. + /// + /// Example: Given a NamespaceDefinitionHandle to "System.Collections.Generic.Test" called 'handle': + /// + /// reader.GetString(GetSimpleName(handle)) == "Test" + /// reader.GetString(GetSimpleName(handle, 0)) == "System" + /// reader.GetString(GetSimpleName(handle, 1)) == "Collections" + /// reader.GetString(GetSimpleName(handle, 2)) == "Generic" + /// reader.GetString(GetSimpleName(handle, 3)) == "Test" + /// reader.GetString(GetSimpleName(handle, 1000)) == "Test" + /// + private StringHandle GetSimpleName(NamespaceDefinitionHandle fullNamespaceHandle, int segmentIndex = Int32.MaxValue) + { + StringHandle handleContainingSegment = fullNamespaceHandle.GetFullName(); + Debug.Assert(!handleContainingSegment.IsVirtual); + + int lastFoundIndex = fullNamespaceHandle.Index - 1; + int currentSegment = 0; + while (currentSegment < segmentIndex) + { + int currentIndex = _metadataReader.StringStream.IndexOfRaw(lastFoundIndex + 1, '.'); + if (currentIndex == -1) + { + break; + } + lastFoundIndex = currentIndex; + ++currentSegment; + } + + Debug.Assert(lastFoundIndex >= 0 || currentSegment == 0); + + // + 1 because lastFoundIndex will either "point" to a '.', or will be -1. Either way, + // we want the next char. + uint resultIndex = (uint)(lastFoundIndex + 1); + return StringHandle.FromIndex(resultIndex).WithDotTermination(); + } + + /// + /// Two distinct namespace handles represent the same namespace if their full names are the same. This + /// method merges builders corresponding to such namespace handles. + /// + private void PopulateNamespaceTable() + { + lock (_namespaceTableAndListLock) + { + if (_namespaceTable != null) + { + return; + } + + var namespaceBuilderTable = new Dictionary(); + + // Make sure to add entry for root namespace. The root namespace is special in that even + // though it might not have types of its own it always has an equivalent representation + // as a nil handle and we don't want to handle it below as dot-terminated synthetic namespace. + // We use NamespaceDefinitionHandle.FromIndexOfFullName(0) instead of default(NamespaceDefinitionHandle) so + // that we never hand back a handle to the user that doesn't have a typeid as that prevents + // round-trip conversion to Handle and back. (We may discover other handle aliases for the + // root namespace (any nil/empty string will do), but we need this one to always be there. + NamespaceDefinitionHandle rootNamespace = NamespaceDefinitionHandle.FromIndexOfFullName(0); + namespaceBuilderTable.Add( + rootNamespace, + new NamespaceDataBuilder( + rootNamespace, + rootNamespace.GetFullName(), + String.Empty)); + + PopulateTableWithTypeDefinitions(namespaceBuilderTable); + PopulateTableWithExportedTypes(namespaceBuilderTable); + + Dictionary stringTable; + MergeDuplicateNamespaces(namespaceBuilderTable, out stringTable); + + List syntheticNamespaces; + ResolveParentChildRelationships(stringTable, out syntheticNamespaces); + + var namespaceTable = new Dictionary(); + + foreach (var group in namespaceBuilderTable) + { + // Freeze() caches the result, so any many-to-one relationships + // between keys and values will be preserved and efficiently handled. + namespaceTable.Add(group.Key, group.Value.Freeze()); + } + + if (syntheticNamespaces != null) + { + foreach (var syntheticNamespace in syntheticNamespaces) + { + namespaceTable.Add(syntheticNamespace.Handle, syntheticNamespace.Freeze()); + } + } + + _namespaceTable = namespaceTable; + _rootNamespace = namespaceTable[rootNamespace]; + } + } + + /// + /// This will take 'table' and merge all of the NamespaceData instances that point to the same + /// namespace. It has to create 'stringTable' as an intermediate dictionary, so it will hand it + /// back to the caller should the caller want to use it. + /// + private void MergeDuplicateNamespaces(Dictionary table, out Dictionary stringTable) + { + var namespaces = new Dictionary(); + List> remaps = null; + foreach (var group in table) + { + NamespaceDataBuilder data = group.Value; + NamespaceDataBuilder existingRecord; + if (namespaces.TryGetValue(data.FullName, out existingRecord)) + { + // Children should not exist until the next step. + Debug.Assert(data.Namespaces.Count == 0); + data.MergeInto(existingRecord); + + if (remaps == null) + { + remaps = new List>(); + } + remaps.Add(new KeyValuePair(group.Key, existingRecord)); + } + else + { + namespaces.Add(data.FullName, data); + } + } + + // Needs to be done outside of foreach (var group in table) to avoid modifying the dictionary while foreach'ing over it. + if (remaps != null) + { + foreach (var tuple in remaps) + { + table[tuple.Key] = tuple.Value; + } + } + + stringTable = namespaces; + } + + /// + /// Creates a NamespaceDataBuilder instance that contains a synthesized NamespaceDefinitionHandle, + /// as well as the name provided. + /// + private NamespaceDataBuilder SynthesizeNamespaceData(string fullName, NamespaceDefinitionHandle realChild) + { + Debug.Assert(realChild.HasFullName); + + int numberOfSegments = 0; + foreach (char c in fullName) + { + if (c == '.') + { + numberOfSegments++; + } + } + + StringHandle simpleName = GetSimpleName(realChild, numberOfSegments); + var namespaceHandle = NamespaceDefinitionHandle.FromIndexOfSimpleName((uint)simpleName.Index); + return new NamespaceDataBuilder(namespaceHandle, simpleName, fullName); + } + + /// + /// Quick convenience method that handles linking together child + parent + /// + private void LinkChildDataToParentData(NamespaceDataBuilder child, NamespaceDataBuilder parent) + { + Debug.Assert(child != null && parent != null); + Debug.Assert(!child.Handle.IsNil); + child.Parent = parent.Handle; + parent.Namespaces.Add(child.Handle); + } + + /// + /// Links a child to its parent namespace. If the parent namespace doesn't exist, this will create a + /// synthetic one. This will automatically link any synthetic namespaces it creates up to its parents. + /// + private void LinkChildToParentNamespace(Dictionary existingNamespaces, + NamespaceDataBuilder realChild, + ref List syntheticNamespaces) + { + Debug.Assert(realChild.Handle.HasFullName); + string childName = realChild.FullName; + var child = realChild; + + // The condition for this loop is very complex -- essentially, we keep going + // until we: + // A. Encounter the root namespace as 'child' + // B. Find a preexisting namespace as 'parent' + while (true) + { + int lastIndex = childName.LastIndexOf('.'); + string parentName; + if (lastIndex == -1) + { + if (childName.Length == 0) + { + return; + } + else + { + parentName = String.Empty; + } + } + else + { + parentName = childName.Substring(0, lastIndex); + } + + NamespaceDataBuilder parentData; + if (existingNamespaces.TryGetValue(parentName, out parentData)) + { + LinkChildDataToParentData(child, parentData); + return; + } + + if (syntheticNamespaces != null) + { + foreach (var data in syntheticNamespaces) + { + if (data.FullName == parentName) + { + LinkChildDataToParentData(child, data); + return; + } + } + } + else + { + syntheticNamespaces = new List(); + } + + var syntheticParent = SynthesizeNamespaceData(parentName, realChild.Handle); + LinkChildDataToParentData(child, syntheticParent); + syntheticNamespaces.Add(syntheticParent); + childName = syntheticParent.FullName; + child = syntheticParent; + } + } + + /// + /// This will link all parents/children in the given namespaces dictionary up to each other. + /// + /// In some cases, we need to synthesize namespaces that do not have any type definitions or forwarders + /// of their own, but do have child namespaces. These are returned via the syntheticNamespaces out + /// parameter. + /// + private void ResolveParentChildRelationships(Dictionary namespaces, out List syntheticNamespaces) + { + syntheticNamespaces = null; + foreach (var namespaceData in namespaces.Values) + { + LinkChildToParentNamespace(namespaces, namespaceData, ref syntheticNamespaces); + } + } + + /// + /// Loops through all type definitions in metadata, adding them to the given table + /// + private void PopulateTableWithTypeDefinitions(Dictionary table) + { + Debug.Assert(table != null); + + foreach (var typeHandle in _metadataReader.TypeDefinitions) + { + TypeDefinition type = _metadataReader.GetTypeDefinition(typeHandle); + if (type.Attributes.IsNested()) + { + continue; + } + + NamespaceDefinitionHandle namespaceHandle = _metadataReader.TypeDefTable.GetNamespace(typeHandle); + NamespaceDataBuilder builder; + if (table.TryGetValue(namespaceHandle, out builder)) + { + builder.TypeDefinitions.Add(typeHandle); + } + else + { + StringHandle name = GetSimpleName(namespaceHandle); + string fullName = _metadataReader.GetString(namespaceHandle); + var newData = new NamespaceDataBuilder(namespaceHandle, name, fullName); + newData.TypeDefinitions.Add(typeHandle); + table.Add(namespaceHandle, newData); + } + } + } + + /// + /// Loops through all type forwarders in metadata, adding them to the given table + /// + private void PopulateTableWithExportedTypes(Dictionary table) + { + Debug.Assert(table != null); + + foreach (var exportedTypeHandle in _metadataReader.ExportedTypes) + { + ExportedType exportedType = _metadataReader.GetExportedType(exportedTypeHandle); + if (exportedType.Implementation.Kind == HandleKind.ExportedType) + { + continue; // skip nested exported types. + } + + NamespaceDefinitionHandle namespaceHandle = exportedType.Namespace; + NamespaceDataBuilder builder; + if (table.TryGetValue(namespaceHandle, out builder)) + { + builder.ExportedTypes.Add(exportedTypeHandle); + } + else + { + Debug.Assert(namespaceHandle.HasFullName); + StringHandle simpleName = GetSimpleName(namespaceHandle); + string fullName = _metadataReader.GetString(namespaceHandle); + var newData = new NamespaceDataBuilder(namespaceHandle, simpleName, fullName); + newData.ExportedTypes.Add(exportedTypeHandle); + table.Add(namespaceHandle, newData); + } + } + } + + /// + /// Populates namespaceList with distinct namespaces. No ordering is guaranteed. + /// + private void PopulateNamespaceList() + { + lock (_namespaceTableAndListLock) + { + if (_namespaceList != null) + { + return; + } + + Debug.Assert(_namespaceTable != null); + var namespaceNameSet = new HashSet(); + var namespaceListBuilder = ImmutableArray.CreateBuilder(); + + foreach (var group in _namespaceTable) + { + var data = group.Value; + if (namespaceNameSet.Add(data.FullName)) + { + namespaceListBuilder.Add(group.Key); + } + } + + _namespaceList = namespaceListBuilder.ToImmutable(); + } + } + + /// + /// If the namespace table doesn't exist, populates it! + /// + private void EnsureNamespaceTableIsPopulated() + { + // PERF: Branch will rarely be taken; do work in PopulateNamespaceList() so this can be inlined easily. + if (_namespaceTable == null) + { + PopulateNamespaceTable(); + } + Debug.Assert(_namespaceTable != null); + } + + /// + /// If the namespace list doesn't exist, populates it! + /// + private void EnsureNamespaceListIsPopulated() + { + if (_namespaceList == null) + { + PopulateNamespaceList(); + } + Debug.Assert(_namespaceList != null); + } + + /// + /// An intermediate class used to build NamespaceData instances. This was created because we wanted to + /// use ImmutableArrays in NamespaceData, but having ArrayBuilders and ImmutableArrays that served the + /// same purpose in NamespaceData got ugly. With the current design of how we create our Namespace + /// dictionary, this needs to be a class because we have a many-to-one mapping between NamespaceHandles + /// and NamespaceData. So, the pointer semantics must be preserved. + /// + /// This class assumes that the builders will not be modified in any way after the first call to + /// Freeze(). + /// + private class NamespaceDataBuilder + { + public readonly NamespaceDefinitionHandle Handle; + public readonly StringHandle Name; + public readonly string FullName; + public NamespaceDefinitionHandle Parent; + public ImmutableArray.Builder Namespaces; + public ImmutableArray.Builder TypeDefinitions; + public ImmutableArray.Builder ExportedTypes; + + private NamespaceData _frozen; + + public NamespaceDataBuilder(NamespaceDefinitionHandle handle, StringHandle name, string fullName) + { + Handle = handle; + Name = name; + FullName = fullName; + Namespaces = ImmutableArray.CreateBuilder(); + TypeDefinitions = ImmutableArray.CreateBuilder(); + ExportedTypes = ImmutableArray.CreateBuilder(); + } + + /// + /// Returns a NamespaceData that represents this NamespaceDataBuilder instance. After calling + /// this method, it is an error to use any methods or fields except Freeze() on the target + /// NamespaceDataBuilder. + /// + public NamespaceData Freeze() + { + // It is not an error to call this function multiple times. We cache the result + // because it's immutable. + if (_frozen == null) + { + var namespaces = Namespaces.ToImmutable(); + Namespaces = null; + + var typeDefinitions = TypeDefinitions.ToImmutable(); + TypeDefinitions = null; + + var exportedTypes = ExportedTypes.ToImmutable(); + ExportedTypes = null; + + _frozen = new NamespaceData(Name, FullName, Parent, namespaces, typeDefinitions, exportedTypes); + } + + return _frozen; + } + + public void MergeInto(NamespaceDataBuilder other) + { + Parent = default(NamespaceDefinitionHandle); + other.Namespaces.AddRange(this.Namespaces); + other.TypeDefinitions.AddRange(this.TypeDefinitions); + other.ExportedTypes.AddRange(this.ExportedTypes); + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceData.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceData.cs new file mode 100644 index 0000000..73c1efc --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/NamespaceData.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal sealed class NamespaceData + { + public readonly StringHandle Name; + public readonly string FullName; + public readonly NamespaceDefinitionHandle Parent; + public readonly ImmutableArray NamespaceDefinitions; + public readonly ImmutableArray TypeDefinitions; + public readonly ImmutableArray ExportedTypes; + + public NamespaceData( + StringHandle name, + string fullName, + NamespaceDefinitionHandle parent, + ImmutableArray namespaceDefinitions, + ImmutableArray typeDefinitions, + ImmutableArray exportedTypes) + { + this.Name = name; + this.FullName = fullName; + this.Parent = parent; + this.NamespaceDefinitions = namespaceDefinitions; + this.TypeDefinitions = typeDefinitions; + this.ExportedTypes = exportedTypes; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ResolutionScopeTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ResolutionScopeTag.cs new file mode 100644 index 0000000..b8cd2bc --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/ResolutionScopeTag.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class ResolutionScopeTag + { + internal const int NumberOfBits = 2; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint Module = 0x00000000; + internal const uint ModuleRef = 0x00000001; + internal const uint AssemblyRef = 0x00000002; + internal const uint TypeRef = 0x00000003; + internal const uint TagMask = 0x00000003; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.Module >> 24 | TokenTypeIds.ModuleRef >> 16 | TokenTypeIds.AssemblyRef >> 8 | TokenTypeIds.TypeRef; + internal const TableMask TablesReferenced = + TableMask.Module + | TableMask.ModuleRef + | TableMask.AssemblyRef + | TableMask.TypeRef; + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint resolutionScope) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(resolutionScope & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (resolutionScope >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/StreamHeader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/StreamHeader.cs new file mode 100644 index 0000000..90392bb --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/StreamHeader.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + internal struct StreamHeader + { + internal uint Offset; + internal int Size; + internal string Name; + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Tables.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Tables.cs new file mode 100644 index 0000000..e2a3369 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Tables.cs @@ -0,0 +1,2612 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Internal; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal struct ModuleTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsGUIDHeapRefSizeSmall; + private readonly int _GenerationOffset; + private readonly int _NameOffset; + private readonly int _MVIdOffset; + private readonly int _EnCIdOffset; + private readonly int _EnCBaseIdOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ModuleTableReader( + uint numberOfRows, + int stringHeapRefSize, + int guidHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsGUIDHeapRefSizeSmall = guidHeapRefSize == 2; + _GenerationOffset = 0; + _NameOffset = _GenerationOffset + sizeof(UInt16); + _MVIdOffset = _NameOffset + stringHeapRefSize; + _EnCIdOffset = _MVIdOffset + guidHeapRefSize; + _EnCBaseIdOffset = _EnCIdOffset + guidHeapRefSize; + this.RowSize = _EnCBaseIdOffset + guidHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, this.RowSize * (int)numberOfRows); + } + + internal ushort GetGeneration() + { + Debug.Assert(NumberOfRows > 0); + return this.Block.PeekUInt16(_GenerationOffset); + } + + internal StringHandle GetName() + { + Debug.Assert(NumberOfRows > 0); + return StringHandle.FromIndex(this.Block.PeekReference(_NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal GuidHandle GetMvid() + { + Debug.Assert(NumberOfRows > 0); + return GuidHandle.FromIndex(this.Block.PeekReference(_MVIdOffset, _IsGUIDHeapRefSizeSmall)); + } + + internal GuidHandle GetEncId() + { + Debug.Assert(NumberOfRows > 0); + return GuidHandle.FromIndex(this.Block.PeekReference(_EnCIdOffset, _IsGUIDHeapRefSizeSmall)); + } + + internal GuidHandle GetEncBaseId() + { + Debug.Assert(NumberOfRows > 0); + return GuidHandle.FromIndex(this.Block.PeekReference(_EnCBaseIdOffset, _IsGUIDHeapRefSizeSmall)); + } + } + + internal struct TypeRefTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsResolutionScopeRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _ResolutionScopeOffset; + private readonly int _NameOffset; + private readonly int _NamespaceOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal TypeRefTableReader( + uint numberOfRows, + int resolutionScopeRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsResolutionScopeRefSizeSmall = resolutionScopeRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _ResolutionScopeOffset = 0; + _NameOffset = _ResolutionScopeOffset + resolutionScopeRefSize; + _NamespaceOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _NamespaceOffset + stringHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal Handle GetResolutionScope(TypeReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return ResolutionScopeTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ResolutionScopeOffset, _IsResolutionScopeRefSizeSmall)); + } + + internal StringHandle GetName(TypeReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetNamespace(TypeReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NamespaceOffset, _IsStringHeapRefSizeSmall)); + } + } + + internal struct TypeDefTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsFieldRefSizeSmall; + private readonly bool _IsMethodRefSizeSmall; + private readonly bool _IsTypeDefOrRefRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _NamespaceOffset; + private readonly int _ExtendsOffset; + private readonly int _FieldListOffset; + private readonly int _MethodListOffset; + internal readonly int RowSize; + internal MemoryBlock Block; + + internal TypeDefTableReader( + uint numberOfRows, + int fieldRefSize, + int methodRefSize, + int typeDefOrRefRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsFieldRefSizeSmall = fieldRefSize == 2; + _IsMethodRefSizeSmall = methodRefSize == 2; + _IsTypeDefOrRefRefSizeSmall = typeDefOrRefRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _FlagsOffset = 0; + _NameOffset = _FlagsOffset + sizeof(UInt32); + _NamespaceOffset = _NameOffset + stringHeapRefSize; + _ExtendsOffset = _NamespaceOffset + stringHeapRefSize; + _FieldListOffset = _ExtendsOffset + typeDefOrRefRefSize; + _MethodListOffset = _FieldListOffset + fieldRefSize; + this.RowSize = _MethodListOffset + methodRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal TypeAttributes GetFlags(TypeDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (TypeAttributes)this.Block.PeekUInt32(rowOffset + _FlagsOffset); + } + + internal NamespaceDefinitionHandle GetNamespace(TypeDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return NamespaceDefinitionHandle.FromIndexOfFullName(this.Block.PeekReference(rowOffset + _NamespaceOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetNamespaceString(TypeDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NamespaceOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetName(TypeDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetExtends(TypeDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return TypeDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ExtendsOffset, _IsTypeDefOrRefRefSizeSmall)); + } + + internal uint GetFieldStart(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekReference(rowOffset + _FieldListOffset, _IsFieldRefSizeSmall); + } + + internal uint GetMethodStart(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekReference(rowOffset + _MethodListOffset, _IsMethodRefSizeSmall); + } + + internal TypeDefinitionHandle FindTypeContainingMethod(uint methodDefOrPtrRowId, int numberOfMethods) + { + uint numOfRows = this.NumberOfRows; + int slot = this.Block.BinarySearchForSlot(numOfRows, this.RowSize, _MethodListOffset, methodDefOrPtrRowId, _IsMethodRefSizeSmall); + uint row = (uint)(slot + 1); + if (row == 0) return default(TypeDefinitionHandle); + + if (row > numOfRows) + { + if (methodDefOrPtrRowId <= numberOfMethods) return TypeDefinitionHandle.FromRowId(numOfRows); + + return default(TypeDefinitionHandle); + } + + uint value = this.GetMethodStart(row); + if (value == methodDefOrPtrRowId) + { + while (row < numOfRows) + { + uint newRow = row + 1; + value = this.GetMethodStart(newRow); + if (value == methodDefOrPtrRowId) + row = newRow; + else + break; + } + } + + return TypeDefinitionHandle.FromRowId(row); + } + + internal TypeDefinitionHandle FindTypeContainingField(uint fieldDefOrPtrRowId, int numberOfFields) + { + uint numOfRows = this.NumberOfRows; + int slot = this.Block.BinarySearchForSlot(numOfRows, this.RowSize, _FieldListOffset, fieldDefOrPtrRowId, _IsFieldRefSizeSmall); + uint row = (uint)(slot + 1); + if (row == 0) return default(TypeDefinitionHandle); + + if (row > numOfRows) + { + if (fieldDefOrPtrRowId <= numberOfFields) return TypeDefinitionHandle.FromRowId(numOfRows); + + return default(TypeDefinitionHandle); + } + + uint value = this.GetFieldStart(row); + if (value == fieldDefOrPtrRowId) + { + while (row < numOfRows) + { + uint newRow = row + 1; + value = this.GetFieldStart(newRow); + if (value == fieldDefOrPtrRowId) + row = newRow; + else + break; + } + } + + return TypeDefinitionHandle.FromRowId(row); + } + } + + internal struct FieldPtrTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsFieldTableRowRefSizeSmall; + private readonly int _FieldOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FieldPtrTableReader( + uint numberOfRows, + int fieldTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsFieldTableRowRefSizeSmall = fieldTableRowRefSize == 2; + _FieldOffset = 0; + this.RowSize = _FieldOffset + fieldTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal FieldDefinitionHandle GetFieldFor(int rowId) + { + int rowOffset = (rowId - 1) * this.RowSize; + return FieldDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _FieldOffset, _IsFieldTableRowRefSizeSmall)); + } + + internal uint GetRowIdForFieldDefRow(uint fieldDefRowId) + { + return (uint)(this.Block.LinearSearchReference(this.RowSize, _FieldOffset, fieldDefRowId, _IsFieldTableRowRefSizeSmall) + 1); + } + } + + internal struct FieldTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _SignatureOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FieldTableReader( + uint numberOfRows, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _FlagsOffset = 0; + _NameOffset = _FlagsOffset + sizeof(UInt16); + _SignatureOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _SignatureOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal StringHandle GetName(FieldDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal FieldAttributes GetFlags(FieldDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (FieldAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal BlobHandle GetSignature(FieldDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct MethodPtrTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsMethodTableRowRefSizeSmall; + private readonly int _MethodOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal MethodPtrTableReader( + uint numberOfRows, + int methodTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsMethodTableRowRefSizeSmall = methodTableRowRefSize == 2; + _MethodOffset = 0; + this.RowSize = _MethodOffset + methodTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + // returns a rid + internal MethodDefinitionHandle GetMethodFor(int rowId) + { + int rowOffset = (rowId - 1) * this.RowSize; + return MethodDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _MethodOffset, _IsMethodTableRowRefSizeSmall)); ; + } + + internal uint GetRowIdForMethodDefRow(uint methodDefRowId) + { + return (uint)(this.Block.LinearSearchReference(this.RowSize, _MethodOffset, methodDefRowId, _IsMethodTableRowRefSizeSmall) + 1); + } + } + + internal struct MethodTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsParamRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _RVAOffset; + private readonly int _ImplFlagsOffset; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _SignatureOffset; + private readonly int _ParamListOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal MethodTableReader( + uint numberOfRows, + int paramRefSize, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsParamRefSizeSmall = paramRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _RVAOffset = 0; + _ImplFlagsOffset = _RVAOffset + sizeof(UInt32); + _FlagsOffset = _ImplFlagsOffset + sizeof(UInt16); + _NameOffset = _FlagsOffset + sizeof(UInt16); + _SignatureOffset = _NameOffset + stringHeapRefSize; + _ParamListOffset = _SignatureOffset + blobHeapRefSize; + this.RowSize = _ParamListOffset + paramRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal uint GetParamStart(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekReference(rowOffset + _ParamListOffset, _IsParamRefSizeSmall); + } + + internal BlobHandle GetSignature(MethodDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + + internal int GetRva(MethodDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return this.Block.PeekInt32(rowOffset + _RVAOffset); + } + + internal StringHandle GetName(MethodDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal MethodAttributes GetFlags(MethodDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (MethodAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal MethodImplAttributes GetImplFlags(MethodDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (MethodImplAttributes)this.Block.PeekUInt16(rowOffset + _ImplFlagsOffset); + } + + internal int GetNextRVA( + int rva + ) + { + int nextRVA = int.MaxValue; + int endOffset = (int)this.NumberOfRows * this.RowSize; + for (int iterOffset = _RVAOffset; iterOffset < endOffset; iterOffset += this.RowSize) + { + int currentRVA = this.Block.PeekInt32(iterOffset); + if (currentRVA > rva && currentRVA < nextRVA) + { + nextRVA = currentRVA; + } + } + + return nextRVA == int.MaxValue ? -1 : nextRVA; + } + } + + internal struct ParamPtrTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsParamTableRowRefSizeSmall; + private readonly int _ParamOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ParamPtrTableReader( + uint numberOfRows, + int paramTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsParamTableRowRefSizeSmall = paramTableRowRefSize == 2; + _ParamOffset = 0; + this.RowSize = _ParamOffset + paramTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal ParameterHandle GetParamFor(int rowId) + { + int rowOffset = (rowId - 1) * this.RowSize; + return ParameterHandle.FromRowId(this.Block.PeekReference(rowOffset + _ParamOffset, _IsParamTableRowRefSizeSmall)); + } + } + + internal struct ParamTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _SequenceOffset; + private readonly int _NameOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ParamTableReader( + uint numberOfRows, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _FlagsOffset = 0; + _SequenceOffset = _FlagsOffset + sizeof(UInt16); + _NameOffset = _SequenceOffset + sizeof(UInt16); + this.RowSize = _NameOffset + stringHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal ParameterAttributes GetFlags(ParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (ParameterAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal ushort GetSequence(ParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return this.Block.PeekUInt16(rowOffset + _SequenceOffset); + } + + internal StringHandle GetName(ParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + } + + internal struct InterfaceImplTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly bool _IsTypeDefOrRefRefSizeSmall; + private readonly int _ClassOffset; + private readonly int _InterfaceOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal InterfaceImplTableReader( + uint numberOfRows, + bool declaredSorted, + int typeDefTableRowRefSize, + int typeDefOrRefRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _IsTypeDefOrRefRefSizeSmall = typeDefOrRefRefSize == 2; + _ClassOffset = 0; + _InterfaceOffset = _ClassOffset + typeDefTableRowRefSize; + this.RowSize = _InterfaceOffset + typeDefOrRefRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.InterfaceImpl); + } + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ClassOffset, _IsTypeDefTableRowRefSizeSmall); + } + + internal void GetInterfaceImplRange( + TypeDefinitionHandle typeDef, + out int firstImplRowId, + out int lastImplRowId) + { + uint typeDefRid = typeDef.RowId; + + int startRowNumber, endRowNumber; + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _ClassOffset, + typeDefRid, + _IsTypeDefTableRowRefSizeSmall, + out startRowNumber, + out endRowNumber + ); + + if (startRowNumber == -1) + { + firstImplRowId = 1; + lastImplRowId = 0; + } + else + { + firstImplRowId = startRowNumber + 1; + lastImplRowId = endRowNumber + 1; + } + } + + internal Handle GetInterface(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _InterfaceOffset, _IsTypeDefOrRefRefSizeSmall)); + } + } + + internal struct MemberRefTableReader + { + internal uint NumberOfRows; + private readonly bool _IsMemberRefParentRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _ClassOffset; + private readonly int _NameOffset; + private readonly int _SignatureOffset; + internal readonly int RowSize; + internal MemoryBlock Block; + + internal MemberRefTableReader( + uint numberOfRows, + int memberRefParentRefSize, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsMemberRefParentRefSizeSmall = memberRefParentRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _ClassOffset = 0; + _NameOffset = _ClassOffset + memberRefParentRefSize; + _SignatureOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _SignatureOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal BlobHandle GetSignature(MemberReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + + internal StringHandle GetName(MemberReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetClass(MemberReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return MemberRefParentTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ClassOffset, _IsMemberRefParentRefSizeSmall)); + } + } + + internal struct ConstantTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsHasConstantRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _TypeOffset; + private readonly int _ParentOffset; + private readonly int _ValueOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ConstantTableReader( + uint numberOfRows, + bool declaredSorted, + int hasConstantRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsHasConstantRefSizeSmall = hasConstantRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _TypeOffset = 0; + _ParentOffset = _TypeOffset + sizeof(Byte) + 1; // Alignment here (+1)... + _ValueOffset = _ParentOffset + hasConstantRefSize; + this.RowSize = _ValueOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.Constant); + } + } + + internal ConstantTypeCode GetType(ConstantHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (ConstantTypeCode)this.Block.PeekByte(rowOffset + _TypeOffset); + } + + internal BlobHandle GetValue(ConstantHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _ValueOffset, _IsBlobHeapRefSizeSmall)); + } + + internal Handle GetParent(ConstantHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return HasConstantTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ParentOffset, _IsHasConstantRefSizeSmall)); + } + + internal ConstantHandle FindConstant( + Handle parentToken + ) + { + int foundRowNumber = + this.Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _ParentOffset, + HasConstantTag.ConvertToTag(parentToken), + _IsHasConstantRefSizeSmall + ); + return ConstantHandle.FromRowId((uint)(foundRowNumber + 1)); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ParentOffset, _IsHasConstantRefSizeSmall); + } + } + + internal struct CustomAttributeTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsHasCustomAttributeRefSizeSmall; + private readonly bool _IsCustomAttributeTypeRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _ParentOffset; + private readonly int _TypeOffset; + private readonly int _ValueOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + // row ids in the CustomAttribute table sorted by parents + internal readonly uint[] PtrTable; + + internal CustomAttributeTableReader( + uint numberOfRows, + bool declaredSorted, + int hasCustomAttributeRefSize, + int customAttributeTypeRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsHasCustomAttributeRefSizeSmall = hasCustomAttributeRefSize == 2; + _IsCustomAttributeTypeRefSizeSmall = customAttributeTypeRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _ParentOffset = 0; + _TypeOffset = _ParentOffset + hasCustomAttributeRefSize; + _ValueOffset = _TypeOffset + customAttributeTypeRefSize; + this.RowSize = _ValueOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + this.PtrTable = null; + + if (!declaredSorted && !CheckSorted()) + { + this.PtrTable = this.Block.BuildPtrTable( + (int)numberOfRows, + this.RowSize, + _ParentOffset, + _IsHasCustomAttributeRefSizeSmall); + } + } + + internal Handle GetParent(CustomAttributeHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return HasCustomAttributeTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ParentOffset, _IsHasCustomAttributeRefSizeSmall)); + } + + internal Handle GetConstructor(CustomAttributeHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return CustomAttributeTypeTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _TypeOffset, _IsCustomAttributeTypeRefSizeSmall)); + } + + internal BlobHandle GetValue(CustomAttributeHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _ValueOffset, _IsBlobHeapRefSizeSmall)); + } + + private uint GetParentTag(int index) + { + return this.Block.PeekReference(index * this.RowSize + _ParentOffset, _IsHasCustomAttributeRefSizeSmall); + } + + internal void GetAttributeRange(Handle parentHandle, out int firstImplRowId, out int lastImplRowId) + { + int startRowNumber, endRowNumber; + + if (this.PtrTable != null) + { + this.Block.BinarySearchReferenceRange( + this.PtrTable, + this.RowSize, + _ParentOffset, + HasCustomAttributeTag.ConvertToTag(parentHandle), + _IsHasCustomAttributeRefSizeSmall, + out startRowNumber, + out endRowNumber + ); + } + else + { + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _ParentOffset, + HasCustomAttributeTag.ConvertToTag(parentHandle), + _IsHasCustomAttributeRefSizeSmall, + out startRowNumber, + out endRowNumber + ); + } + + if (startRowNumber == -1) + { + firstImplRowId = 1; + lastImplRowId = 0; + } + else + { + firstImplRowId = startRowNumber + 1; + lastImplRowId = endRowNumber + 1; + } + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ParentOffset, _IsHasCustomAttributeRefSizeSmall); + } + } + + internal struct FieldMarshalTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsHasFieldMarshalRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _ParentOffset; + private readonly int _NativeTypeOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FieldMarshalTableReader( + uint numberOfRows, + bool declaredSorted, + int hasFieldMarshalRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsHasFieldMarshalRefSizeSmall = hasFieldMarshalRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _ParentOffset = 0; + _NativeTypeOffset = _ParentOffset + hasFieldMarshalRefSize; + this.RowSize = _NativeTypeOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.FieldMarshal); + } + } + + internal Handle GetParent(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return HasFieldMarshalTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ParentOffset, _IsHasFieldMarshalRefSizeSmall)); + } + + internal BlobHandle GetNativeType(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _NativeTypeOffset, _IsBlobHeapRefSizeSmall)); + } + + internal uint FindFieldMarshalRowId(Handle handle) + { + int foundRowNumber = + this.Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _ParentOffset, + HasFieldMarshalTag.ConvertToTag(handle), + _IsHasFieldMarshalRefSizeSmall + ); + return (uint)(foundRowNumber + 1); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ParentOffset, _IsHasFieldMarshalRefSizeSmall); + } + } + + internal struct DeclSecurityTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsHasDeclSecurityRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _ActionOffset; + private readonly int _ParentOffset; + private readonly int _PermissionSetOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal DeclSecurityTableReader( + uint numberOfRows, + bool declaredSorted, + int hasDeclSecurityRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsHasDeclSecurityRefSizeSmall = hasDeclSecurityRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _ActionOffset = 0; + _ParentOffset = _ActionOffset + sizeof(UInt16); + _PermissionSetOffset = _ParentOffset + hasDeclSecurityRefSize; + this.RowSize = _PermissionSetOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.DeclSecurity); + } + } + + internal DeclarativeSecurityAction GetAction(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return (DeclarativeSecurityAction)this.Block.PeekUInt16(rowOffset + _ActionOffset); + } + + internal Handle GetParent(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return HasDeclSecurityTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ParentOffset, _IsHasDeclSecurityRefSizeSmall)); + } + + internal BlobHandle GetPermissionSet(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _PermissionSetOffset, _IsBlobHeapRefSizeSmall)); + } + + internal void GetAttributeRange(Handle parentToken, out int firstImplRowId, out int lastImplRowId) + { + int startRowNumber, endRowNumber; + + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _ParentOffset, + HasDeclSecurityTag.ConvertToTag(parentToken), + _IsHasDeclSecurityRefSizeSmall, + out startRowNumber, + out endRowNumber); + + if (startRowNumber == -1) + { + firstImplRowId = 1; + lastImplRowId = 0; + } + else + { + firstImplRowId = startRowNumber + 1; + lastImplRowId = endRowNumber + 1; + } + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ParentOffset, _IsHasDeclSecurityRefSizeSmall); + } + } + + internal struct ClassLayoutTableReader + { + internal uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly int _PackagingSizeOffset; + private readonly int _ClassSizeOffset; + private readonly int _ParentOffset; + internal readonly int RowSize; + internal MemoryBlock Block; + + internal ClassLayoutTableReader( + uint numberOfRows, + bool declaredSorted, + int typeDefTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _PackagingSizeOffset = 0; + _ClassSizeOffset = _PackagingSizeOffset + sizeof(UInt16); + _ParentOffset = _ClassSizeOffset + sizeof(UInt32); + this.RowSize = _ParentOffset + typeDefTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.ClassLayout); + } + } + + internal TypeDefinitionHandle GetParent(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _ParentOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal ushort GetPackingSize(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt16(rowOffset + _PackagingSizeOffset); + } + + internal uint GetClassSize(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _ClassSizeOffset); + } + + // Returns RowId (0 means we there is no record in this table corresponding to the specified type). + internal uint FindRow(TypeDefinitionHandle typeDef) + { + return (uint)(1 + this.Block.BinarySearchReference(this.NumberOfRows, this.RowSize, _ParentOffset, typeDef.RowId, _IsTypeDefTableRowRefSizeSmall)); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ParentOffset, _IsTypeDefTableRowRefSizeSmall); + } + } + + internal struct FieldLayoutTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsFieldTableRowRefSizeSmall; + private readonly int _OffsetOffset; + private readonly int _FieldOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FieldLayoutTableReader( + uint numberOfRows, + bool declaredSorted, + int fieldTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsFieldTableRowRefSizeSmall = fieldTableRowRefSize == 2; + _OffsetOffset = 0; + _FieldOffset = _OffsetOffset + sizeof(UInt32); + this.RowSize = _FieldOffset + fieldTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.FieldLayout); + } + } + + /// + /// Returns field offset for given field RowId, or -1 if not available. + /// + internal uint FindFieldLayoutRowId(FieldDefinitionHandle handle) + { + int rowNumber = + this.Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _FieldOffset, + handle.RowId, + _IsFieldTableRowRefSizeSmall + ); + + return (uint)(rowNumber + 1); + } + + internal uint GetOffset(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _OffsetOffset); + } + + internal FieldDefinitionHandle GetField(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return FieldDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _FieldOffset, _IsFieldTableRowRefSizeSmall)); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _FieldOffset, _IsFieldTableRowRefSizeSmall); + } + } + + internal struct StandAloneSigTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _SignatureOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal StandAloneSigTableReader( + uint numberOfRows, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _SignatureOffset = 0; + this.RowSize = _SignatureOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal BlobHandle GetSignature(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct EventMapTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly bool _IsEventRefSizeSmall; + private readonly int _ParentOffset; + private readonly int _EventListOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal EventMapTableReader( + uint numberOfRows, + int typeDefTableRowRefSize, + int eventRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _IsEventRefSizeSmall = eventRefSize == 2; + _ParentOffset = 0; + _EventListOffset = _ParentOffset + typeDefTableRowRefSize; + this.RowSize = _EventListOffset + eventRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal uint FindEventMapRowIdFor(TypeDefinitionHandle typeDef) + { + // We do a linear scan here because we don't have these tables sorted + // TODO: We can scan the table to see if it is sorted and use binary search if so. + // Also, the compilers should make sure it's sorted. + int rowNumber = + this.Block.LinearSearchReference( + this.RowSize, + _ParentOffset, + typeDef.RowId, + _IsTypeDefTableRowRefSizeSmall + ); + return (uint)(rowNumber + 1); + } + + internal TypeDefinitionHandle GetParentType(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _ParentOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal uint GetEventListStartFor(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekReference(rowOffset + _EventListOffset, _IsEventRefSizeSmall); + } + } + + internal struct EventPtrTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsEventTableRowRefSizeSmall; + private readonly int _EventOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal EventPtrTableReader( + uint numberOfRows, + int eventTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsEventTableRowRefSizeSmall = eventTableRowRefSize == 2; + _EventOffset = 0; + this.RowSize = _EventOffset + eventTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal EventDefinitionHandle GetEventFor(int rowId) + { + int rowOffset = (rowId - 1) * this.RowSize; + return EventDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _EventOffset, _IsEventTableRowRefSizeSmall)); + } + } + + internal struct EventTableReader + { + internal uint NumberOfRows; + private readonly bool _IsTypeDefOrRefRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _EventTypeOffset; + internal readonly int RowSize; + internal MemoryBlock Block; + + internal EventTableReader( + uint numberOfRows, + int typeDefOrRefRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefOrRefRefSizeSmall = typeDefOrRefRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _FlagsOffset = 0; + _NameOffset = _FlagsOffset + sizeof(UInt16); + _EventTypeOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _EventTypeOffset + typeDefOrRefRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal EventAttributes GetFlags(EventDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (EventAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal StringHandle GetName(EventDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetEventType(EventDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return TypeDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _EventTypeOffset, _IsTypeDefOrRefRefSizeSmall)); + } + } + + internal struct PropertyMapTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly bool _IsPropertyRefSizeSmall; + private readonly int _ParentOffset; + private readonly int _PropertyListOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal PropertyMapTableReader( + uint numberOfRows, + int typeDefTableRowRefSize, + int propertyRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _IsPropertyRefSizeSmall = propertyRefSize == 2; + _ParentOffset = 0; + _PropertyListOffset = _ParentOffset + typeDefTableRowRefSize; + this.RowSize = _PropertyListOffset + propertyRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal uint FindPropertyMapRowIdFor(TypeDefinitionHandle typeDef) + { + // We do a linear scan here because we don't have these tables sorted. + // TODO: We can scan the table to see if it is sorted and use binary search if so. + // Also, the compilers should make sure it's sorted. + int rowNumber = + this.Block.LinearSearchReference( + this.RowSize, + _ParentOffset, + typeDef.RowId, + _IsTypeDefTableRowRefSizeSmall + ); + return (uint)(rowNumber + 1); + } + + internal TypeDefinitionHandle GetParentType(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _ParentOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal uint GetPropertyListStartFor(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + uint propertyList = this.Block.PeekReference(rowOffset + _PropertyListOffset, _IsPropertyRefSizeSmall); + return propertyList; + } + } + + internal struct PropertyPtrTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsPropertyTableRowRefSizeSmall; + private readonly int _PropertyOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal PropertyPtrTableReader( + uint numberOfRows, + int propertyTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsPropertyTableRowRefSizeSmall = propertyTableRowRefSize == 2; + _PropertyOffset = 0; + this.RowSize = _PropertyOffset + propertyTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal PropertyDefinitionHandle GetPropertyFor( + int rowId + ) + // ^ requires rowId <= this.NumberOfRows; + { + int rowOffset = (rowId - 1) * this.RowSize; + return PropertyDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _PropertyOffset, _IsPropertyTableRowRefSizeSmall)); + } + } + + internal struct PropertyTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _SignatureOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal PropertyTableReader( + uint numberOfRows, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _FlagsOffset = 0; + _NameOffset = _FlagsOffset + sizeof(UInt16); + _SignatureOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _SignatureOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal PropertyAttributes GetFlags(PropertyDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (PropertyAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal StringHandle GetName(PropertyDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal BlobHandle GetSignature(PropertyDefinitionHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct MethodSemanticsTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsMethodTableRowRefSizeSmall; + private readonly bool _IsHasSemanticRefSizeSmall; + private readonly int _SemanticsFlagOffset; + private readonly int _MethodOffset; + private readonly int _AssociationOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal MethodSemanticsTableReader( + uint numberOfRows, + bool declaredSorted, + int methodTableRowRefSize, + int hasSemanticRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsMethodTableRowRefSizeSmall = methodTableRowRefSize == 2; + _IsHasSemanticRefSizeSmall = hasSemanticRefSize == 2; + _SemanticsFlagOffset = 0; + _MethodOffset = _SemanticsFlagOffset + sizeof(UInt16); + _AssociationOffset = _MethodOffset + methodTableRowRefSize; + this.RowSize = _AssociationOffset + hasSemanticRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.MethodSemantics); + } + } + + internal MethodDefinitionHandle GetMethod(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return MethodDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _MethodOffset, _IsMethodTableRowRefSizeSmall)); + } + + internal MethodSemanticsAttributes GetSemantics(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return (MethodSemanticsAttributes)this.Block.PeekUInt16(rowOffset + _SemanticsFlagOffset); + } + + internal Handle GetAssociation(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return HasSemanticsTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _AssociationOffset, _IsHasSemanticRefSizeSmall)); + } + + // returns rowID + internal uint FindSemanticMethodsForEvent(EventDefinitionHandle eventDef, out ushort methodCount) + { + methodCount = 0; + uint searchCodedTag = HasSemanticsTag.ConvertEventHandleToTag(eventDef); + return this.BinarySearchTag(searchCodedTag, ref methodCount); + } + + internal uint FindSemanticMethodsForProperty(PropertyDefinitionHandle propertyDef, out ushort methodCount) + { + methodCount = 0; + uint searchCodedTag = HasSemanticsTag.ConvertPropertyHandleToTag(propertyDef); + return this.BinarySearchTag(searchCodedTag, ref methodCount); + } + + private uint BinarySearchTag(uint searchCodedTag, ref ushort methodCount) + { + int startRowNumber, endRowNumber; + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _AssociationOffset, + searchCodedTag, + _IsHasSemanticRefSizeSmall, + out startRowNumber, + out endRowNumber + ); + + if (startRowNumber == -1) + { + methodCount = 0; + return 0; + } + + methodCount = (ushort)(endRowNumber - startRowNumber + 1); + return (uint)(startRowNumber + 1); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _AssociationOffset, _IsHasSemanticRefSizeSmall); + } + } + + internal struct MethodImplTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly bool _IsMethodDefOrRefRefSizeSmall; + private readonly int _ClassOffset; + private readonly int _MethodBodyOffset; + private readonly int _MethodDeclarationOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal MethodImplTableReader( + uint numberOfRows, + bool declaredSorted, + int typeDefTableRowRefSize, + int methodDefOrRefRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _IsMethodDefOrRefRefSizeSmall = methodDefOrRefRefSize == 2; + _ClassOffset = 0; + _MethodBodyOffset = _ClassOffset + typeDefTableRowRefSize; + _MethodDeclarationOffset = _MethodBodyOffset + methodDefOrRefRefSize; + this.RowSize = _MethodDeclarationOffset + methodDefOrRefRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.MethodImpl); + } + } + + internal TypeDefinitionHandle GetClass(MethodImplementationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _ClassOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal Handle GetMethodBody(MethodImplementationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return MethodDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _MethodBodyOffset, _IsMethodDefOrRefRefSizeSmall)); + } + + internal Handle GetMethodDeclaration(MethodImplementationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return MethodDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _MethodDeclarationOffset, _IsMethodDefOrRefRefSizeSmall)); + } + + internal void GetMethodImplRange( + TypeDefinitionHandle typeDef, + out int firstImplRowId, + out int lastImplRowId) + { + uint typeDefRid = typeDef.RowId; + + int startRowNumber, endRowNumber; + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _ClassOffset, + typeDefRid, + _IsTypeDefTableRowRefSizeSmall, + out startRowNumber, + out endRowNumber + ); + + if (startRowNumber == -1) + { + firstImplRowId = 1; + lastImplRowId = 0; + } + else + { + firstImplRowId = startRowNumber + 1; + lastImplRowId = endRowNumber + 1; + } + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _ClassOffset, _IsTypeDefTableRowRefSizeSmall); + } + } + + internal struct ModuleRefTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _NameOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ModuleRefTableReader( + uint numberOfRows, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _NameOffset = 0; + this.RowSize = _NameOffset + stringHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal StringHandle GetName(ModuleReferenceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + } + + internal struct TypeSpecTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _SignatureOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal TypeSpecTableReader( + uint numberOfRows, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _SignatureOffset = 0; + this.RowSize = _SignatureOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal BlobHandle GetSignature(TypeSpecificationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _SignatureOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct ImplMapTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsModuleRefTableRowRefSizeSmall; + private readonly bool _IsMemberForwardRowRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _MemberForwardedOffset; + private readonly int _ImportNameOffset; + private readonly int _ImportScopeOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ImplMapTableReader( + uint numberOfRows, + bool declaredSorted, + int moduleRefTableRowRefSize, + int memberForwardedRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsModuleRefTableRowRefSizeSmall = moduleRefTableRowRefSize == 2; + _IsMemberForwardRowRefSizeSmall = memberForwardedRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _FlagsOffset = 0; + _MemberForwardedOffset = _FlagsOffset + sizeof(UInt16); + _ImportNameOffset = _MemberForwardedOffset + memberForwardedRefSize; + _ImportScopeOffset = _ImportNameOffset + stringHeapRefSize; + this.RowSize = _ImportScopeOffset + moduleRefTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.ImplMap); + } + } + + internal MethodImport this[uint rowId] // This is 1 based... + { + get + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + var pInvokeMapFlags = (MethodImportAttributes)Block.PeekUInt16(rowOffset + _FlagsOffset); + var importName = StringHandle.FromIndex(Block.PeekReference(rowOffset + _ImportNameOffset, _IsStringHeapRefSizeSmall)); + var importScope = ModuleReferenceHandle.FromRowId(Block.PeekReference(rowOffset + _ImportScopeOffset, _IsModuleRefTableRowRefSizeSmall)); + return new MethodImport(pInvokeMapFlags, importName, importScope); + } + } + + internal Handle GetMemberForwarded(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return MemberForwardedTag.ConvertToToken(Block.PeekTaggedReference(rowOffset + _MemberForwardedOffset, _IsMemberForwardRowRefSizeSmall)); + } + + internal uint FindImplForMethod(MethodDefinitionHandle methodDef) + { + uint searchCodedTag = MemberForwardedTag.ConvertMethodDefToTag(methodDef); + return this.BinarySearchTag(searchCodedTag); + } + + private uint BinarySearchTag(uint searchCodedTag) + { + int foundRowNumber = + this.Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _MemberForwardedOffset, + searchCodedTag, + _IsMemberForwardRowRefSizeSmall + ); + return (uint)(foundRowNumber + 1); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _MemberForwardedOffset, _IsMemberForwardRowRefSizeSmall); + } + } + + internal struct FieldRVATableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsFieldTableRowRefSizeSmall; + private readonly int _RVAOffset; + private readonly int _FieldOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FieldRVATableReader( + uint numberOfRows, + bool declaredSorted, + int fieldTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsFieldTableRowRefSizeSmall = fieldTableRowRefSize == 2; + _RVAOffset = 0; + _FieldOffset = _RVAOffset + sizeof(UInt32); + this.RowSize = _FieldOffset + fieldTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.FieldRva); + } + } + + internal int GetRVA(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return Block.PeekInt32(rowOffset + _RVAOffset); + } + + internal uint FindFieldRVARowId(uint fieldDefRowId) + { + int foundRowNumber = Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _FieldOffset, + fieldDefRowId, + _IsFieldTableRowRefSizeSmall + ); + + return (uint)(foundRowNumber + 1); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _FieldOffset, _IsFieldTableRowRefSizeSmall); + } + } + + internal struct EnCLogTableReader + { + internal readonly uint NumberOfRows; + private readonly int _TokenOffset; + private readonly int _FuncCodeOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal EnCLogTableReader( + uint numberOfRows, + MemoryBlock containingBlock, + int containingBlockOffset, + MetadataStreamKind metadataStreamKind) + { + // EnC tables are not allowed in a compressed stream. + // However when asked for a snapshot of the current metadata after an EnC change has been applied + // the CLR includes the EnCLog table into the snapshot (but not EnCMap). We pretend EnCLog is empty. + this.NumberOfRows = (metadataStreamKind == MetadataStreamKind.Compressed) ? 0 : numberOfRows; + + _TokenOffset = 0; + _FuncCodeOffset = _TokenOffset + sizeof(uint); + this.RowSize = _FuncCodeOffset + sizeof(uint); + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal uint GetToken(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _TokenOffset); + } + +#pragma warning disable 618 // Edit and continue API marked obsolete to give us more time to refactor + internal EditAndContinueOperation GetFuncCode(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return (EditAndContinueOperation)this.Block.PeekUInt32(rowOffset + _FuncCodeOffset); + } + } + + internal struct EnCMapTableReader + { + internal readonly uint NumberOfRows; + private readonly int _TokenOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal EnCMapTableReader( + uint numberOfRows, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _TokenOffset = 0; + this.RowSize = _TokenOffset + sizeof(uint); + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal uint GetToken(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _TokenOffset); + } + } +#pragma warning restore 618 // Edit and continue API marked obsolete to give us more time to refactor + + internal struct AssemblyTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _HashAlgIdOffset; + private readonly int _MajorVersionOffset; + private readonly int _MinorVersionOffset; + private readonly int _BuildNumberOffset; + private readonly int _RevisionNumberOffset; + private readonly int _FlagsOffset; + private readonly int _PublicKeyOffset; + private readonly int _NameOffset; + private readonly int _CultureOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyTableReader( + uint numberOfRows, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + // NOTE: obfuscated assemblies may have more than one row in Assembly table, + // we ignore all rows but the first one + this.NumberOfRows = numberOfRows > 1 ? 1 : numberOfRows; + + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _HashAlgIdOffset = 0; + _MajorVersionOffset = _HashAlgIdOffset + sizeof(UInt32); + _MinorVersionOffset = _MajorVersionOffset + sizeof(UInt16); + _BuildNumberOffset = _MinorVersionOffset + sizeof(UInt16); + _RevisionNumberOffset = _BuildNumberOffset + sizeof(UInt16); + _FlagsOffset = _RevisionNumberOffset + sizeof(UInt16); + _PublicKeyOffset = _FlagsOffset + sizeof(UInt32); + _NameOffset = _PublicKeyOffset + blobHeapRefSize; + _CultureOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _CultureOffset + stringHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal AssemblyHashAlgorithm GetHashAlgorithm() + { + Debug.Assert(NumberOfRows == 1); + return (AssemblyHashAlgorithm)this.Block.PeekUInt32(_HashAlgIdOffset); + } + + internal Version GetVersion() + { + Debug.Assert(NumberOfRows == 1); + return new Version( + this.Block.PeekUInt16(_MajorVersionOffset), + this.Block.PeekUInt16(_MinorVersionOffset), + this.Block.PeekUInt16(_BuildNumberOffset), + this.Block.PeekUInt16(_RevisionNumberOffset)); + } + + internal AssemblyFlags GetFlags() + { + Debug.Assert(NumberOfRows == 1); + return (AssemblyFlags)this.Block.PeekUInt32(_FlagsOffset); + } + + internal BlobHandle GetPublicKey() + { + Debug.Assert(NumberOfRows == 1); + return BlobHandle.FromIndex(this.Block.PeekReference(_PublicKeyOffset, _IsBlobHeapRefSizeSmall)); + } + + internal StringHandle GetName() + { + Debug.Assert(NumberOfRows == 1); + return StringHandle.FromIndex(this.Block.PeekReference(_NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetCulture() + { + Debug.Assert(NumberOfRows == 1); + return StringHandle.FromIndex(this.Block.PeekReference(_CultureOffset, _IsStringHeapRefSizeSmall)); + } + } + + internal struct AssemblyProcessorTableReader + { + internal readonly uint NumberOfRows; + private readonly int _ProcessorOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyProcessorTableReader( + uint numberOfRows, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _ProcessorOffset = 0; + this.RowSize = _ProcessorOffset + sizeof(UInt32); + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + } + + internal struct AssemblyOSTableReader + { + internal readonly uint NumberOfRows; + private readonly int _OSPlatformIdOffset; + private readonly int _OSMajorVersionIdOffset; + private readonly int _OSMinorVersionIdOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyOSTableReader( + uint numberOfRows, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _OSPlatformIdOffset = 0; + _OSMajorVersionIdOffset = _OSPlatformIdOffset + sizeof(UInt32); + _OSMinorVersionIdOffset = _OSMajorVersionIdOffset + sizeof(UInt32); + this.RowSize = _OSMinorVersionIdOffset + sizeof(UInt32); + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + } + + internal struct AssemblyRefTableReader + { + /// + /// In CLI metadata equal to the actual number of entries in AssemblyRef table. + /// In WinMD metadata it includes synthesized AssemblyRefs in addition. + /// + internal readonly int NumberOfNonVirtualRows; + internal readonly int NumberOfVirtualRows; + + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _MajorVersionOffset; + private readonly int _MinorVersionOffset; + private readonly int _BuildNumberOffset; + private readonly int _RevisionNumberOffset; + private readonly int _FlagsOffset; + private readonly int _PublicKeyOrTokenOffset; + private readonly int _NameOffset; + private readonly int _CultureOffset; + private readonly int _HashValueOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyRefTableReader( + int numberOfRows, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset, + MetadataKind metadataKind) + { + this.NumberOfNonVirtualRows = numberOfRows; + this.NumberOfVirtualRows = (metadataKind == MetadataKind.Ecma335) ? 0 : (int)AssemblyReferenceHandle.VirtualIndex.Count; + + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _MajorVersionOffset = 0; + _MinorVersionOffset = _MajorVersionOffset + sizeof(UInt16); + _BuildNumberOffset = _MinorVersionOffset + sizeof(UInt16); + _RevisionNumberOffset = _BuildNumberOffset + sizeof(UInt16); + _FlagsOffset = _RevisionNumberOffset + sizeof(UInt16); + _PublicKeyOrTokenOffset = _FlagsOffset + sizeof(UInt32); + _NameOffset = _PublicKeyOrTokenOffset + blobHeapRefSize; + _CultureOffset = _NameOffset + stringHeapRefSize; + _HashValueOffset = _CultureOffset + stringHeapRefSize; + this.RowSize = _HashValueOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, this.RowSize * numberOfRows); + } + + internal Version GetVersion(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return new Version( + this.Block.PeekUInt16(rowOffset + _MajorVersionOffset), + this.Block.PeekUInt16(rowOffset + _MinorVersionOffset), + this.Block.PeekUInt16(rowOffset + _BuildNumberOffset), + this.Block.PeekUInt16(rowOffset + _RevisionNumberOffset)); + } + + internal AssemblyFlags GetFlags(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return (AssemblyFlags)this.Block.PeekUInt32(rowOffset + _FlagsOffset); + } + + internal BlobHandle GetPublicKeyOrToken(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _PublicKeyOrTokenOffset, _IsBlobHeapRefSizeSmall)); + } + + internal StringHandle GetName(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetCulture(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _CultureOffset, _IsStringHeapRefSizeSmall)); + } + + internal BlobHandle GetHashValue(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _HashValueOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct AssemblyRefProcessorTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsAssemblyRefTableRowSizeSmall; + private readonly int _ProcessorOffset; + private readonly int _AssemblyRefOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyRefProcessorTableReader( + uint numberOfRows, + int assemblyRefTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsAssemblyRefTableRowSizeSmall = assemblyRefTableRowRefSize == 2; + _ProcessorOffset = 0; + _AssemblyRefOffset = _ProcessorOffset + sizeof(UInt32); + this.RowSize = _AssemblyRefOffset + assemblyRefTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + } + + internal struct AssemblyRefOSTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsAssemblyRefTableRowRefSizeSmall; + private readonly int _OSPlatformIdOffset; + private readonly int _OSMajorVersionIdOffset; + private readonly int _OSMinorVersionIdOffset; + private readonly int _AssemblyRefOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal AssemblyRefOSTableReader( + uint numberOfRows, + int assemblyRefTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsAssemblyRefTableRowRefSizeSmall = assemblyRefTableRowRefSize == 2; + _OSPlatformIdOffset = 0; + _OSMajorVersionIdOffset = _OSPlatformIdOffset + sizeof(UInt32); + _OSMinorVersionIdOffset = _OSMajorVersionIdOffset + sizeof(UInt32); + _AssemblyRefOffset = _OSMinorVersionIdOffset + sizeof(UInt32); + this.RowSize = _AssemblyRefOffset + assemblyRefTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + } + + internal struct FileTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _HashValueOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal FileTableReader( + uint numberOfRows, + int stringHeapRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _FlagsOffset = 0; + _NameOffset = _FlagsOffset + sizeof(UInt32); + _HashValueOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _HashValueOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal BlobHandle GetHashValue(AssemblyFileHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _HashValueOffset, _IsBlobHeapRefSizeSmall)); + } + + internal uint GetFlags(AssemblyFileHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _FlagsOffset); + } + + internal StringHandle GetName(AssemblyFileHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + } + + internal struct ExportedTypeTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsImplementationRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _FlagsOffset; + private readonly int _TypeDefIdOffset; + private readonly int _TypeNameOffset; + private readonly int _TypeNamespaceOffset; + private readonly int _ImplementationOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ExportedTypeTableReader( + uint numberOfRows, + int implementationRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsImplementationRefSizeSmall = implementationRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _FlagsOffset = 0; + _TypeDefIdOffset = _FlagsOffset + sizeof(UInt32); + _TypeNameOffset = _TypeDefIdOffset + sizeof(UInt32); + _TypeNamespaceOffset = _TypeNameOffset + stringHeapRefSize; + _ImplementationOffset = _TypeNamespaceOffset + stringHeapRefSize; + this.RowSize = _ImplementationOffset + implementationRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal StringHandle GetTypeName(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _TypeNameOffset, _IsStringHeapRefSizeSmall)); + } + + internal StringHandle GetTypeNamespaceString(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _TypeNamespaceOffset, _IsStringHeapRefSizeSmall)); + } + + internal NamespaceDefinitionHandle GetTypeNamespace(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return NamespaceDefinitionHandle.FromIndexOfFullName(this.Block.PeekReference(rowOffset + _TypeNamespaceOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetImplementation(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return ImplementationTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ImplementationOffset, _IsImplementationRefSizeSmall)); + } + + internal TypeAttributes GetFlags(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return (TypeAttributes)this.Block.PeekUInt32(rowOffset + _FlagsOffset); + } + + internal uint GetTypeDefId(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _TypeDefIdOffset); + } + + internal uint GetNamespace(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + uint typeNamespace = this.Block.PeekReference(rowOffset + _TypeNamespaceOffset, _IsStringHeapRefSizeSmall); + return typeNamespace; + } + } + + internal struct ManifestResourceTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsImplementationRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _OffsetOffset; + private readonly int _FlagsOffset; + private readonly int _NameOffset; + private readonly int _ImplementationOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal ManifestResourceTableReader( + uint numberOfRows, + int implementationRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsImplementationRefSizeSmall = implementationRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _OffsetOffset = 0; + _FlagsOffset = _OffsetOffset + sizeof(UInt32); + _NameOffset = _FlagsOffset + sizeof(UInt32); + _ImplementationOffset = _NameOffset + stringHeapRefSize; + this.RowSize = _ImplementationOffset + implementationRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal StringHandle GetName(ManifestResourceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetImplementation(ManifestResourceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return ImplementationTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ImplementationOffset, _IsImplementationRefSizeSmall)); + } + + internal uint GetOffset(ManifestResourceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return this.Block.PeekUInt32(rowOffset + _OffsetOffset); + } + + internal ManifestResourceAttributes GetFlags(ManifestResourceHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (ManifestResourceAttributes)this.Block.PeekUInt32(rowOffset + _FlagsOffset); + } + } + + internal struct NestedClassTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeDefTableRowRefSizeSmall; + private readonly int _NestedClassOffset; + private readonly int _EnclosingClassOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal NestedClassTableReader( + uint numberOfRows, + bool declaredSorted, + int typeDefTableRowRefSize, + MemoryBlock containingBlock, + int containingBlockOffset + ) + { + this.NumberOfRows = numberOfRows; + _IsTypeDefTableRowRefSizeSmall = typeDefTableRowRefSize == 2; + _NestedClassOffset = 0; + _EnclosingClassOffset = _NestedClassOffset + typeDefTableRowRefSize; + this.RowSize = _EnclosingClassOffset + typeDefTableRowRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.NestedClass); + } + } + + internal TypeDefinitionHandle GetNestedClass(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _NestedClassOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal TypeDefinitionHandle GetEnclosingClass(uint rowId) + { + int rowOffset = (int)(rowId - 1) * this.RowSize; + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowOffset + _EnclosingClassOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + internal TypeDefinitionHandle FindEnclosingType(TypeDefinitionHandle nestedTypeDef) + { + int rowNumber = + this.Block.BinarySearchReference( + this.NumberOfRows, + this.RowSize, + _NestedClassOffset, + nestedTypeDef.RowId, + _IsTypeDefTableRowRefSizeSmall); + + if (rowNumber == -1) + return default(TypeDefinitionHandle); + + return TypeDefinitionHandle.FromRowId(this.Block.PeekReference(rowNumber * this.RowSize + _EnclosingClassOffset, _IsTypeDefTableRowRefSizeSmall)); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _NestedClassOffset, _IsTypeDefTableRowRefSizeSmall); + } + } + + internal struct GenericParamTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsTypeOrMethodDefRefSizeSmall; + private readonly bool _IsStringHeapRefSizeSmall; + private readonly int _NumberOffset; + private readonly int _FlagsOffset; + private readonly int _OwnerOffset; + private readonly int _NameOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal GenericParamTableReader( + uint numberOfRows, + bool declaredSorted, + int typeOrMethodDefRefSize, + int stringHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsTypeOrMethodDefRefSizeSmall = typeOrMethodDefRefSize == 2; + _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; + _NumberOffset = 0; + _FlagsOffset = _NumberOffset + sizeof(UInt16); + _OwnerOffset = _FlagsOffset + sizeof(UInt16); + _NameOffset = _OwnerOffset + typeOrMethodDefRefSize; + this.RowSize = _NameOffset + stringHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.GenericParam); + } + } + + internal ushort GetNumber(GenericParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return this.Block.PeekUInt16(rowOffset + _NumberOffset); + } + + internal GenericParameterAttributes GetFlags(GenericParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return (GenericParameterAttributes)this.Block.PeekUInt16(rowOffset + _FlagsOffset); + } + + internal StringHandle GetName(GenericParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return StringHandle.FromIndex(this.Block.PeekReference(rowOffset + _NameOffset, _IsStringHeapRefSizeSmall)); + } + + internal Handle GetOwner(GenericParameterHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return TypeOrMethodDefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _OwnerOffset, _IsTypeOrMethodDefRefSizeSmall)); + } + + internal GenericParameterHandleCollection FindGenericParametersForType(TypeDefinitionHandle typeDef) + { + ushort count = 0; + uint searchCodedTag = TypeOrMethodDefTag.ConvertTypeDefRowIdToTag(typeDef); + int startRid = (int)this.BinarySearchTag(searchCodedTag, ref count); + + return new GenericParameterHandleCollection(startRid, count); + } + + internal GenericParameterHandleCollection FindGenericParametersForMethod(MethodDefinitionHandle methodDef) + { + ushort count = 0; + uint searchCodedTag = TypeOrMethodDefTag.ConvertMethodDefToTag(methodDef); + int startRid = (int)this.BinarySearchTag(searchCodedTag, ref count); + + return new GenericParameterHandleCollection(startRid, count); + } + + private uint BinarySearchTag(uint searchCodedTag, ref ushort genericParamCount) + { + int startRowNumber, endRowNumber; + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _OwnerOffset, + searchCodedTag, + _IsTypeOrMethodDefRefSizeSmall, + out startRowNumber, + out endRowNumber); + + if (startRowNumber == -1) + { + genericParamCount = 0; + return 0; + } + + genericParamCount = (ushort)(endRowNumber - startRowNumber + 1); + return (uint)(startRowNumber + 1); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _OwnerOffset, _IsTypeOrMethodDefRefSizeSmall); + } + } + + internal struct MethodSpecTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsMethodDefOrRefRefSizeSmall; + private readonly bool _IsBlobHeapRefSizeSmall; + private readonly int _MethodOffset; + private readonly int _InstantiationOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal MethodSpecTableReader( + uint numberOfRows, + int methodDefOrRefRefSize, + int blobHeapRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsMethodDefOrRefRefSizeSmall = methodDefOrRefRefSize == 2; + _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; + _MethodOffset = 0; + _InstantiationOffset = _MethodOffset + methodDefOrRefRefSize; + this.RowSize = _InstantiationOffset + blobHeapRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + } + + internal Handle GetMethod(MethodSpecificationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return MethodDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _MethodOffset, _IsMethodDefOrRefRefSizeSmall)); + } + + internal BlobHandle GetInstantiation(MethodSpecificationHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return BlobHandle.FromIndex(this.Block.PeekReference(rowOffset + _InstantiationOffset, _IsBlobHeapRefSizeSmall)); + } + } + + internal struct GenericParamConstraintTableReader + { + internal readonly uint NumberOfRows; + private readonly bool _IsGenericParamTableRowRefSizeSmall; + private readonly bool _IsTypeDefOrRefRefSizeSmall; + private readonly int _OwnerOffset; + private readonly int _ConstraintOffset; + internal readonly int RowSize; + internal readonly MemoryBlock Block; + + internal GenericParamConstraintTableReader( + uint numberOfRows, + bool declaredSorted, + int genericParamTableRowRefSize, + int typeDefOrRefRefSize, + MemoryBlock containingBlock, + int containingBlockOffset) + { + this.NumberOfRows = numberOfRows; + _IsGenericParamTableRowRefSizeSmall = genericParamTableRowRefSize == 2; + _IsTypeDefOrRefRefSizeSmall = typeDefOrRefRefSize == 2; + _OwnerOffset = 0; + _ConstraintOffset = _OwnerOffset + genericParamTableRowRefSize; + this.RowSize = _ConstraintOffset + typeDefOrRefRefSize; + this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); + + if (!declaredSorted && !CheckSorted()) + { + MetadataReader.ThrowTableNotSorted(TableIndex.GenericParamConstraint); + } + } + + internal GenericParameterConstraintHandleCollection FindConstraintsForGenericParam(GenericParameterHandle genericParameter) + { + int startRowNumber, endRowNumber; + this.Block.BinarySearchReferenceRange( + this.NumberOfRows, + this.RowSize, + _OwnerOffset, + genericParameter.RowId, + _IsGenericParamTableRowRefSizeSmall, + out startRowNumber, + out endRowNumber); + + if (startRowNumber == -1) + { + return default(GenericParameterConstraintHandleCollection); + } + + return new GenericParameterConstraintHandleCollection( + firstRowId: startRowNumber + 1, + count: (ushort)(endRowNumber - startRowNumber + 1)); + } + + private bool CheckSorted() + { + return this.Block.IsOrderedByReferenceAscending(this.RowSize, _OwnerOffset, _IsGenericParamTableRowRefSizeSmall); + } + + internal Handle GetConstraint(GenericParameterConstraintHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return TypeDefOrRefTag.ConvertToToken(this.Block.PeekTaggedReference(rowOffset + _ConstraintOffset, _IsTypeDefOrRefRefSizeSmall)); + } + + internal GenericParameterHandle GetOwner(GenericParameterConstraintHandle handle) + { + int rowOffset = (int)(handle.RowId - 1) * this.RowSize; + return GenericParameterHandle.FromRowId(this.Block.PeekReference(rowOffset + _OwnerOffset, _IsGenericParamTableRowRefSizeSmall)); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Treatments.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Treatments.cs new file mode 100644 index 0000000..f0b25cf --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/Treatments.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata.Ecma335 +{ + [Flags] + internal enum TypeDefTreatment : byte + { + None = 0, + + KindMask = 0x0f, + NormalNonAttribute = 1, + NormalAttribute = 2, + UnmangleWinRTName = 3, + PrefixWinRTName = 4, + RedirectedToClrType = 5, + RedirectedToClrAttribute = 6, + + MarkAbstractFlag = 0x10, + MarkInternalFlag = 0x20 + } + + internal enum TypeRefTreatment : byte + { + None = 0, + SystemDelegate = 1, + SystemAttribute = 2, + + // RowId is an index to the projection info table. + UseProjectionInfo = 3, + } + + [Flags] + internal enum MethodDefTreatment : byte + { + None = 0, + + KindMask = 0x0f, + Other = 1, + DelegateMethod = 2, + AttributeMethod = 3, + InterfaceMethod = 4, + Implementation = 5, + HiddenInterfaceImplementation = 6, + DisposeMethod = 7, + + MarkAbstractFlag = 0x10, + MarkPublicFlag = 0x20, + // TODO: In the latest Adapter.cpp sources this seems to be no longer applicable (confirm?) + // MarkSpecialName = 0x40 + } + + [Flags] + internal enum FieldDefTreatment : byte + { + None = 0, + EnumValue = 1, + } + + [Flags] + internal enum MemberRefTreatment : byte + { + None = 0, + Dispose = 1, + } + + [Flags] + internal enum CustomAttributeTreatment : byte + { + None = 0, + WinMD = 1, + } + + [Flags] + internal enum CustomAttributeValueTreatment : byte + { + None = 0, + AttributeUsageAllowSingle = 1, + AttributeUsageAllowMultiple = 2, + AttributeUsageVersionAttribute = 3, + AttributeUsageDeprecatedAttribute = 4, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeDefOrRefTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeDefOrRefTag.cs new file mode 100644 index 0000000..a6621ca --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeDefOrRefTag.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class TypeDefOrRefTag + { + internal const int NumberOfBits = 2; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint TypeDef = 0x00000000; + internal const uint TypeRef = 0x00000001; + internal const uint TypeSpec = 0x00000002; + internal const uint TagMask = 0x00000003; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.TypeDef >> 24 | TokenTypeIds.TypeRef >> 16 | TokenTypeIds.TypeSpec >> 8; + internal const TableMask TablesReferenced = + TableMask.TypeDef + | TableMask.TypeRef + | TableMask.TypeSpec; + + // inlining improves perf of the tight loop in FindSystemObjectTypeDef by 25% + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint typeDefOrRefTag) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(typeDefOrRefTag & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (typeDefOrRefTag >> NumberOfBits); + + if (tokenType == 0 || (rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeOrMethodDefTag.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeOrMethodDefTag.cs new file mode 100644 index 0000000..dbc598b --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Internal/TypeOrMethodDefTag.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata.Ecma335 +{ + internal static class TypeOrMethodDefTag + { + internal const int NumberOfBits = 1; + internal const uint LargeRowSize = 0x00000001 << (16 - NumberOfBits); + internal const uint TypeDef = 0x00000000; + internal const uint MethodDef = 0x00000001; + internal const uint TagMask = 0x0000001; + internal const uint TagToTokenTypeByteVector = TokenTypeIds.TypeDef >> 24 | TokenTypeIds.MethodDef >> 16; + internal const TableMask TablesReferenced = + TableMask.TypeDef + | TableMask.MethodDef; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Handle ConvertToToken(uint typeOrMethodDef) + { + uint tokenType = (TagToTokenTypeByteVector >> ((int)(typeOrMethodDef & TagMask) << 3)) << TokenTypeIds.RowIdBitCount; + uint rowId = (typeOrMethodDef >> NumberOfBits); + + if ((rowId & ~TokenTypeIds.RIDMask) != 0) + { + Handle.ThrowInvalidCodedIndex(); + } + + return new Handle(tokenType | rowId); + } + + internal static uint ConvertTypeDefRowIdToTag(TypeDefinitionHandle typeDef) + { + return typeDef.RowId << NumberOfBits | TypeDef; + } + + internal static uint ConvertMethodDefToTag(MethodDefinitionHandle methodDef) + { + return methodDef.RowId << NumberOfBits | MethodDef; + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ManifestResource.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ManifestResource.cs new file mode 100644 index 0000000..cd13d5a --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ManifestResource.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct ManifestResource + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal ManifestResource(MetadataReader reader, ManifestResourceHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private ManifestResourceHandle Handle + { + get { return ManifestResourceHandle.FromRowId(_rowId); } + } + + /// + /// Specifies the byte offset within the referenced file at which this resource record begins. + /// + /// + /// Corresponds to Offset field of ManifestResource table in ECMA-335 Standard. + /// + public long Offset + { + get { return _reader.ManifestResourceTable.GetOffset(Handle); } + } + + /// + /// Resource attributes. + /// + /// + /// Corresponds to Flags field of ManifestResource table in ECMA-335 Standard. + /// + public ManifestResourceAttributes Attributes + { + get { return _reader.ManifestResourceTable.GetFlags(Handle); } + } + + /// + /// Name of the resource. + /// + /// + /// Corresponds to Name field of ManifestResource table in ECMA-335 Standard. + /// + public StringHandle Name + { + get { return _reader.ManifestResourceTable.GetName(Handle); } + } + + /// + /// , , or nil handle. + /// + /// + /// Corresponds to Implementation field of ManifestResource table in ECMA-335 Standard. + /// + /// If nil then is an offset in the PE image that contains the metadata, + /// starting from the Resource entry in the CLI header. + /// + public Handle Implementation + { + get { return _reader.ManifestResourceTable.GetImplementation(Handle); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReference.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReference.cs new file mode 100644 index 0000000..18eb3aa --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReference.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct MemberReference + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal MemberReference(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private MemberRefTreatment Treatment + { + get { return (MemberRefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + private MemberReferenceHandle Handle + { + get { return MemberReferenceHandle.FromRowId(RowId); } + } + + /// + /// MethodDef, ModuleRef,TypeDef, TypeRef, or TypeSpec handle. + /// + public Handle Parent + { + get + { + if (Treatment == 0) + { + return _reader.MemberRefTable.GetClass(Handle); + } + + return GetProjectedParent(); + } + } + + public StringHandle Name + { + get + { + if (Treatment == 0) + { + return _reader.MemberRefTable.GetName(Handle); + } + + return GetProjectedName(); + } + } + + public BlobHandle Signature + { + get + { + if (Treatment == 0) + { + return _reader.MemberRefTable.GetSignature(Handle); + } + + return GetProjectedSignature(); + } + } + + /// + /// Determines if the member reference is to a method or field. + /// + public MemberReferenceKind GetKind() + { + BlobReader blobReader = _reader.GetBlobReader(this.Signature); + SignatureHeader header = blobReader.ReadSignatureHeader(); + + switch (header.Kind) + { + case SignatureKind.Method: + return MemberReferenceKind.Method; + + case SignatureKind.Field: + return MemberReferenceKind.Field; + + default: + throw new BadImageFormatException(); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + #region Projections + + private Handle GetProjectedParent() + { + // no change + return _reader.MemberRefTable.GetClass(Handle); + } + + private StringHandle GetProjectedName() + { + if (Treatment == MemberRefTreatment.Dispose) + { + return StringHandle.FromVirtualIndex(StringHandle.VirtualIndex.Dispose); + } + + return _reader.MemberRefTable.GetName(Handle); + } + + private BlobHandle GetProjectedSignature() + { + // no change + return _reader.MemberRefTable.GetSignature(Handle); + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReferenceKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReferenceKind.cs new file mode 100644 index 0000000..be0a0a7 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MemberReferenceKind.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + /// + /// Indicates whether a MemberReference references a method or field. + /// + public enum MemberReferenceKind + { + /// + /// The MemberReference references a method. + /// + Method, + + /// + /// The MemberReference references a field. + /// + Field, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataAggregator.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataAggregator.cs new file mode 100644 index 0000000..cdadee9 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataAggregator.cs @@ -0,0 +1,326 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; + +namespace System.Reflection.Metadata.Ecma335 +{ + public sealed class MetadataAggregator + { + // For each heap handle and each delta contains aggregate heap lengths. + // heapSizes[heap kind][reader index] == Sum { 0..index | reader[i].XxxHeapLength } + private readonly ImmutableArray> _heapSizes; + + private readonly ImmutableArray> _rowCounts; + + // internal for testing + internal struct RowCounts : IComparable + { + public int AggregateInserts; + public int Updates; + + public int CompareTo(RowCounts other) + { + return AggregateInserts - other.AggregateInserts; + } + + public override string ToString() + { + return string.Format("+0x{0:x} ~0x{1:x}", AggregateInserts, Updates); + } + } + + public MetadataAggregator(MetadataReader baseReader, IReadOnlyList deltaReaders) + : this(baseReader, null, null, deltaReaders) + { + } + + public MetadataAggregator( + IReadOnlyList baseTableRowCounts, + IReadOnlyList baseHeapSizes, + IReadOnlyList deltaReaders) + : this(null, baseTableRowCounts, baseHeapSizes, deltaReaders) + { + } + + private MetadataAggregator( + MetadataReader baseReader, + IReadOnlyList baseTableRowCounts, + IReadOnlyList baseHeapSizes, + IReadOnlyList deltaReaders) + { + if (baseTableRowCounts == null) + { + if (baseReader == null) + { + throw new ArgumentNullException("deltaReaders"); + } + + if (baseReader.GetTableRowCount(TableIndex.EncMap) != 0) + { + throw new ArgumentException("Base reader must be a full metadata reader.", "baseReader"); + } + + CalculateBaseCounts(baseReader, out baseTableRowCounts, out baseHeapSizes); + } + else + { + if (baseTableRowCounts == null) + { + throw new ArgumentNullException("baseTableRowCounts"); + } + + if (baseTableRowCounts.Count != MetadataTokens.TableCount) + { + throw new ArgumentException("Must have " + MetadataTokens.TableCount + " elements", "baseTableRowCounts"); + } + + if (baseHeapSizes == null) + { + throw new ArgumentNullException("baseHeapSizes"); + } + + if (baseHeapSizes.Count != MetadataTokens.HeapCount) + { + throw new ArgumentException("Must have " + MetadataTokens.HeapCount + " elements", "baseTableRowCounts"); + } + } + + if (deltaReaders == null || deltaReaders.Count == 0) + { + throw new ArgumentException("Must not be empty.", "deltaReaders"); + } + + for (int i = 0; i < deltaReaders.Count; i++) + { + if (deltaReaders[i].GetTableRowCount(TableIndex.EncMap) == 0 || !deltaReaders[i].IsMinimalDelta) + { + throw new ArgumentException("All delta readers must be minimal delta metadata readers.", "deltaReaders"); + } + } + + _heapSizes = CalculateHeapSizes(baseHeapSizes, deltaReaders); + _rowCounts = CalculateRowCounts(baseTableRowCounts, deltaReaders); + } + + // for testing only + internal MetadataAggregator(RowCounts[][] rowCounts, int[][] heapSizes) + { + _rowCounts = ToImmutable(rowCounts); + _heapSizes = ToImmutable(heapSizes); + } + + private static void CalculateBaseCounts( + MetadataReader baseReader, + out IReadOnlyList baseTableRowCounts, + out IReadOnlyList baseHeapSizes) + { + int[] rowCounts = new int[MetadataTokens.TableCount]; + int[] heapSizes = new int[MetadataTokens.HeapCount]; + + for (int i = 0; i < rowCounts.Length; i++) + { + rowCounts[i] = baseReader.GetTableRowCount((TableIndex)i); + } + + for (int i = 0; i < heapSizes.Length; i++) + { + heapSizes[i] = baseReader.GetHeapSize((HeapIndex)i); + } + + baseTableRowCounts = rowCounts; + baseHeapSizes = heapSizes; + } + + private static ImmutableArray> CalculateHeapSizes( + IReadOnlyList baseSizes, + IReadOnlyList deltaReaders) + { + // GUID heap index is multiple of sizeof(Guid) == 16 + const int guidSize = 16; + int generationCount = 1 + deltaReaders.Count; + + var userStringSizes = new int[generationCount]; + var stringSizes = new int[generationCount]; + var blobSizes = new int[generationCount]; + var guidSizes = new int[generationCount]; + + userStringSizes[0] = baseSizes[(int)HeapIndex.UserString]; + stringSizes[0] = baseSizes[(int)HeapIndex.String]; + blobSizes[0] = baseSizes[(int)HeapIndex.Blob]; + guidSizes[0] = baseSizes[(int)HeapIndex.Guid] / guidSize; + + for (int r = 0; r < deltaReaders.Count; r++) + { + userStringSizes[r + 1] = userStringSizes[r] + deltaReaders[r].GetHeapSize(HeapIndex.UserString); + stringSizes[r + 1] = stringSizes[r] + deltaReaders[r].GetHeapSize(HeapIndex.String); + blobSizes[r + 1] = blobSizes[r] + deltaReaders[r].GetHeapSize(HeapIndex.Blob); + guidSizes[r + 1] = guidSizes[r] + deltaReaders[r].GetHeapSize(HeapIndex.Guid) / guidSize; + } + + return ImmutableArray.Create( + userStringSizes.ToImmutableArray(), + stringSizes.ToImmutableArray(), + blobSizes.ToImmutableArray(), + guidSizes.ToImmutableArray()); + } + + private static ImmutableArray> CalculateRowCounts( + IReadOnlyList baseRowCounts, + IReadOnlyList deltaReaders) + { + // TODO: optimize - we don't need to allocate all these arrays + var rowCounts = GetBaseRowCounts(baseRowCounts, generations: 1 + deltaReaders.Count); + + for (int generation = 1; generation <= deltaReaders.Count; generation++) + { + CalculateDeltaRowCountsForGeneration(rowCounts, generation, ref deltaReaders[generation - 1].EncMapTable); + } + + return ToImmutable(rowCounts); + } + + private static ImmutableArray> ToImmutable(T[][] array) + { + var immutable = new ImmutableArray[array.Length]; + for (int i = 0; i < array.Length; i++) + { + immutable[i] = array[i].ToImmutableArray(); + } + + return immutable.ToImmutableArray(); + } + + // internal for testing + internal static RowCounts[][] GetBaseRowCounts(IReadOnlyList baseRowCounts, int generations) + { + var rowCounts = new RowCounts[TableIndexExtensions.Count][]; + + for (int t = 0; t < rowCounts.Length; t++) + { + rowCounts[t] = new RowCounts[generations]; + rowCounts[t][0].AggregateInserts = baseRowCounts[t]; + } + + return rowCounts; + } + + // internal for testing + internal static void CalculateDeltaRowCountsForGeneration(RowCounts[][] rowCounts, int generation, ref EnCMapTableReader encMapTable) + { + foreach (var tableRowCounts in rowCounts) + { + tableRowCounts[generation].AggregateInserts = tableRowCounts[generation - 1].AggregateInserts; + } + + int mapRowCount = (int)encMapTable.NumberOfRows; + for (uint mapRid = 1; mapRid <= mapRowCount; mapRid++) + { + uint token = encMapTable.GetToken(mapRid); + int rid = (int)(token & TokenTypeIds.RIDMask); + + var tableRowCounts = rowCounts[token >> TokenTypeIds.RowIdBitCount]; + + if (rid > tableRowCounts[generation].AggregateInserts) + { + if (rid != tableRowCounts[generation].AggregateInserts + 1) + { + throw new BadImageFormatException(MetadataResources.EnCMapNotSorted); + } + + // insert: + tableRowCounts[generation].AggregateInserts = rid; + } + else + { + // update: + tableRowCounts[generation].Updates++; + } + } + } + + public Handle GetGenerationHandle(Handle handle, out int generation) + { + if (handle.IsVirtual) + { + // TODO: if a virtual handle is connected to real handle then translate the rid, + // otherwise return vhandle and base. + throw new NotSupportedException(); + } + + int rowId = (int)handle.RowId; + uint typeId = handle.TokenType; + int relativeRowId; + + if (handle.IsHeapHandle) + { + HeapIndex heapIndex; + MetadataTokens.TryGetHeapIndex(handle.Kind, out heapIndex); + + var sizes = _heapSizes[(int)heapIndex]; + + generation = sizes.BinarySearch(rowId); + if (generation >= 0) + { + Debug.Assert(sizes[generation] == rowId); + + // the index points to the start of the next generation that added data to the heap: + do + { + generation++; + } + while (generation < sizes.Length && sizes[generation] == rowId); + } + else + { + generation = ~generation; + } + + if (generation >= sizes.Length) + { + throw new ArgumentException("Handle belongs to a future generation", "handle"); + } + + // GUID heap accumulates - previous heap is copied to the next generation + relativeRowId = (typeId == TokenTypeIds.Guid || generation == 0) ? rowId : rowId - sizes[generation - 1]; + } + else + { + var sizes = _rowCounts[(int)handle.value >> TokenTypeIds.RowIdBitCount]; + + generation = sizes.BinarySearch(new RowCounts { AggregateInserts = rowId }); + if (generation >= 0) + { + Debug.Assert(sizes[generation].AggregateInserts == rowId); + + // the row is in a generation that inserted exactly one row -- the one that we are looking for; + // or it's in a preceding generation if the current one didn't insert any rows of the kind: + while (generation > 0 && sizes[generation - 1].AggregateInserts == rowId) + { + generation--; + } + } + else + { + // the row is in a generation that inserted multiple new rows: + generation = ~generation; + + if (generation >= sizes.Length) + { + throw new ArgumentException("Handle belongs to a future generation", "handle"); + } + } + + // In each delta table updates always precede inserts. + relativeRowId = (generation == 0) ? rowId : + rowId - + sizes[generation - 1].AggregateInserts + + sizes[generation].Updates; + } + + return new Handle(typeId | (uint)relativeRowId); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataKind.cs new file mode 100644 index 0000000..c0c008d --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataKind.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public enum MetadataKind + { + /// + /// CLI metadata. + /// + Ecma335, + + /// + /// Windows Metadata. + /// + WindowsMetadata, + + /// + /// Windows Metadata generated by managed compilers. + /// + ManagedWindowsMetadata, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.WinMD.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.WinMD.cs new file mode 100644 index 0000000..2176188 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.WinMD.cs @@ -0,0 +1,827 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata +{ + partial class MetadataReader + { + internal const string ClrPrefix = ""; + + internal static readonly byte[] WinRTPrefix = new[] { + (byte)'<', + (byte)'W', + (byte)'i', + (byte)'n', + (byte)'R', + (byte)'T', + (byte)'>' + }; + + #region Projection Tables + + // Maps names of projected types to projection information for each type. + // Both arrays are of the same length and sorted by the type name. + private static string[] s_projectedTypeNames; + private static ProjectionInfo[] s_projectionInfos; + + private struct ProjectionInfo + { + public readonly string WinRTNamespace; + public readonly StringHandle.VirtualIndex ClrNamespace; + public readonly StringHandle.VirtualIndex ClrName; + public readonly AssemblyReferenceHandle.VirtualIndex AssemblyRef; + public readonly TypeDefTreatment Treatment; + public readonly bool IsIDisposable; + + public ProjectionInfo( + string winRtNamespace, + StringHandle.VirtualIndex clrNamespace, + StringHandle.VirtualIndex clrName, + AssemblyReferenceHandle.VirtualIndex clrAssembly, + TypeDefTreatment treatment = TypeDefTreatment.RedirectedToClrType, + bool isIDisposable = false) + { + this.WinRTNamespace = winRtNamespace; + this.ClrNamespace = clrNamespace; + this.ClrName = clrName; + this.AssemblyRef = clrAssembly; + this.Treatment = treatment; + this.IsIDisposable = isIDisposable; + } + } + + private TypeDefTreatment GetWellKnownTypeDefinitionTreatment(TypeDefinitionHandle typeDef) + { + InitializeProjectedTypes(); + + StringHandle name = TypeDefTable.GetName(typeDef); + + int index = StringStream.BinarySearchRaw(s_projectedTypeNames, name); + if (index < 0) + { + return TypeDefTreatment.None; + } + + StringHandle namespaceName = TypeDefTable.GetNamespaceString(typeDef); + if (StringStream.EqualsRaw(namespaceName, StringStream.GetVirtualValue(s_projectionInfos[index].ClrNamespace))) + { + return s_projectionInfos[index].Treatment; + } + + // TODO: we can avoid this comparison if info.DotNetNamespace == info.WinRtNamespace + if (StringStream.EqualsRaw(namespaceName, s_projectionInfos[index].WinRTNamespace)) + { + return s_projectionInfos[index].Treatment | TypeDefTreatment.MarkInternalFlag; + } + + return TypeDefTreatment.None; + } + + private int GetProjectionIndexForTypeReference(TypeReferenceHandle typeRef, out bool isIDisposable) + { + InitializeProjectedTypes(); + + int index = StringStream.BinarySearchRaw(s_projectedTypeNames, TypeRefTable.GetName(typeRef)); + if (index >= 0 && StringStream.EqualsRaw(TypeRefTable.GetNamespace(typeRef), s_projectionInfos[index].WinRTNamespace)) + { + isIDisposable = s_projectionInfos[index].IsIDisposable; + return index; + } + + isIDisposable = false; + return -1; + } + + internal static AssemblyReferenceHandle GetProjectedAssemblyRef(int projectionIndex) + { + Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length); + return AssemblyReferenceHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].AssemblyRef); + } + + internal static StringHandle GetProjectedName(int projectionIndex) + { + Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length); + return StringHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].ClrName); + } + + internal static StringHandle GetProjectedNamespace(int projectionIndex) + { + Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length); + return StringHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].ClrNamespace); + } + + private static void InitializeProjectedTypes() + { + if (s_projectedTypeNames == null || s_projectionInfos == null) + { + var systemRuntimeWindowsRuntime = AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime; + var systemRuntime = AssemblyReferenceHandle.VirtualIndex.System_Runtime; + var systemObjectModel = AssemblyReferenceHandle.VirtualIndex.System_ObjectModel; + var systemRuntimeWindowsUiXaml = AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml; + var systemRuntimeInterop = AssemblyReferenceHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime; + var systemNumericsVectors = AssemblyReferenceHandle.VirtualIndex.System_Numerics_Vectors; + + // sorted by name + var keys = new string[50]; + var values = new ProjectionInfo[50]; + int k = 0, v = 0; + + // WARNING: Keys must be sorted by name and must only contain ASCII characters. WinRTNamespace must also be ASCII only. + + keys[k++] = "AttributeTargets"; values[v++] = new ProjectionInfo("Windows.Foundation.Metadata", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.AttributeTargets, systemRuntime); + keys[k++] = "AttributeUsageAttribute"; values[v++] = new ProjectionInfo("Windows.Foundation.Metadata", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.AttributeUsageAttribute, systemRuntime, treatment: TypeDefTreatment.RedirectedToClrAttribute); + keys[k++] = "Color"; values[v++] = new ProjectionInfo("Windows.UI", StringHandle.VirtualIndex.Windows_UI, StringHandle.VirtualIndex.Color, systemRuntimeWindowsRuntime); + keys[k++] = "CornerRadius"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.CornerRadius, systemRuntimeWindowsUiXaml); + keys[k++] = "DateTime"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.DateTimeOffset, systemRuntime); + keys[k++] = "Duration"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.Duration, systemRuntimeWindowsUiXaml); + keys[k++] = "DurationType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.DurationType, systemRuntimeWindowsUiXaml); + keys[k++] = "EventHandler`1"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.EventHandler1, systemRuntime); + keys[k++] = "EventRegistrationToken"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime, StringHandle.VirtualIndex.EventRegistrationToken, systemRuntimeInterop); + keys[k++] = "GeneratorPosition"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Controls.Primitives", StringHandle.VirtualIndex.Windows_UI_Xaml_Controls_Primitives, StringHandle.VirtualIndex.GeneratorPosition, systemRuntimeWindowsUiXaml); + keys[k++] = "GridLength"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.GridLength, systemRuntimeWindowsUiXaml); + keys[k++] = "GridUnitType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.GridUnitType, systemRuntimeWindowsUiXaml); + keys[k++] = "HResult"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Exception, systemRuntime); + keys[k++] = "IBindableIterable"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections, StringHandle.VirtualIndex.IEnumerable, systemRuntime); + keys[k++] = "IBindableVector"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections, StringHandle.VirtualIndex.IList, systemRuntime); + keys[k++] = "IClosable"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.IDisposable, systemRuntime, isIDisposable: true); + keys[k++] = "ICommand"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Input", StringHandle.VirtualIndex.System_Windows_Input, StringHandle.VirtualIndex.ICommand, systemObjectModel); + keys[k++] = "IIterable`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IEnumerable1, systemRuntime); + keys[k++] = "IKeyValuePair`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.KeyValuePair2, systemRuntime); + keys[k++] = "IMapView`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IReadOnlyDictionary2, systemRuntime); + keys[k++] = "IMap`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IDictionary2, systemRuntime); + keys[k++] = "INotifyCollectionChanged"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.INotifyCollectionChanged, systemObjectModel); + keys[k++] = "INotifyPropertyChanged"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.INotifyPropertyChanged, systemObjectModel); + keys[k++] = "IReference`1"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Nullable1, systemRuntime); + keys[k++] = "IVectorView`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IReadOnlyList1, systemRuntime); + keys[k++] = "IVector`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IList1, systemRuntime); + keys[k++] = "KeyTime"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.KeyTime, systemRuntimeWindowsUiXaml); + keys[k++] = "Matrix"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media", StringHandle.VirtualIndex.Windows_UI_Xaml_Media, StringHandle.VirtualIndex.Matrix, systemRuntimeWindowsUiXaml); + keys[k++] = "Matrix3D"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Media3D", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Media3D, StringHandle.VirtualIndex.Matrix3D, systemRuntimeWindowsUiXaml); + keys[k++] = "Matrix3x2"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Matrix3x2, systemNumericsVectors); + keys[k++] = "Matrix4x4"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Matrix4x4, systemNumericsVectors); + keys[k++] = "NotifyCollectionChangedAction"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedAction, systemObjectModel); + keys[k++] = "NotifyCollectionChangedEventArgs"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedEventArgs, systemObjectModel); + keys[k++] = "NotifyCollectionChangedEventHandler"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedEventHandler, systemObjectModel); + keys[k++] = "Plane"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Plane, systemNumericsVectors); + keys[k++] = "Point"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Point, systemRuntimeWindowsRuntime); + keys[k++] = "PropertyChangedEventArgs"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.PropertyChangedEventArgs, systemObjectModel); + keys[k++] = "PropertyChangedEventHandler"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.PropertyChangedEventHandler, systemObjectModel); + keys[k++] = "Quaternion"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Quaternion, systemNumericsVectors); + keys[k++] = "Rect"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Rect, systemRuntimeWindowsRuntime); + keys[k++] = "RepeatBehavior"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.RepeatBehavior, systemRuntimeWindowsUiXaml); + keys[k++] = "RepeatBehaviorType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.RepeatBehaviorType, systemRuntimeWindowsUiXaml); + keys[k++] = "Size"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Size, systemRuntimeWindowsRuntime); + keys[k++] = "Thickness"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.Thickness, systemRuntimeWindowsUiXaml); + keys[k++] = "TimeSpan"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.TimeSpan, systemRuntime); + keys[k++] = "TypeName"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Type, systemRuntime); + keys[k++] = "Uri"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Uri, systemRuntime); + keys[k++] = "Vector2"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector2, systemNumericsVectors); + keys[k++] = "Vector3"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector3, systemNumericsVectors); + keys[k++] = "Vector4"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector4, systemNumericsVectors); + + Debug.Assert(k == keys.Length && v == keys.Length && k == v); + AssertSorted(keys); + + s_projectedTypeNames = keys; + s_projectionInfos = values; + } + } + + [Conditional("DEBUG")] + private static void AssertSorted(string[] keys) + { + for (int i = 0; i < keys.Length - 1; i++) + { + Debug.Assert(String.CompareOrdinal(keys[i], keys[i + 1]) < 0); + } + } + + // test only + internal static string[] GetProjectedTypeNames() + { + InitializeProjectedTypes(); + return s_projectedTypeNames; + } + + #endregion + + private static uint TreatmentAndRowId(byte treatment, uint rowId) + { + return ((uint)treatment << TokenTypeIds.RowIdBitCount) | rowId; + } + + #region TypeDef + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + internal uint CalculateTypeDefTreatmentAndRowId(TypeDefinitionHandle handle) + { + Debug.Assert(_metadataKind != MetadataKind.Ecma335); + + TypeDefTreatment treatment; + + TypeAttributes flags = TypeDefTable.GetFlags(handle); + Handle extends = TypeDefTable.GetExtends(handle); + + if ((flags & TypeAttributes.WindowsRuntime) != 0) + { + if (_metadataKind == MetadataKind.WindowsMetadata) + { + treatment = GetWellKnownTypeDefinitionTreatment(handle); + if (treatment != TypeDefTreatment.None) + { + return TreatmentAndRowId((byte)treatment, handle.RowId); + } + + // Is this an attribute? + if (extends.Kind == HandleKind.TypeReference && IsSystemAttribute((TypeReferenceHandle)extends)) + { + treatment = TypeDefTreatment.NormalAttribute; + } + else + { + treatment = TypeDefTreatment.NormalNonAttribute; + } + } + else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && NeedsWinRTPrefix(flags, extends)) + { + // WinMDExp emits two versions of RuntimeClasses and Enums: + // + // public class Foo {} // the WinRT reference class + // internal class Foo {} // the implementation class that we want WinRT consumers to ignore + // + // The adapter's job is to undo WinMDExp's transformations. I.e. turn the above into: + // + // internal class Foo {} // the WinRT reference class that we want CLR consumers to ignore + // public class Foo {} // the implementation class + // + // We only add the prefix here since the WinRT view is the only view that is marked WindowsRuntime + // De-mangling the CLR name is done below. + + + // tomat: The CLR adapter implements a back-compat quirk: Enums exported with an older WinMDExp have only one version + // not marked with tdSpecialName. These enums should *not* be mangled and flipped to private. + // We don't implement this flag since the WinMDs producted by the older WinMDExp are not used in the wild. + + treatment = TypeDefTreatment.PrefixWinRTName; + } + else + { + treatment = TypeDefTreatment.None; + } + + // Scan through Custom Attributes on type, looking for interesting bits. We only + // need to do this for RuntimeClasses + if ((treatment == TypeDefTreatment.PrefixWinRTName || treatment == TypeDefTreatment.NormalNonAttribute)) + { + if ((flags & TypeAttributes.Interface) == 0 + && HasAttribute(handle, "Windows.UI.Xaml", "TreatAsAbstractComposableClassAttribute")) + { + treatment |= TypeDefTreatment.MarkAbstractFlag; + } + } + } + else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && IsClrImplementationType(handle)) + { + // implementation classes are not marked WindowsRuntime, but still need to be modified + // by the adapter. + treatment = TypeDefTreatment.UnmangleWinRTName; + } + else + { + treatment = TypeDefTreatment.None; + } + + return TreatmentAndRowId((byte)treatment, handle.RowId); + } + + private bool IsClrImplementationType(TypeDefinitionHandle typeDef) + { + var attrs = TypeDefTable.GetFlags(typeDef); + + if ((attrs & (TypeAttributes.VisibilityMask | TypeAttributes.SpecialName)) != TypeAttributes.SpecialName) + { + return false; + } + + return StringStream.StartsWithRaw(TypeDefTable.GetName(typeDef), ClrPrefix); + } + + #endregion + + #region TypeRef + + internal uint CalculateTypeRefTreatmentAndRowId(TypeReferenceHandle handle) + { + Debug.Assert(_metadataKind != MetadataKind.Ecma335); + + bool isIDisposable; + int projectionIndex = GetProjectionIndexForTypeReference(handle, out isIDisposable); + if (projectionIndex >= 0) + { + return TreatmentAndRowId((byte)TypeRefTreatment.UseProjectionInfo, (uint)projectionIndex); + } + else + { + return TreatmentAndRowId((byte)GetSpecialTypeRefTreatment(handle), handle.RowId); + } + } + + private TypeRefTreatment GetSpecialTypeRefTreatment(TypeReferenceHandle handle) + { + if (StringStream.EqualsRaw(TypeRefTable.GetNamespace(handle), "System")) + { + StringHandle name = TypeRefTable.GetName(handle); + + if (StringStream.EqualsRaw(name, "MulticastDelegate")) + { + return TypeRefTreatment.SystemDelegate; + } + + if (StringStream.EqualsRaw(name, "Attribute")) + { + return TypeRefTreatment.SystemAttribute; + } + } + + return TypeRefTreatment.None; + } + + private bool IsSystemAttribute(TypeReferenceHandle handle) + { + return StringStream.EqualsRaw(TypeRefTable.GetNamespace(handle), "System") && + StringStream.EqualsRaw(TypeRefTable.GetName(handle), "Attribute"); + } + + private bool IsSystemEnum(TypeReferenceHandle handle) + { + return StringStream.EqualsRaw(TypeRefTable.GetNamespace(handle), "System") && + StringStream.EqualsRaw(TypeRefTable.GetName(handle), "Enum"); + } + + private bool NeedsWinRTPrefix(TypeAttributes flags, Handle extends) + { + if ((flags & (TypeAttributes.VisibilityMask | TypeAttributes.Interface)) != TypeAttributes.Public) + { + return false; + } + + if (extends.Kind != HandleKind.TypeReference) + { + return false; + } + + // Check if the type is a delegate, struct, or attribute + TypeReferenceHandle extendsRefHandle = (TypeReferenceHandle)extends; + if (StringStream.EqualsRaw(TypeRefTable.GetNamespace(extendsRefHandle), "System")) + { + StringHandle nameHandle = TypeRefTable.GetName(extendsRefHandle); + if (StringStream.EqualsRaw(nameHandle, "MulticastDelegate") + || StringStream.EqualsRaw(nameHandle, "ValueType") + || StringStream.EqualsRaw(nameHandle, "Attribute")) + { + return false; + } + } + return true; + } + + #endregion + + #region MethodDef + + private uint CalculateMethodDefTreatmentAndRowId(MethodDefinitionHandle methodDef) + { + MethodDefTreatment treatment = MethodDefTreatment.Implementation; + + TypeDefinitionHandle parentTypeDef = GetDeclaringType(methodDef); + TypeAttributes parentFlags = TypeDefTable.GetFlags(parentTypeDef); + + if ((parentFlags & TypeAttributes.WindowsRuntime) != 0) + { + if (IsClrImplementationType(parentTypeDef)) + { + treatment = MethodDefTreatment.Implementation; + } + else if (parentFlags.IsNested()) + { + treatment = MethodDefTreatment.Implementation; + } + else if ((parentFlags & TypeAttributes.Interface) != 0) + { + treatment = MethodDefTreatment.InterfaceMethod; + } + else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && (parentFlags & TypeAttributes.Public) == 0) + { + treatment = MethodDefTreatment.Implementation; + } + else + { + treatment = MethodDefTreatment.Other; + + var parentBaseType = TypeDefTable.GetExtends(parentTypeDef); + if (parentBaseType.Kind == HandleKind.TypeReference) + { + switch (GetSpecialTypeRefTreatment((TypeReferenceHandle)parentBaseType)) + { + case TypeRefTreatment.SystemAttribute: + treatment = MethodDefTreatment.AttributeMethod; + break; + + case TypeRefTreatment.SystemDelegate: + treatment = MethodDefTreatment.DelegateMethod | MethodDefTreatment.MarkPublicFlag; + break; + } + } + } + } + + if (treatment == MethodDefTreatment.Other) + { + // we want to hide the method if it implements + // only redirected interfaces + // We also want to check if the methodImpl is IClosable.Close, + // so we can change the name + bool seenRedirectedInterfaces = false; + bool seenNonRedirectedInterfaces = false; + + bool isIClosableClose = false; + + foreach (var methodImplHandle in new MethodImplementationHandleCollection(this, parentTypeDef)) + { + MethodImplementation methodImpl = GetMethodImplementation(methodImplHandle); + if (methodImpl.MethodBody == methodDef) + { + Handle declaration = methodImpl.MethodDeclaration; + + // See if this MethodImpl implements a redirected interface + // In WinMD, MethodImpl will always use MemberRef and TypeRefs to refer to redirected interfaces, + // even if they are in the same module. + if (declaration.Kind == HandleKind.MemberReference && + ImplementsRedirectedInterface((MemberReferenceHandle)declaration, out isIClosableClose)) + { + seenRedirectedInterfaces = true; + if (isIClosableClose) + { + // This method implements IClosable.Close + // Let's rename to IDisposable later + // Once we know this implements IClosable.Close, we are done + // looking + break; + } + } + else + { + // Now we know this implements a non-redirected interface + // But we need to keep looking, just in case we got a methodimpl that + // implements the IClosable.Close method and needs to be renamed + seenNonRedirectedInterfaces = true; + } + } + } + + if (isIClosableClose) + { + treatment = MethodDefTreatment.DisposeMethod; + } + else if (seenRedirectedInterfaces && !seenNonRedirectedInterfaces) + { + // Only hide if all the interfaces implemented are redirected + treatment = MethodDefTreatment.HiddenInterfaceImplementation; + } + } + + // If treatment is other, then this is a non-managed WinRT runtime class definition + // Find out about various bits that we apply via attributes and name parsing + if (treatment == MethodDefTreatment.Other) + { + treatment |= GetMethodTreatmentFromCustomAttributes(methodDef); + } + + return TreatmentAndRowId((byte)treatment, methodDef.RowId); + } + + private MethodDefTreatment GetMethodTreatmentFromCustomAttributes(MethodDefinitionHandle methodDef) + { + MethodDefTreatment treatment = 0; + + foreach (var caHandle in GetCustomAttributes(methodDef)) + { + StringHandle namespaceHandle, nameHandle; + if (!GetAttributeTypeNameRaw(caHandle, out namespaceHandle, out nameHandle)) + { + continue; + } + + Debug.Assert(!namespaceHandle.IsVirtual && !nameHandle.IsVirtual); + + if (StringStream.EqualsRaw(namespaceHandle, "Windows.UI.Xaml")) + { + if (StringStream.EqualsRaw(nameHandle, "TreatAsPublicMethodAttribute")) + { + treatment |= MethodDefTreatment.MarkPublicFlag; + } + + if (StringStream.EqualsRaw(nameHandle, "TreatAsAbstractMethodAttribute")) + { + treatment |= MethodDefTreatment.MarkAbstractFlag; + } + } + } + + return treatment; + } + + #endregion + + #region FieldDef + + /// + /// The backing field of a WinRT enumeration type is not public although the backing fields + /// of managed enumerations are. To allow managed languages to directly access this field, + /// it is made public by the metadata adapter. + /// + private uint CalculateFieldDefTreatmentAndRowId(FieldDefinitionHandle handle) + { + var flags = FieldTable.GetFlags(handle); + FieldDefTreatment treatment = FieldDefTreatment.None; + + if ((flags & FieldAttributes.RTSpecialName) != 0 && StringStream.EqualsRaw(FieldTable.GetName(handle), "value__")) + { + TypeDefinitionHandle typeDef = GetDeclaringType(handle); + + Handle baseTypeHandle = TypeDefTable.GetExtends(typeDef); + if (baseTypeHandle.Kind == HandleKind.TypeReference) + { + var typeRef = (TypeReferenceHandle)baseTypeHandle; + + if (StringStream.EqualsRaw(TypeRefTable.GetName(typeRef), "Enum") && + StringStream.EqualsRaw(TypeRefTable.GetNamespace(typeRef), "System")) + { + treatment = FieldDefTreatment.EnumValue; + } + } + } + + return TreatmentAndRowId((byte)treatment, handle.RowId); + } + + #endregion + + #region MemberRef + + private uint CalculateMemberRefTreatmentAndRowId(MemberReferenceHandle handle) + { + MemberRefTreatment treatment; + + // We need to rename the MemberRef for IClosable.Close as well + // so that the MethodImpl for the Dispose method can be correctly shown + // as IDisposable.Dispose instead of IDisposable.Close + bool isIDisposable; + if (ImplementsRedirectedInterface(handle, out isIDisposable) && isIDisposable) + { + treatment = MemberRefTreatment.Dispose; + } + else + { + treatment = MemberRefTreatment.None; + } + + return TreatmentAndRowId((byte)treatment, handle.RowId); + } + + /// + /// We want to know if a given method implements a redirected interface. + /// For example, if we are given the method RemoveAt on a class "A" + /// which implements the IVector interface (which is redirected + /// to IList in .NET) then this method would return true. The most + /// likely reason why we would want to know this is that we wish to hide + /// (mark private) all methods which implement methods on a redirected + /// interface. + /// + /// The declaration token for the method + /// + /// Returns true if the redirected interface is . + /// + /// True if the method implements a method on a redirected interface. + /// False otherwise. + private bool ImplementsRedirectedInterface(MemberReferenceHandle memberRef, out bool isIDisposable) + { + isIDisposable = false; + + Handle parent = MemberRefTable.GetClass(memberRef); + + TypeReferenceHandle typeRef; + if (parent.Kind == HandleKind.TypeReference) + { + typeRef = (TypeReferenceHandle)parent; + } + else if (parent.Kind == HandleKind.TypeSpecification) + { + BlobHandle blob = TypeSpecTable.GetSignature((TypeSpecificationHandle)parent); + BlobReader sig = BlobStream.GetBlobReader(blob); + + if (sig.Length < 2 || + sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_GENERICINST || + sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_CLASS) + { + return false; + } + + Handle token = sig.ReadTypeHandle(); + if (token.Kind != HandleKind.TypeReference) + { + return false; + } + + typeRef = (TypeReferenceHandle)token; + } + else + { + return false; + } + + return GetProjectionIndexForTypeReference(typeRef, out isIDisposable) >= 0; + } + + #endregion + + #region AssemblyRef + + private uint FindMscorlibAssemblyRefNoProjection() + { + for (uint i = 1; i <= AssemblyRefTable.NumberOfNonVirtualRows; i++) + { + if (StringStream.EqualsRaw(AssemblyRefTable.GetName(i), "mscorlib")) + { + return i; + } + } + + throw new BadImageFormatException(MetadataResources.WinMDMissingMscorlibRef); + } + + #endregion + + #region CustomAttribute + + internal CustomAttributeValueTreatment CalculateCustomAttributeValueTreatment(CustomAttributeHandle handle) + { + Debug.Assert(_metadataKind != MetadataKind.Ecma335); + + var parent = CustomAttributeTable.GetParent(handle); + + // Check for Windows.Foundation.Metadata.AttributeUsageAttribute. + // WinMD rules: + // - The attribute is only applicable on TypeDefs. + // - Constructor must be a MemberRef with TypeRef. + if (!IsWindowsAttributeUsageAttribute(parent, handle)) + { + return CustomAttributeValueTreatment.None; + } + + var targetTypeDef = (TypeDefinitionHandle)parent; + if (StringStream.EqualsRaw(TypeDefTable.GetNamespaceString(targetTypeDef), "Windows.Foundation.Metadata")) + { + if (StringStream.EqualsRaw(TypeDefTable.GetName(targetTypeDef), "VersionAttribute")) + { + return CustomAttributeValueTreatment.AttributeUsageVersionAttribute; + } + + if (StringStream.EqualsRaw(TypeDefTable.GetName(targetTypeDef), "DeprecatedAttribute")) + { + return CustomAttributeValueTreatment.AttributeUsageDeprecatedAttribute; + } + } + + bool allowMultiple = HasAttribute(targetTypeDef, "Windows.Foundation.Metadata", "AllowMultipleAttribute"); + return allowMultiple ? CustomAttributeValueTreatment.AttributeUsageAllowMultiple : CustomAttributeValueTreatment.AttributeUsageAllowSingle; + } + + private bool IsWindowsAttributeUsageAttribute(Handle targetType, CustomAttributeHandle attributeHandle) + { + // Check for Windows.Foundation.Metadata.AttributeUsageAttribute. + // WinMD rules: + // - The attribute is only applicable on TypeDefs. + // - Constructor must be a MemberRef with TypeRef. + + if (targetType.Kind != HandleKind.TypeDefinition) + { + return false; + } + + var attributeCtor = CustomAttributeTable.GetConstructor(attributeHandle); + if (attributeCtor.Kind != HandleKind.MemberReference) + { + return false; + } + + var attributeType = MemberRefTable.GetClass((MemberReferenceHandle)attributeCtor); + if (attributeType.Kind != HandleKind.TypeReference) + { + return false; + } + + var attributeTypeRef = (TypeReferenceHandle)attributeType; + return StringStream.EqualsRaw(TypeRefTable.GetName(attributeTypeRef), "AttributeUsageAttribute") && + StringStream.EqualsRaw(TypeRefTable.GetNamespace(attributeTypeRef), "Windows.Foundation.Metadata"); + } + + private bool HasAttribute(Handle token, string asciiNamespaceName, string asciiTypeName) + { + foreach (var caHandle in GetCustomAttributes(token)) + { + StringHandle namespaceName, typeName; + if (GetAttributeTypeNameRaw(caHandle, out namespaceName, out typeName) && + StringStream.EqualsRaw(typeName, asciiTypeName) && + StringStream.EqualsRaw(namespaceName, asciiNamespaceName)) + { + return true; + } + } + + return false; + } + + private bool GetAttributeTypeNameRaw(CustomAttributeHandle caHandle, out StringHandle namespaceName, out StringHandle typeName) + { + namespaceName = typeName = default(StringHandle); + + Handle typeDefOrRef = GetAttributeTypeRaw(caHandle); + if (typeDefOrRef.IsNil) + { + return false; + } + + if (typeDefOrRef.Kind == HandleKind.TypeReference) + { + TypeReferenceHandle typeRef = (TypeReferenceHandle)typeDefOrRef; + var resolutionScope = TypeRefTable.GetResolutionScope(typeRef); + + if (!resolutionScope.IsNil && resolutionScope.Kind == HandleKind.TypeReference) + { + // we don't need to handle nested types + return false; + } + + // other resolution scopes don't affect full name + + typeName = TypeRefTable.GetName(typeRef); + namespaceName = TypeRefTable.GetNamespace(typeRef); + } + else if (typeDefOrRef.Kind == HandleKind.TypeDefinition) + { + TypeDefinitionHandle typeDef = (TypeDefinitionHandle)typeDefOrRef; + + if (TypeDefTable.GetFlags(typeDef).IsNested()) + { + // we don't need to handle nested types + return false; + } + + typeName = TypeDefTable.GetName(typeDef); + namespaceName = TypeDefTable.GetNamespaceString(typeDef); + } + else + { + // invalid metadata + return false; + } + + return true; + } + + /// + /// Returns the type definition or reference handle of the attribute type. + /// + /// or or nil token if the metadata is invalid and the type can't be determined. + private Handle GetAttributeTypeRaw(CustomAttributeHandle handle) + { + var ctor = CustomAttributeTable.GetConstructor(handle); + + if (ctor.Kind == HandleKind.MethodDefinition) + { + return GetDeclaringType((MethodDefinitionHandle)ctor); + } + + if (ctor.Kind == HandleKind.MemberReference) + { + // In general the parent can be MethodDef, ModuleRef, TypeDef, TypeRef, or TypeSpec. + // For attributes only TypeDef and TypeRef are applicable. + Handle typeDefOrRef = MemberRefTable.GetClass((MemberReferenceHandle)ctor); + HandleKind handleType = typeDefOrRef.Kind; + + if (handleType == HandleKind.TypeReference || handleType == HandleKind.TypeDefinition) + { + return typeDefOrRef; + } + } + + return default(Handle); + } + #endregion + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.cs new file mode 100644 index 0000000..658a881 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReader.cs @@ -0,0 +1,1278 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Internal; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Reflection.Metadata +{ + /// + /// Reads metadata as defined byte the ECMA 335 CLI specification. + /// + public sealed partial class MetadataReader + { + private readonly MetadataReaderOptions _options; + internal readonly MetadataStringDecoder utf8Decoder; + internal readonly NamespaceCache namespaceCache; + private Dictionary> _lazyNestedTypesMap; + internal readonly MemoryBlock Block; + + // A row id of "mscorlib" AssemblyRef in a WinMD file (each WinMD file must have such a reference). + internal readonly uint WinMDMscorlibRef; + + #region Constructors + + /// + /// Creates a metadata reader from the metadata stored at the given memory location. + /// + /// + /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the . + /// + public unsafe MetadataReader(byte* metadata, int length) + : this(metadata, length, MetadataReaderOptions.Default, null) + { + } + + /// + /// Creates a metadata reader from the metadata stored at the given memory location. + /// + /// + /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the . + /// Use to obtain + /// metadata from a PE image. + /// + public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options) + : this(metadata, length, options, null) + { + } + + /// + /// Creates a metadata reader from the metadata stored at the given memory location. + /// + /// + /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the . + /// Use to obtain + /// metadata from a PE image. + /// + public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) + { + if (length <= 0) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (metadata == null) + { + throw new ArgumentNullException("metadata"); + } + + if (utf8Decoder == null) + { + utf8Decoder = MetadataStringDecoder.DefaultUTF8; + } + + if (!(utf8Decoder.Encoding is UTF8Encoding)) + { + throw new ArgumentException(MetadataResources.MetadataStringDecoderEncodingMustBeUtf8, "utf8Decoder"); + } + + if (!BitConverter.IsLittleEndian) + { + throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); + } + + this.Block = new MemoryBlock(metadata, length); + + _options = options; + this.utf8Decoder = utf8Decoder; + + BlobReader memReader = new BlobReader(this.Block); + + this.ReadMetadataHeader(ref memReader); + + // storage header and stream headers: + MemoryBlock metadataTableStream; + var streamHeaders = this.ReadStreamHeaders(ref memReader); + this.InitializeStreamReaders(ref this.Block, streamHeaders, out metadataTableStream); + + memReader = new BlobReader(metadataTableStream); + + uint[] metadataTableRowCounts; + this.ReadMetadataTableHeader(ref memReader, out metadataTableRowCounts); + this.InitializeTableReaders(memReader.GetMemoryBlockAt(0, memReader.RemainingBytes), metadataTableRowCounts); + + // This previously could occur in obfuscated assemblies but a check was added to prevent + // it getting to this point + Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); + + // Although the specification states that the module table will have exactly one row, + // the native metadata reader would successfully read files containing more than one row. + // Such files exist in the wild and may be produced by obfuscators. + if (this.ModuleTable.NumberOfRows < 1) + { + throw new BadImageFormatException(string.Format(MetadataResources.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); + } + + // read + this.namespaceCache = new NamespaceCache(this); + + if (_metadataKind != MetadataKind.Ecma335) + { + this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); + } + } + + #endregion + + #region Metadata Headers + + private MetadataHeader _metadataHeader; + private MetadataKind _metadataKind; + private MetadataStreamKind _metadataStreamKind; + + internal StringStreamReader StringStream; + internal BlobStreamReader BlobStream; + internal GuidStreamReader GuidStream; + internal UserStringStreamReader UserStringStream; + + /// + /// True if the metadata stream has minimal delta format. Used for EnC. + /// + /// + /// The metadata stream has minimal delta format if "#JTD" stream is present. + /// Minimal delta format uses large size (4B) when encoding table/heap references. + /// The heaps in minimal delta only contain data of the delta, + /// there is no padding at the beginning of the heaps that would align them + /// with the original full metadata heaps. + /// + internal bool IsMinimalDelta; + + /// + /// Looks like this function reads beginning of the header described in + /// Ecma-335 24.2.1 Metadata root + /// + private void ReadMetadataHeader(ref BlobReader memReader) + { + if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) + { + throw new BadImageFormatException(MetadataResources.MetadataHeaderTooSmall); + } + + _metadataHeader.Signature = memReader.ReadUInt32(); + if (_metadataHeader.Signature != COR20Constants.COR20MetadataSignature) + { + throw new BadImageFormatException(MetadataResources.MetadataSignature); + } + + _metadataHeader.MajorVersion = memReader.ReadUInt16(); + _metadataHeader.MinorVersion = memReader.ReadUInt16(); + _metadataHeader.ExtraData = memReader.ReadUInt32(); + _metadataHeader.VersionStringSize = memReader.ReadInt32(); + if (memReader.RemainingBytes < _metadataHeader.VersionStringSize) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForVersionString); + } + + int numberOfBytesRead; + _metadataHeader.VersionString = memReader.GetMemoryBlockAt(0, _metadataHeader.VersionStringSize).PeekUtf8NullTerminated(0, null, utf8Decoder, out numberOfBytesRead, '\0'); + memReader.SkipBytes(_metadataHeader.VersionStringSize); + _metadataKind = GetMetadataKind(_metadataHeader.VersionString); + } + + private MetadataKind GetMetadataKind(string versionString) + { + // Treat metadata as CLI raw metadata if the client doesn't want to see projections. + if ((_options & MetadataReaderOptions.ApplyWindowsRuntimeProjections) == 0) + { + return MetadataKind.Ecma335; + } + + if (!versionString.Contains("WindowsRuntime")) + { + return MetadataKind.Ecma335; + } + else if (versionString.Contains("CLR")) + { + return MetadataKind.ManagedWindowsMetadata; + } + else + { + return MetadataKind.WindowsMetadata; + } + } + + /// + /// Reads stream headers described in Ecma-335 24.2.2 Stream header + /// + private StreamHeader[] ReadStreamHeaders(ref BlobReader memReader) + { + // storage header: + memReader.ReadUInt16(); + int streamCount = memReader.ReadInt16(); + + var streamHeaders = new StreamHeader[streamCount]; + for (int i = 0; i < streamHeaders.Length; i++) + { + if (memReader.RemainingBytes < COR20Constants.MinimumSizeofStreamHeader) + { + throw new BadImageFormatException(MetadataResources.StreamHeaderTooSmall); + } + + streamHeaders[i].Offset = memReader.ReadUInt32(); + streamHeaders[i].Size = memReader.ReadInt32(); + streamHeaders[i].Name = memReader.ReadUtf8NullTerminated(); + bool aligned = memReader.TryAlign(4); + + if (!aligned || memReader.RemainingBytes == 0) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForStreamHeaderName); + } + } + + return streamHeaders; + } + + private void InitializeStreamReaders(ref MemoryBlock metadataRoot, StreamHeader[] streamHeaders, out MemoryBlock metadataTableStream) + { + metadataTableStream = default(MemoryBlock); + + foreach (StreamHeader streamHeader in streamHeaders) + { + switch (streamHeader.Name) + { + case COR20Constants.StringStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForStringStream); + } + + this.StringStream = new StringStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size), _metadataKind); + break; + + case COR20Constants.BlobStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForBlobStream); + } + + this.BlobStream = new BlobStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size), _metadataKind); + break; + + case COR20Constants.GUIDStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForGUIDStream); + } + + this.GuidStream = new GuidStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size)); + break; + + case COR20Constants.UserStringStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForBlobStream); + } + + this.UserStringStream = new UserStringStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size)); + break; + + case COR20Constants.CompressedMetadataTableStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); + } + + _metadataStreamKind = MetadataStreamKind.Compressed; + metadataTableStream = metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size); + break; + + case COR20Constants.UncompressedMetadataTableStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); + } + + _metadataStreamKind = MetadataStreamKind.Uncompressed; + metadataTableStream = metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size); + break; + + case COR20Constants.MinimalDeltaMetadataTableStreamName: + if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) + { + throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); + } + + // the content of the stream is ignored + this.IsMinimalDelta = true; + break; + + default: + // Skip unknown streams. Some obfuscators insert invalid streams. + continue; + } + } + + if (IsMinimalDelta && _metadataStreamKind != MetadataStreamKind.Uncompressed) + { + throw new BadImageFormatException(MetadataResources.InvalidMetadataStreamFormat); + } + } + + #endregion + + #region Tables and Heaps + + private MetadataTableHeader _MetadataTableHeader; + + /// + /// A row count for each possible table. May be indexed by . + /// + internal uint[] TableRowCounts; + + internal ModuleTableReader ModuleTable; + internal TypeRefTableReader TypeRefTable; + internal TypeDefTableReader TypeDefTable; + internal FieldPtrTableReader FieldPtrTable; + internal FieldTableReader FieldTable; + internal MethodPtrTableReader MethodPtrTable; + internal MethodTableReader MethodDefTable; + internal ParamPtrTableReader ParamPtrTable; + internal ParamTableReader ParamTable; + internal InterfaceImplTableReader InterfaceImplTable; + internal MemberRefTableReader MemberRefTable; + internal ConstantTableReader ConstantTable; + internal CustomAttributeTableReader CustomAttributeTable; + internal FieldMarshalTableReader FieldMarshalTable; + internal DeclSecurityTableReader DeclSecurityTable; + internal ClassLayoutTableReader ClassLayoutTable; + internal FieldLayoutTableReader FieldLayoutTable; + internal StandAloneSigTableReader StandAloneSigTable; + internal EventMapTableReader EventMapTable; + internal EventPtrTableReader EventPtrTable; + internal EventTableReader EventTable; + internal PropertyMapTableReader PropertyMapTable; + internal PropertyPtrTableReader PropertyPtrTable; + internal PropertyTableReader PropertyTable; + internal MethodSemanticsTableReader MethodSemanticsTable; + internal MethodImplTableReader MethodImplTable; + internal ModuleRefTableReader ModuleRefTable; + internal TypeSpecTableReader TypeSpecTable; + internal ImplMapTableReader ImplMapTable; + internal FieldRVATableReader FieldRvaTable; + internal EnCLogTableReader EncLogTable; + internal EnCMapTableReader EncMapTable; + internal AssemblyTableReader AssemblyTable; + internal AssemblyProcessorTableReader AssemblyProcessorTable; // unused + internal AssemblyOSTableReader AssemblyOSTable; // unused + internal AssemblyRefTableReader AssemblyRefTable; + internal AssemblyRefProcessorTableReader AssemblyRefProcessorTable; // unused + internal AssemblyRefOSTableReader AssemblyRefOSTable; // unused + internal FileTableReader FileTable; + internal ExportedTypeTableReader ExportedTypeTable; + internal ManifestResourceTableReader ManifestResourceTable; + internal NestedClassTableReader NestedClassTable; + internal GenericParamTableReader GenericParamTable; + internal MethodSpecTableReader MethodSpecTable; + internal GenericParamConstraintTableReader GenericParamConstraintTable; + + private void ReadMetadataTableHeader(ref BlobReader memReader, out uint[] metadataTableRowCounts) + { + if (memReader.RemainingBytes < MetadataStreamConstants.SizeOfMetadataTableHeader) + { + throw new BadImageFormatException(MetadataResources.MetadataTableHeaderTooSmall); + } + + _MetadataTableHeader.Reserved = memReader.ReadUInt32(); + _MetadataTableHeader.MajorVersion = memReader.ReadByte(); + _MetadataTableHeader.MinorVersion = memReader.ReadByte(); + _MetadataTableHeader.HeapSizeFlags = (HeapSizeFlag)memReader.ReadByte(); + _MetadataTableHeader.RowId = memReader.ReadByte(); + _MetadataTableHeader.ValidTables = (TableMask)memReader.ReadUInt64(); + _MetadataTableHeader.SortedTables = (TableMask)memReader.ReadUInt64(); + ulong presentTables = (ulong)_MetadataTableHeader.ValidTables; + + // According to ECMA-335, MajorVersion and MinorVersion have fixed values and, + // based on recommendation in 24.1 Fixed fields: When writing these fields it + // is best that they be set to the value indicated, on reading they should be ignored.? + // we will not be checking version values. We will continue checking that the set of + // present tables is within the set we understand. + ulong validTables = (ulong)TableMask.V2_0_TablesMask; + + if ((presentTables & ~validTables) != 0) + { + throw new BadImageFormatException(string.Format(MetadataResources.UnknownTables, presentTables)); + } + + if (_metadataStreamKind == MetadataStreamKind.Compressed) + { + // In general Ptr tables and EnC tables are not allowed in a compressed stream. + // However when asked for a snapshot of the current metadata after an EnC change has been applied + // the CLR includes the EnCLog table into the snapshot. We need to be able to read the image, + // so we'll allow the table here but pretend it's empty later. + if ((presentTables & (ulong)(TableMask.PtrTables | TableMask.EnCMap)) != 0) + { + throw new BadImageFormatException(MetadataResources.IllegalTablesInCompressedMetadataStream); + } + } + + int numberOfTables = _MetadataTableHeader.GetNumberOfTablesPresent(); + if (memReader.RemainingBytes < numberOfTables * sizeof(int)) + { + throw new BadImageFormatException(MetadataResources.TableRowCountSpaceTooSmall); + } + + var rowCounts = new uint[numberOfTables]; + for (int i = 0; i < rowCounts.Length; i++) + { + rowCounts[i] = memReader.ReadUInt32(); + } + + metadataTableRowCounts = rowCounts; + } + + private const int SmallIndexSize = 2; + private const int LargeIndexSize = 4; + + private void InitializeTableReaders(MemoryBlock metadataTablesMemoryBlock, uint[] compressedRowCounts) + { + // Only sizes of tables present in metadata are recorded in rowCountCompressedArray. + // This array contains a slot for each possible table, not just those that are present in the metadata. + uint[] rowCounts = new uint[TableIndexExtensions.Count]; + + // Size of reference tags in each table. + int[] referenceSizes = new int[TableIndexExtensions.Count]; + + ulong validTables = (ulong)_MetadataTableHeader.ValidTables; + int compressedRowCountIndex = 0; + for (int i = 0; i < TableIndexExtensions.Count; i++) + { + bool fitsSmall; + + if ((validTables & 1UL) != 0) + { + uint rowCount = compressedRowCounts[compressedRowCountIndex++]; + rowCounts[i] = rowCount; + fitsSmall = rowCount < MetadataStreamConstants.LargeTableRowCount; + } + else + { + fitsSmall = true; + } + + referenceSizes[i] = (fitsSmall && !IsMinimalDelta) ? SmallIndexSize : LargeIndexSize; + validTables >>= 1; + } + + this.TableRowCounts = rowCounts; + + // Compute ref sizes for tables that can have pointer tables for it + int fieldRefSize = referenceSizes[(int)TableIndex.FieldPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Field]; + int methodRefSize = referenceSizes[(int)TableIndex.MethodPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.MethodDef]; + int paramRefSize = referenceSizes[(int)TableIndex.ParamPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Param]; + int eventRefSize = referenceSizes[(int)TableIndex.EventPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Event]; + int propertyRefSize = referenceSizes[(int)TableIndex.PropertyPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Property]; + + // Compute the coded token ref sizes + int typeDefOrRefRefSize = ComputeCodedTokenSize(TypeDefOrRefTag.LargeRowSize, rowCounts, TypeDefOrRefTag.TablesReferenced); + int hasConstantRefSize = ComputeCodedTokenSize(HasConstantTag.LargeRowSize, rowCounts, HasConstantTag.TablesReferenced); + int hasCustomAttributeRefSize = ComputeCodedTokenSize(HasCustomAttributeTag.LargeRowSize, rowCounts, HasCustomAttributeTag.TablesReferenced); + int hasFieldMarshalRefSize = ComputeCodedTokenSize(HasFieldMarshalTag.LargeRowSize, rowCounts, HasFieldMarshalTag.TablesReferenced); + int hasDeclSecurityRefSize = ComputeCodedTokenSize(HasDeclSecurityTag.LargeRowSize, rowCounts, HasDeclSecurityTag.TablesReferenced); + int memberRefParentRefSize = ComputeCodedTokenSize(MemberRefParentTag.LargeRowSize, rowCounts, MemberRefParentTag.TablesReferenced); + int hasSemanticsRefSize = ComputeCodedTokenSize(HasSemanticsTag.LargeRowSize, rowCounts, HasSemanticsTag.TablesReferenced); + int methodDefOrRefRefSize = ComputeCodedTokenSize(MethodDefOrRefTag.LargeRowSize, rowCounts, MethodDefOrRefTag.TablesReferenced); + int memberForwardedRefSize = ComputeCodedTokenSize(MemberForwardedTag.LargeRowSize, rowCounts, MemberForwardedTag.TablesReferenced); + int implementationRefSize = ComputeCodedTokenSize(ImplementationTag.LargeRowSize, rowCounts, ImplementationTag.TablesReferenced); + int customAttributeTypeRefSize = ComputeCodedTokenSize(CustomAttributeTypeTag.LargeRowSize, rowCounts, CustomAttributeTypeTag.TablesReferenced); + int resolutionScopeRefSize = ComputeCodedTokenSize(ResolutionScopeTag.LargeRowSize, rowCounts, ResolutionScopeTag.TablesReferenced); + int typeOrMethodDefRefSize = ComputeCodedTokenSize(TypeOrMethodDefTag.LargeRowSize, rowCounts, TypeOrMethodDefTag.TablesReferenced); + + // Compute HeapRef Sizes + int stringHeapRefSize = (_MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.StringHeapLarge) == HeapSizeFlag.StringHeapLarge ? LargeIndexSize : SmallIndexSize; + int guidHeapRefSize = (_MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.GuidHeapLarge) == HeapSizeFlag.GuidHeapLarge ? LargeIndexSize : SmallIndexSize; + int blobHeapRefSize = (_MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.BlobHeapLarge) == HeapSizeFlag.BlobHeapLarge ? LargeIndexSize : SmallIndexSize; + + // Populate the Table blocks + int totalRequiredSize = 0; + this.ModuleTable = new ModuleTableReader(rowCounts[(int)TableIndex.Module], stringHeapRefSize, guidHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ModuleTable.Block.Length; + + this.TypeRefTable = new TypeRefTableReader(rowCounts[(int)TableIndex.TypeRef], resolutionScopeRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.TypeRefTable.Block.Length; + + this.TypeDefTable = new TypeDefTableReader(rowCounts[(int)TableIndex.TypeDef], fieldRefSize, methodRefSize, typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.TypeDefTable.Block.Length; + + this.FieldPtrTable = new FieldPtrTableReader(rowCounts[(int)TableIndex.FieldPtr], referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FieldPtrTable.Block.Length; + + this.FieldTable = new FieldTableReader(rowCounts[(int)TableIndex.Field], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FieldTable.Block.Length; + + this.MethodPtrTable = new MethodPtrTableReader(rowCounts[(int)TableIndex.MethodPtr], referenceSizes[(int)TableIndex.MethodDef], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MethodPtrTable.Block.Length; + + this.MethodDefTable = new MethodTableReader(rowCounts[(int)TableIndex.MethodDef], paramRefSize, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MethodDefTable.Block.Length; + + this.ParamPtrTable = new ParamPtrTableReader(rowCounts[(int)TableIndex.ParamPtr], referenceSizes[(int)TableIndex.Param], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ParamPtrTable.Block.Length; + + this.ParamTable = new ParamTableReader(rowCounts[(int)TableIndex.Param], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ParamTable.Block.Length; + + this.InterfaceImplTable = new InterfaceImplTableReader(rowCounts[(int)TableIndex.InterfaceImpl], IsDeclaredSorted(TableMask.InterfaceImpl), referenceSizes[(int)TableIndex.TypeDef], typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.InterfaceImplTable.Block.Length; + + this.MemberRefTable = new MemberRefTableReader(rowCounts[(int)TableIndex.MemberRef], memberRefParentRefSize, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MemberRefTable.Block.Length; + + this.ConstantTable = new ConstantTableReader(rowCounts[(int)TableIndex.Constant], IsDeclaredSorted(TableMask.Constant), hasConstantRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ConstantTable.Block.Length; + + this.CustomAttributeTable = new CustomAttributeTableReader(rowCounts[(int)TableIndex.CustomAttribute], + IsDeclaredSorted(TableMask.CustomAttribute), + hasCustomAttributeRefSize, + customAttributeTypeRefSize, + blobHeapRefSize, + metadataTablesMemoryBlock, + totalRequiredSize); + totalRequiredSize += this.CustomAttributeTable.Block.Length; + + this.FieldMarshalTable = new FieldMarshalTableReader(rowCounts[(int)TableIndex.FieldMarshal], IsDeclaredSorted(TableMask.FieldMarshal), hasFieldMarshalRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FieldMarshalTable.Block.Length; + + this.DeclSecurityTable = new DeclSecurityTableReader(rowCounts[(int)TableIndex.DeclSecurity], IsDeclaredSorted(TableMask.DeclSecurity), hasDeclSecurityRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.DeclSecurityTable.Block.Length; + + this.ClassLayoutTable = new ClassLayoutTableReader(rowCounts[(int)TableIndex.ClassLayout], IsDeclaredSorted(TableMask.ClassLayout), referenceSizes[(int)TableIndex.TypeDef], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ClassLayoutTable.Block.Length; + + this.FieldLayoutTable = new FieldLayoutTableReader(rowCounts[(int)TableIndex.FieldLayout], IsDeclaredSorted(TableMask.FieldLayout), referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FieldLayoutTable.Block.Length; + + this.StandAloneSigTable = new StandAloneSigTableReader(rowCounts[(int)TableIndex.StandAloneSig], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.StandAloneSigTable.Block.Length; + + this.EventMapTable = new EventMapTableReader(rowCounts[(int)TableIndex.EventMap], referenceSizes[(int)TableIndex.TypeDef], eventRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.EventMapTable.Block.Length; + + this.EventPtrTable = new EventPtrTableReader(rowCounts[(int)TableIndex.EventPtr], referenceSizes[(int)TableIndex.Event], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.EventPtrTable.Block.Length; + + this.EventTable = new EventTableReader(rowCounts[(int)TableIndex.Event], typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.EventTable.Block.Length; + + this.PropertyMapTable = new PropertyMapTableReader(rowCounts[(int)TableIndex.PropertyMap], referenceSizes[(int)TableIndex.TypeDef], propertyRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.PropertyMapTable.Block.Length; + + this.PropertyPtrTable = new PropertyPtrTableReader(rowCounts[(int)TableIndex.PropertyPtr], referenceSizes[(int)TableIndex.Property], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.PropertyPtrTable.Block.Length; + + this.PropertyTable = new PropertyTableReader(rowCounts[(int)TableIndex.Property], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.PropertyTable.Block.Length; + + this.MethodSemanticsTable = new MethodSemanticsTableReader(rowCounts[(int)TableIndex.MethodSemantics], IsDeclaredSorted(TableMask.MethodSemantics), referenceSizes[(int)TableIndex.MethodDef], hasSemanticsRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MethodSemanticsTable.Block.Length; + + this.MethodImplTable = new MethodImplTableReader(rowCounts[(int)TableIndex.MethodImpl], IsDeclaredSorted(TableMask.MethodImpl), referenceSizes[(int)TableIndex.TypeDef], methodDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MethodImplTable.Block.Length; + + this.ModuleRefTable = new ModuleRefTableReader(rowCounts[(int)TableIndex.ModuleRef], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ModuleRefTable.Block.Length; + + this.TypeSpecTable = new TypeSpecTableReader(rowCounts[(int)TableIndex.TypeSpec], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.TypeSpecTable.Block.Length; + + this.ImplMapTable = new ImplMapTableReader(rowCounts[(int)TableIndex.ImplMap], IsDeclaredSorted(TableMask.ImplMap), referenceSizes[(int)TableIndex.ModuleRef], memberForwardedRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ImplMapTable.Block.Length; + + this.FieldRvaTable = new FieldRVATableReader(rowCounts[(int)TableIndex.FieldRva], IsDeclaredSorted(TableMask.FieldRva), referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FieldRvaTable.Block.Length; + + this.EncLogTable = new EnCLogTableReader(rowCounts[(int)TableIndex.EncLog], metadataTablesMemoryBlock, totalRequiredSize, _metadataStreamKind); + totalRequiredSize += this.EncLogTable.Block.Length; + + this.EncMapTable = new EnCMapTableReader(rowCounts[(int)TableIndex.EncMap], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.EncMapTable.Block.Length; + + this.AssemblyTable = new AssemblyTableReader(rowCounts[(int)TableIndex.Assembly], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.AssemblyTable.Block.Length; + + this.AssemblyProcessorTable = new AssemblyProcessorTableReader(rowCounts[(int)TableIndex.AssemblyProcessor], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.AssemblyProcessorTable.Block.Length; + + this.AssemblyOSTable = new AssemblyOSTableReader(rowCounts[(int)TableIndex.AssemblyOS], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.AssemblyOSTable.Block.Length; + + this.AssemblyRefTable = new AssemblyRefTableReader((int)rowCounts[(int)TableIndex.AssemblyRef], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize, _metadataKind); + totalRequiredSize += this.AssemblyRefTable.Block.Length; + + this.AssemblyRefProcessorTable = new AssemblyRefProcessorTableReader(rowCounts[(int)TableIndex.AssemblyRefProcessor], referenceSizes[(int)TableIndex.AssemblyRef], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.AssemblyRefProcessorTable.Block.Length; + + this.AssemblyRefOSTable = new AssemblyRefOSTableReader(rowCounts[(int)TableIndex.AssemblyRefOS], referenceSizes[(int)TableIndex.AssemblyRef], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.AssemblyRefOSTable.Block.Length; + + this.FileTable = new FileTableReader(rowCounts[(int)TableIndex.File], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.FileTable.Block.Length; + + this.ExportedTypeTable = new ExportedTypeTableReader(rowCounts[(int)TableIndex.ExportedType], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ExportedTypeTable.Block.Length; + + this.ManifestResourceTable = new ManifestResourceTableReader(rowCounts[(int)TableIndex.ManifestResource], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.ManifestResourceTable.Block.Length; + + this.NestedClassTable = new NestedClassTableReader(rowCounts[(int)TableIndex.NestedClass], IsDeclaredSorted(TableMask.NestedClass), referenceSizes[(int)TableIndex.TypeDef], metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.NestedClassTable.Block.Length; + + this.GenericParamTable = new GenericParamTableReader(rowCounts[(int)TableIndex.GenericParam], IsDeclaredSorted(TableMask.GenericParam), typeOrMethodDefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.GenericParamTable.Block.Length; + + this.MethodSpecTable = new MethodSpecTableReader(rowCounts[(int)TableIndex.MethodSpec], methodDefOrRefRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.MethodSpecTable.Block.Length; + + this.GenericParamConstraintTable = new GenericParamConstraintTableReader(rowCounts[(int)TableIndex.GenericParamConstraint], IsDeclaredSorted(TableMask.GenericParamConstraint), referenceSizes[(int)TableIndex.GenericParam], typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); + totalRequiredSize += this.GenericParamConstraintTable.Block.Length; + + if (totalRequiredSize > metadataTablesMemoryBlock.Length) + { + throw new BadImageFormatException(MetadataResources.MetadataTablesTooSmall); + } + } + + private int ComputeCodedTokenSize(uint largeRowSize, uint[] rowCountArray, TableMask tablesReferenced) + { + if (IsMinimalDelta) + { + return LargeIndexSize; + } + + bool isAllReferencedTablesSmall = true; + ulong tablesReferencedMask = (ulong)tablesReferenced; + for (int tableIndex = 0; tableIndex < TableIndexExtensions.Count; tableIndex++) + { + if ((tablesReferencedMask & 1UL) != 0) + { + isAllReferencedTablesSmall = isAllReferencedTablesSmall && (rowCountArray[tableIndex] < largeRowSize); + } + + tablesReferencedMask >>= 1; + } + + return isAllReferencedTablesSmall ? SmallIndexSize : LargeIndexSize; + } + + private bool IsDeclaredSorted(TableMask index) + { + return (_MetadataTableHeader.SortedTables & index) != 0; + } + + #endregion + + #region Helpers + + // internal for testing + internal NamespaceCache NamespaceCache + { + get { return namespaceCache; } + } + + internal bool UseFieldPtrTable + { + get { return this.FieldPtrTable.NumberOfRows > 0; } + } + + internal bool UseMethodPtrTable + { + get { return this.MethodPtrTable.NumberOfRows > 0; } + } + + internal bool UseParamPtrTable + { + get { return this.ParamPtrTable.NumberOfRows > 0; } + } + + internal bool UseEventPtrTable + { + get { return this.EventPtrTable.NumberOfRows > 0; } + } + + internal bool UsePropertyPtrTable + { + get { return this.PropertyPtrTable.NumberOfRows > 0; } + } + + internal void GetFieldRange(TypeDefinitionHandle typeDef, out int firstFieldRowId, out int lastFieldRowId) + { + uint typeDefRowId = typeDef.RowId; + + firstFieldRowId = (int)this.TypeDefTable.GetFieldStart(typeDefRowId); + if (firstFieldRowId == 0) + { + firstFieldRowId = 1; + lastFieldRowId = 0; + } + else if (typeDefRowId == this.TypeDefTable.NumberOfRows) + { + lastFieldRowId = (int)(this.UseFieldPtrTable ? this.FieldPtrTable.NumberOfRows : this.FieldTable.NumberOfRows); + } + else + { + lastFieldRowId = (int)this.TypeDefTable.GetFieldStart(typeDefRowId + 1) - 1; + } + } + + internal void GetMethodRange(TypeDefinitionHandle typeDef, out int firstMethodRowId, out int lastMethodRowId) + { + uint typeDefRowId = typeDef.RowId; + firstMethodRowId = (int)this.TypeDefTable.GetMethodStart(typeDefRowId); + if (firstMethodRowId == 0) + { + firstMethodRowId = 1; + lastMethodRowId = 0; + } + else if (typeDefRowId == this.TypeDefTable.NumberOfRows) + { + lastMethodRowId = (int)(this.UseMethodPtrTable ? this.MethodPtrTable.NumberOfRows : this.MethodDefTable.NumberOfRows); + } + else + { + lastMethodRowId = (int)this.TypeDefTable.GetMethodStart(typeDefRowId + 1) - 1; + } + } + + internal void GetEventRange(TypeDefinitionHandle typeDef, out int firstEventRowId, out int lastEventRowId) + { + uint eventMapRowId = this.EventMapTable.FindEventMapRowIdFor(typeDef); + if (eventMapRowId == 0) + { + firstEventRowId = 1; + lastEventRowId = 0; + return; + } + + firstEventRowId = (int)this.EventMapTable.GetEventListStartFor(eventMapRowId); + if (eventMapRowId == this.EventMapTable.NumberOfRows) + { + lastEventRowId = (int)(this.UseEventPtrTable ? this.EventPtrTable.NumberOfRows : this.EventTable.NumberOfRows); + } + else + { + lastEventRowId = (int)this.EventMapTable.GetEventListStartFor(eventMapRowId + 1) - 1; + } + } + + internal void GetPropertyRange(TypeDefinitionHandle typeDef, out int firstPropertyRowId, out int lastPropertyRowId) + { + uint propertyMapRowId = this.PropertyMapTable.FindPropertyMapRowIdFor(typeDef); + if (propertyMapRowId == 0) + { + firstPropertyRowId = 1; + lastPropertyRowId = 0; + return; + } + + firstPropertyRowId = (int)this.PropertyMapTable.GetPropertyListStartFor(propertyMapRowId); + if (propertyMapRowId == this.PropertyMapTable.NumberOfRows) + { + lastPropertyRowId = (int)(this.UsePropertyPtrTable ? this.PropertyPtrTable.NumberOfRows : this.PropertyTable.NumberOfRows); + } + else + { + lastPropertyRowId = (int)this.PropertyMapTable.GetPropertyListStartFor(propertyMapRowId + 1) - 1; + } + } + + internal void GetParameterRange(MethodDefinitionHandle methodDef, out int firstParamRowId, out int lastParamRowId) + { + uint rid = methodDef.RowId; + + firstParamRowId = (int)this.MethodDefTable.GetParamStart(rid); + if (firstParamRowId == 0) + { + firstParamRowId = 1; + lastParamRowId = 0; + } + else if (rid == this.MethodDefTable.NumberOfRows) + { + lastParamRowId = (int)(this.UseParamPtrTable ? this.ParamPtrTable.NumberOfRows : this.ParamTable.NumberOfRows); + } + else + { + lastParamRowId = (int)this.MethodDefTable.GetParamStart(rid + 1) - 1; + } + } + + // TODO: move throw helpers to common place. + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowValueArgumentNull() + { + throw new ArgumentNullException("value"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ThrowTableNotSorted(TableIndex tableIndex) + { + throw new BadImageFormatException(string.Format(MetadataResources.MetadataTableNotSorted, (int)tableIndex)); + } + + #endregion + + #region Public APIs + + public MetadataReaderOptions Options + { + get { return _options; } + } + + public string MetadataVersion + { + get { return _metadataHeader.VersionString; } + } + + public MetadataKind MetadataKind + { + get { return _metadataKind; } + } + + public MetadataStringComparer StringComparer + { + get { return new MetadataStringComparer(this); } + } + + public bool IsAssembly + { + get { return this.AssemblyTable.NumberOfRows == 1; } + } + + public AssemblyReferenceHandleCollection AssemblyReferences + { + get { return new AssemblyReferenceHandleCollection(this); } + } + + public TypeDefinitionHandleCollection TypeDefinitions + { + get { return new TypeDefinitionHandleCollection((int)TypeDefTable.NumberOfRows); } + } + + public TypeReferenceHandleCollection TypeReferences + { + get { return new TypeReferenceHandleCollection((int)TypeRefTable.NumberOfRows); } + } + + public CustomAttributeHandleCollection CustomAttributes + { + get { return new CustomAttributeHandleCollection(this); } + } + + public DeclarativeSecurityAttributeHandleCollection DeclarativeSecurityAttributes + { + get { return new DeclarativeSecurityAttributeHandleCollection(this); } + } + + public MemberReferenceHandleCollection MemberReferences + { + get { return new MemberReferenceHandleCollection((int)MemberRefTable.NumberOfRows); } + } + + public ManifestResourceHandleCollection ManifestResources + { + get { return new ManifestResourceHandleCollection((int)ManifestResourceTable.NumberOfRows); } + } + + public AssemblyFileHandleCollection AssemblyFiles + { + get { return new AssemblyFileHandleCollection((int)FileTable.NumberOfRows); } + } + + public ExportedTypeHandleCollection ExportedTypes + { + get { return new ExportedTypeHandleCollection((int)ExportedTypeTable.NumberOfRows); } + } + + public MethodDefinitionHandleCollection MethodDefinitions + { + get { return new MethodDefinitionHandleCollection(this); } + } + + public FieldDefinitionHandleCollection FieldDefinitions + { + get { return new FieldDefinitionHandleCollection(this); } + } + + public EventDefinitionHandleCollection EventDefinitions + { + get { return new EventDefinitionHandleCollection(this); } + } + + public PropertyDefinitionHandleCollection PropertyDefinitions + { + get { return new PropertyDefinitionHandleCollection(this); } + } + + public AssemblyDefinition GetAssemblyDefinition() + { + if (!IsAssembly) + { + throw new InvalidOperationException(MetadataResources.MetadataImageDoesNotRepresentAnAssembly); + } + + return new AssemblyDefinition(this); + } + + public string GetString(StringHandle handle) + { + return StringStream.GetString(handle, utf8Decoder); + } + + public string GetString(NamespaceDefinitionHandle handle) + { + if (handle.HasFullName) + { + return StringStream.GetString(handle.GetFullName(), utf8Decoder); + } + + return namespaceCache.GetFullName(handle); + } + + public byte[] GetBlobBytes(BlobHandle handle) + { + return BlobStream.GetBytes(handle); + } + + public ImmutableArray GetBlobContent(BlobHandle handle) + { + // TODO: We can skip a copy for virtual blobs. + byte[] bytes = GetBlobBytes(handle); + return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref bytes); + } + + public BlobReader GetBlobReader(BlobHandle handle) + { + return BlobStream.GetBlobReader(handle); + } + + public string GetUserString(UserStringHandle handle) + { + return UserStringStream.GetString(handle); + } + + public Guid GetGuid(GuidHandle handle) + { + return GuidStream.GetGuid(handle); + } + + public ModuleDefinition GetModuleDefinition() + { + return new ModuleDefinition(this); + } + + public AssemblyReference GetAssemblyReference(AssemblyReferenceHandle handle) + { + return new AssemblyReference(this, handle.Token & TokenTypeIds.VirtualBitAndRowIdMask); + } + + public TypeDefinition GetTypeDefinition(TypeDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new TypeDefinition(this, GetTypeDefTreatmentAndRowId(handle)); + } + + public NamespaceDefinition GetNamespaceDefinitionRoot() + { + NamespaceData data = namespaceCache.GetRootNamespace(); + return new NamespaceDefinition(data); + } + + public NamespaceDefinition GetNamespaceDefinition(NamespaceDefinitionHandle handle) + { + NamespaceData data = namespaceCache.GetNamespaceData(handle); + return new NamespaceDefinition(data); + } + + private uint GetTypeDefTreatmentAndRowId(TypeDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return CalculateTypeDefTreatmentAndRowId(handle); + } + + public TypeReference GetTypeReference(TypeReferenceHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new TypeReference(this, GetTypeRefTreatmentAndRowId(handle)); + } + + private uint GetTypeRefTreatmentAndRowId(TypeReferenceHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return CalculateTypeRefTreatmentAndRowId(handle); + } + + public ExportedType GetExportedType(ExportedTypeHandle handle) + { + return new ExportedType(this, handle.RowId); + } + + public CustomAttributeHandleCollection GetCustomAttributes(Handle handle) + { + Debug.Assert(!handle.IsNil); + return new CustomAttributeHandleCollection(this, handle); + } + + public CustomAttribute GetCustomAttribute(CustomAttributeHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new CustomAttribute(this, GetCustomAttributeTreatmentAndRowId(handle)); + } + + private uint GetCustomAttributeTreatmentAndRowId(CustomAttributeHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return TreatmentAndRowId((byte)CustomAttributeTreatment.WinMD, handle.RowId); + } + + public DeclarativeSecurityAttribute GetDeclarativeSecurityAttribute(DeclarativeSecurityAttributeHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new DeclarativeSecurityAttribute(this, handle.RowId); + } + + public Constant GetConstant(ConstantHandle handle) + { + return new Constant(this, handle.RowId); + } + + public MethodDefinition GetMethodDefinition(MethodDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new MethodDefinition(this, GetMethodDefTreatmentAndRowId(handle)); + } + + private uint GetMethodDefTreatmentAndRowId(MethodDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return CalculateMethodDefTreatmentAndRowId(handle); + } + + public FieldDefinition GetFieldDefinition(FieldDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new FieldDefinition(this, GetFieldDefTreatmentAndRowId(handle)); + } + + private uint GetFieldDefTreatmentAndRowId(FieldDefinitionHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return CalculateFieldDefTreatmentAndRowId(handle); + } + + public PropertyDefinition GetPropertyDefinition(PropertyDefinitionHandle handle) + { + return new PropertyDefinition(this, handle); + } + + public EventDefinition GetEventDefinition(EventDefinitionHandle handle) + { + return new EventDefinition(this, handle); + } + + public MethodImplementation GetMethodImplementation(MethodImplementationHandle handle) + { + return new MethodImplementation(this, handle); + } + + public MemberReference GetMemberReference(MemberReferenceHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + return new MemberReference(this, GetMemberRefTreatmentAndRowId(handle)); + } + + private uint GetMemberRefTreatmentAndRowId(MemberReferenceHandle handle) + { + // PERF: This code pattern is JIT friendly and results in very efficient code. + if (_metadataKind == MetadataKind.Ecma335) + { + return handle.RowId; + } + + return CalculateMemberRefTreatmentAndRowId(handle); + } + + public MethodSpecification GetMethodSpecification(MethodSpecificationHandle handle) + { + return new MethodSpecification(this, handle); + } + + public Parameter GetParameter(ParameterHandle handle) + { + return new Parameter(this, handle); + } + + public GenericParameter GetGenericParameter(GenericParameterHandle handle) + { + return new GenericParameter(this, handle); + } + + public GenericParameterConstraint GetGenericParameterConstraint(GenericParameterConstraintHandle handle) + { + return new GenericParameterConstraint(this, handle); + } + + public ManifestResource GetManifestResource(ManifestResourceHandle handle) + { + return new ManifestResource(this, handle); + } + + public AssemblyFile GetAssemblyFile(AssemblyFileHandle handle) + { + return new AssemblyFile(this, handle); + } + + public StandaloneSignature GetStandaloneSignature(StandaloneSignatureHandle handle) + { + return new StandaloneSignature(this, handle); + } + + public TypeSpecification GetTypeSpecification(TypeSpecificationHandle handle) + { + return new TypeSpecification(this, handle); + } + + public ModuleReference GetModuleReference(ModuleReferenceHandle handle) + { + return new ModuleReference(this, handle); + } + + public InterfaceImplementation GetInterfaceImplementation(InterfaceImplementationHandle handle) + { + return new InterfaceImplementation(this, handle); + } + + internal TypeDefinitionHandle GetDeclaringType(MethodDefinitionHandle methodDef) + { + uint methodRowId; + if (UseMethodPtrTable) + { + methodRowId = MethodPtrTable.GetRowIdForMethodDefRow(methodDef.RowId); + } + else + { + methodRowId = methodDef.RowId; + } + + return TypeDefTable.FindTypeContainingMethod(methodRowId, (int)MethodDefTable.NumberOfRows); + } + + internal TypeDefinitionHandle GetDeclaringType(FieldDefinitionHandle fieldDef) + { + uint fieldRowId; + if (UseFieldPtrTable) + { + fieldRowId = FieldPtrTable.GetRowIdForFieldDefRow(fieldDef.RowId); + } + else + { + fieldRowId = fieldDef.RowId; + } + + return TypeDefTable.FindTypeContainingField(fieldRowId, (int)FieldTable.NumberOfRows); + } + + #endregion + + #region Nested Types + + private void InitializeNestedTypesMap() + { + var groupedNestedTypes = new Dictionary.Builder>(); + + uint numberOfNestedTypes = NestedClassTable.NumberOfRows; + ImmutableArray.Builder builder = null; + TypeDefinitionHandle previousEnclosingClass = default(TypeDefinitionHandle); + + for (uint i = 1; i <= numberOfNestedTypes; i++) + { + TypeDefinitionHandle enclosingClass = NestedClassTable.GetEnclosingClass(i); + + Debug.Assert(!enclosingClass.IsNil); + + if (enclosingClass != previousEnclosingClass) + { + if (!groupedNestedTypes.TryGetValue(enclosingClass, out builder)) + { + builder = ImmutableArray.CreateBuilder(); + groupedNestedTypes.Add(enclosingClass, builder); + } + + previousEnclosingClass = enclosingClass; + } + else + { + Debug.Assert(builder == groupedNestedTypes[enclosingClass]); + } + + builder.Add(NestedClassTable.GetNestedClass(i)); + } + + var nestedTypesMap = new Dictionary>(); + foreach (var group in groupedNestedTypes) + { + nestedTypesMap.Add(group.Key, group.Value.ToImmutable()); + } + + _lazyNestedTypesMap = nestedTypesMap; + } + + /// + /// Returns an array of types nested in the specified type. + /// + internal ImmutableArray GetNestedTypes(TypeDefinitionHandle typeDef) + { + if (_lazyNestedTypesMap == null) + { + InitializeNestedTypesMap(); + } + + ImmutableArray nestedTypes; + if (_lazyNestedTypesMap.TryGetValue(typeDef, out nestedTypes)) + { + return nestedTypes; + } + + return ImmutableArray.Empty; + } + #endregion + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReaderOptions.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReaderOptions.cs new file mode 100644 index 0000000..e0eacd9 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataReaderOptions.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + [Flags] + public enum MetadataReaderOptions + { + /// + /// All options are disabled. + /// + None = 0x0, + + /// + /// The options that are used when a is obtained + /// via an overload that does not take a + /// argument. + /// + Default = ApplyWindowsRuntimeProjections, + + /// + /// Windows Runtime projections are enabled (on by default). + /// + ApplyWindowsRuntimeProjections = 0x1 + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringComparer.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringComparer.cs new file mode 100644 index 0000000..2f35969 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringComparer.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Reflection.Metadata +{ + /// + /// Provides string comparison helpers to query strings in metadata while + /// avoiding allocation where possible. + /// + /// + /// + /// No allocation is performed unless both the handle argument and the + /// value argument contain non-ascii text. + /// + /// Obtain instances using . + /// + /// A default-initialized instance is useless and behaves as a null reference. + /// + /// The code is optimized such that there is no additional overhead in + /// re-obtaining a a comparer over hoisting it in to a local. + /// + /// That is to say that a construct like: + /// + /// + /// if (reader.StringComparer.Equals(typeDef.Namespace, "System") && + /// reader.StringComparer.Equals(typeDef.Name, "Object") + /// { + /// // found System.Object + /// } + /// + /// + /// is no less efficient than: + /// + /// + /// var comparer = reader.StringComparer; + /// if (comparer.Equals(typeDef.Namespace, "System") && + /// comparer.Equals(typeDef.Name, "Object") + /// { + /// // found System.Object + /// } + /// + /// + /// The choice between them is therefore one of style and not performance. + /// + public struct MetadataStringComparer + { + private readonly MetadataReader _reader; + + internal MetadataStringComparer(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + } + + public bool Equals(StringHandle handle, string value) + { + if (value == null) + { + ThrowValueArgumentNull(); + } + + return _reader.StringStream.Equals(handle, value, _reader.utf8Decoder); + } + + public bool Equals(NamespaceDefinitionHandle handle, string value) + { + if (value == null) + { + ThrowValueArgumentNull(); + } + + if (handle.HasFullName) + { + return _reader.StringStream.Equals(handle.GetFullName(), value, _reader.utf8Decoder); + } + + return value == _reader.namespaceCache.GetFullName(handle); + } + + public bool StartsWith(StringHandle handle, string value) + { + if (value == null) + { + ThrowValueArgumentNull(); + } + + return _reader.StringStream.StartsWith(handle, value, _reader.utf8Decoder); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowValueArgumentNull() + { + throw new ArgumentNullException("value"); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringDecoder.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringDecoder.cs new file mode 100644 index 0000000..eb183a6 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MetadataStringDecoder.cs @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Internal; +using System.Text; + +namespace System.Reflection.Metadata +{ + /// + /// Provides the with a custom mechanism for decoding + /// byte sequences in metadata that represent text. + /// + /// + /// This can be used for the following purposes: + /// + /// 1) To customize the treatment of invalid input. When no decoder is provided, + /// the uses the default fallback replacement + /// with \uFFFD) + /// + /// 2) To reuse existing strings instead of allocating a new one for each decoding + /// operation. + /// + public class MetadataStringDecoder + { + private static readonly MetadataStringDecoder s_defaultUTF8 = new MetadataStringDecoder(Encoding.UTF8); + private readonly Encoding _encoding; + + /// + /// The default decoder used by to decode UTF-8 when + /// no decoder is provided to the constructor. + /// + public static MetadataStringDecoder DefaultUTF8 + { + get { return s_defaultUTF8; } + } + + /// + /// Creates a for the given encoding. + /// + /// The encoding to use. + /// + /// To cache and reuse existing strings. Create a derived class and override + /// + public MetadataStringDecoder(Encoding encoding) + { + if (encoding == null) + { + throw new ArgumentNullException("encoding"); + } + + // Non-enforcement of (encoding is UTF8Encoding) here is by design. + // + // This type is not itself aware of any particular encoding. However, the constructor argument that accepts a + // MetadataStringDecoder argument is validated however because it must be a UTF8 decoder. + // + // Above architectural purity, the fact that you can get our default implementation of Encoding.GetString + // is a hidden feature to use our light-up of unsafe Encoding.GetString outside this assembly on an arbitrary + // encoding. I'm more comfortable sharing that hack than having the reflection over internal + // CreateStringFromEncoding spread. + + _encoding = encoding; + } + + /// + /// Gets the encoding used by this instance. + /// + public Encoding Encoding + { + get { return _encoding; } + } + + /// + /// The mechanism through which the obtains strings + /// for byte sequences in metadata. Override this to cache strings if required. + /// Otherwise, it is implemented by forwarding straight to + /// and every call will allocate a new string. + /// + /// Pointer to bytes to decode. + /// Number of bytes to decode. + /// The decoded string. + public unsafe virtual String GetString(byte* bytes, int byteCount) + { + Debug.Assert(_encoding != null); + + // Note that this call is currently wired to the light-up extension in EncodingHelper + // for portability. + return _encoding.GetString(bytes, byteCount); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodBodyBlock.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodBodyBlock.cs new file mode 100644 index 0000000..e0c6cff --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodBodyBlock.cs @@ -0,0 +1,228 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Internal; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; + +namespace System.Reflection.Metadata +{ + public sealed class MethodBodyBlock + { + private readonly MemoryBlock _il; + private readonly int _size; + private readonly ushort _maxStack; + private readonly bool _localVariablesInitialized; + private readonly StandaloneSignatureHandle _localSignature; + private readonly ImmutableArray _exceptionRegions; + + private MethodBodyBlock( + bool localVariablesInitialized, + ushort maxStack, + StandaloneSignatureHandle localSignatureHandle, + MemoryBlock il, + ImmutableArray exceptionRegions, + int size) + { + Debug.Assert(!exceptionRegions.IsDefault); + + _localVariablesInitialized = localVariablesInitialized; + _maxStack = maxStack; + _localSignature = localSignatureHandle; + _il = il; + _exceptionRegions = exceptionRegions; + _size = size; + } + + /// + /// Size of the method body - includes the header, IL and exception regions. + /// + public int Size + { + get { return _size; } + } + + public int MaxStack + { + get { return _maxStack; } + } + + public bool LocalVariablesInitialized + { + get { return _localVariablesInitialized; } + } + + public StandaloneSignatureHandle LocalSignature + { + get { return _localSignature; } + } + + public ImmutableArray ExceptionRegions + { + get { return _exceptionRegions; } + } + + public byte[] GetILBytes() + { + return _il.ToArray(); + } + + public ImmutableArray GetILContent() + { + byte[] bytes = GetILBytes(); + return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref bytes); + } + + public BlobReader GetILReader() + { + return new BlobReader(_il); + } + + private const byte ILTinyFormat = 0x02; + private const byte ILFatFormat = 0x03; + private const byte ILFormatMask = 0x03; + private const int ILTinyFormatSizeShift = 2; + private const byte ILMoreSects = 0x08; + private const byte ILInitLocals = 0x10; + private const byte ILFatFormatHeaderSize = 0x03; + private const int ILFatFormatHeaderSizeShift = 4; + private const byte SectEHTable = 0x01; + private const byte SectOptILTable = 0x02; + private const byte SectFatFormat = 0x40; + private const byte SectMoreSects = 0x40; + + public static MethodBodyBlock Create(BlobReader reader) + { + int startOffset = reader.Offset; + int ilSize; + + // Error need to check if the Memory Block is empty. This is false for all the calls... + byte headByte = reader.ReadByte(); + if ((headByte & ILFormatMask) == ILTinyFormat) + { + // tiny IL can't have locals so technically this shouldn't matter, + // but false is consistent with other metadata readers and helps + // for use cases involving comparing our output with theirs. + const bool initLocalsForTinyIL = false; + + ilSize = headByte >> ILTinyFormatSizeShift; + return new MethodBodyBlock( + initLocalsForTinyIL, + 8, + default(StandaloneSignatureHandle), + reader.GetMemoryBlockAt(0, ilSize), + ImmutableArray.Empty, + 1 + ilSize // header + IL + ); + } + + if ((headByte & ILFormatMask) != ILFatFormat) + { + throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader1, headByte)); + } + + // FatILFormat + byte headByte2 = reader.ReadByte(); + if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) + { + throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader2, headByte, headByte2)); + } + + bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; + bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; + + ushort maxStack = reader.ReadUInt16(); + ilSize = reader.ReadInt32(); + + int localSignatureToken = reader.ReadInt32(); + StandaloneSignatureHandle localSignatureHandle; + if (localSignatureToken == 0) + { + localSignatureHandle = default(StandaloneSignatureHandle); + } + else if ((localSignatureToken & TokenTypeIds.TokenTypeMask) == TokenTypeIds.Signature) + { + localSignatureHandle = StandaloneSignatureHandle.FromRowId((uint)localSignatureToken & TokenTypeIds.RIDMask); + } + else + { + throw new BadImageFormatException(string.Format(MetadataResources.InvalidLocalSignatureToken, unchecked((uint)localSignatureToken))); + } + + var ilBlock = reader.GetMemoryBlockAt(0, ilSize); + reader.SkipBytes(ilSize); + + ImmutableArray exceptionHandlers; + if (hasExceptionHandlers) + { + reader.Align(4); + byte sehHeader = reader.ReadByte(); + if ((sehHeader & SectEHTable) != SectEHTable) + { + throw new BadImageFormatException(string.Format(MetadataResources.InvalidSehHeader, sehHeader)); + } + + bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; + int dataSize = reader.ReadByte(); + if (sehFatFormat) + { + dataSize += reader.ReadUInt16() << 8; + exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); + } + else + { + reader.SkipBytes(2); // skip over reserved field + exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); + } + } + else + { + exceptionHandlers = ImmutableArray.Empty; + } + + return new MethodBodyBlock( + localsInitialized, + maxStack, + localSignatureHandle, + ilBlock, + exceptionHandlers, + reader.Offset - startOffset); + } + + private static ImmutableArray ReadSmallExceptionHandlers(ref BlobReader memReader, int count) + { + var result = new ExceptionRegion[count]; + for (int i = 0; i < result.Length; i++) + { + var kind = (ExceptionRegionKind)memReader.ReadUInt16(); + var tryOffset = memReader.ReadUInt16(); + var tryLength = memReader.ReadByte(); + var handlerOffset = memReader.ReadUInt16(); + var handlerLength = memReader.ReadByte(); + var classTokenOrFilterOffset = memReader.ReadInt32(); + result[i] = new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); + } + + return ImmutableArray.Create(result); + } + + private static ImmutableArray ReadFatExceptionHandlers(ref BlobReader memReader, int count) + { + var result = new ExceptionRegion[count]; + for (int i = 0; i < result.Length; i++) + { + var sehFlags = (ExceptionRegionKind)memReader.ReadUInt32(); + int tryOffset = memReader.ReadInt32(); + int tryLength = memReader.ReadInt32(); + int handlerOffset = memReader.ReadInt32(); + int handlerLength = memReader.ReadInt32(); + int classTokenOrFilterOffset = memReader.ReadInt32(); + result[i] = new ExceptionRegion(sehFlags, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); + } + + return ImmutableArray.Create(result); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodDefinition.cs new file mode 100644 index 0000000..4b48209 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodDefinition.cs @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct MethodDefinition + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal MethodDefinition(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private MethodDefTreatment Treatment + { + get { return (MethodDefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + private MethodDefinitionHandle Handle + { + get { return MethodDefinitionHandle.FromRowId(RowId); } + } + + public StringHandle Name + { + get + { + if (Treatment == 0) + { + return _reader.MethodDefTable.GetName(Handle); + } + + return GetProjectedName(); + } + } + + public BlobHandle Signature + { + get + { + if (Treatment == 0) + { + return _reader.MethodDefTable.GetSignature(Handle); + } + + return GetProjectedSignature(); + } + } + + public int RelativeVirtualAddress + { + get + { + if (Treatment == 0) + { + return _reader.MethodDefTable.GetRva(Handle); + } + + return GetProjectedRelativeVirtualAddress(); + } + } + + public MethodAttributes Attributes + { + get + { + if (Treatment == 0) + { + return _reader.MethodDefTable.GetFlags(Handle); + } + + return GetProjectedFlags(); + } + } + + public MethodImplAttributes ImplAttributes + { + get + { + if (Treatment == 0) + { + return _reader.MethodDefTable.GetImplFlags(Handle); + } + + return GetProjectedImplFlags(); + } + } + + public TypeDefinitionHandle GetDeclaringType() + { + return _reader.GetDeclaringType(Handle); + } + + public ParameterHandleCollection GetParameters() + { + return new ParameterHandleCollection(_reader, Handle); + } + + public GenericParameterHandleCollection GetGenericParameters() + { + return _reader.GenericParamTable.FindGenericParametersForMethod(Handle); + } + + public MethodImport GetImport() + { + uint implMapRid = _reader.ImplMapTable.FindImplForMethod(Handle); + if (implMapRid == 0) + { + return default(MethodImport); + } + + return _reader.ImplMapTable[implMapRid]; + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + public DeclarativeSecurityAttributeHandleCollection GetDeclarativeSecurityAttributes() + { + return new DeclarativeSecurityAttributeHandleCollection(_reader, Handle); + } + + #region Projections + + private StringHandle GetProjectedName() + { + if ((Treatment & MethodDefTreatment.KindMask) == MethodDefTreatment.DisposeMethod) + { + return StringHandle.FromVirtualIndex(StringHandle.VirtualIndex.Dispose); + } + + return _reader.MethodDefTable.GetName(Handle); + } + + private MethodAttributes GetProjectedFlags() + { + MethodAttributes flags = _reader.MethodDefTable.GetFlags(Handle); + MethodDefTreatment treatment = Treatment; + + if ((treatment & MethodDefTreatment.KindMask) == MethodDefTreatment.HiddenInterfaceImplementation) + { + flags = (flags & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Private; + } + + if ((treatment & MethodDefTreatment.MarkAbstractFlag) != 0) + { + flags |= MethodAttributes.Abstract; + } + + if ((treatment & MethodDefTreatment.MarkPublicFlag) != 0) + { + flags = (flags & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public; + } + + + return flags | MethodAttributes.HideBySig; + } + + private MethodImplAttributes GetProjectedImplFlags() + { + MethodImplAttributes flags = _reader.MethodDefTable.GetImplFlags(Handle); + + switch (Treatment & MethodDefTreatment.KindMask) + { + case MethodDefTreatment.DelegateMethod: + flags |= MethodImplAttributes.Runtime; + break; + + case MethodDefTreatment.DisposeMethod: + case MethodDefTreatment.AttributeMethod: + case MethodDefTreatment.InterfaceMethod: + case MethodDefTreatment.HiddenInterfaceImplementation: + case MethodDefTreatment.Other: + flags |= MethodImplAttributes.Runtime | MethodImplAttributes.InternalCall; + break; + } + + return flags; + } + + private BlobHandle GetProjectedSignature() + { + return _reader.MethodDefTable.GetSignature(Handle); + } + + private int GetProjectedRelativeVirtualAddress() + { + return 0; + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImplementation.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImplementation.cs new file mode 100644 index 0000000..97bbf06 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImplementation.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct MethodImplementation + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal MethodImplementation(MetadataReader reader, MethodImplementationHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private MethodImplementationHandle Handle + { + get { return MethodImplementationHandle.FromRowId(_rowId); } + } + + public TypeDefinitionHandle Type + { + get + { + return _reader.MethodImplTable.GetClass(Handle); + } + } + + public Handle MethodBody + { + get + { + return _reader.MethodImplTable.GetMethodBody(Handle); + } + } + + public Handle MethodDeclaration + { + get + { + return _reader.MethodImplTable.GetMethodDeclaration(Handle); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImport.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImport.cs new file mode 100644 index 0000000..f7b3c2e --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodImport.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public struct MethodImport + { + private readonly MethodImportAttributes _attributes; + private readonly StringHandle _name; + private readonly ModuleReferenceHandle _module; + + internal MethodImport(MethodImportAttributes attributes, StringHandle name, ModuleReferenceHandle module) + { + _attributes = attributes; + _name = name; + _module = module; + } + + public MethodImportAttributes Attributes { get { return _attributes; } } + public StringHandle Name { get { return _name; } } + public ModuleReferenceHandle Module { get { return _module; } } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodSpecification.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodSpecification.cs new file mode 100644 index 0000000..347f774 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/MethodSpecification.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct MethodSpecification + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal MethodSpecification(MetadataReader reader, MethodSpecificationHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private MethodSpecificationHandle Handle + { + get { return MethodSpecificationHandle.FromRowId(_rowId); } + } + + /// + /// MethodDef or MemberRef handle specifying to which generic method this refers, + /// that is which generic method is it an instantiation of. + /// + public Handle Method + { + get + { + return _reader.MethodSpecTable.GetMethod(Handle); + } + } + + /// + /// Blob handle holding the signature of this instantiation. + /// + public BlobHandle Signature + { + get + { + return _reader.MethodSpecTable.GetInstantiation(Handle); + } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleDefinition.cs new file mode 100644 index 0000000..3d3afad --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleDefinition.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct ModuleDefinition + { + private readonly MetadataReader _reader; + + internal ModuleDefinition(MetadataReader reader) + { + Debug.Assert(reader != null); + _reader = reader; + } + + public int Generation + { + get + { + return (int)_reader.ModuleTable.GetGeneration(); + } + } + + public StringHandle Name + { + get + { + return _reader.ModuleTable.GetName(); + } + } + + public GuidHandle Mvid + { + get + { + return _reader.ModuleTable.GetMvid(); + } + } + + public GuidHandle GenerationId + { + get + { + return _reader.ModuleTable.GetEncId(); + } + } + + public GuidHandle BaseGenerationId + { + get + { + return _reader.ModuleTable.GetEncBaseId(); + } + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleReference.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleReference.cs new file mode 100644 index 0000000..e3a6262 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/ModuleReference.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct ModuleReference + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal ModuleReference(MetadataReader reader, ModuleReferenceHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private ModuleReferenceHandle Handle + { + get { return ModuleReferenceHandle.FromRowId(_rowId); } + } + + public StringHandle Name + { + get { return _reader.ModuleRefTable.GetName(Handle); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/NamespaceDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/NamespaceDefinition.cs new file mode 100644 index 0000000..4b607f0 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/NamespaceDefinition.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct NamespaceDefinition + { + private NamespaceData _data; + + internal NamespaceDefinition(NamespaceData data) + { + Debug.Assert(data != null); + _data = data; + } + + /// + /// Gets the unqualified name of the NamespaceDefinition. + /// + public StringHandle Name + { + get { return _data.Name; } + } + + /// + /// Gets the parent namespace. + /// + public NamespaceDefinitionHandle Parent + { + get { return _data.Parent; } + } + + /// + /// Gets the namespace definitions that are direct children of the current + /// namespace definition. + /// + /// System.Collections and System.Linq are direct children of System. + /// System.Collections.Generic is a direct child of System.Collections. + /// System.Collections.Generic is *not* a direct child of System. + /// + public ImmutableArray NamespaceDefinitions + { + get { return _data.NamespaceDefinitions; } + } + + /// + /// Gets all type definitions that reside directly in a namespace. + /// + public ImmutableArray TypeDefinitions + { + get { return _data.TypeDefinitions; } + } + + /// + /// Gets all exported types that reside directly in a namespace. + /// + public ImmutableArray ExportedTypes + { + get { return _data.ExportedTypes; } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/PEReaderExtensions.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/PEReaderExtensions.cs new file mode 100644 index 0000000..a0e1c39 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/PEReaderExtensions.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; +using System.Reflection.PortableExecutable; + +namespace System.Reflection.Metadata +{ + // EditorBrowsable(Never) so that we don't clutter completion list with this type because a user that only has System.Reflection.Metadata + // imported and has type PE is likely looking to resolve PEReader from the System.Reflection.PortableExecutable and not looking to invoke + // these extensions as regular statics. + [EditorBrowsable(EditorBrowsableState.Never)] + public static class PEReaderExtensions + { + /// + /// Returns a body block of a method with specified Relative Virtual Address (RVA); + /// + /// is null. + /// The body is not found in the metadata or is invalid. + /// Section where the method is stored is not available. + public static unsafe MethodBodyBlock GetMethodBody(this PEReader peReader, int relativeVirtualAddress) + { + if (peReader == null) + { + throw new ArgumentNullException("peReader"); + } + + var block = peReader.GetSectionData(relativeVirtualAddress); + if (block.Length == 0) + { + throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodRva, relativeVirtualAddress)); + } + + // Call to validating public BlobReader constructor is by design -- we need to throw PlatformNotSupported on big-endian architecture. + var blobReader = new BlobReader(block.Pointer, block.Length); + return MethodBodyBlock.Create(blobReader); + } + + /// + /// Gets a from a . + /// + /// + /// The caller must keep the alive and undisposed throughout the lifetime of the metadata reader. + /// + public static MetadataReader GetMetadataReader(this PEReader peReader) + { + return GetMetadataReader(peReader, MetadataReaderOptions.ApplyWindowsRuntimeProjections, null); + } + + /// + /// Gets a from a . + /// + /// + /// The caller must keep the alive and undisposed throughout the lifetime of the metadata reader. + /// + + public static MetadataReader GetMetadataReader(this PEReader peReader, MetadataReaderOptions options) + { + return GetMetadataReader(peReader, options, null); + } + + /// + /// Gets a from a . + /// + /// + /// The caller must keep the alive and undisposed throughout the lifetime of the metadata reader. + /// + public static unsafe MetadataReader GetMetadataReader(this PEReader peReader, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) + { + var metadata = peReader.GetMetadata(); + return new MetadataReader(metadata.Pointer, metadata.Length, options, utf8Decoder); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/Parameter.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/Parameter.cs new file mode 100644 index 0000000..2d379be --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/Parameter.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct Parameter + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal Parameter(MetadataReader reader, ParameterHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private ParameterHandle Handle + { + get { return ParameterHandle.FromRowId(_rowId); } + } + + public ParameterAttributes Attributes + { + get + { + return _reader.ParamTable.GetFlags(Handle); + } + } + + public int SequenceNumber + { + get + { + return _reader.ParamTable.GetSequence(Handle); + } + } + + public StringHandle Name + { + get + { + return _reader.ParamTable.GetName(Handle); + } + } + + public ConstantHandle GetDefaultValue() + { + return _reader.ConstantTable.FindConstant(Handle); + } + + public BlobHandle GetMarshallingDescriptor() + { + uint marshalRowId = _reader.FieldMarshalTable.FindFieldMarshalRowId(Handle); + if (marshalRowId == 0) + { + return default(BlobHandle); + } + + return _reader.FieldMarshalTable.GetNativeType(marshalRowId); + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/PropertyDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/PropertyDefinition.cs new file mode 100644 index 0000000..b3dc905 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/PropertyDefinition.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct PropertyDefinition + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal PropertyDefinition(MetadataReader reader, PropertyDefinitionHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private PropertyDefinitionHandle Handle + { + get { return PropertyDefinitionHandle.FromRowId(_rowId); } + } + + public StringHandle Name + { + get + { + return _reader.PropertyTable.GetName(Handle); + } + } + + public PropertyAttributes Attributes + { + get + { + return _reader.PropertyTable.GetFlags(Handle); + } + } + + public BlobHandle Signature + { + get + { + return _reader.PropertyTable.GetSignature(Handle); + } + } + + public ConstantHandle GetDefaultValue() + { + return _reader.ConstantTable.FindConstant(Handle); + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + public PropertyAccessors GetAccessors() + { + uint getter = 0; + uint setter = 0; + + ushort methodCount; + var firstRowId = _reader.MethodSemanticsTable.FindSemanticMethodsForProperty(Handle, out methodCount); + for (ushort i = 0; i < methodCount; i++) + { + uint rowId = firstRowId + i; + switch (_reader.MethodSemanticsTable.GetSemantics(rowId)) + { + case MethodSemanticsAttributes.Getter: + getter = _reader.MethodSemanticsTable.GetMethod(rowId).RowId; + break; + + case MethodSemanticsAttributes.Setter: + setter = _reader.MethodSemanticsTable.GetMethod(rowId).RowId; + break; + // TODO: expose 'Other' collection on PropertyAccessors for completeness. + } + } + + return new PropertyAccessors(getter, setter); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SerializationTypeCode.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SerializationTypeCode.cs new file mode 100644 index 0000000..ba91cf2 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SerializationTypeCode.cs @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public enum SerializationTypeCode : byte + { + /// + /// Equivalent to . + /// + Invalid = SignatureTypeCode.Invalid, + + /// + /// Equivalent to . + /// + Boolean = SignatureTypeCode.Boolean, + + /// + /// Equivalent to . + /// + Char = SignatureTypeCode.Char, + + /// + /// Equivalent to . + /// + SByte = SignatureTypeCode.SByte, + + /// + /// Equivalent to . + /// + Byte = SignatureTypeCode.Byte, + + /// + /// Equivalent to . + /// + Int16 = SignatureTypeCode.Int16, + + /// + /// Equivalent to . + /// + UInt16 = SignatureTypeCode.UInt16, + + /// + /// Equivalent to . + /// + Int32 = SignatureTypeCode.Int32, + + /// + /// Equivalent to . + /// + UInt32 = SignatureTypeCode.UInt32, + + /// + /// Equivalent to . + /// + Int64 = SignatureTypeCode.Int64, + + /// + /// Equivalent to . + /// + UInt64 = SignatureTypeCode.UInt64, + + /// + /// Equivalent to . + /// + Single = SignatureTypeCode.Single, + + /// + /// Equivalent to . + /// + Double = SignatureTypeCode.Double, + + /// + /// Equivalent to . + /// + String = SignatureTypeCode.String, + + /// + /// Equivalent to . + /// + SZArray = SignatureTypeCode.SZArray, + + /// + /// The attribute argument is a System.Type instance. + /// + Type = 0x50, + + /// + /// The attribute argument is "boxed" (passed to a parameter, field, or property of type object) and carries type information in the attribute blob. + /// + TaggedObject = 0x51, + + /// + /// The attribute argument is an Enum instance. + /// + Enum = 0x55, + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureAttributes.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureAttributes.cs new file mode 100644 index 0000000..c17a6eb --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureAttributes.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + /// + /// Specified additional flags that can be applied to method signatures. + /// Underlying values correspond to the representation in the leading signature + /// byte represented by . + /// + [Flags] + public enum SignatureAttributes : byte + { + /// + /// No flags. + /// + None = 0x00, + + /// + /// Generic method. + /// + Generic = 0x10, + + /// + /// Instance method. + /// + /// Ecma 335 CLI Specification refers to this flag as HAS_THIS. + Instance = 0x20, + + /// + /// The first explicitly declared parameter represents the instance pointer. + /// + ExplicitThis = 0x40, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureCallingConvention.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureCallingConvention.cs new file mode 100644 index 0000000..26c1a21 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureCallingConvention.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + /// + /// Specifies how arguments in a given signature are passed from the caller to the callee. + /// Underlying values correspond to the representation in the leading signature byte + /// represented by . + /// + public enum SignatureCallingConvention : byte + { + /// + /// Managed calling convention with fixed-length argument list. + /// + Default = 0x0, + + /// + /// Unmanaged C/C++-style calling convention where the call stack is cleaned by the caller. + /// + CDecl = 0x1, + + /// + /// Unmanaged calling convention where call stack is cleaned up by the callee. + /// + StdCall = 0x2, + + /// + /// Unmanaged C++-style calling convention for calling instance member functions with a fixed argument list. + /// + ThisCall = 0x3, + + /// + /// Unmanaged calling convention where arguments are passed in registers when possible. + /// + FastCall = 0x4, + + /// + /// Managed calling convention for passing extra arguments. + /// + VarArgs = 0x5, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureHeader.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureHeader.cs new file mode 100644 index 0000000..a59edab --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureHeader.cs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Text; + +namespace System.Reflection.Metadata +{ + /// + /// Represents the signature characteristics specified by the leading byte of signature blobs. + /// + /// + /// This header byte is present in all method definition, method reference, standalone method, field, + /// property, and local variable signatures, but not in type specification signatures. + /// + public struct SignatureHeader : IEquatable + { + private byte _rawValue; + public const byte CallingConventionOrKindMask = 0x0F; + private const byte maxCallingConvention = (byte)SignatureCallingConvention.VarArgs; + + public SignatureHeader(byte rawValue) + { + _rawValue = rawValue; + } + + public byte RawValue + { + get { return _rawValue; } + } + + public SignatureCallingConvention CallingConvention + { + get + { + int callingConventionOrKind = _rawValue & CallingConventionOrKindMask; + + if (callingConventionOrKind > maxCallingConvention) + { + return SignatureCallingConvention.Default; + } + + return (SignatureCallingConvention)callingConventionOrKind; + } + } + + public SignatureKind Kind + { + get + { + int callingConventionOrKind = _rawValue & CallingConventionOrKindMask; + + if (callingConventionOrKind <= maxCallingConvention) + { + return SignatureKind.Method; + } + + return (SignatureKind)callingConventionOrKind; + } + } + + public SignatureAttributes Attributes + { + get { return (SignatureAttributes)(_rawValue & ~CallingConventionOrKindMask); } + } + + public bool HasExplicitThis + { + get { return (_rawValue & (byte)SignatureAttributes.ExplicitThis) != 0; } + } + + public bool IsInstance + { + get { return (_rawValue & (byte)SignatureAttributes.Instance) != 0; } + } + + public bool IsGeneric + { + get { return (_rawValue & (byte)SignatureAttributes.Generic) != 0; } + } + + public override bool Equals(object obj) + { + return obj is SignatureHeader && Equals((SignatureHeader)obj); + } + + public bool Equals(SignatureHeader other) + { + return _rawValue == other._rawValue; + } + + public override int GetHashCode() + { + return _rawValue; + } + + public static bool operator ==(SignatureHeader left, SignatureHeader right) + { + return left._rawValue == right._rawValue; + } + + public static bool operator !=(SignatureHeader left, SignatureHeader right) + { + return left._rawValue != right._rawValue; + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append(Kind.ToString()); + + if (Kind == SignatureKind.Method) + { + sb.Append(','); + sb.Append(CallingConvention.ToString()); + } + + if (Attributes != SignatureAttributes.None) + { + sb.Append(','); + sb.Append(Attributes.ToString()); + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureKind.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureKind.cs new file mode 100644 index 0000000..30a211e --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureKind.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + /// + /// Specifies the signature kind. Underlying values correspond to the representation + /// in the leading signature byte represented by . + /// + public enum SignatureKind : byte + { + /// + /// Method reference, method definition, or standalone method signature. + /// + Method = 0x0, + + /// + /// Field signature. + /// + Field = 0x6, + + /// + /// Local variables signature. + /// + LocalVariables = 0x7, + + /// + /// Property signature. + /// + Property = 0x8, + + /// + /// Method specification signature. + /// + MethodSpecification = 0xA, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureTypeCode.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureTypeCode.cs new file mode 100644 index 0000000..e9f49c2 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/SignatureTypeCode.cs @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + /// + /// Represents the type codes that are used in signature encoding. + /// + public enum SignatureTypeCode : byte + { + /// + /// Represents an invalid or uninitialized type code. It will not appear in valid signatures. + /// + Invalid = 0x0, + + /// + /// Represents in signatures. + /// + Void = CorElementType.ELEMENT_TYPE_VOID, + + /// + /// Represents in signatures. + /// + Boolean = CorElementType.ELEMENT_TYPE_BOOLEAN, + + /// + /// Represents in signatures. + /// + Char = CorElementType.ELEMENT_TYPE_CHAR, + + /// + /// Represents in signatures. + /// + SByte = CorElementType.ELEMENT_TYPE_I1, + + /// + /// Represents in signatures. + /// + Byte = CorElementType.ELEMENT_TYPE_U1, + + /// + /// Represents in signatures. + /// + Int16 = CorElementType.ELEMENT_TYPE_I2, + + /// + /// Represents in signatures. + /// + UInt16 = CorElementType.ELEMENT_TYPE_U2, + + /// + /// Represents in signatures. + /// + Int32 = CorElementType.ELEMENT_TYPE_I4, + + /// + /// Represents in signatures. + /// + UInt32 = CorElementType.ELEMENT_TYPE_U4, + + /// + /// Represents in signatures. + /// + Int64 = CorElementType.ELEMENT_TYPE_I8, + + /// + /// Represents in signatures. + /// + UInt64 = CorElementType.ELEMENT_TYPE_U8, + + /// + /// Represents in signatures. + /// + Single = CorElementType.ELEMENT_TYPE_R4, + + /// + /// Represents in signatures. + /// + Double = CorElementType.ELEMENT_TYPE_R8, + + /// + /// Represents in signatures. + /// + String = CorElementType.ELEMENT_TYPE_STRING, + + // every type above PTR will be simple type + + /// + /// Represents a unmanaged pointers in signatures. + /// It is followed in the blob by the signature encoding of the underlying type. + /// + Pointer = CorElementType.ELEMENT_TYPE_PTR, // PTR + + /// + /// Represents managed pointers (byref return values and parameters) in signatures. + /// It is followed in the blob by the signature encoding of the underlying type. + /// + ByReference = CorElementType.ELEMENT_TYPE_BYREF, // BYREF + + // ELEMENT_TYPE_VALUETYPE (0x11) and ELEMENT_TYPE_CLASS (0x12) are unified to ELEMENT_TYPE_HANDLE. + + /// + /// Represents a generic type parameter used within a signature. + /// + GenericTypeParameter = CorElementType.ELEMENT_TYPE_VAR, // a class type variable VAR + + /// + /// Represents a generalized in signatures. + /// + Array = CorElementType.ELEMENT_TYPE_ARRAY, // MDARRAY ... ... + /// + /// Represents the instantiation of a generic type in signatures. + /// + GenericTypeInstance = CorElementType.ELEMENT_TYPE_GENERICINST, // GENERICINST ... + + // Doc issue: We can't use because System.TypedReference isn't portable. + /// + /// Represents a System.TypedReference in signatures. + /// + TypedReference = CorElementType.ELEMENT_TYPE_TYPEDBYREF, // TYPEDREF (it takes no args) a typed reference to some other type + + /// + /// Represents a in signatures. + /// + IntPtr = CorElementType.ELEMENT_TYPE_I, + + /// + /// Represents a in signatures. + /// + UIntPtr = CorElementType.ELEMENT_TYPE_U, + + /// + /// Represents function pointer types in signatures. + /// + FunctionPointer = CorElementType.ELEMENT_TYPE_FNPTR, // FNPTR + + /// + /// Represents + /// + Object = CorElementType.ELEMENT_TYPE_OBJECT, + + /// + /// Represents a single dimensional with 0 lower bound. + /// + SZArray = CorElementType.ELEMENT_TYPE_SZARRAY, + + // SZARRAY + + /// + /// Represents a generic method parameter used within a signature. + /// + GenericMethodParameter = CorElementType.ELEMENT_TYPE_MVAR, // a method type variable MVAR + + // This is only for binding + /// + /// Represents a custom modifier applied to a type within a signature that the caller must understand. + /// + RequiredModifier = CorElementType.ELEMENT_TYPE_CMOD_REQD, // required C modifier : E_T_CMOD_REQD + + /// + /// Represents a custom modifier applied to a type within a signature that the caller can ignore. + /// + OptionalModifier = CorElementType.ELEMENT_TYPE_CMOD_OPT, // optional C modifier : E_T_CMOD_OPT + + /// + /// Precedes a type in signatures. + /// + /// + /// In raw metadata, this will be encoded as either ELEMENT_TYPE_CLASS (0x12) for reference + /// types and ELEMENT_TYPE_VALUETYPE (0x11) for value types. This is collapsed to a single + /// code because Windows Runtime projections can project from class to value type or vice-versa + /// and the raw code is misleading in those cases. + /// + TypeHandle = CorElementType.ELEMENT_TYPE_HANDLE, // CLASS | VALUETYPE + + /// + /// Represents a marker to indicate the end of fixed arguments and the beginning of variable arguments. + /// + Sentinel = CorElementType.ELEMENT_TYPE_SENTINEL, + + /// + /// Represents a local variable that is pinned by garbage collector + /// + Pinned = CorElementType.ELEMENT_TYPE_PINNED, + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/StandaloneSignature.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/StandaloneSignature.cs new file mode 100644 index 0000000..e4a5ac0 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/StandaloneSignature.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct StandaloneSignature + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal StandaloneSignature(MetadataReader reader, StandaloneSignatureHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private StandaloneSignatureHandle Handle + { + get { return StandaloneSignatureHandle.FromRowId(_rowId); } + } + + public BlobHandle Signature + { + get { return _reader.StandAloneSigTable.GetSignature(_rowId); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeDefinition.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeDefinition.cs new file mode 100644 index 0000000..99e2ac9 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeDefinition.cs @@ -0,0 +1,267 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct TypeDefinition + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal TypeDefinition(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private TypeDefTreatment Treatment + { + get { return (TypeDefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + private TypeDefinitionHandle Handle + { + get { return TypeDefinitionHandle.FromRowId(RowId); } + } + + public TypeAttributes Attributes + { + get + { + if (Treatment == 0) + { + return _reader.TypeDefTable.GetFlags(Handle); + } + + return GetProjectedFlags(); + } + } + + /// + /// Name of the type. + /// + public StringHandle Name + { + get + { + if (Treatment == 0) + { + return _reader.TypeDefTable.GetName(Handle); + } + + return GetProjectedName(); + } + } + + /// + /// Namespace of the type, or nil if the type is nested or defined in a root namespace. + /// + public NamespaceDefinitionHandle Namespace + { + get + { + if (Treatment == 0) + { + return _reader.TypeDefTable.GetNamespace(Handle); + } + + return GetProjectedNamespace(); + } + } + + /// + /// The base type of the type definition: either + /// , or . + /// + public Handle BaseType + { + get + { + if (Treatment == 0) + { + return _reader.TypeDefTable.GetExtends(Handle); + } + + return GetProjectedBaseType(); + } + } + + public TypeLayout GetLayout() + { + uint classLayoutRowId = _reader.ClassLayoutTable.FindRow(Handle); + if (classLayoutRowId == 0) + { + // NOTE: We don't need a bool/TryGetLayout because zero also means use default: + // + // Spec: + // ClassSize of zero does not mean the class has zero size. It means that no .size directive was specified + // at definition time, in which case, the actual size is calculated from the field types, taking account of + // packing size (default or specified) and natural alignment on the target, runtime platform. + // + // PackingSize shall be one of {0, 1, 2, 4, 8, 16, 32, 64, 128}. (0 means use + // the default pack size for the platform on which the application is + // running.) + + return default(TypeLayout); + } + + int size = (int)_reader.ClassLayoutTable.GetClassSize(classLayoutRowId); + int packingSize = _reader.ClassLayoutTable.GetPackingSize(classLayoutRowId); + return new TypeLayout(size, packingSize); + } + + /// + /// Returns the enclosing type of a specified nested type or nil handle if the type is not nested. + /// + public TypeDefinitionHandle GetDeclaringType() + { + return _reader.NestedClassTable.FindEnclosingType(Handle); + } + + public GenericParameterHandleCollection GetGenericParameters() + { + return _reader.GenericParamTable.FindGenericParametersForType(Handle); + } + + public MethodDefinitionHandleCollection GetMethods() + { + return new MethodDefinitionHandleCollection(_reader, Handle); + } + + public FieldDefinitionHandleCollection GetFields() + { + return new FieldDefinitionHandleCollection(_reader, Handle); + } + + public PropertyDefinitionHandleCollection GetProperties() + { + return new PropertyDefinitionHandleCollection(_reader, Handle); + } + + public EventDefinitionHandleCollection GetEvents() + { + return new EventDefinitionHandleCollection(_reader, Handle); + } + + /// + /// Returns an array of types nested in the specified type. + /// + public ImmutableArray GetNestedTypes() + { + return _reader.GetNestedTypes(Handle); + } + + public MethodImplementationHandleCollection GetMethodImplementations() + { + return new MethodImplementationHandleCollection(_reader, Handle); + } + + public InterfaceImplementationHandleCollection GetInterfaceImplementations() + { + return new InterfaceImplementationHandleCollection(_reader, Handle); + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + + public DeclarativeSecurityAttributeHandleCollection GetDeclarativeSecurityAttributes() + { + return new DeclarativeSecurityAttributeHandleCollection(_reader, Handle); + } + + #region Projections + + private TypeAttributes GetProjectedFlags() + { + var flags = _reader.TypeDefTable.GetFlags(Handle); + var treatment = Treatment; + + switch (treatment & TypeDefTreatment.KindMask) + { + case TypeDefTreatment.NormalNonAttribute: + flags |= TypeAttributes.WindowsRuntime | TypeAttributes.Import; + break; + + case TypeDefTreatment.NormalAttribute: + flags |= TypeAttributes.WindowsRuntime | TypeAttributes.Sealed; + break; + + case TypeDefTreatment.UnmangleWinRTName: + flags = flags & ~TypeAttributes.SpecialName | TypeAttributes.Public; + break; + + case TypeDefTreatment.PrefixWinRTName: + flags = flags & ~TypeAttributes.Public | TypeAttributes.Import; + break; + + case TypeDefTreatment.RedirectedToClrType: + flags = flags & ~TypeAttributes.Public | TypeAttributes.Import; + break; + + case TypeDefTreatment.RedirectedToClrAttribute: + flags &= ~TypeAttributes.Public; + break; + } + + if ((treatment & TypeDefTreatment.MarkAbstractFlag) != 0) + { + flags |= TypeAttributes.Abstract; + } + + if ((treatment & TypeDefTreatment.MarkInternalFlag) != 0) + { + flags &= ~TypeAttributes.Public; + } + + return flags; + } + + private StringHandle GetProjectedName() + { + var name = _reader.TypeDefTable.GetName(Handle); + + switch (Treatment & TypeDefTreatment.KindMask) + { + case TypeDefTreatment.UnmangleWinRTName: + return name.SuffixRaw(MetadataReader.ClrPrefix.Length); + + case TypeDefTreatment.PrefixWinRTName: + return name.WithWinRTPrefix(); + } + + return name; + } + + private NamespaceDefinitionHandle GetProjectedNamespace() + { + // NOTE: NamespaceDefinitionHandle currently relies on never having virtual values. If this ever gets projected + // to a virtual namespace name, then that assumption will need to be removed. + + // no change: + return _reader.TypeDefTable.GetNamespace(Handle); + } + + private Handle GetProjectedBaseType() + { + // no change: + return _reader.TypeDefTable.GetExtends(Handle); + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeLayout.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeLayout.cs new file mode 100644 index 0000000..edafdaf --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeLayout.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.Metadata +{ + public struct TypeLayout + { + private readonly int _size; + private readonly int _packingSize; + + public TypeLayout(int size, int packingSize) + { + _size = size; + _packingSize = packingSize; + } + + public int Size + { + get { return _size; } + } + + public int PackingSize + { + get { return _packingSize; } + } + + public bool IsDefault + { + get { return _size == 0 && _packingSize == 0; } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeReference.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeReference.cs new file mode 100644 index 0000000..bf3a2b6 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeReference.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.Metadata +{ + public struct TypeReference + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _treatmentAndRowId; + + internal TypeReference(MetadataReader reader, uint treatmentAndRowId) + { + Debug.Assert(reader != null); + Debug.Assert(treatmentAndRowId != 0); + + _reader = reader; + _treatmentAndRowId = treatmentAndRowId; + } + + private uint RowId + { + get { return _treatmentAndRowId & TokenTypeIds.RIDMask; } + } + + private TypeRefTreatment Treatment + { + get { return (TypeRefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); } + } + + private TypeReferenceHandle Handle + { + get { return TypeReferenceHandle.FromRowId(RowId); } + } + + /// + /// Resolution scope in which the target type is defined and is uniquely identified by the specified and . + /// + /// + /// Resolution scope can be one of the following handles: + /// + /// of the enclosing type, if the target type is a nested type. + /// , if the target type is defined in another module within the same assembly as this one. + /// , if the target type is defined in the current module. This should not occur in a CLI compressed metadata module. + /// , if the target type is defined in a different assembly from the current module. + /// Nil handle if the target type must be resolved by searching the for a matching and . + /// + /// + public Handle ResolutionScope + { + get + { + if (Treatment == 0) + { + return _reader.TypeRefTable.GetResolutionScope(Handle); + } + + return GetProjectedResolutionScope(); + } + } + + /// + /// Name of the target type. + /// + public StringHandle Name + { + get + { + if (Treatment == 0) + { + return _reader.TypeRefTable.GetName(Handle); + } + + return GetProjectedName(); + } + } + + /// + /// Name of the namespace where the target type is defined, or nil if the type is nested or defined in a root namespace. + /// + public StringHandle Namespace + { + get + { + if (Treatment == 0) + { + return _reader.TypeRefTable.GetNamespace(Handle); + } + + return GetProjectedNamespace(); + } + } + + #region Projections + + private Handle GetProjectedResolutionScope() + { + switch (Treatment) + { + case TypeRefTreatment.SystemAttribute: + case TypeRefTreatment.SystemDelegate: + return AssemblyReferenceHandle.FromVirtualIndex(AssemblyReferenceHandle.VirtualIndex.System_Runtime); + + case TypeRefTreatment.UseProjectionInfo: + return MetadataReader.GetProjectedAssemblyRef((int)RowId); + } + + Debug.Assert(false, "Unknown TypeRef treatment"); + return default(AssemblyReferenceHandle); + } + + private StringHandle GetProjectedName() + { + if (Treatment == TypeRefTreatment.UseProjectionInfo) + { + return MetadataReader.GetProjectedName((int)RowId); + } + else + { + return _reader.TypeRefTable.GetName(Handle); + } + } + + private StringHandle GetProjectedNamespace() + { + switch (Treatment) + { + case TypeRefTreatment.SystemAttribute: + case TypeRefTreatment.SystemDelegate: + return StringHandle.FromVirtualIndex(StringHandle.VirtualIndex.System); + + case TypeRefTreatment.UseProjectionInfo: + return MetadataReader.GetProjectedNamespace((int)RowId); + } + + Debug.Assert(false, "Unknown TypeRef treatment"); + return default(StringHandle); + } + #endregion + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeSpecification.cs b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeSpecification.cs new file mode 100644 index 0000000..04648c4 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/Metadata/TypeSpecification.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; + +namespace System.Reflection.Metadata +{ + public struct TypeSpecification + { + private readonly MetadataReader _reader; + + // Workaround: JIT doesn't generate good code for nested structures, so use RowId. + private readonly uint _rowId; + + internal TypeSpecification(MetadataReader reader, TypeSpecificationHandle handle) + { + Debug.Assert(reader != null); + Debug.Assert(!handle.IsNil); + + _reader = reader; + _rowId = handle.RowId; + } + + private TypeSpecificationHandle Handle + { + get { return TypeSpecificationHandle.FromRowId(_rowId); } + } + + public BlobHandle Signature + { + get { return _reader.TypeSpecTable.GetSignature(Handle); } + } + + public CustomAttributeHandleCollection GetCustomAttributes() + { + return new CustomAttributeHandleCollection(_reader, Handle); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/MetadataResources.Designer.cs b/SigningService/Signers/StrongName/MetadataReader/MetadataResources.Designer.cs new file mode 100644 index 0000000..24608be --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/MetadataResources.Designer.cs @@ -0,0 +1,582 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.35317 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System.Reflection.Metadata { + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class MetadataResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal MetadataResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Reflection.Metadata.Resources.MetadataResources", typeof(MetadataResources).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Invalid number of rows of Assembly table: {0}.. + /// + internal static string AssemblyTableInvalidNumberOfRows { + get { + return ResourceManager.GetString("AssemblyTableInvalidNumberOfRows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can't get a heap offset for a virtual heap handle. + /// + internal static string CantGetOffsetForVirtualHeapHandle { + get { + return ResourceManager.GetString("CantGetOffsetForVirtualHeapHandle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EnCMap table not sorted or has missing records.. + /// + internal static string EnCMapNotSorted { + get { + return ResourceManager.GetString("EnCMapNotSorted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Illegal tables in compressed metadata stream.. + /// + internal static string IllegalTablesInCompressedMetadataStream { + get { + return ResourceManager.GetString("IllegalTablesInCompressedMetadataStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image is too small.. + /// + internal static string ImageTooSmall { + get { + return ResourceManager.GetString("ImageTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image is either too small or contains an invalid byte offset or count.. + /// + internal static string ImageTooSmallOrContainsInvalidOffsetOrCount { + get { + return ResourceManager.GetString("ImageTooSmallOrContainsInvalidOffsetOrCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid coded index.. + /// + internal static string InvalidCodedIndex { + get { + return ResourceManager.GetString("InvalidCodedIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid compressed integer.. + /// + internal static string InvalidCompressedInteger { + get { + return ResourceManager.GetString("InvalidCompressedInteger", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid COR header size.. + /// + internal static string InvalidCorHeaderSize { + get { + return ResourceManager.GetString("InvalidCorHeaderSize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid handle.. + /// + internal static string InvalidHandle { + get { + return ResourceManager.GetString("InvalidHandle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid local signature token: 0x{0:X8}. + /// + internal static string InvalidLocalSignatureToken { + get { + return ResourceManager.GetString("InvalidLocalSignatureToken", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid metadata section span.. + /// + internal static string InvalidMetadataSectionSpan { + get { + return ResourceManager.GetString("InvalidMetadataSectionSpan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Metadata stream format.. + /// + internal static string InvalidMetadataStreamFormat { + get { + return ResourceManager.GetString("InvalidMetadataStreamFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid method header: 0x{0:X2}. + /// + internal static string InvalidMethodHeader1 { + get { + return ResourceManager.GetString("InvalidMethodHeader1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid method header: 0x{0:X2} 0x{1:X2}. + /// + internal static string InvalidMethodHeader2 { + get { + return ResourceManager.GetString("InvalidMethodHeader2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid relative virtual address (RVA): 0x{0:X8}. + /// + internal static string InvalidMethodRva { + get { + return ResourceManager.GetString("InvalidMethodRva", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid number of sections in declared in PE header.. + /// + internal static string InvalidNumberOfSections { + get { + return ResourceManager.GetString("InvalidNumberOfSections", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid PE signature.. + /// + internal static string InvalidPESignature { + get { + return ResourceManager.GetString("InvalidPESignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid section name. + /// + internal static string InvalidSectionName { + get { + return ResourceManager.GetString("InvalidSectionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid SEH header: 0x{0:X2}. + /// + internal static string InvalidSehHeader { + get { + return ResourceManager.GetString("InvalidSehHeader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid serialized string.. + /// + internal static string InvalidSerializedString { + get { + return ResourceManager.GetString("InvalidSerializedString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid signature.. + /// + internal static string InvalidSignature { + get { + return ResourceManager.GetString("InvalidSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid token.. + /// + internal static string InvalidToken { + get { + return ResourceManager.GetString("InvalidToken", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Little-endian architecture required.. + /// + internal static string LitteEndianArchitectureRequired { + get { + return ResourceManager.GetString("LitteEndianArchitectureRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata header too small.. + /// + internal static string MetadataHeaderTooSmall { + get { + return ResourceManager.GetString("MetadataHeaderTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata image doesn't represent an assembly.. + /// + internal static string MetadataImageDoesNotRepresentAnAssembly { + get { + return ResourceManager.GetString("MetadataImageDoesNotRepresentAnAssembly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid COR20 header signature.. + /// + internal static string MetadataSignature { + get { + return ResourceManager.GetString("MetadataSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The MetadataStringDecoder instance used to instantiate the Metadata reader must have a UTF8 encoding.. + /// + internal static string MetadataStringDecoderEncodingMustBeUtf8 { + get { + return ResourceManager.GetString("MetadataStringDecoderEncodingMustBeUtf8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata table header too small.. + /// + internal static string MetadataTableHeaderTooSmall { + get { + return ResourceManager.GetString("MetadataTableHeaderTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata table 0x{0:x2} not sorted.. + /// + internal static string MetadataTableNotSorted { + get { + return ResourceManager.GetString("MetadataTableNotSorted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata tables too small.. + /// + internal static string MetadataTablesTooSmall { + get { + return ResourceManager.GetString("MetadataTablesTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Missing data directory.. + /// + internal static string MissingDataDirectory { + get { + return ResourceManager.GetString("MissingDataDirectory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid number of rows of Module table: {0}.. + /// + internal static string ModuleTableInvalidNumberOfRows { + get { + return ResourceManager.GetString("ModuleTableInvalidNumberOfRows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Negative byte count or offset.. + /// + internal static string NegativeByteCountOrOffset { + get { + return ResourceManager.GetString("NegativeByteCountOrOffset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for Blob stream.. + /// + internal static string NotEnoughSpaceForBlobStream { + get { + return ResourceManager.GetString("NotEnoughSpaceForBlobStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for GUID stream.. + /// + internal static string NotEnoughSpaceForGUIDStream { + get { + return ResourceManager.GetString("NotEnoughSpaceForGUIDStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for Metadata stream.. + /// + internal static string NotEnoughSpaceForMetadataStream { + get { + return ResourceManager.GetString("NotEnoughSpaceForMetadataStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for stream header name.. + /// + internal static string NotEnoughSpaceForStreamHeaderName { + get { + return ResourceManager.GetString("NotEnoughSpaceForStreamHeaderName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for String stream.. + /// + internal static string NotEnoughSpaceForStringStream { + get { + return ResourceManager.GetString("NotEnoughSpaceForStringStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not enough space for version string.. + /// + internal static string NotEnoughSpaceForVersionString { + get { + return ResourceManager.GetString("NotEnoughSpaceForVersionString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specified handle is not a valid metadata heap handle.. + /// + internal static string NotMetadataHeapHandle { + get { + return ResourceManager.GetString("NotMetadataHeapHandle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specified handle is not a valid metadata table handle.. + /// + internal static string NotMetadataTableHandle { + get { + return ResourceManager.GetString("NotMetadataTableHandle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specified handle is not a valid metadata table or UserString heap handle.. + /// + internal static string NotMetadataTableOrUserStringHandle { + get { + return ResourceManager.GetString("NotMetadataTableOrUserStringHandle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read out of bounds.. + /// + internal static string OutOfBoundsRead { + get { + return ResourceManager.GetString("OutOfBoundsRead", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PE image does not have metadata.. + /// + internal static string PEImageDoesNotHaveMetadata { + get { + return ResourceManager.GetString("PEImageDoesNotHaveMetadata", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PE image not available.. + /// + internal static string PEImageNotAvailable { + get { + return ResourceManager.GetString("PEImageNotAvailable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Row ID or heap offset is too large.. + /// + internal static string RowIdOrHeapOffsetTooLarge { + get { + return ResourceManager.GetString("RowIdOrHeapOffsetTooLarge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Section too small.. + /// + internal static string SectionTooSmall { + get { + return ResourceManager.GetString("SectionTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream header too small.. + /// + internal static string StreamHeaderTooSmall { + get { + return ResourceManager.GetString("StreamHeaderTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream must support read and seek operations.. + /// + internal static string StreamMustSupportReadAndSeek { + get { + return ResourceManager.GetString("StreamMustSupportReadAndSeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream length minus starting position is too large to hold a PEImage.. + /// + internal static string StreamTooLarge { + get { + return ResourceManager.GetString("StreamTooLarge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Table row count space to small.. + /// + internal static string TableRowCountSpaceTooSmall { + get { + return ResourceManager.GetString("TableRowCountSpaceTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read metadata file.. + /// + internal static string UnableToReadMetadataFile { + get { + return ResourceManager.GetString("UnableToReadMetadataFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected stream end.. + /// + internal static string UnexpectedStreamEnd { + get { + return ResourceManager.GetString("UnexpectedStreamEnd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown file format.. + /// + internal static string UnknownFileFormat { + get { + return ResourceManager.GetString("UnknownFileFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown PE Magic value.. + /// + internal static string UnknownPEMagicValue { + get { + return ResourceManager.GetString("UnknownPEMagicValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown tables: 0x{0:x16}.. + /// + internal static string UnknownTables { + get { + return ResourceManager.GetString("UnknownTables", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Missing mscorlib reference in AssemblyRef table.. + /// + internal static string WinMDMissingMscorlibRef { + get { + return ResourceManager.GetString("WinMDMissingMscorlibRef", resourceCulture); + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CoffHeader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CoffHeader.cs new file mode 100644 index 0000000..9ef290d --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CoffHeader.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public sealed class CoffHeader + { + /// + /// The type of target machine. + /// + public Machine Machine { get; private set; } + + /// + /// The number of sections. This indicates the size of the section table, which immediately follows the headers. + /// + public short NumberOfSections { get; private set; } + + /// + /// The low 32 bits of the number of seconds since 00:00 January 1, 1970, that indicates when the file was created. + /// + public int TimeDateStamp { get; private set; } + + /// + /// The file pointer to the COFF symbol table, or zero if no COFF symbol table is present. + /// This value should be zero for a PE image. + /// + public int PointerToSymbolTable { get; private set; } + + /// + /// The number of entries in the symbol table. This data can be used to locate the string table, + /// which immediately follows the symbol table. This value should be zero for a PE image. + /// + public int NumberOfSymbols { get; private set; } + + /// + /// The size of the optional header, which is required for executable files but not for object files. + /// This value should be zero for an object file. + /// + public short SizeOfOptionalHeader { get; private set; } + + /// + /// The flags that indicate the attributes of the file. + /// + public Characteristics Characteristics { get; private set; } + + internal CoffHeader(ref PEBinaryReader reader) + { + Machine = (Machine)reader.ReadUInt16(); + NumberOfSections = reader.ReadInt16(); + TimeDateStamp = reader.ReadInt32(); + PointerToSymbolTable = reader.ReadInt32(); + NumberOfSymbols = reader.ReadInt32(); + SizeOfOptionalHeader = reader.ReadInt16(); + Characteristics = (Characteristics)reader.ReadUInt16(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorFlags.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorFlags.cs new file mode 100644 index 0000000..ba6fb5f --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorFlags.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + /// + /// COR20Flags + /// + [Flags] + public enum CorFlags + { + ILOnly = 0x00000001, + Requires32Bit = 0x00000002, + ILLibrary = 0x00000004, + StrongNameSigned = 0x00000008, + NativeEntryPoint = 0x00000010, + TrackDebugData = 0x00010000, + Prefers32Bit = 0x00020000, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorHeader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorHeader.cs new file mode 100644 index 0000000..88c5450 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/CorHeader.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public sealed class CorHeader + { + public ushort MajorRuntimeVersion { get; private set; } + public ushort MinorRuntimeVersion { get; private set; } + public DirectoryEntry MetadataDirectory { get; private set; } + public int FlagsOffset { get; private set; } + public CorFlags Flags { get; private set; } + public int EntryPointTokenOrRelativeVirtualAddress { get; private set; } + public DirectoryEntry ResourcesDirectory { get; private set; } + public DirectoryEntry StrongNameSignatureDirectory { get; private set; } + public DirectoryEntry CodeManagerTableDirectory { get; private set; } + public DirectoryEntry VtableFixupsDirectory { get; private set; } + public DirectoryEntry ExportAddressTableJumpsDirectory { get; private set; } + public DirectoryEntry ManagedNativeHeaderDirectory { get; private set; } + + internal CorHeader(ref PEBinaryReader reader) + { + // byte count + reader.ReadInt32(); + + MajorRuntimeVersion = reader.ReadUInt16(); + MinorRuntimeVersion = reader.ReadUInt16(); + MetadataDirectory = new DirectoryEntry(ref reader); + FlagsOffset = reader.CurrentOffset; + Flags = (CorFlags)reader.ReadUInt32(); + EntryPointTokenOrRelativeVirtualAddress = reader.ReadInt32(); + ResourcesDirectory = new DirectoryEntry(ref reader); + StrongNameSignatureDirectory = new DirectoryEntry(ref reader); + CodeManagerTableDirectory = new DirectoryEntry(ref reader); + VtableFixupsDirectory = new DirectoryEntry(ref reader); + ExportAddressTableJumpsDirectory = new DirectoryEntry(ref reader); + ManagedNativeHeaderDirectory = new DirectoryEntry(ref reader); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/DirectoryEntry.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/DirectoryEntry.cs new file mode 100644 index 0000000..0a515ac --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/DirectoryEntry.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public struct DirectoryEntry + { + public readonly int HeaderOffset; + public readonly int RelativeVirtualAddress; + public readonly int Size; + + internal DirectoryEntry(ref PEBinaryReader reader) + { + HeaderOffset = reader.CurrentOffset; + RelativeVirtualAddress = reader.ReadInt32(); + Size = reader.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/Machine.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/Machine.cs new file mode 100644 index 0000000..2db5518 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/Machine.cs @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public enum Machine : ushort + { + /// + /// The target CPU is unknown or not specified. + /// + Unknown = 0x0000, + + /// + /// Intel 386. + /// + I386 = 0x014C, + + /// + /// MIPS little-endian WCE v2 + /// + WceMipsV2 = 0x0169, + + /// + /// Alpha + /// + Alpha = 0x0184, + + /// + /// Hitachi SH3 little endian + /// + SH3 = 0x01a2, + + /// + /// Hitachi SH3 DSP. + /// + SH3Dsp = 0x01a3, + + /// + /// Hitachi SH3 little endian. + /// + SH3E = 0x01a4, + + /// + /// Hitachi SH4 little endian. + /// + SH4 = 0x01a6, + + /// + /// Hitachi SH5. + /// + SH5 = 0x01a8, + + /// + /// ARM little endian + /// + Arm = 0x01c0, + + /// + /// Thumb. + /// + Thumb = 0x01c2, + + /// + /// ARM Thumb-2 little endian. + /// + ArmThumb2 = 0x01c4, + + /// + /// Matsushita AM33. + /// + AM33 = 0x01d3, + + /// + /// IBM PowerPC little endian. + /// + PowerPC = 0x01F0, + + /// + /// PowerPCFP + /// + PowerPCFP = 0x01f1, + + /// + /// Intel 64 + /// + IA64 = 0x0200, + + /// + /// MIPS + /// + MIPS16 = 0x0266, + + /// + /// ALPHA64 + /// + Alpha64 = 0x0284, + + /// + /// MIPS with FPU. + /// + MipsFpu = 0x0366, + + /// + /// MIPS16 with FPU. + /// + MipsFpu16 = 0x0466, + + /// + /// Infineon + /// + Tricore = 0x0520, + + /// + /// EFI Byte Code + /// + Ebc = 0x0EBC, + + /// + /// AMD64 (K8) + /// + Amd64 = 0x8664, + + /// + /// M32R little-endian + /// + M32R = 0x9041, + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEBinaryReader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEBinaryReader.cs new file mode 100644 index 0000000..0c2c02a --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEBinaryReader.cs @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.IO; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Reflection.PortableExecutable +{ + /// + /// Simple BinaryReader wrapper to: + /// + /// 1) throw BadImageFormat instead of EndOfStream or ArgumentOutOfRange. + /// 2) limit reads to a subset of the base stream. + /// + /// Only methods that are needed to read PE headers are implemented. + /// + internal struct PEBinaryReader + { + private readonly long _startOffset; + private readonly long _maxOffset; + private readonly BinaryReader _reader; + + public PEBinaryReader(Stream stream, int size) + { + Debug.Assert(size >= 0 && size <= (stream.Length - stream.Position)); + + _startOffset = stream.Position; + _maxOffset = _startOffset + (uint)size; + _reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true); + } + + public int CurrentOffset + { + get { return (int)(_reader.BaseStream.Position - _startOffset); } + } + + public void Seek(int offset) + { + CheckBounds(_startOffset, offset); + _reader.BaseStream.Seek(offset, SeekOrigin.Begin); + } + + public byte[] ReadBytes(int count) + { + CheckBounds(_reader.BaseStream.Position, count); + return _reader.ReadBytes(count); + } + + public Byte ReadByte() + { + CheckBounds(sizeof(Byte)); + return _reader.ReadByte(); + } + + public Int16 ReadInt16() + { + CheckBounds(sizeof(Int16)); + return _reader.ReadInt16(); + } + + public UInt16 ReadUInt16() + { + CheckBounds(sizeof(UInt16)); + return _reader.ReadUInt16(); + } + + public Int32 ReadInt32() + { + CheckBounds(sizeof(Int32)); + return _reader.ReadInt32(); + } + + public UInt32 ReadUInt32() + { + CheckBounds(sizeof(UInt32)); + return _reader.ReadUInt32(); + } + + public ulong ReadUInt64() + { + CheckBounds(sizeof(UInt64)); + return _reader.ReadUInt64(); + } + + public string ReadUTF8(int byteCount) + { + byte[] bytes = ReadBytes(byteCount); + return Encoding.UTF8.GetString(bytes, 0, byteCount); + } + + /// + /// Resolve image size as either the given user-specified size or distance from current position to end-of-stream. + /// Also performs the relevant argument validation and publicly visible caller has same argument names. + /// + /// size is null and distance from current position to end-of-stream can't fit in Int32. + /// Size is negative or extends past the end-of-stream from current position. + public static int GetAndValidateSize(Stream peStream, int? size) + { + long maxSize = peStream.Length - peStream.Position; + + if (size.HasValue) + { + if (unchecked((uint)size.Value) > maxSize) + { + throw new ArgumentOutOfRangeException("size"); + } + + return size.Value; + } + else + { + if (maxSize > int.MaxValue) + { + throw new ArgumentException(MetadataResources.StreamTooLarge, "peStream"); + } + + return (int)maxSize; + } + } + + private void CheckBounds(uint count) + { + Debug.Assert(count <= sizeof(Int64)); // Error message assumes we're trying to read constant small number of bytes. + Debug.Assert(_reader.BaseStream.Position >= 0 && _maxOffset >= 0); + + // Add cannot overflow because the worst case is (ulong)long.MaxValue + uint.MaxValue < ulong.MaxValue. + if ((ulong)_reader.BaseStream.Position + count > (ulong)_maxOffset) + { + ThrowImageTooSmall(); + } + } + + private void CheckBounds(long startPosition, int count) + { + Debug.Assert(startPosition >= 0 && _maxOffset >= 0); + + // Add cannot overflow because the worst case is (ulong)long.MaxValue + uint.MaxValue < ulong.MaxValue. + // Negative count is handled by overflow to greater than maximum size = int.MaxValue. + if ((ulong)startPosition + unchecked((uint)count) > (ulong)_maxOffset) + { + ThrowImageTooSmallOrContainsInvalidOffsetOrCount(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowImageTooSmall() + { + throw new BadImageFormatException(MetadataResources.ImageTooSmall); + } + + // TODO: move throw helpers together. + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ThrowImageTooSmallOrContainsInvalidOffsetOrCount() + { + throw new BadImageFormatException(MetadataResources.ImageTooSmallOrContainsInvalidOffsetOrCount); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileConstants.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileConstants.cs new file mode 100644 index 0000000..feab213 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileConstants.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + internal static class PEFileConstants + { + internal const ushort DosSignature = 0x5A4D; // MZ + internal const int PESignatureOffsetLocation = 0x3C; + internal const uint PESignature = 0x00004550; // PE00 + internal const int BasicPEHeaderSize = PESignatureOffsetLocation; + internal const int SizeofCOFFFileHeader = 20; + internal const int SizeofOptionalHeaderStandardFields32 = 28; + internal const int SizeofOptionalHeaderStandardFields64 = 24; + internal const int SizeofOptionalHeaderNTAdditionalFields32 = 68; + internal const int SizeofOptionalHeaderNTAdditionalFields64 = 88; + internal const int NumberofOptionalHeaderDirectoryEntries = 16; + internal const int SizeofOptionalHeaderDirectoriesEntries = 16 * 8; + internal const int SizeofSectionHeader = 40; + internal const int SizeofSectionName = 8; + internal const int SizeofResourceDirectory = 16; + internal const int SizeofResourceDirectoryEntry = 8; + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileFlags.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileFlags.cs new file mode 100644 index 0000000..bc2327e --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEFileFlags.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public enum Characteristics : ushort + { + RelocsStripped = 0x0001, // Relocation info stripped from file. + ExecutableImage = 0x0002, // File is executable (i.e. no unresolved external references). + LineNumsStripped = 0x0004, // Line numbers stripped from file. + LocalSymsStripped = 0x0008, // Local symbols stripped from file. + AggressiveWSTrim = 0x0010, // Aggressively trim working set + LargeAddressAware = 0x0020, // App can handle >2gb addresses + BytesReversedLo = 0x0080, // Bytes of machine word are reversed. + Bit32Machine = 0x0100, // 32 bit word machine. + DebugStripped = 0x0200, // Debugging info stripped from file in .DBG file + RemovableRunFromSwap = 0x0400, // If Image is on removable media, copy and run from the swap file. + NetRunFromSwap = 0x0800, // If Image is on Net, copy and run from the swap file. + System = 0x1000, // System File. + Dll = 0x2000, // File is a DLL. + UpSystemOnly = 0x4000, // File should only be run on a UP machine + BytesReversedHi = 0x8000, // Bytes of machine word are reversed. + } + + public enum PEMagic : ushort + { + PE32 = 0x010B, + PE32Plus = 0x020B, + } + + public enum Subsystem : ushort + { + Unknown = 0, // Unknown subsystem. + Native = 1, // Image doesn't require a subsystem. + WindowsGui = 2, // Image runs in the Windows GUI subsystem. + WindowsCui = 3, // Image runs in the Windows character subsystem. + OS2Cui = 5, // image runs in the OS/2 character subsystem. + PosixCui = 7, // image runs in the Posix character subsystem. + NativeWindows = 8, // image is a native Win9x driver. + WindowsCEGui = 9, // Image runs in the Windows CE subsystem. + EfiApplication = 10, // Extensible Firmware Interface (EFI) application. + EfiBootServiceDriver = 11, // EFI driver with boot services. + EfiRuntimeDriver = 12, // EFI driver with run-time services. + EfiRom = 13, // EFI ROM image. + Xbox = 14, + } + + [Flags] + public enum DllCharacteristics : ushort + { + ProcessInit = 0x0001, // Reserved. + ProcessTerm = 0x0002, // Reserved. + ThreadInit = 0x0004, // Reserved. + ThreadTerm = 0x0008, // Reserved. + DynamicBase = 0x0040, // + NxCompatible = 0x0100, // + NoIsolation = 0x0200, // Image understands isolation and doesn't want it + NoSeh = 0x0400, // Image does not use SEH. No SE handler may reside in this image + NoBind = 0x0800, // Do not bind this image. + AppContainer = 0x1000, // The image must run inside an AppContainer + WdmDriver = 0x2000, // Driver uses WDM model + // 0x4000 // Reserved. + TerminalServerAware = 0x8000, + } + + [Flags] + public enum SectionCharacteristics : uint + { + TypeReg = 0x00000000, // Reserved. + TypeDSect = 0x00000001, // Reserved. + TypeNoLoad = 0x00000002, // Reserved. + TypeGroup = 0x00000004, // Reserved. + TypeNoPad = 0x00000008, // Reserved. + TypeCopy = 0x00000010, // Reserved. + + ContainsCode = 0x00000020, // Section contains code. + ContainsInitializedData = 0x00000040, // Section contains initialized data. + ContainsUninitializedData = 0x00000080, // Section contains uninitialized data. + + LinkerOther = 0x00000100, // Reserved. + LinkerInfo = 0x00000200, // Section contains comments or some other type of information. + TypeOver = 0x00000400, // Reserved. + LinkerRemove = 0x00000800, // Section contents will not become part of image. + LinkerComdat = 0x00001000, // Section contents comdat. + // 0x00002000 // Reserved. + MemProtected = 0x00004000, + NoDeferSpecExc = 0x00004000, // Reset speculative exceptions handling bits in the TLB entries for this section. + GPRel = 0x00008000, // Section content can be accessed relative to GP + MemFardata = 0x00008000, + MemSysheap = 0x00010000, + MemPurgeable = 0x00020000, + Mem16Bit = 0x00020000, + MemLocked = 0x00040000, + MemPreload = 0x00080000, + + Align1Bytes = 0x00100000, // + Align2Bytes = 0x00200000, // + Align4Bytes = 0x00300000, // + Align8Bytes = 0x00400000, // + Align16Bytes = 0x00500000, // Default alignment if no others are specified. + Align32Bytes = 0x00600000, // + Align64Bytes = 0x00700000, // + Align128Bytes = 0x00800000, // + Align256Bytes = 0x00900000, // + Align512Bytes = 0x00A00000, // + Align1024Bytes = 0x00B00000, // + Align2048Bytes = 0x00C00000, // + Align4096Bytes = 0x00D00000, // + Align8192Bytes = 0x00E00000, // + // Unused 0x00F00000 + AlignMask = 0x00F00000, + + LinkerNRelocOvfl = 0x01000000, // Section contains extended relocations. + MemDiscardable = 0x02000000, // Section can be discarded. + MemNotCached = 0x04000000, // Section is not cachable. + MemNotPaged = 0x08000000, // Section is not pageable. + MemShared = 0x10000000, // Section is shareable. + MemExecute = 0x20000000, // Section is executable. + MemRead = 0x40000000, // Section is readable. + MemWrite = 0x80000000, // Section is writeable. + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeader.cs new file mode 100644 index 0000000..fd69c05 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeader.cs @@ -0,0 +1,291 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Reflection.Metadata; + +namespace System.Reflection.PortableExecutable +{ + public sealed class PEHeader + { + #region Standard fields + + /// + /// Identifies the format of the image file. + /// + public PEMagic Magic { get; private set; } + + /// + /// The linker major version number. + /// + public byte MajorLinkerVersion { get; private set; } + + /// + /// The linker minor version number. + /// + public byte MinorLinkerVersion { get; private set; } + + /// + /// The size of the code (text) section, or the sum of all code sections if there are multiple sections. + /// + public int SizeOfCode { get; private set; } + + /// + /// The size of the initialized data section, or the sum of all such sections if there are multiple data sections. + /// + public int SizeOfInitializedData { get; private set; } + + /// + /// The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections. + /// + public int SizeOfUninitializedData { get; private set; } + + /// + /// The address of the entry point relative to the image base when the PE file is loaded into memory. + /// For program images, this is the starting address. For device drivers, this is the address of the initialization function. + /// An entry point is optional for DLLs. When no entry point is present, this field must be zero. + /// + public int AddressOfEntryPoint { get; private set; } + + /// + /// The address that is relative to the image base of the beginning-of-code section when it is loaded into memory. + /// + public int BaseOfCode { get; private set; } + + /// + /// The address that is relative to the image base of the beginning-of-data section when it is loaded into memory. + /// + public int BaseOfData { get; private set; } + + #endregion + + #region Windows Specific Fields + + /// + /// The preferred address of the first byte of image when loaded into memory; + /// must be a multiple of 64K. + /// + public ulong ImageBase { get; private set; } + + /// + /// The alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to . + /// The default is the page size for the architecture. + /// + public int SectionAlignment { get; private set; } + + /// + /// The alignment factor (in bytes) that is used to align the raw data of sections in the image file. + /// The value should be a power of 2 between 512 and 64K, inclusive. The default is 512. + /// If the is less than the architecture's page size, + /// then must match . + /// + public int FileAlignment { get; private set; } + + /// + /// The major version number of the required operating system. + /// + public ushort MajorOperatingSystemVersion { get; private set; } + + /// + /// The minor version number of the required operating system. + /// + public ushort MinorOperatingSystemVersion { get; private set; } + + /// + /// The major version number of the image. + /// + public ushort MajorImageVersion { get; private set; } + + /// + /// The minor version number of the image. + /// + public ushort MinorImageVersion { get; private set; } + + /// + /// The major version number of the subsystem. + /// + public ushort MajorSubsystemVersion { get; private set; } + + /// + /// The minor version number of the subsystem. + /// + public ushort MinorSubsystemVersion { get; private set; } + + /// + /// The size (in bytes) of the image, including all headers, as the image is loaded in memory. + /// It must be a multiple of . + /// + public int SizeOfImage { get; private set; } + + /// + /// The combined size of an MS DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment. + /// + public int SizeOfHeaders { get; private set; } + + /// + /// The image file checksum. + /// + public uint CheckSum { get; private set; } + public int CheckSumOffset { get; private set; } + public int CheckSumSize { get { return 4; } } + + /// + /// The subsystem that is required to run this image. + /// + public Subsystem Subsystem { get; private set; } + + public DllCharacteristics DllCharacteristics { get; private set; } + + /// + /// The size of the stack to reserve. Only is committed; + /// the rest is made available one page at a time until the reserve size is reached. + /// + public ulong SizeOfStackReserve { get; private set; } + + /// + /// The size of the stack to commit. + /// + public ulong SizeOfStackCommit { get; private set; } + + /// + /// The size of the local heap space to reserve. Only is committed; + /// the rest is made available one page at a time until the reserve size is reached. + /// + public ulong SizeOfHeapReserve { get; private set; } + + /// + /// The size of the local heap space to commit. + /// + public ulong SizeOfHeapCommit { get; private set; } + + /// + /// The number of data-directory entries in the remainder of the . Each describes a location and size. + /// + public int NumberOfRvaAndSizes { get; private set; } + + #endregion + + #region Directory Entries + + public DirectoryEntry ExportTableDirectory { get; private set; } + public DirectoryEntry ImportTableDirectory { get; private set; } + public DirectoryEntry ResourceTableDirectory { get; private set; } + public DirectoryEntry ExceptionTableDirectory { get; private set; } + + /// + /// The Certificate Table entry points to a table of attribute certificates. + /// These certificates are not loaded into memory as part of the image. + /// As such, the first field of this entry, which is normally an RVA, is a file pointer instead. + /// + public DirectoryEntry CertificateTableDirectory { get; private set; } + public DirectoryEntry BaseRelocationTableDirectory { get; private set; } + public DirectoryEntry DebugTableDirectory { get; private set; } + public DirectoryEntry CopyrightTableDirectory { get; private set; } + public DirectoryEntry GlobalPointerTableDirectory { get; private set; } + public DirectoryEntry ThreadLocalStorageTableDirectory { get; private set; } + public DirectoryEntry LoadConfigTableDirectory { get; private set; } + public DirectoryEntry BoundImportTableDirectory { get; private set; } + public DirectoryEntry ImportAddressTableDirectory { get; private set; } + public DirectoryEntry DelayImportTableDirectory { get; private set; } + public DirectoryEntry CorHeaderTableDirectory { get; private set; } + + #endregion + + internal PEHeader(ref PEBinaryReader reader) + { + PEMagic magic = (PEMagic)reader.ReadUInt16(); + if (magic != PEMagic.PE32 && magic != PEMagic.PE32Plus) + { + throw new BadImageFormatException(MetadataResources.UnknownPEMagicValue); + } + + Magic = magic; + MajorLinkerVersion = reader.ReadByte(); + MinorLinkerVersion = reader.ReadByte(); + SizeOfCode = reader.ReadInt32(); + SizeOfInitializedData = reader.ReadInt32(); + SizeOfUninitializedData = reader.ReadInt32(); + AddressOfEntryPoint = reader.ReadInt32(); + BaseOfCode = reader.ReadInt32(); + + if (magic == PEMagic.PE32Plus) + { + BaseOfData = 0; // not present + } + else + { + Debug.Assert(magic == PEMagic.PE32); + BaseOfData = reader.ReadInt32(); + } + + if (magic == PEMagic.PE32Plus) + { + ImageBase = reader.ReadUInt64(); + } + else + { + ImageBase = reader.ReadUInt32(); + } + + // NT additional fields: + SectionAlignment = reader.ReadInt32(); + FileAlignment = reader.ReadInt32(); + MajorOperatingSystemVersion = reader.ReadUInt16(); + MinorOperatingSystemVersion = reader.ReadUInt16(); + MajorImageVersion = reader.ReadUInt16(); + MinorImageVersion = reader.ReadUInt16(); + MajorSubsystemVersion = reader.ReadUInt16(); + MinorSubsystemVersion = reader.ReadUInt16(); + + // Win32VersionValue (reserved, should be 0) + reader.ReadUInt32(); + + SizeOfImage = reader.ReadInt32(); + SizeOfHeaders = reader.ReadInt32(); + CheckSumOffset = reader.CurrentOffset; + CheckSum = reader.ReadUInt32(); + Subsystem = (Subsystem)reader.ReadUInt16(); + DllCharacteristics = (DllCharacteristics)reader.ReadUInt16(); + + if (magic == PEMagic.PE32Plus) + { + SizeOfStackReserve = reader.ReadUInt64(); + SizeOfStackCommit = reader.ReadUInt64(); + SizeOfHeapReserve = reader.ReadUInt64(); + SizeOfHeapCommit = reader.ReadUInt64(); + } + else + { + SizeOfStackReserve = reader.ReadUInt32(); + SizeOfStackCommit = reader.ReadUInt32(); + SizeOfHeapReserve = reader.ReadUInt32(); + SizeOfHeapCommit = reader.ReadUInt32(); + } + + // loader flags + reader.ReadUInt32(); + + NumberOfRvaAndSizes = reader.ReadInt32(); + + // directory entries: + ExportTableDirectory = new DirectoryEntry(ref reader); + ImportTableDirectory = new DirectoryEntry(ref reader); + ResourceTableDirectory = new DirectoryEntry(ref reader); + ExceptionTableDirectory = new DirectoryEntry(ref reader); + CertificateTableDirectory = new DirectoryEntry(ref reader); + BaseRelocationTableDirectory = new DirectoryEntry(ref reader); + DebugTableDirectory = new DirectoryEntry(ref reader); + CopyrightTableDirectory = new DirectoryEntry(ref reader); + GlobalPointerTableDirectory = new DirectoryEntry(ref reader); + ThreadLocalStorageTableDirectory = new DirectoryEntry(ref reader); + LoadConfigTableDirectory = new DirectoryEntry(ref reader); + BoundImportTableDirectory = new DirectoryEntry(ref reader); + ImportAddressTableDirectory = new DirectoryEntry(ref reader); + DelayImportTableDirectory = new DirectoryEntry(ref reader); + CorHeaderTableDirectory = new DirectoryEntry(ref reader); + + // ReservedDirectory (should be 0, 0) + new DirectoryEntry(ref reader); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeaders.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeaders.cs new file mode 100644 index 0000000..0c07840 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEHeaders.cs @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +namespace System.Reflection.PortableExecutable +{ + /// + /// An object used to read PE (Portable Executable) and COFF (Common Object File Format) headers from a stream. + /// + public sealed class PEHeaders + { + private readonly CoffHeader _coffHeader; + private readonly PEHeader _peHeader; + private readonly ImmutableArray _sectionHeaders; + private readonly CorHeader _corHeader; + private readonly int _metadataStartOffset = -1; + private readonly int _metadataSize; + private readonly int _coffHeaderStartOffset = -1; + private readonly int _corHeaderStartOffset = -1; + private readonly int _peHeaderStartOffset = -1; + + public int SectionsHeadersEndOffset { get; private set; } + + /// + /// Reads PE headers from the current location in the stream. + /// + /// Stream containing PE image starting at the stream's current position and ending at the end of the stream. + /// The data read from stream have invalid format. + /// Error reading from the stream. + /// The stream doesn't support seek operations. + /// is null. + public PEHeaders(Stream peStream) + : this(peStream, null) + { + } + + /// + /// Reads PE headers from the current location in the stream. + /// + /// Stream containing PE image of the given size starting at its current position. + /// Size of the PE image. + /// The data read from stream have invalid format. + /// Error reading from the stream. + /// The stream doesn't support seek operations. + /// is null. + /// Size is negative or extends past the end of the stream. + public PEHeaders(Stream peStream, int size) + : this(peStream, (int?)size) + { + } + + private PEHeaders(Stream peStream, int? sizeOpt) + { + if (peStream == null) + { + throw new ArgumentNullException("peStream"); + } + + if (!peStream.CanRead || !peStream.CanSeek) + { + throw new ArgumentException(MetadataResources.StreamMustSupportReadAndSeek, "peStream"); + } + + int size = PEBinaryReader.GetAndValidateSize(peStream, sizeOpt); + var reader = new PEBinaryReader(peStream, size); + + bool isCoffOnly; + SkipDosHeader(ref reader, out isCoffOnly); + + _coffHeaderStartOffset = reader.CurrentOffset; + _coffHeader = new CoffHeader(ref reader); + + if (!isCoffOnly) + { + _peHeaderStartOffset = reader.CurrentOffset; + _peHeader = new PEHeader(ref reader); + } + + _sectionHeaders = this.ReadSectionHeaders(ref reader); + SectionsHeadersEndOffset = reader.CurrentOffset; + + if (!isCoffOnly) + { + int offset; + if (TryCalculateCorHeaderOffset(size, out offset)) + { + _corHeaderStartOffset = offset; + reader.Seek(offset); + _corHeader = new CorHeader(ref reader); + } + } + + CalculateMetadataLocation(size, out _metadataStartOffset, out _metadataSize); + } + + /// + /// Gets the offset (in bytes) from the start of the PE image to the start of the CLI metadata. + /// or -1 if the image does not contain metadata. + /// + public int MetadataStartOffset + { + get { return _metadataStartOffset; } + } + + /// + /// Gets the size of the CLI metadata 0 if the image does not contain metadata.) + /// + public int MetadataSize + { + get { return _metadataSize; } + } + + /// + /// Gets the COFF header of the image. + /// + public CoffHeader CoffHeader + { + get { return _coffHeader; } + } + + /// + /// Gets the byte offset from the start of the PE image to the start of the COFF header. + /// + public int CoffHeaderStartOffset + { + get { return _coffHeaderStartOffset; } + } + + /// + /// Determines if the image is Coff only. + /// + public bool IsCoffOnly + { + get { return _peHeader == null; } + } + + /// + /// Gets the PE header of the image or null if the image is COFF only. + /// + public PEHeader PEHeader + { + get { return _peHeader; } + } + + /// + /// Gets the byte offset from the start of the image to + /// + public int PEHeaderStartOffset + { + get { return _peHeaderStartOffset; } + } + + /// + /// Gets the PE section headers. + /// + public ImmutableArray SectionHeaders + { + get { return _sectionHeaders; } + } + + /// + /// Gets the CLI header or null if the image does not have one. + /// + public CorHeader CorHeader + { + get { return _corHeader; } + } + + /// + /// Gets the byte offset from the start of the image to the COR header or -1 if the image does not have one. + /// + public int CorHeaderStartOffset + { + get { return _corHeaderStartOffset; } + } + + /// + /// Determines if the image represents a Windows console application. + /// + public bool IsConsoleApplication + { + get + { + return _peHeader != null && _peHeader.Subsystem == Subsystem.WindowsCui; + } + } + + /// + /// Determines if the image represents a dynamically linked library. + /// + public bool IsDll + { + get + { + return (_coffHeader.Characteristics & Characteristics.Dll) != 0; + } + } + + /// + /// Determines if the image represents an executable. + /// + public bool IsExe + { + get + { + return (_coffHeader.Characteristics & Characteristics.Dll) == 0; + } + } + + private bool TryCalculateCorHeaderOffset(long peStreamSize, out int startOffset) + { + if (!TryGetDirectoryOffset(_peHeader.CorHeaderTableDirectory, out startOffset)) + { + startOffset = -1; + return false; + } + + int length = _peHeader.CorHeaderTableDirectory.Size; + if (length < COR20Constants.SizeOfCorHeader) + { + throw new BadImageFormatException(MetadataResources.InvalidCorHeaderSize); + } + + return true; + } + + private void SkipDosHeader(ref PEBinaryReader reader, out bool isCOFFOnly) + { + // Look for DOS Signature "MZ" + ushort dosSig = reader.ReadUInt16(); + + if (dosSig != PEFileConstants.DosSignature) + { + // If image doesn't start with DOS signature, let's assume it is a + // COFF (Common Object File Format), aka .OBJ file. + // See CLiteWeightStgdbRW::FindObjMetaData in ndp\clr\src\MD\enc\peparse.cpp + + if (dosSig != 0 || reader.ReadUInt16() != 0xffff) + { + isCOFFOnly = true; + reader.Seek(0); + } + else + { + // Might need to handle other formats. Anonymous or LTCG objects, for example. + throw new BadImageFormatException(MetadataResources.UnknownFileFormat); + } + } + else + { + isCOFFOnly = false; + } + + if (!isCOFFOnly) + { + // Skip the DOS Header + reader.Seek(PEFileConstants.PESignatureOffsetLocation); + + int ntHeaderOffset = reader.ReadInt32(); + reader.Seek(ntHeaderOffset); + + // Look for PESignature "PE\0\0" + uint ntSignature = reader.ReadUInt32(); + if (ntSignature != PEFileConstants.PESignature) + { + throw new BadImageFormatException(MetadataResources.InvalidPESignature); + } + } + } + + private ImmutableArray ReadSectionHeaders(ref PEBinaryReader reader) + { + int numberOfSections = _coffHeader.NumberOfSections; + if (numberOfSections < 0) + { + throw new BadImageFormatException(MetadataResources.InvalidNumberOfSections); + } + + var builder = ImmutableArray.CreateBuilder(numberOfSections); + + for (int i = 0; i < numberOfSections; i++) + { + builder.Add(new SectionHeader(ref reader)); + } + + return builder.ToImmutable(); + } + + /// + /// Gets the offset (in bytes) from the start of the image to the given directory entry. + /// + /// + /// + /// The section containing the directory could not be found. + /// The section containing the + public bool TryGetDirectoryOffset(DirectoryEntry directory, out int offset) + { + int sectionIndex = GetContainingSectionIndex(directory.RelativeVirtualAddress); + if (sectionIndex < 0) + { + offset = -1; + return false; + } + + int relativeOffset = directory.RelativeVirtualAddress - _sectionHeaders[sectionIndex].VirtualAddress; + + offset = _sectionHeaders[sectionIndex].PointerToRawData + relativeOffset; + return true; + } + + /// + /// Searches sections of the PE image for the one that contains specified Relative Virtual Address. + /// + /// Address. + /// + /// Index of the section that contains , + /// or -1 if there is none. + /// + public int GetContainingSectionIndex(int relativeVirtualAddress) + { + for (int i = 0; i < _sectionHeaders.Length; i++) + { + if (_sectionHeaders[i].VirtualAddress <= relativeVirtualAddress && + relativeVirtualAddress < _sectionHeaders[i].VirtualAddress + _sectionHeaders[i].VirtualSize) + { + return i; + } + } + + return -1; + } + + private int IndexOfSection(string name) + { + for (int i = 0; i < SectionHeaders.Length; i++) + { + if (SectionHeaders[i].Name.Equals(name, StringComparison.Ordinal)) + { + return i; + } + } + + return -1; + } + + private void CalculateMetadataLocation(long peImageSize, out int start, out int size) + { + if (IsCoffOnly) + { + int cormeta = IndexOfSection(".cormeta"); + if (cormeta == -1) + { + start = -1; + size = 0; + return; + } + + start = SectionHeaders[cormeta].PointerToRawData; + size = SectionHeaders[cormeta].SizeOfRawData; + } + else if (_corHeader == null) + { + start = 0; + size = 0; + return; + } + else + { + if (!TryGetDirectoryOffset(_corHeader.MetadataDirectory, out start)) + { + throw new BadImageFormatException(MetadataResources.MissingDataDirectory); + } + + size = _corHeader.MetadataDirectory.Size; + } + + if (start < 0 || + start >= peImageSize || + size <= 0 || + start > peImageSize - size) + { + throw new BadImageFormatException(MetadataResources.InvalidMetadataSectionSpan); + } + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEMemoryBlock.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEMemoryBlock.cs new file mode 100644 index 0000000..990ec61 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEMemoryBlock.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Internal; + +namespace System.Reflection.PortableExecutable +{ + public struct PEMemoryBlock + { + private readonly AbstractMemoryBlock _block; + public readonly int _offset; + + internal PEMemoryBlock(AbstractMemoryBlock block, int offset = 0) + { + Debug.Assert(block != null); + Debug.Assert(offset >= 0 && offset < block.Size); + + _block = block; + _offset = offset; + } + + public unsafe byte* Pointer + { + get + { + return (_block != null) ? _block.Pointer + _offset : null; + } + } + + public int Length + { + get + { + return (_block != null) ? _block.Size - _offset : 0; + } + } + + // TODO: GetBytes (mutable) + + public ImmutableArray GetContent() + { + return (_block != null) ? _block.GetContent(_offset) : ImmutableArray.Empty; + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEReader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEReader.cs new file mode 100644 index 0000000..d19bb13 --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEReader.cs @@ -0,0 +1,450 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Reflection.Internal; +using System.Reflection.Metadata; +using System.Threading; + +namespace System.Reflection.PortableExecutable +{ + /// + /// Portable Executable format reader. + /// + /// + /// The implementation is thread-safe, that is multiple threads can read data from the reader in parallel. + /// Disposal of the reader is not thread-safe (see ). + /// + public sealed class PEReader : IDisposable + { + // May be null in the event that the entire image is not + // deemed necessary and we have been instructed to read + // the image contents without being lazy. + internal MemoryBlockProvider _peImage; + + // If we read the data from the image lazily (peImage != null) we defer reading the PE headers. + private PEHeaders _lazyPEHeaders; + + private AbstractMemoryBlock _lazyMetadataBlock; + private AbstractMemoryBlock _lazyImageBlock; + private AbstractMemoryBlock[] _lazyPESectionBlocks; + + /// + /// Creates a Portable Executable reader over a PE image stored in memory. + /// + /// Pointer to the start of the PE image. + /// The size of the PE image. + /// is . + /// is negative. + /// + /// The memory is owned by the caller and not released on disposal of the . + /// The caller is responsible for keeping the memory alive and unmodified throughout the lifetime of the . + /// The content of the image is not read during the construction of the + /// + public unsafe PEReader(byte* peImage, int size) + { + if (peImage == null) + { + throw new ArgumentNullException("peImage"); + } + + if (size < 0) + { + throw new ArgumentOutOfRangeException("size"); + } + + _peImage = new ExternalMemoryBlockProvider(peImage, size); + } + + /// + /// Creates a Portable Executable reader over a PE image stored in a stream. + /// + /// PE image stream. + /// is null. + /// + /// is specified and the PE headers of the image are invalid. + /// + /// + /// Ownership of the stream is transferred to the upon successful validation of constructor arguments. It will be + /// disposed by the and the caller must not manipulate it. + /// + public PEReader(Stream peStream) + : this(peStream, PEStreamOptions.Default) + { + } + + /// + /// Creates a Portable Executable reader over a PE image stored in a stream beginning at its current position and ending at the end of the stream. + /// + /// PE image stream. + /// + /// Options specifying how sections of the PE image are read from the stream. + /// + /// Unless is specified, ownership of the stream is transferred to the + /// upon successful argument validation. It will be disposed by the and the caller must not manipulate it. + /// + /// Unless or is specified no data + /// is read from the stream during the construction of the . Furthermore, the stream must not be manipulated + /// by caller while the is alive and undisposed. + /// + /// If or , the + /// will have read all of the data requested during construction. As such, if is also + /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the + /// after construction. + /// + /// is null. + /// has an invalid value. + /// + /// is specified and the PE headers of the image are invalid. + /// + public PEReader(Stream peStream, PEStreamOptions options) + : this(peStream, options, (int?)null) + { + } + + /// + /// Creates a Portable Executable reader over a PE image of the given size beginning at the stream's current position. + /// + /// PE image stream. + /// PE image size. + /// + /// Options specifying how sections of the PE image are read from the stream. + /// + /// Unless is specified, ownership of the stream is transferred to the + /// upon successful argument validation. It will be disposed by the and the caller must not manipulate it. + /// + /// Unless or is specified no data + /// is read from the stream during the construction of the . Furthermore, the stream must not be manipulated + /// by caller while the is alive and undisposed. + /// + /// If or , the + /// will have read all of the data requested during construction. As such, if is also + /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the + /// after construction. + /// + /// Size is negative or extends past the end of the stream. + public PEReader(Stream peStream, PEStreamOptions options, int size) + : this(peStream, options, (int?)size) + + { + } + + private unsafe PEReader(Stream peStream, PEStreamOptions options, int? sizeOpt) + { + if (peStream == null) + { + throw new ArgumentNullException("peStream"); + } + + if (!peStream.CanRead || !peStream.CanSeek) + { + throw new ArgumentException(MetadataResources.StreamMustSupportReadAndSeek, "peStream"); + } + + if (!options.IsValid()) + { + throw new ArgumentOutOfRangeException("options"); + } + + long start = peStream.Position; + int size = PEBinaryReader.GetAndValidateSize(peStream, sizeOpt); + + bool closeStream = true; + try + { + bool isFileStream = FileStreamReadLightUp.IsFileStream(peStream); + + if ((options & (PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) == 0) + { + _peImage = new StreamMemoryBlockProvider(peStream, start, size, isFileStream, (options & PEStreamOptions.LeaveOpen) != 0); + closeStream = false; + } + else + { + // Read in the entire image or metadata blob: + if ((options & PEStreamOptions.PrefetchEntireImage) != 0) + { + var imageBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, 0, (int)Math.Min(peStream.Length, int.MaxValue)); + _lazyImageBlock = imageBlock; + _peImage = new ExternalMemoryBlockProvider(imageBlock.Pointer, imageBlock.Size); + + // if the caller asked for metadata initialize the PE headers (calculates metadata offset): + if ((options & PEStreamOptions.PrefetchMetadata) != 0) + { + InitializePEHeaders(); + } + } + else + { + // The peImage is left null, but the lazyMetadataBlock is initialized up front. + _lazyPEHeaders = new PEHeaders(peStream); + _lazyMetadataBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, _lazyPEHeaders.MetadataStartOffset, _lazyPEHeaders.MetadataSize); + } + // We read all we need, the stream is going to be closed. + } + } + finally + { + if (closeStream && (options & PEStreamOptions.LeaveOpen) == 0) + { + peStream.Dispose(); + } + } + } + + /// + /// Creates a Portable Executable reader over a PE image stored in a byte array. + /// + /// PE image. + /// + /// The content of the image is not read during the construction of the + /// + /// is null. + public PEReader(ImmutableArray peImage) + { + if (peImage.IsDefault) + { + throw new ArgumentNullException("peImage"); + } + + _peImage = new ByteArrayMemoryProvider(peImage); + } + + /// + /// Disposes all memory allocated by the reader. + /// + /// + /// can be called multiple times (even in parallel). + /// However, it is not safe to call in parallel with any other operation on the + /// or reading from s retrieved from the reader. + /// + public void Dispose() + { + var image = _peImage; + if (image != null) + { + image.Dispose(); + _peImage = null; + } + + var imageBlock = _lazyImageBlock; + if (imageBlock != null) + { + imageBlock.Dispose(); + _lazyImageBlock = null; + } + + var metadataBlock = _lazyMetadataBlock; + if (metadataBlock != null) + { + metadataBlock.Dispose(); + _lazyMetadataBlock = null; + } + + var peSectionBlocks = _lazyPESectionBlocks; + if (peSectionBlocks != null) + { + foreach (var block in peSectionBlocks) + { + if (block != null) + { + block.Dispose(); + } + } + + _lazyPESectionBlocks = null; + } + } + + /// + /// Gets the PE headers. + /// + /// The headers contain invalid data. + public PEHeaders PEHeaders + { + get + { + if (_lazyPEHeaders == null) + { + InitializePEHeaders(); + } + + return _lazyPEHeaders; + } + } + + private void InitializePEHeaders() + { + Debug.Assert(_peImage != null); + + StreamConstraints constraints; + Stream stream = _peImage.GetStream(out constraints); + + PEHeaders headers; + if (constraints.GuardOpt != null) + { + lock (constraints.GuardOpt) + { + headers = ReadPEHeadersNoLock(stream, constraints.ImageStart, constraints.ImageSize); + } + } + else + { + headers = ReadPEHeadersNoLock(stream, constraints.ImageStart, constraints.ImageSize); + } + + Interlocked.CompareExchange(ref _lazyPEHeaders, headers, null); + } + + private static PEHeaders ReadPEHeadersNoLock(Stream stream, long imageStartPosition, int imageSize) + { + Debug.Assert(imageStartPosition >= 0 && imageStartPosition <= stream.Length); + stream.Seek(imageStartPosition, SeekOrigin.Begin); + return new PEHeaders(stream, imageSize); + } + + /// + /// Returns a view of the entire image as a pointer and length. + /// + /// PE image not available. + private AbstractMemoryBlock GetEntireImageBlock() + { + if (_lazyImageBlock == null) + { + if (_peImage == null) + { + throw new InvalidOperationException(MetadataResources.PEImageNotAvailable); + } + + var newBlock = _peImage.GetMemoryBlock(); + if (Interlocked.CompareExchange(ref _lazyImageBlock, newBlock, null) != null) + { + // another thread created the block already, we need to dispose ours: + newBlock.Dispose(); + } + } + + return _lazyImageBlock; + } + + private AbstractMemoryBlock GetMetadataBlock() + { + if (!HasMetadata) + { + throw new InvalidOperationException(MetadataResources.PEImageDoesNotHaveMetadata); + } + + if (_lazyMetadataBlock == null) + { + Debug.Assert(_peImage != null, "We always have metadata if peImage is not available."); + + var newBlock = _peImage.GetMemoryBlock(PEHeaders.MetadataStartOffset, PEHeaders.MetadataSize); + if (Interlocked.CompareExchange(ref _lazyMetadataBlock, newBlock, null) != null) + { + // another thread created the block already, we need to dispose ours: + newBlock.Dispose(); + } + } + + return _lazyMetadataBlock; + } + + private AbstractMemoryBlock GetPESectionBlock(int index) + { + Debug.Assert(index >= 0 && index < PEHeaders.SectionHeaders.Length); + Debug.Assert(_peImage != null); + + if (_lazyPESectionBlocks == null) + { + Interlocked.CompareExchange(ref _lazyPESectionBlocks, new AbstractMemoryBlock[PEHeaders.SectionHeaders.Length], null); + } + + var newBlock = _peImage.GetMemoryBlock( + PEHeaders.SectionHeaders[index].PointerToRawData, + PEHeaders.SectionHeaders[index].SizeOfRawData); + + if (Interlocked.CompareExchange(ref _lazyPESectionBlocks[index], newBlock, null) != null) + { + // another thread created the block already, we need to dispose ours: + newBlock.Dispose(); + } + + return _lazyPESectionBlocks[index]; + } + + /// + /// Return true if the reader can access the entire PE image. + /// + /// + /// Returns false if the is constructed from a stream and only part of it is prefetched into memory. + /// + public bool IsEntireImageAvailable + { + get { return _lazyImageBlock != null || _peImage != null; } + } + + /// + /// Gets a pointer to and size of the PE image if available (). + /// + /// The entire PE image is not available. + public PEMemoryBlock GetEntireImage() + { + return new PEMemoryBlock(GetEntireImageBlock()); + } + + /// + /// Returns true if the PE image contains CLI metadata. + /// + /// The PE headers contain invalid data. + public bool HasMetadata + { + get { return PEHeaders.MetadataSize > 0; } + } + + /// + /// Loads PE section that contains CLI metadata. + /// + /// The PE image doesn't contain metadata ( returns false). + /// The PE headers contain invalid data. + public PEMemoryBlock GetMetadata() + { + return new PEMemoryBlock(GetMetadataBlock()); + } + + /// + /// Loads PE section that contains the specified into memory + /// and returns a memory block that starts at and ends at the end of the containing section. + /// + /// Relative Virtual Address of the data to read. + /// + /// An empty block if doesn't represent a location in any of the PE sections of this PE image. + /// + /// The PE headers contain invalid data. + public PEMemoryBlock GetSectionData(int relativeVirtualAddress) + { + var sectionIndex = PEHeaders.GetContainingSectionIndex(relativeVirtualAddress); + if (sectionIndex < 0) + { + return default(PEMemoryBlock); + } + + int relativeOffset = relativeVirtualAddress - PEHeaders.SectionHeaders[sectionIndex].VirtualAddress; + int size = PEHeaders.SectionHeaders[sectionIndex].VirtualSize - relativeOffset; + + AbstractMemoryBlock block; + if (_peImage != null) + { + block = GetPESectionBlock(sectionIndex); + } + else + { + block = GetEntireImageBlock(); + relativeOffset += PEHeaders.SectionHeaders[sectionIndex].PointerToRawData; + } + + return new PEMemoryBlock(block, relativeOffset); + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEStreamOptions.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEStreamOptions.cs new file mode 100644 index 0000000..3519e9a --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/PEStreamOptions.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + [Flags] + public enum PEStreamOptions + { + /// + /// By default the stream is disposed when is disposed and sections of the PE image are read lazily. + /// + Default = 0, + + /// + /// Keep the stream open when the is disposed. + /// + LeaveOpen = 1, + + /// + /// Reads metadata section into memory right away. + /// + /// + /// Reading from other sections of the file is not allowed ( is thrown by the ). + /// The underlying file may be closed and even deleted after is constructed. + /// + /// closes the stream automatically by the time the constructor returns unless is specified. + /// + PrefetchMetadata = 1 << 1, + + /// + /// Reads the entire image into memory right away. + /// + /// + /// closes the stream automatically by the time the constructor returns unless is specified. + /// + PrefetchEntireImage = 1 << 2 + } + + internal static class PEStreamOptionsExtensions + { + public static bool IsValid(this PEStreamOptions options) + { + return (options & ~(PEStreamOptions.LeaveOpen | PEStreamOptions.PrefetchEntireImage | PEStreamOptions.PrefetchMetadata)) == 0; + } + } +} diff --git a/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/SectionHeader.cs b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/SectionHeader.cs new file mode 100644 index 0000000..64a375c --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/PortableExecutable/SectionHeader.cs @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection.PortableExecutable +{ + public struct SectionHeader + { + private readonly int _virtualSize; + private readonly string _name; + private readonly int _virtualAddress; + private readonly int _sizeOfRawData; + private readonly int _pointerToRawData; + private readonly int _pointerToRelocations; + private readonly int _pointerToLineNumbers; + private readonly ushort _numberOfRelocations; + private readonly ushort _numberOfLineNumbers; + private readonly SectionCharacteristics _sectionCharacteristics; + + /// + /// An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8 characters long, there is no terminating null. + /// + public string Name { get { return _name; } } + + /// + /// The total size of the section when loaded into memory. + /// If this value is greater than , the section is zero-padded. + /// This field is valid only for PE images and should be set to zero for object files. + /// + public int VirtualSize { get { return _virtualSize; } } + + /// + /// For PE images, the address of the first byte of the section relative to the image base when the + /// section is loaded into memory. For object files, this field is the address of the first byte before + /// relocation is applied; for simplicity, compilers should set this to zero. Otherwise, + /// it is an arbitrary value that is subtracted from offsets during relocation. + /// + public int VirtualAddress { get { return _virtualAddress; } } + + /// + /// The size of the section (for object files) or the size of the initialized data on disk (for image files). + /// For PE images, this must be a multiple of . + /// If this is less than , the remainder of the section is zero-filled. + /// Because the field is rounded but the field is not, + /// it is possible for to be greater than as well. + /// When a section contains only uninitialized data, this field should be zero. + /// + public int SizeOfRawData { get { return _sizeOfRawData; } } + + /// + /// The file pointer to the first page of the section within the COFF file. + /// For PE images, this must be a multiple of . + /// For object files, the value should be aligned on a 4 byte boundary for best performance. + /// When a section contains only uninitialized data, this field should be zero. + /// + public int PointerToRawData { get { return _pointerToRawData; } } + + /// + /// The file pointer to the beginning of relocation entries for the section. + /// This is set to zero for PE images or if there are no relocations. + /// + public int PointerToRelocations { get { return _pointerToRelocations; } } + + /// + /// The file pointer to the beginning of line-number entries for the section. + /// This is set to zero if there are no COFF line numbers. + /// This value should be zero for an image because COFF debugging information is deprecated. + /// + public int PointerToLineNumbers { get { return _pointerToLineNumbers; } } + + /// + /// The number of relocation entries for the section. This is set to zero for PE images. + /// + public ushort NumberOfRelocations { get { return _numberOfRelocations; } } + + /// + /// The number of line-number entries for the section. + /// This value should be zero for an image because COFF debugging information is deprecated. + /// + public ushort NumberOfLineNumbers { get { return _numberOfLineNumbers; } } + + /// + /// The flags that describe the characteristics of the section. + /// + public SectionCharacteristics SectionCharacteristics { get { return _sectionCharacteristics; } } + + internal SectionHeader(ref PEBinaryReader reader) + { + _name = reader.ReadUTF8(PEFileConstants.SizeofSectionName); + _virtualSize = reader.ReadInt32(); + _virtualAddress = reader.ReadInt32(); + _sizeOfRawData = reader.ReadInt32(); + _pointerToRawData = reader.ReadInt32(); + _pointerToRelocations = reader.ReadInt32(); + _pointerToLineNumbers = reader.ReadInt32(); + _numberOfRelocations = reader.ReadUInt16(); + _numberOfLineNumbers = reader.ReadUInt16(); + _sectionCharacteristics = (SectionCharacteristics)reader.ReadUInt32(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/MetadataReader/System.Reflection.cs b/SigningService/Signers/StrongName/MetadataReader/System.Reflection.cs new file mode 100644 index 0000000..5ed114d --- /dev/null +++ b/SigningService/Signers/StrongName/MetadataReader/System.Reflection.cs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Reflection +{ + [Flags] + internal enum MethodSemanticsAttributes + { + /// + /// Used to modify the value of the property. + /// CLS-compliant setters are named with set_ prefix. + /// + Setter = 0x0001, + + /// + /// Used to read the value of the property. + /// CLS-compliant getters are named with get_ prefix. + /// + Getter = 0x0002, + + /// + /// Other method for property (not getter or setter) or event (not adder, remover, or raiser). + /// + Other = 0x0004, + + /// + /// Used to add a handler for an event. + /// Corresponds to the AddOn flag in the Ecma 335 CLI specification. + /// CLS-compliant adders are named with add_ prefix. + /// + Adder = 0x0008, + + /// + /// Used to remove a handler for an event. + /// Corresponds to the RemoveOn flag in the Ecma 335 CLI specification. + /// CLS-compliant removers are named with remove_ prefix. + /// + Remover = 0x0010, + + /// + /// Used to indicate that an event has occurred. + /// Corresponds to the Fire flag in the Ecma 335 CLI specification. + /// CLS-compliant raisers are named with raise_ prefix. + /// + Raiser = 0x0020, + } + + /// + /// Specifies the security actions that can be performed using declarative security. + /// + public enum DeclarativeSecurityAction : short + { + /// + /// No declarative security action. + /// + None = 0x0000, + + /// + /// Check that all callers in the call chain have been granted specified permission, + /// + Demand = 0x0002, + + /// + /// The calling code can access the resource identified by the current permission object, even if callers higher in the stack have not been granted permission to access the resource. + /// + Assert = 0x0003, + + /// + /// Without further checks refuse Demand for the specified permission. + /// + Deny = 0x0004, + + /// + /// Without further checks, refuse Demand for all permissions other than those specified. + /// + PermitOnly = 0x0005, + + /// + /// Check that the immediate caller has been granted the specified permission; + /// + LinkDemand = 0x0006, + + /// + /// The derived class inheriting the class or overriding a method is required to have been granted the specified permission. + /// + InheritanceDemand = 0x0007, + + /// + /// The request for the minimum permissions required for code to run. This action can only be used within the scope of the assembly. + /// + RequestMinimum = 0x0008, + + /// + /// The request for additional permissions that are optional (not required to run). This request implicitly refuses all other permissions not specifically requested. This action can only be used within the scope of the assembly. + /// + RequestOptional = 0x0009, + + /// + /// The request that permissions that might be misused will not be granted to the calling code. This action can only be used within the scope of the assembly. + /// + RequestRefuse = 0x000A, + // Wait for an actual need before exposing these. They all have ilasm keywords, but some are missing from the CLI spec and + // and none are defined in System.Security.Permissions.SecurityAction. + //Request = 0x0001, + //PrejitGrant = 0x000B, + //PrejitDeny = 0x000C, + //NonCasDemand = 0x000D, + //NonCasLinkDemand = 0x000E, + //NonCasInheritanceDemand = 0x000F, + } + + [Flags] + public enum MethodImportAttributes : short + { + None = 0x0, + ExactSpelling = 0x0001, + BestFitMappingDisable = 0x0020, + BestFitMappingEnable = 0x0010, + BestFitMappingMask = 0x0030, + CharSetAnsi = 0x0002, + CharSetUnicode = 0x0004, + CharSetAuto = 0x0006, + CharSetMask = 0x0006, + ThrowOnUnmappableCharEnable = 0x1000, + ThrowOnUnmappableCharDisable = 0x2000, + ThrowOnUnmappableCharMask = 0x3000, + SetLastError = 0x0040, + CallingConventionWinApi = 0x0100, + CallingConventionCDecl = 0x0200, + CallingConventionStdCall = 0x0300, + CallingConventionThisCall = 0x0400, + CallingConventionFastCall = 0x0500, + CallingConventionMask = 0x0700, + } + + [Flags] + public enum ManifestResourceAttributes + { + /// + /// The Resource is exported from the Assembly + /// + Public = 0x00000001, + + /// + /// The Resource is not exported from the Assembly + /// + Private = 0x00000002, + + /// + /// Masks just the visibility-related attributes. + /// + VisibilityMask = 0x00000007, // Although it is odd that there is a 3rd bit with no corresponding flag, it is defined this way by the CLI spec. + } + + /// + /// Specifies all the hash algorithms used for hashing assembly files and for generating the strong name. + /// + public enum AssemblyHashAlgorithm + { + /// + /// A mask indicating that there is no hash algorithm. If you specify None for a multi-module assembly, the common language runtime defaults to the SHA1 algorithm, since multi-module assemblies need to generate a hash. + /// + None = 0, + + /// + /// Retrieves the MD5 message-digest algorithm. MD5 was developed by Rivest in 1991. It is basically MD4 with safety-belts and while it is slightly slower than MD4, it helps provide more security. The algorithm consists of four distinct rounds, which has a slightly different design from that of MD4. Message-digest size, as well as padding requirements, remain the same. + /// + MD5 = 0x8003, + + /// + /// Retrieves a revision of the Secure Hash Algorithm that corrects an unpublished flaw in SHA. + /// + Sha1 = 0x8004, + + /// + /// Retrieves a version of the Secure Hash Algorithm with a hash size of 256 bits. + /// + Sha256 = 0x800c, + + /// + /// Retrieves a version of the Secure Hash Algorithm with a hash size of 384 bits. + /// + Sha384 = 0x800d, + + /// + /// Retrieves a version of the Secure Hash Algorithm with a hash size of 512 bits. + /// + Sha512 = 0x800e + } + + [Flags] + public enum AssemblyFlags + { + /// + /// The assembly reference holds the full (unhashed) public key. + /// Not applicable on assembly definition. + /// + PublicKey = 0x00000001, + + /// + /// The implementation of the referenced assembly used at runtime is not expected to match the version seen at compile time. + /// + Retargetable = 0x00000100, + + /// + /// The assembly contains Windows Runtime code. + /// + WindowsRuntime = 0x00000200, + + /// + /// Content type mask. Masked bits correspond to values of . + /// + ContentTypeMask = 0x00000e00, + + /// + /// Specifies that just-in-time (JIT) compiler optimization is disabled for the assembly. + /// + DisableJitCompileOptimizer = 0x4000, + + /// + /// Specifies that just-in-time (JIT) compiler tracking is enabled for the assembly. + /// + EnableJitCompileTracking = 0x8000, + } + + internal static class TypeAttributesExtensions + { + // This flag will be added to the BCL (Bug #1041207), but we still + // need to define a copy here for downlevel portability. + private const TypeAttributes Forwarder = (TypeAttributes)0x00200000; + + // This mask is the fastest way to check if a type is nested from its flags, + // but it should not be added to the BCL enum as its semantics can be misleading. + // Consider, for example, that (NestedFamANDAssem & NestedMask) == NestedFamORAssem. + // Only comparison of the masked value to 0 is meaningful, which is different from + // the other masks in the enum. + private const TypeAttributes NestedMask = (TypeAttributes)0x00000006; + + public static bool IsForwarder(this TypeAttributes flags) + { + return (flags & Forwarder) != 0; + } + + public static bool IsNested(this TypeAttributes flags) + { + return (flags & NestedMask) != 0; + } + } +} diff --git a/SigningService/Signers/StrongName/PublicKeyBlob.cs b/SigningService/Signers/StrongName/PublicKeyBlob.cs new file mode 100644 index 0000000..17f9d00 --- /dev/null +++ b/SigningService/Signers/StrongName/PublicKeyBlob.cs @@ -0,0 +1,177 @@ +using SigningService.Extensions; +using SigningService.Models; +using System; +using System.IO; +using System.Reflection; +using System.Security.Cryptography; + +namespace SigningService.Signers.StrongName +{ + // Public Key Blob should look as following: + // 12 bytes header: + // - Signature Algorithm Id (4 bytes) + // - Hash Algorithm Id (4 bytes) + // - Public Key Struct Size (4 bytes) + // + // Public Key struct + // - Prefix (4 bytes) -> (1b - type, 1b - version, 2b - reserved) + // - Signature Algorithm Id (4 bytes) + // - "RSA1" (4 bytes) + // - Modulus size in bits (4 bytes) + // - Exponent (4 bytes) + // - Modulus bytes (var size) + internal class PublicKeyBlob + { + private struct PublicKeyBlobLayout + { + public const byte TypePublicKeyBlob = 0x06; + public const UInt32 Rsa1 = 0x31415352; + public const int HeaderSize = 12; + public const int StructSizeMinusModulusSize = 32; + + public PublicKeyBlobLayout(byte[] publicKeyBlob) : this() + { + using (MemoryStream ms = new MemoryStream(publicKeyBlob)) + { + BinaryReader binaryReader = new BinaryReader(ms); + + AlgId = binaryReader.ReadUInt32(); + HashAlgorithm = (AssemblyHashAlgorithm)binaryReader.ReadUInt32(); + PublicKeyStructSize = binaryReader.ReadUInt32(); + + Type = binaryReader.ReadByte(); + Version = binaryReader.ReadByte(); + Reserved = binaryReader.ReadUInt16(); + KeyAlg = binaryReader.ReadUInt32(); + Magic = binaryReader.ReadUInt32(); + ModulusBitLength = binaryReader.ReadInt32(); + PublicExponent = binaryReader.ReadBytes(4); + Modulus = binaryReader.ReadBytes(ModulusBitLength / 8); + Modulus.ReverseInplace(); + } + } + + // header + public UInt32 AlgId; + public AssemblyHashAlgorithm HashAlgorithm; + public UInt32 PublicKeyStructSize; + +#region PUBLICKEYBLOB https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601%28v=vs.85%29.aspx +#region PUBLICKEYSTRUC https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453%28v=vs.85%29.aspx + // blob header + public byte Type; + public byte Version; + public UInt16 Reserved; + public UInt32 KeyAlg; +#endregion + +#region RSAPUBKEY https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685%28v=vs.85%29.aspx + // RSA Public Key + public UInt32 Magic; + public Int32 ModulusBitLength; + public byte[] PublicExponent; +#endregion + + public byte[] Modulus; +#endregion + } + + private PublicKeyBlobLayout data; + + public PublicKeyBlob(byte[] publicKeyBlob) + { + data = new PublicKeyBlobLayout(publicKeyBlob); + + if (data.Type != PublicKeyBlobLayout.TypePublicKeyBlob) + { + ExceptionsHelper.ThrowBadImageFormatException("Expected public key blob!"); + } + + if (data.Magic != PublicKeyBlobLayout.Rsa1) + { + ExceptionsHelper.ThrowBadImageFormatException("Only RSA1 is supported!"); + } + + if ((PublicKeyBlobLayout.HeaderSize + data.PublicKeyStructSize != publicKeyBlob.Length) + || (PublicKeyBlobLayout.StructSizeMinusModulusSize + data.Modulus.Length != publicKeyBlob.Length)) + { + ExceptionsHelper.ThrowBadImageFormatException("Invalid size of public key blob!"); + } + + Blob = publicKeyBlob; + PublicKey = new PublicKey(data.PublicExponent, data.Modulus); + _publicKeyToken = new Lazy(GetPublicKeyToken); + } + + public PublicKeyBlob(string publicKeyBlobHex) + : this(publicKeyBlobHex.FromHexToByteArray()) { } + + private Lazy _publicKeyToken; + public byte[] Blob { get; private set; } + public PublicKey PublicKey { get; private set; } + public string PublicKeyToken { get { return _publicKeyToken.Value; } } + public AssemblyHashAlgorithm HashAlgorithm { get { return data.HashAlgorithm; } } + + private string GetPublicKeyToken() + { + byte[] ret = new byte[8]; + HashAlgorithm sha1 = SHA1.Create(); + + sha1.TransformFinalBlock(Blob, 0, Blob.Length); + + for (int i = 0; i < 8; i++) + { + ret[i] = sha1.Hash[sha1.Hash.Length - i - 1]; + } + + return ret.ToHex(); + } + + /// + /// Hashes the data, decrypts the hash and compares + /// + /// + /// + public bool VerifyData(byte[] data, byte[] signature) + { + //byte[] decryptedHash = PublicKey.Encrypt(encryptedHash); + HashAlgorithm hashAlgorithm = HashingHelpers.CreateHashAlgorithm(HashAlgorithm); + if (hashAlgorithm == null) + { + ExceptionsHelper.ThrowArgumentOutOfRange("HashAlgorithm"); + } + + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + RSAParameters rsap = rsa.ExportParameters(false); + // Trailing zeros do not change Exponent/Modulus value + // but cause CryptoProvider to throw + rsap.Exponent = RemoveTrailingZeros(PublicKey.Exponent); + rsap.Modulus = RemoveTrailingZeros(PublicKey.Modulus); + rsa.ImportParameters(rsap); + + return rsa.VerifyData(data, hashAlgorithm.GetType(), signature); + } + + private static byte[] RemoveTrailingZeros(byte[] bytes) + { + int lastByte = bytes.Length - 1; + for (; lastByte > 0; lastByte--) + { + if (bytes[lastByte] != 0) + { + break; + } + } + + byte[] ret = new byte[lastByte + 1]; + Array.Copy(bytes, 0, ret, 0, ret.Length); + + return ret; + } + + public override string ToString() + { + return Blob.ToHex(); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/SectionInfo.cs b/SigningService/Signers/StrongName/SectionInfo.cs new file mode 100644 index 0000000..4f874fc --- /dev/null +++ b/SigningService/Signers/StrongName/SectionInfo.cs @@ -0,0 +1,17 @@ +using SigningService.Extensions; + +namespace SigningService.Signers.StrongName +{ + internal class SectionInfo + { + public string Name; + public int Offset; + public int Size; + + public override string ToString() + { + string name = Name.RemoveSpecialCharacters(); + return string.Format("SECTION(Name = {0}, Start = {1}, Size = {2})", name, Offset, Size); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/StrongNameSigner.cs b/SigningService/Signers/StrongName/StrongNameSigner.cs new file mode 100644 index 0000000..2e1abf8 --- /dev/null +++ b/SigningService/Signers/StrongName/StrongNameSigner.cs @@ -0,0 +1,80 @@ +using SigningService.Agents; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; + +namespace SigningService.Signers.StrongName +{ + public class StrongNameSigner : IPackagePartSigner + { + private IKeyVaultAgent _keyVaultAgent; + + public StrongNameSigner(IKeyVaultAgent keyVaultAgent) + { + _keyVaultAgent = keyVaultAgent; + } + + public async Task TrySignAsync(Stream peStream) + { + StrongNameSignerHelper strongNameSigner = new StrongNameSignerHelper(peStream); + if (strongNameSigner.CanSign) + { + if (!SupportsHashAlgorithm(strongNameSigner.SignaturePublicKeyBlob.HashAlgorithm)) + { + return false; + } + + byte[] hash = strongNameSigner.PrepareForSigningAndComputeHash(); + + string keyId = await GetKeyVaultId(strongNameSigner); + if (keyId == null) + { + return false; + } + + byte[] signature = await _keyVaultAgent.SignAsync(keyId, hash); + if (strongNameSigner.StrongNameSignatureSize != signature.Length) + { + return false; + } + + strongNameSigner.StrongNameSignature = signature; + return true; + } + + return false; + } + + public async Task CanSignAsync(Stream peStream) + { + StrongNameSignerHelper strongNameSigner = new StrongNameSignerHelper(peStream); + if (!strongNameSigner.CanSign) + { + return false; + } + + string keyId = await GetKeyVaultId(strongNameSigner); + return keyId != null; + } + + private static bool SupportsHashAlgorithm(AssemblyHashAlgorithm hashAlgorithm) + { + switch (hashAlgorithm) + { + case AssemblyHashAlgorithm.Sha256: + case AssemblyHashAlgorithm.Sha384: + case AssemblyHashAlgorithm.Sha512: + return true; + default: return false; + } + } + + /// + /// Gets KeyVault KeyId related to signature public key + /// + internal async Task GetKeyVaultId(StrongNameSignerHelper strongNameSigner) + { + return await _keyVaultAgent.GetRsaKeyIdAsync(strongNameSigner.SignaturePublicKeyBlob.PublicKey.Exponent, strongNameSigner.SignaturePublicKeyBlob.PublicKey.Modulus); + } + } +} \ No newline at end of file diff --git a/SigningService/Signers/StrongName/StrongNameSignerException.cs b/SigningService/Signers/StrongName/StrongNameSignerException.cs new file mode 100644 index 0000000..423b8b8 --- /dev/null +++ b/SigningService/Signers/StrongName/StrongNameSignerException.cs @@ -0,0 +1,10 @@ +using System; + +namespace SigningService.Signers.StrongName +{ + public class StrongNameSignerException : Exception + { + public StrongNameSignerException(string message) : base(message) { } + public StrongNameSignerException(string format, params object[] args) : base(string.Format(format, args)) { } + } +} diff --git a/SigningService/Signers/StrongName/StrongNameSignerHelper.cs b/SigningService/Signers/StrongName/StrongNameSignerHelper.cs new file mode 100644 index 0000000..47914a4 --- /dev/null +++ b/SigningService/Signers/StrongName/StrongNameSignerHelper.cs @@ -0,0 +1,360 @@ +using SigningService.Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection.PortableExecutable; +using System.Security.Cryptography; +using System.Text; + +namespace SigningService.Signers.StrongName +{ + internal class StrongNameSignerHelper + { + private Stream _peStream; + + private bool _strongNameSignedBitSet = false; + private bool _strongNameSignedBitOverwritten = false; + + // Lazy fields + private Lazy _hashAlgorithm; + private Lazy _dataExtractor; + private Lazy> _hashingBlocks; + + public StrongNameSignerHelper(Stream peStream) + { + _peStream = peStream; + _dataExtractor = new Lazy(InitDataExtractor); + _hashAlgorithm = new Lazy(InitHashAlgorithm); + _hashingBlocks = new Lazy>(InitHashingBlocks); + } + +#region StrongNameSignature + public bool CanEmbedSignature { get { return CanHash & _peStream.CanWrite; } } + public bool HasStrongNameSignature + { + get + { + if (!HasStrongNameSignatureDirectory) + { + return false; + } + + return StrongNameSignedFlag; + } + } + public bool HasStrongNameSignatureDirectory { get { return _dataExtractor.Value.HasStrongNameSignatureDirectory; } } + public int StrongNameSignatureSize { get { return _dataExtractor.Value.StrongNameSignatureDirectorySize; } } + public byte[] StrongNameSignature { get { return GetStrongNameSignature(); } set { SetStrongNameSignature(value); } } + private void SetStrongNameSignature(byte[] signature) + { + if (signature == null) + { + throw new ArgumentNullException("signature"); + } + + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + + if (!HasStrongNameSignatureDirectory) + { + ExceptionsHelper.ThrowNoStrongNameSignatureDirectory(); + return; + } + + if (dataExtractor.StrongNameSignatureDirectorySize != signature.Length) + { + ExceptionsHelper.ThrowStrongNameSignatureDirectorySizeIsDifferentThanProvidedSignature(dataExtractor.StrongNameSignatureDirectorySize, signature.Length); + return; + } + + ExceptionsHelper.ThrowIfStreamNotWritable(_peStream); + + _peStream.Seek(dataExtractor.StrongNameSignatureDirectoryOffset, SeekOrigin.Begin); + _peStream.Write(signature, 0, signature.Length); + } + private byte[] GetStrongNameSignature() + { + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + if (!HasStrongNameSignatureDirectory) + { + ExceptionsHelper.ThrowNoStrongNameSignatureDirectory(); + return null; + } + + _peStream.Seek(dataExtractor.StrongNameSignatureDirectoryOffset, SeekOrigin.Begin); + int left = dataExtractor.StrongNameSignatureDirectorySize; + byte[] signature = new byte[left]; + while (left > 0) + { + int bytesRead = _peStream.Read(signature, signature.Length - left, signature.Length); + if (bytesRead <= 0) + { + ExceptionsHelper.ThrowUnexpectedEndOfStream(_peStream.Position); + return null; + } + left -= bytesRead; + } + + return signature; + } + + public void EmbedEmptyStrongNameSignature() + { + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + byte[] signature = new byte[dataExtractor.StrongNameSignatureDirectorySize]; + SetStrongNameSignature(signature); + } + public void RemoveStrongNameSignature() + { + StrongNameSignedFlag = false; + EmbedEmptyStrongNameSignature(); + } +#endregion + +#region StrongNameSigned flag + public bool StrongNameSignedFlag { get { return GetStrongNameSignedFlag(); } set { SetStrongNameSignedFlag(_peStream, value); } } + + private bool GetStrongNameSignedFlag() + { + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + return _strongNameSignedBitOverwritten ? _strongNameSignedBitSet : dataExtractor.HasStrongNameSignedFlag; + } + + private void SetStrongNameSignedFlag(Stream writablePEStream, bool value) + { + ExceptionsHelper.ThrowIfStreamNotWritable(writablePEStream); + + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + + using (BinaryWriter bw = new BinaryWriter(writablePEStream, Encoding.ASCII, leaveOpen : true)) + { + bw.Seek(dataExtractor.CorFlagsOffset, SeekOrigin.Begin); + CorFlags corFlags = dataExtractor.CorFlagsValue; + if (value) + { + corFlags |= CorFlags.StrongNameSigned; + } + else + { + corFlags &= ~(CorFlags.StrongNameSigned); + } + bw.Write((UInt32)(corFlags)); + } + + if (writablePEStream == _peStream) + { + _strongNameSignedBitSet = value; + _strongNameSignedBitOverwritten = true; + } + } +#endregion + +#region Hashing + public bool CanHash + { + get + { + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + bool ret = _peStream.CanSeek && _peStream.CanRead; + ret &= dataExtractor.HasStrongNameSignatureDirectory; + ret &= _hashAlgorithm.Value != null; + return ret; + } + } + + public bool CanSign + { + get + { + return CanHash && CanEmbedSignature && VerifyCounterSignature() && !StrongNameSignedFlag; + } + } + + public byte[] ComputeHash() + { + if (!CanHash) + { + ExceptionsHelper.ThrowAssemblyNotHashable(); + } + + using (MemoryStream ms = new MemoryStream()) + { + _peStream.Seek(0, SeekOrigin.Begin); + _peStream.CopyTo(ms); + return PrepareForSigningAndComputeHash(ms); + } + } + + public byte[] PrepareForSigningAndComputeHash() + { + return PrepareForSigningAndComputeHash(_peStream); + } + + private byte[] PrepareForSigningAndComputeHash(Stream writablePEStream) + { + ExceptionsHelper.ThrowIfStreamNotWritable(writablePEStream); + + PrepareForSigning(writablePEStream); + return HashingHelpers.CalculateAssemblyHash(writablePEStream, _hashAlgorithm.Value, _hashingBlocks.Value); + } + + private void PrepareForSigning(Stream writablePEStream) + { + SetStrongNameSignedFlag(writablePEStream, true); + EraseChecksum(writablePEStream); + } +#endregion + +#region Public Key Blobs + public bool HasUniqueSignatureAndIdentityPublicKeyBlobs { get { return AssemblySignatureKeyAttributePublicKeyBlob != null; } } + public PublicKeyBlob SignaturePublicKeyBlob + { + get + { + if (HasUniqueSignatureAndIdentityPublicKeyBlobs) + { + return AssemblySignatureKeyAttributePublicKeyBlob; + } + else + { + return AssemblyDefinitionPublicKeyBlob; + } + } + } + public PublicKeyBlob IdentityPublicKeyBlob { get { return AssemblyDefinitionPublicKeyBlob; } } + public PublicKeyBlob AssemblyDefinitionPublicKeyBlob { get { return _dataExtractor.Value.AssemblyDefinitionPublicKeyBlob; } } + public PublicKeyBlob AssemblySignatureKeyAttributePublicKeyBlob { get { return _dataExtractor.Value.AssemblySignatureKeyAttributePublicKeyBlob; } } + + public byte[] CounterSignature { get { return _dataExtractor.Value.AssemblySignatureKeyAttributeCounterSignatureBlob; } } + public bool VerifyCounterSignature() + { + if (HasUniqueSignatureAndIdentityPublicKeyBlobs) + { + return IdentityPublicKeyBlob.VerifyData(SignaturePublicKeyBlob.Blob, CounterSignature); + } + + // If no counter signature then verification passes since there is nothing to verify + return true; + } + +#endregion + +#region Lazy fields initializers + /// + /// Initializes lazy private field _dataExtractor + /// + /// Data extractor for PE file with CLI metadata + private AssemblyMetadataExtractor InitDataExtractor() + { + return new AssemblyMetadataExtractor(_peStream); + } + + /// + /// Initializes lazy private field _hashAlgorithm + /// + /// Instance of the System.Security.Cryptography.HashAlgorithm related to signature public key + private HashAlgorithm InitHashAlgorithm() + { + return HashingHelpers.CreateHashAlgorithm(SignaturePublicKeyBlob.HashAlgorithm); + } + + /// + /// Initializes lazy private field _hashingBlocks which decides what parts of PE will be hashed + /// + private List InitHashingBlocks() + { + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + + List hashingBlocks = new List(16); + + hashingBlocks.Add(new HashingBlock(HashingBlockHashing.Hash, "PE Headers", 0, dataExtractor.PaddingBetweenTheSectionHeadersAndSectionsOffset)); + foreach (var section in dataExtractor.SectionsInfo) + { + string name = string.Format("Section {0}", section.Name); + hashingBlocks.Add(new HashingBlock(HashingBlockHashing.Hash, name, section.Offset, section.Size)); + } + + hashingBlocks.Add(new HashingBlock(HashingBlockHashing.HashZeros, "Checksum", dataExtractor.ChecksumOffset, dataExtractor.ChecksumSize)); + + // According to ECMA-335 this block should be zeroed and hashed (HashingBlockHashing.HashZeros) + // For compat reasons we fully hash it + //specialHashingBlocks.Add(new HashingBlock(HashingBlockHashing.Hash, "StrongNameSignatureDirectory header", StrongNameSignatureDirectoryHeaderOffset, StrongNameSignatureDirectoryHeaderSize)); + + hashingBlocks.Add(new HashingBlock(HashingBlockHashing.HashZeros, "CertificateTableDirectory header", dataExtractor.CertificateTableDirectoryHeaderOffset, dataExtractor.CertificateTableDirectoryHeaderSize)); + + if (dataExtractor.HasStrongNameSignatureDirectory) + { + hashingBlocks.Add(new HashingBlock(HashingBlockHashing.Skip, "StrongNameSignatureDirectory", dataExtractor.StrongNameSignatureDirectoryOffset, dataExtractor.StrongNameSignatureDirectorySize)); + } + else + { + ExceptionsHelper.ThrowNoStrongNameSignatureDirectory(); + } + + // In theory we should be hashing it, in practice in some cases it might be past the last section + // and for compat reasons we do not. + //if (HasCertificateTableDirectory) + //{ + // specialHashingBlocks.Add(new DataBlock(DataBlockHashing.Hash, "CertificateTableDirectory", CertificateTableDirectoryOffset, CertificateTableDirectorySize)); + //} + + return HashingHelpers.SortAndJoinIntersectingHashingBlocks(hashingBlocks); + } +#endregion + +#region Checksum + public void EraseChecksum() + { + EraseChecksum(_peStream); + } + + private void EraseChecksum(Stream writablePEStream) + { + ExceptionsHelper.ThrowIfStreamNotWritable(writablePEStream); + + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + + // 0-initialized byte array + byte[] newChecksum = new byte[dataExtractor.ChecksumSize]; + writablePEStream.Seek(dataExtractor.ChecksumOffset, SeekOrigin.Begin); + writablePEStream.Write(newChecksum, 0, newChecksum.Length); + } +#endregion + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + AssemblyMetadataExtractor dataExtractor = _dataExtractor.Value; + + sb.AppendLine("Signature directory size: {0}", dataExtractor.StrongNameSignatureDirectorySize); + sb.AppendLine("AssemblyDefinition hash algorithm: {0}", AssemblyDefinitionPublicKeyBlob.HashAlgorithm); + sb.AppendLine("Identity public key: {0}", IdentityPublicKeyBlob.ToString()); + sb.AppendLine("Identity public key: {0}", IdentityPublicKeyBlob.PublicKey.ToString()); + if (HasUniqueSignatureAndIdentityPublicKeyBlobs) + { + sb.AppendLine("Signature public key: {0}", SignaturePublicKeyBlob.ToString()); + sb.AppendLine("Signature public key: {0}", SignaturePublicKeyBlob.PublicKey.ToString()); + sb.AppendLine("Counter signature: {0}", CounterSignature.ToHex()); + sb.AppendLine("AssemblySignatureKeyAttribute hash algorithm: {0}", AssemblySignatureKeyAttributePublicKeyBlob.HashAlgorithm); + + } + byte[] hash = ComputeHash(); + + sb.AppendLine("Computed hash size: {0}", hash.Length); + sb.AppendLine("Computed hash: {0}", hash.ToHex()); + + foreach (var block in _hashingBlocks.Value) + { + sb.AppendLine(block.ToString()); + } + + sb.AppendLine("Number of sections = {0}", dataExtractor.NumberOfSections); + sb.AppendLine("SectionsHeadersEndOffset = {0}", dataExtractor.SectionsHeadersEndOffset); + foreach (SectionInfo section in dataExtractor.SectionsInfo) + { + sb.AppendLine(section.ToString()); + } + + return sb.ToString(); + } + } +} diff --git a/SigningService/SigningService.csproj b/SigningService/SigningService.csproj index 41fd7cc..b796d05 100644 --- a/SigningService/SigningService.csproj +++ b/SigningService/SigningService.csproj @@ -30,6 +30,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -143,6 +144,10 @@ ..\packages\Swashbuckle.Core.5.0.0\lib\net40\Swashbuckle.Core.dll + + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + ..\packages\System.IdentityModel.Tokens.Jwt.4.0.0\lib\net45\System.IdentityModel.Tokens.Jwt.dll @@ -222,12 +227,14 @@ + + Global.asax - + @@ -237,7 +244,142 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SigningService/StrongNameSigner.cs b/SigningService/StrongNameSigner.cs deleted file mode 100644 index 0b14788..0000000 --- a/SigningService/StrongNameSigner.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.IO.Packaging; -using System.Threading.Tasks; -using SigningService.Agents; - -namespace SigningService -{ - public class StrongNameSigner : IPackagePartSigner - { - private readonly IKeyVaultAgent _keyVaultAgent; - - public StrongNameSigner(IKeyVaultAgent keyVaultAgent) - { - _keyVaultAgent = keyVaultAgent; - } - - public bool TrySign(PackagePart packagePart) - { - if (!CanSign(packagePart)) - return false; - - var digest = GetDigest(packagePart); - - var signedDigest = _keyVaultAgent.Sign(digest); - - InsertSignedDigest(packagePart, signedDigest); - - return true; - } - - private static bool CanSign(PackagePart packagePart) - { - if (!IsAssembly(packagePart)) - { - return false; - } - - if (IsSigned(packagePart)) - { - return false; - } - - return true; - } - - private static bool IsSigned(PackagePart packagePart) - { - throw new NotImplementedException(); - } - - private static bool IsAssembly(PackagePart packagePart) - { - throw new NotImplementedException(); - } - - private void InsertSignedDigest(PackagePart packagePart, Task signedDigest) - { - throw new NotImplementedException(); - } - - private byte[] GetDigest(PackagePart packagePart) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/SigningService/packages.config b/SigningService/packages.config index 68f47d8..919a103 100644 --- a/SigningService/packages.config +++ b/SigningService/packages.config @@ -32,6 +32,7 @@ +