├── test ├── pch.cpp ├── pch.h ├── main.cpp ├── database.cpp ├── filter.cpp ├── winmd.sln ├── cache.cpp └── winmd.vcxproj ├── .gitignore ├── nuget ├── SignConfig.xml ├── readme.md ├── readme.txt ├── Microsoft.Windows.WinMD.props └── Microsoft.Windows.WinMD.nuspec ├── CODE_OF_CONDUCT.md ├── src ├── winmd_reader.h └── impl │ ├── winmd_reader │ ├── type_helpers.h │ ├── index.h │ ├── filter.h │ ├── helpers.h │ ├── pe.h │ ├── key.h │ ├── enum_traits.h │ ├── cache.h │ ├── view.h │ ├── enum.h │ ├── table.h │ ├── custom_attribute.h │ ├── schema.h │ ├── column.h │ ├── signature.h │ └── flags.h │ └── base.h ├── .github └── workflows │ └── stale.yml ├── .config └── 1espt │ └── PipelineAutobaseliningConfig.yml ├── LICENSE ├── README.md ├── .pipelines ├── SyncMirror-Pipeline.yml └── Pipeline.yml ├── SECURITY.md └── vs └── winmd.natvis /test/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .vs 3 | x86 4 | x64 5 | *.user 6 | -------------------------------------------------------------------------------- /test/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "catch.hpp" 4 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_RUNNER 2 | #include "catch.hpp" 3 | 4 | int main(int const argc, char** argv) 5 | { 6 | return Catch::Session().run(argc, argv); 7 | } 8 | -------------------------------------------------------------------------------- /nuget/SignConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /nuget/readme.md: -------------------------------------------------------------------------------- 1 | # Microsoft.Windows.WinMD NuGet Package 2 | 3 | ## Overview 4 | 5 | Please visit [Microsoft.Windows.WinMD](https://www.nuget.org/packages/Microsoft.Windows.WinMD/) for official Microsoft-signed builds of the NuGet package. 6 | 7 | The Microsoft.Windows.WinMD NuGet package provides a pure C++ header metadata parsing library. Adding a reference to this package adds the library to the project's additional include directories. For details on library use, please consult the Microsoft.Windows.WinMD github repo's [readme.md](https://github.com/microsoft/winmd/blob/master/README.md). 8 | -------------------------------------------------------------------------------- /nuget/readme.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | Microsoft.Windows.WinMD C++ metadata parsing library 3 | ======================================================================== 4 | 5 | The Microsoft.Windows.WinMD NuGet package provides a pure C++ header metadata parsing library. 6 | Adding a reference to this package adds the library to the project's additional include directories. 7 | 8 | ======================================================================== 9 | For more information, visit: 10 | https://github.com/microsoft/winmd/ 11 | ======================================================================== 12 | -------------------------------------------------------------------------------- /src/winmd_reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "impl/base.h" 4 | #include "impl/winmd_reader/pe.h" 5 | #include "impl/winmd_reader/view.h" 6 | #include "impl/winmd_reader/enum.h" 7 | #include "impl/winmd_reader/enum_traits.h" 8 | #include "impl/winmd_reader/flags.h" 9 | #include "impl/winmd_reader/table.h" 10 | #include "impl/winmd_reader/index.h" 11 | #include "impl/winmd_reader/signature.h" 12 | #include "impl/winmd_reader/schema.h" 13 | #include "impl/winmd_reader/database.h" 14 | #include "impl/winmd_reader/column.h" 15 | #include "impl/winmd_reader/type_helpers.h" 16 | #include "impl/winmd_reader/key.h" 17 | #include "impl/winmd_reader/cache.h" 18 | #include "impl/winmd_reader/filter.h" 19 | #include "impl/winmd_reader/custom_attribute.h" 20 | #include "impl/winmd_reader/helpers.h" 21 | -------------------------------------------------------------------------------- /nuget/Microsoft.Windows.WinMD.props: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)))..\..\ 10 | 11 | 12 | 13 | 14 | $(WinMDPackageDir);%(AdditionalIncludeDirectories) 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | 15 | steps: 16 | - uses: actions/stale@v6 17 | with: 18 | repo-token: ${{ secrets.GITHUB_TOKEN }} 19 | days-before-stale: 10 20 | days-before-close: 5 21 | stale-issue-message: 'This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.' 22 | stale-pr-message: 'This pull request is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.' 23 | stale-issue-label: 'no-issue-activity' 24 | stale-pr-label: 'no-pr-activity' 25 | -------------------------------------------------------------------------------- /.config/1espt/PipelineAutobaseliningConfig.yml: -------------------------------------------------------------------------------- 1 | ## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details. 2 | 3 | pipelines: 4 | 108608: 5 | retail: 6 | source: 7 | credscan: 8 | lastModifiedDate: 2023-10-27 9 | eslint: 10 | lastModifiedDate: 2023-10-27 11 | psscriptanalyzer: 12 | lastModifiedDate: 2023-10-27 13 | armory: 14 | lastModifiedDate: 2023-10-27 15 | 108527: 16 | retail: 17 | source: 18 | credscan: 19 | lastModifiedDate: 2023-10-27 20 | eslint: 21 | lastModifiedDate: 2023-10-27 22 | psscriptanalyzer: 23 | lastModifiedDate: 2023-10-27 24 | armory: 25 | lastModifiedDate: 2023-10-27 26 | binary: 27 | credscan: 28 | lastModifiedDate: 2023-10-27 29 | binskim: 30 | lastModifiedDate: 2023-10-27 31 | spotbugs: 32 | lastModifiedDate: 2023-10-27 33 | -------------------------------------------------------------------------------- /nuget/Microsoft.Windows.WinMD.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Microsoft.Windows.WinMD 5 | 1.0.0.0 6 | Windows Metadata Parsing Library 7 | Microsoft 8 | Microsoft 9 | false 10 | Microsoft.Windows.WinMD is a pure C++ header library for parsing Windows Metadata (WinMD) files. 11 | 12 | native C++ WinRT WinMD nativepackage 13 | © Microsoft Corporation. All rights reserved. 14 | LICENSE 15 | https://github.com/Microsoft/winmd/tree/master/ 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /test/database.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include 3 | 4 | using namespace winmd::reader; 5 | 6 | TEST_CASE("database") 7 | { 8 | std::array local{}; 9 | 10 | #ifdef _WIN64 11 | ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); 12 | #else 13 | ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); 14 | #endif 15 | 16 | std::filesystem::path path = local.data(); 17 | path.append("Windows.Foundation.winmd"); 18 | database db(path.string()); 19 | 20 | TypeDef stringable; 21 | 22 | for (auto&& type : db.TypeDef) 23 | { 24 | if (type.TypeName() == "IStringable") 25 | { 26 | stringable = type; 27 | break; 28 | } 29 | } 30 | 31 | REQUIRE(stringable.TypeName() == "IStringable"); 32 | REQUIRE(stringable.TypeNamespace() == "Windows.Foundation"); 33 | REQUIRE(stringable.Flags().WindowsRuntime()); 34 | REQUIRE(stringable.Flags().Semantics() == TypeSemantics::Interface); 35 | 36 | auto methods = stringable.MethodList(); 37 | REQUIRE(methods.first + 1 == methods.second); 38 | MethodDef method = methods.first; 39 | REQUIRE(method.Name() == "ToString"); 40 | } 41 | -------------------------------------------------------------------------------- /test/filter.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include 3 | 4 | using namespace winmd::reader; 5 | 6 | TEST_CASE("filter_simple") 7 | { 8 | std::vector include = { "N1", "N3", "N3.N4.N5" }; 9 | std::vector exclude = { "N2", "N3.N4" }; 10 | 11 | filter f{ include, exclude }; 12 | 13 | REQUIRE(!f.empty()); 14 | 15 | REQUIRE(!f.includes("NN.T")); 16 | 17 | REQUIRE(f.includes("N1.T")); 18 | REQUIRE(f.includes("N3.T")); 19 | 20 | REQUIRE(!f.includes("N2.T")); 21 | REQUIRE(!f.includes("N3.N4.T")); 22 | 23 | REQUIRE(f.includes("N3.N4.N5.T")); 24 | } 25 | 26 | TEST_CASE("filter_excludes_same_length") 27 | { 28 | std::vector include = { "N.N1", "N.N2" }; 29 | std::vector exclude = { "N.N3", "N.N4" }; 30 | 31 | filter f{ include, exclude }; 32 | 33 | REQUIRE(!f.empty()); 34 | 35 | REQUIRE(f.includes("N.N1.T")); 36 | REQUIRE(f.includes("N.N2.T")); 37 | 38 | REQUIRE(!f.includes("N.N3.T")); 39 | REQUIRE(!f.includes("N.N4.T")); 40 | } 41 | 42 | TEST_CASE("filter_exclude_include_precedence") 43 | { 44 | std::vector include = { "N.T" }; 45 | std::vector exclude = { "N.T" }; 46 | 47 | filter f{ include, exclude }; 48 | 49 | REQUIRE(!f.empty()); 50 | 51 | REQUIRE(!f.includes("N.T")); 52 | } 53 | -------------------------------------------------------------------------------- /test/winmd.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29319.158 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winmd", "winmd.vcxproj", "{50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Debug|x64.ActiveCfg = Debug|x64 17 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Debug|x64.Build.0 = Debug|x64 18 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Debug|x86.ActiveCfg = Debug|Win32 19 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Debug|x86.Build.0 = Debug|Win32 20 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Release|x64.ActiveCfg = Release|x64 21 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Release|x64.Build.0 = Release|x64 22 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Release|x86.ActiveCfg = Release|Win32 23 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F3E277AB-1E32-4C6E-A287-CAA07465622A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/type_helpers.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | inline std::pair get_type_namespace_and_name(coded_index const& type) 5 | { 6 | if (type.type() == TypeDefOrRef::TypeDef) 7 | { 8 | auto const def = type.TypeDef(); 9 | return { def.TypeNamespace(), def.TypeName() }; 10 | } 11 | else if (type.type() == TypeDefOrRef::TypeRef) 12 | { 13 | auto const ref = type.TypeRef(); 14 | return { ref.TypeNamespace(), ref.TypeName() }; 15 | } 16 | else 17 | { 18 | XLANG_ASSERT(false); 19 | return {}; 20 | } 21 | } 22 | 23 | inline std::pair get_base_class_namespace_and_name(TypeDef const& type) 24 | { 25 | return get_type_namespace_and_name(type.Extends()); 26 | } 27 | 28 | inline auto extends_type(TypeDef type, std::string_view typeNamespace, std::string_view typeName) 29 | { 30 | return get_base_class_namespace_and_name(type) == std::pair(typeNamespace, typeName); 31 | } 32 | 33 | inline bool is_nested(TypeDef const& type) 34 | { 35 | const auto visibility = type.Flags().Visibility(); 36 | return !(visibility == TypeVisibility::Public || visibility == TypeVisibility::NotPublic); 37 | } 38 | 39 | inline bool is_nested(TypeRef const& type) 40 | { 41 | return type.ResolutionScope().type() == ResolutionScope::TypeRef; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://dev.azure.com/microsoft/Dart/_apis/build/status/WinMD%20Nuget?branchName=master)](https://dev.azure.com/microsoft/Dart/_build/latest?definitionId=44715&branchName=master) 2 | 3 | # C++ winmd parser 4 | 5 | A winmd parser written in C++ and based on the [ECMA-335](https://ecma-international.org/publications-and-standards/standards/ecma-335/) standard. This winmd parser powers [C++/WinRT](https://github.com/microsoft/cppwinrt). 6 | 7 | * NuGet package: http://aka.ms/winmd/nuget 8 | 9 | The C++ winmd parser is part of the [xlang](https://github.com/microsoft/xlang) family of projects that help developers create APIs that can run on multiple platforms and be used with a variety of languages. 10 | 11 | # Contributing 12 | 13 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 14 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 15 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 16 | 17 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 18 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 19 | provided by the bot. You will only need to do this once across all repos using our CLA. 20 | 21 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 22 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 23 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 24 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/index.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template <> struct typed_index : index_base 5 | { 6 | using index_base::index_base; 7 | 8 | auto MemberRef() const; 9 | auto MethodDef() const; 10 | }; 11 | 12 | template <> struct typed_index : index_base 13 | { 14 | using index_base::index_base; 15 | 16 | auto Field() const; 17 | auto Param() const; 18 | auto Property() const; 19 | }; 20 | 21 | template <> struct typed_index : index_base 22 | { 23 | using index_base::index_base; 24 | 25 | auto Property() const; 26 | auto Event() const; 27 | }; 28 | 29 | template <> struct typed_index : index_base 30 | { 31 | using index_base::index_base; 32 | 33 | auto MethodDef() const; 34 | auto MemberRef() const; 35 | }; 36 | 37 | template <> struct typed_index : index_base 38 | { 39 | using index_base::index_base; 40 | 41 | auto Module() const; 42 | auto ModuleRef() const; 43 | auto AssemblyRef() const; 44 | auto TypeRef() const; 45 | }; 46 | 47 | template <> struct typed_index : index_base 48 | { 49 | using index_base::index_base; 50 | 51 | reader::TypeDef TypeDef() const; 52 | reader::TypeRef TypeRef() const; 53 | reader::TypeSpec TypeSpec() const; 54 | auto CustomAttribute() const; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/impl/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) 4 | #include 5 | #include 6 | #else 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #if defined(_DEBUG) 32 | #define XLANG_DEBUG 33 | #define XLANG_ASSERT assert 34 | #else 35 | #define XLANG_ASSERT(expression) ((void)0) 36 | #endif 37 | 38 | namespace winmd 39 | { 40 | using namespace std::literals; 41 | 42 | namespace impl 43 | { 44 | [[noreturn]] inline void throw_invalid(std::string const& message) 45 | { 46 | throw std::invalid_argument(message); 47 | } 48 | 49 | template 50 | [[noreturn]] inline void throw_invalid(std::string message, T const&... args) 51 | { 52 | (message.append(args), ...); 53 | throw std::invalid_argument(message); 54 | } 55 | 56 | template 57 | auto c_str(std::basic_string_view const& view) noexcept 58 | { 59 | if (*(view.data() + view.size())) 60 | { 61 | std::terminate(); 62 | } 63 | 64 | return view.data(); 65 | } 66 | 67 | inline bool starts_with(std::string_view const& value, std::string_view const& match) noexcept 68 | { 69 | return 0 == value.compare(0, match.size(), match); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.pipelines/SyncMirror-Pipeline.yml: -------------------------------------------------------------------------------- 1 | # Sync branches in a mirror repository to a base repo by running this pipeline 2 | # from the mirror repo, and supplying the base repo as a parameter 3 | name: $(BuildDefinitionName)_$(date:yyMMdd)$(rev:.r) 4 | 5 | parameters: 6 | - name: "SourceToTargetBranches" 7 | type: object 8 | default: 9 | master: master 10 | - name: "SourceRepository" 11 | type: string 12 | default: "https://github.com/microsoft/winmd.git" 13 | 14 | resources: 15 | repositories: 16 | - repository: 1ESPipelineTemplates 17 | type: git 18 | name: 1ESPipelineTemplates/1ESPipelineTemplates 19 | ref: refs/tags/release 20 | extends: 21 | template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates 22 | parameters: 23 | pool: 24 | name: Azure-Pipelines-1ESPT-ExDShared 25 | image: windows-2022 26 | os: windows 27 | customBuildTags: 28 | - ES365AIMigrationTooling 29 | stages: 30 | - stage: stage 31 | jobs: 32 | - job: SyncMirror 33 | strategy: 34 | matrix: 35 | ${{ each branches in parameters.SourceToTargetBranches }}: 36 | ${{ branches.key }}: 37 | SourceBranch: ${{ branches.key }} 38 | TargetBranch: ${{ branches.value }} 39 | dependsOn: [] 40 | steps: 41 | - checkout: self 42 | persistCredentials: true 43 | 44 | - task: PowerShell@2 45 | inputs: 46 | targetType: 'inline' 47 | script: | 48 | Write-Host "SourceBranch " + "$(SourceBranch)" 49 | Write-Host "TargetBranch " + "$(TargetBranch)" 50 | 51 | $repo = "${{ parameters.SourceRepository }}" 52 | git remote add sourcerepo $repo 53 | git remote 54 | 55 | $target = "$(TargetBranch)" 56 | git fetch origin $target 57 | git checkout $target 58 | git pull origin $target 59 | 60 | $source = "$(SourceBranch)" 61 | git fetch sourcerepo $source 62 | git pull sourcerepo $source 63 | 64 | - task: CmdLine@2 65 | inputs: 66 | script: | 67 | git push 68 | 69 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/filter.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct filter 5 | { 6 | filter() noexcept = default; 7 | 8 | template 9 | filter(T const& includes, T const& excludes) 10 | { 11 | for (auto&& include : includes) 12 | { 13 | m_rules.push_back({ include, true }); 14 | } 15 | 16 | for (auto&& exclude : excludes) 17 | { 18 | m_rules.push_back({ exclude, false }); 19 | } 20 | 21 | std::sort(m_rules.begin(), m_rules.end(), [](auto const& lhs, auto const& rhs) 22 | { 23 | return std::pair{ lhs.first.size(), !lhs.second } > std::pair{ rhs.first.size(), !rhs.second }; 24 | }); 25 | } 26 | 27 | bool includes(TypeDef const& type) const 28 | { 29 | return includes(type.TypeNamespace(), type.TypeName()); 30 | } 31 | 32 | bool includes(std::string_view const& type) const 33 | { 34 | auto position = type.find_last_of('.'); 35 | return includes(type.substr(0, position), type.substr(position + 1)); 36 | } 37 | 38 | bool includes(std::vector const& types) const 39 | { 40 | if (m_rules.empty()) 41 | { 42 | return true; 43 | } 44 | 45 | for (auto&& type : types) 46 | { 47 | if (includes(type.TypeNamespace(), type.TypeName())) 48 | { 49 | return true; 50 | } 51 | } 52 | 53 | return false; 54 | } 55 | 56 | bool includes(cache::namespace_members const& members) const 57 | { 58 | if (m_rules.empty()) 59 | { 60 | return true; 61 | } 62 | 63 | for (auto&& type : members.types) 64 | { 65 | if (includes(type.second.TypeNamespace(), type.second.TypeName())) 66 | { 67 | return true; 68 | } 69 | } 70 | 71 | return false; 72 | } 73 | 74 | template 75 | auto bind_each(std::vector const& types) const 76 | { 77 | return [&](auto& writer) 78 | { 79 | for (auto&& type : types) 80 | { 81 | if (includes(type)) 82 | { 83 | F(writer, type); 84 | } 85 | } 86 | }; 87 | } 88 | 89 | bool empty() const noexcept 90 | { 91 | return m_rules.empty(); 92 | } 93 | 94 | private: 95 | 96 | bool includes(std::string_view const& type_namespace, std::string_view const& type_name) const noexcept 97 | { 98 | if (m_rules.empty()) 99 | { 100 | return true; 101 | } 102 | 103 | for (auto&& rule : m_rules) 104 | { 105 | if (match(type_namespace, type_name, rule.first)) 106 | { 107 | return rule.second; 108 | } 109 | } 110 | 111 | return false; 112 | } 113 | 114 | static bool match(std::string_view const& type_namespace, std::string_view const& type_name, std::string_view const& match) noexcept 115 | { 116 | if (match.size() <= type_namespace.size()) 117 | { 118 | return impl::starts_with(type_namespace, match); 119 | } 120 | 121 | if (!impl::starts_with(match, type_namespace)) 122 | { 123 | return false; 124 | } 125 | 126 | if (match[type_namespace.size()] != '.') 127 | { 128 | return false; 129 | } 130 | 131 | return impl::starts_with(type_name, match.substr(type_namespace.size() + 1)); 132 | } 133 | 134 | std::vector> m_rules; 135 | }; 136 | } 137 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/helpers.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | bool empty(std::pair const& range) noexcept 6 | { 7 | return range.first == range.second; 8 | } 9 | 10 | template 11 | std::size_t size(std::pair const& range) noexcept 12 | { 13 | return range.second - range.first; 14 | } 15 | 16 | inline auto find(TypeRef const& type) 17 | { 18 | if (type.ResolutionScope().type() != ResolutionScope::TypeRef) 19 | { 20 | return type.get_database().get_cache().find(type.TypeNamespace(), type.TypeName()); 21 | } 22 | else 23 | { 24 | auto enclosing_type = find(type.ResolutionScope().TypeRef()); 25 | if (!enclosing_type) 26 | { 27 | return TypeDef{}; 28 | } 29 | auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type); 30 | auto iter = std::find_if(nested_types.begin(), nested_types.end(), 31 | [name = type.TypeName()](TypeDef const& arg) 32 | { 33 | return name == arg.TypeName(); 34 | }); 35 | if (iter == nested_types.end()) 36 | { 37 | return TypeDef{}; 38 | } 39 | return *iter; 40 | } 41 | } 42 | 43 | inline auto find_required(TypeRef const& type) 44 | { 45 | if (type.ResolutionScope().type() != ResolutionScope::TypeRef) 46 | { 47 | return type.get_database().get_cache().find_required(type.TypeNamespace(), type.TypeName()); 48 | } 49 | else 50 | { 51 | auto enclosing_type = find_required(type.ResolutionScope().TypeRef()); 52 | auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type); 53 | auto iter = std::find_if(nested_types.begin(), nested_types.end(), 54 | [name = type.TypeName()](TypeDef const& arg) 55 | { 56 | return name == arg.TypeName(); 57 | }); 58 | if (iter == nested_types.end()) 59 | { 60 | impl::throw_invalid("Type '", enclosing_type.TypeName(), ".", type.TypeName(), "' could not be found"); 61 | } 62 | return *iter; 63 | } 64 | } 65 | 66 | inline TypeDef find(coded_index const& type) 67 | { 68 | if (type.type() == TypeDefOrRef::TypeRef) 69 | { 70 | return find(type.TypeRef()); 71 | } 72 | else if (type.type() == TypeDefOrRef::TypeDef) 73 | { 74 | return type.TypeDef(); 75 | } 76 | else 77 | { 78 | XLANG_ASSERT(false); 79 | return {}; 80 | } 81 | } 82 | 83 | inline TypeDef find_required(coded_index const& type) 84 | { 85 | if (type.type() == TypeDefOrRef::TypeRef) 86 | { 87 | return find_required(type.TypeRef()); 88 | } 89 | else if (type.type() == TypeDefOrRef::TypeDef) 90 | { 91 | return type.TypeDef(); 92 | } 93 | else 94 | { 95 | XLANG_ASSERT(false); 96 | return {}; 97 | } 98 | } 99 | 100 | inline bool is_const(ParamSig const& param) 101 | { 102 | auto is_type_const = [](auto&& type) 103 | { 104 | return type.TypeNamespace() == "System.Runtime.CompilerServices" && type.TypeName() == "IsConst"; 105 | }; 106 | 107 | for (auto const& cmod : param.CustomMod()) 108 | { 109 | auto type = cmod.Type(); 110 | 111 | if (type.type() == TypeDefOrRef::TypeDef) 112 | { 113 | if (is_type_const(type.TypeDef())) 114 | { 115 | return true; 116 | } 117 | } 118 | else if (type.type() == TypeDefOrRef::TypeRef) 119 | { 120 | if (is_type_const(type.TypeRef())) 121 | { 122 | return true; 123 | } 124 | } 125 | } 126 | 127 | return false; 128 | }; 129 | } 130 | -------------------------------------------------------------------------------- /.pipelines/Pipeline.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - group: XlangSigning 3 | - name: MajorVersion 4 | value: 1 5 | - name: MinorVersion 6 | value: 0 7 | 8 | name: $(MajorVersion).$(MinorVersion).$(date:yyMMdd)$(rev:.r) 9 | trigger: none 10 | 11 | resources: 12 | repositories: 13 | - repository: 1ESPipelineTemplates 14 | type: git 15 | name: 1ESPipelineTemplates/1ESPipelineTemplates 16 | ref: refs/tags/release 17 | 18 | extends: 19 | template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates 20 | parameters: 21 | customBuildTags: 22 | - 1ES.PT.ViaStartRight 23 | pool: 24 | name: Azure-Pipelines-1ESPT-ExDShared 25 | image: windows-2022 26 | os: windows 27 | sdl: 28 | sourceAnalysisPool: 29 | name: Azure-Pipelines-1ESPT-ExDShared 30 | image: windows-2022 31 | os: windows 32 | 33 | stages: 34 | - stage: BuildNuGet 35 | displayName: Build WinMD NuGet 36 | jobs: 37 | - job: Test 38 | displayName: Test Library 39 | strategy: 40 | maxParallel: 10 41 | matrix: 42 | x64_Debug: 43 | BuildPlatform: 'x64' 44 | BuildConfiguration: 'debug' 45 | x86_Debug: 46 | BuildPlatform: 'x86' 47 | BuildConfiguration: 'debug' 48 | x64_Release: 49 | BuildPlatform: 'x64' 50 | BuildConfiguration: 'release' 51 | x86_Release: 52 | BuildPlatform: 'x86' 53 | BuildConfiguration: 'release' 54 | steps: 55 | - checkout: self 56 | clean: true 57 | persistCredentials: true 58 | - task: VSBuild@1 59 | displayName: Build Tests 60 | inputs: 61 | platform: $(BuildPlatform) 62 | configuration: $(BuildConfiguration) 63 | clean: $(BuildParameters.clean) 64 | - task: CmdLine@2 65 | displayName: Run Tests 66 | inputs: 67 | script: test\$(BuildPlatform)\$(BuildConfiguration)\winmd.exe -o TEST-$(Build.BuildNumber).xml -r junit 68 | - task: PublishTestResults@2 69 | displayName: Publish Results 70 | inputs: 71 | failTaskOnFailedTests: true 72 | 73 | - job: NuGet 74 | displayName: Build NuGet 75 | dependsOn: Test 76 | templateContext: 77 | outputs: 78 | - output: nuget 79 | displayName: 'NuGet push' 80 | packagesToPush: $(Build.ArtifactStagingDirectory)/**/*.nupkg 81 | packageParentPath: '$(Build.ArtifactStagingDirectory)' 82 | publishVstsFeed: WinMD 83 | nuGetFeedType: internal 84 | - output: pipelineArtifact 85 | targetPath: $(Build.ArtifactStagingDirectory) 86 | artifactName: Publish 87 | steps: 88 | - checkout: self 89 | clean: true 90 | persistCredentials: true 91 | - task: NuGetCommand@2 92 | displayName: NuGet pack 93 | inputs: 94 | command: pack 95 | searchPatternPack: nuget/Microsoft.Windows.WinMD.nuspec 96 | configurationToPack: Release 97 | versioningScheme: byBuildNumber 98 | - task: EsrpCodeSigning@5 99 | displayName: ESRP CodeSigning 100 | inputs: 101 | ConnectedServiceName: $(SigningServiceName) 102 | AppRegistrationClientId: $(SigningAppId) 103 | AppRegistrationTenantId: $(SigningTenantId) 104 | AuthAKVName: $(SigningAKVName) 105 | AuthCertName: $(SigningAuthCertName) 106 | AuthSignCertName: $(SigningSignCertName) 107 | FolderPath: $(Build.ArtifactStagingDirectory) 108 | Pattern: '*.nupkg' 109 | signConfigType: inlineSignParams 110 | inlineOperation: | 111 | [ 112 | { 113 | "keyCode": "CP-401405", 114 | "operationSetCode": "NuGetSign", 115 | "parameters": [], 116 | "toolName": "sign", 117 | "toolVersion": "6.2.9304.0" 118 | }, 119 | { 120 | "keyCode": "CP-401405", 121 | "operationSetCode": "NuGetVerify", 122 | "parameters": [ ], 123 | "toolName": "sign", 124 | "toolVersion": "1.0" 125 | } 126 | ] 127 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/pe.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::impl 3 | { 4 | struct image_dos_header 5 | { 6 | uint16_t e_signature; 7 | uint16_t e_cblp; 8 | uint16_t e_cp; 9 | uint16_t e_crlc; 10 | uint16_t e_cparhdr; 11 | uint16_t e_minalloc; 12 | uint16_t e_maxalloc; 13 | uint16_t e_ss; 14 | uint16_t e_sp; 15 | uint16_t e_csum; 16 | uint16_t e_ip; 17 | uint16_t e_cs; 18 | uint16_t e_lfarlc; 19 | uint16_t e_ovno; 20 | uint16_t e_res[4]; 21 | uint16_t e_oemid; 22 | uint16_t e_oeminfo; 23 | uint16_t e_res2[10]; 24 | int32_t e_lfanew; 25 | }; 26 | 27 | struct image_file_header 28 | { 29 | uint16_t Machine; 30 | uint16_t NumberOfSections; 31 | uint32_t TimeDateStamp; 32 | uint32_t PointerToSymbolTable; 33 | uint32_t NumberOfSymbols; 34 | uint16_t SizeOfOptionalHeader; 35 | uint16_t Characteristics; 36 | }; 37 | 38 | struct image_data_directory 39 | { 40 | uint32_t VirtualAddress; 41 | uint32_t Size; 42 | }; 43 | 44 | struct image_optional_header32 45 | { 46 | uint16_t Magic; 47 | uint8_t MajorLinkerVersion; 48 | uint8_t MinorLinkerVersion; 49 | uint32_t SizeOfCode; 50 | uint32_t SizeOfInitializedData; 51 | uint32_t SizeOfUninitializedData; 52 | uint32_t AddressOfEntryPoint; 53 | uint32_t BaseOfCode; 54 | uint32_t BaseOfData; 55 | uint32_t ImageBase; 56 | uint32_t SectionAlignment; 57 | uint32_t FileAlignment; 58 | uint16_t MajorOperatingSystemVersion; 59 | uint16_t MinorOperatingSystemVersion; 60 | uint16_t MajorImageVersion; 61 | uint16_t MinorImageVersion; 62 | uint16_t MajorSubsystemVersion; 63 | uint16_t MinorSubsystemVersion; 64 | uint32_t Win32VersionValue; 65 | uint32_t SizeOfImage; 66 | uint32_t SizeOfHeaders; 67 | uint32_t CheckSum; 68 | uint16_t Subsystem; 69 | uint16_t DllCharacteristics; 70 | uint32_t SizeOfStackReserve; 71 | uint32_t SizeOfStackCommit; 72 | uint32_t SizeOfHeapReserve; 73 | uint32_t SizeOfHeapCommit; 74 | uint32_t LoaderFlags; 75 | uint32_t NumberOfRvaAndSizes; 76 | image_data_directory DataDirectory[16]; 77 | }; 78 | 79 | struct image_nt_headers32 80 | { 81 | uint32_t Signature; 82 | image_file_header FileHeader; 83 | image_optional_header32 OptionalHeader; 84 | }; 85 | 86 | struct image_optional_header32plus 87 | { 88 | uint16_t Magic; 89 | uint8_t MajorLinkerVersion; 90 | uint8_t MinorLinkerVersion; 91 | uint32_t SizeOfCode; 92 | uint32_t SizeOfInitializedData; 93 | uint32_t SizeOfUninitializedData; 94 | uint32_t AddressOfEntryPoint; 95 | uint32_t BaseOfCode; 96 | uint64_t ImageBase; 97 | uint32_t SectionAlignment; 98 | uint32_t FileAlignment; 99 | uint16_t MajorOperatingSystemVersion; 100 | uint16_t MinorOperatingSystemVersion; 101 | uint16_t MajorImageVersion; 102 | uint16_t MinorImageVersion; 103 | uint16_t MajorSubsystemVersion; 104 | uint16_t MinorSubsystemVersion; 105 | uint32_t Win32VersionValue; 106 | uint32_t SizeOfImage; 107 | uint32_t SizeOfHeaders; 108 | uint32_t CheckSum; 109 | uint16_t Subsystem; 110 | uint16_t DllCharacteristics; 111 | uint64_t SizeOfStackReserve; 112 | uint64_t SizeOfStackCommit; 113 | uint64_t SizeOfHeapReserve; 114 | uint64_t SizeOfHeapCommit; 115 | uint32_t LoaderFlags; 116 | uint32_t NumberOfRvaAndSizes; 117 | image_data_directory DataDirectory[16]; 118 | }; 119 | 120 | struct image_nt_headers32plus 121 | { 122 | uint32_t Signature; 123 | image_file_header FileHeader; 124 | image_optional_header32plus OptionalHeader; 125 | }; 126 | 127 | struct image_section_header { 128 | uint8_t Name[8]; // IMAGE_SIZEOF_SHORT_NAME 129 | union 130 | { 131 | uint32_t PhysicalAddress; 132 | uint32_t VirtualSize; 133 | } Misc; 134 | uint32_t VirtualAddress; 135 | uint32_t SizeOfRawData; 136 | uint32_t PointerToRawData; 137 | uint32_t PointerToRelocations; 138 | uint32_t PointerToLinenumbers; 139 | uint16_t NumberOfRelocations; 140 | uint16_t NumberOfLinenumbers; 141 | uint32_t Characteristics; 142 | }; 143 | 144 | struct image_cor20_header 145 | { 146 | uint32_t cb; 147 | uint16_t MajorRuntimeVersion; 148 | uint16_t MinorRuntimeVersion; 149 | image_data_directory MetaData; 150 | uint32_t Flags; 151 | union 152 | { 153 | uint32_t EntryPointToken; 154 | uint32_t EntryPointRVA; 155 | } dummyunionname; 156 | image_data_directory Resources; 157 | image_data_directory StrongNameSignature; 158 | image_data_directory CodeManagerTable; 159 | image_data_directory VTableFixups; 160 | image_data_directory ExportAddressTableJumps; 161 | image_data_directory ManagedNativeHeader; 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/key.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | template 6 | Row index_base::get_row() const 7 | { 8 | XLANG_ASSERT(type() == (index_tag_v)); 9 | return get_database().template get_table()[index()]; 10 | } 11 | 12 | inline auto typed_index::MemberRef() const 13 | { 14 | return get_row(); 15 | } 16 | 17 | inline auto typed_index::MethodDef() const 18 | { 19 | return get_row(); 20 | } 21 | 22 | inline auto typed_index::Field() const 23 | { 24 | return get_row(); 25 | } 26 | 27 | inline auto typed_index::Param() const 28 | { 29 | return get_row(); 30 | } 31 | 32 | inline auto typed_index::Property() const 33 | { 34 | return get_row(); 35 | } 36 | 37 | inline auto typed_index::Property() const 38 | { 39 | return get_row(); 40 | } 41 | 42 | inline auto typed_index::Event() const 43 | { 44 | return get_row(); 45 | } 46 | 47 | inline auto typed_index::MethodDef() const 48 | { 49 | return get_row(); 50 | } 51 | 52 | inline auto typed_index::MemberRef() const 53 | { 54 | return get_row(); 55 | } 56 | 57 | inline auto typed_index::Module() const 58 | { 59 | return get_row(); 60 | } 61 | 62 | inline auto typed_index::ModuleRef() const 63 | { 64 | return get_row(); 65 | } 66 | 67 | inline auto typed_index::AssemblyRef() const 68 | { 69 | return get_row(); 70 | } 71 | 72 | inline auto typed_index::TypeRef() const 73 | { 74 | return get_row(); 75 | } 76 | 77 | inline TypeDef typed_index::TypeDef() const 78 | { 79 | return get_row(); 80 | } 81 | 82 | inline TypeRef typed_index::TypeRef() const 83 | { 84 | return get_row(); 85 | } 86 | 87 | inline TypeSpec typed_index::TypeSpec() const 88 | { 89 | return get_row(); 90 | } 91 | 92 | inline auto typed_index::CustomAttribute() const 93 | { 94 | if (type() == TypeDefOrRef::TypeDef) 95 | { 96 | return TypeDef().CustomAttribute(); 97 | } 98 | 99 | if (type() == TypeDefOrRef::TypeRef) 100 | { 101 | return TypeRef().CustomAttribute(); 102 | } 103 | 104 | return TypeSpec().CustomAttribute(); 105 | } 106 | 107 | inline auto typed_index::TypeRef() const 108 | { 109 | return get_row(); 110 | } 111 | 112 | inline auto typed_index::TypeDef() const 113 | { 114 | return get_row(); 115 | } 116 | 117 | inline bool TypeDef::is_enum() const 118 | { 119 | return extends_type(*this, "System"sv, "Enum"sv); 120 | } 121 | 122 | struct EnumDefinition 123 | { 124 | explicit EnumDefinition(TypeDef const& type) 125 | : m_typedef(type) 126 | { 127 | XLANG_ASSERT(type.is_enum()); 128 | for (auto field : type.FieldList()) 129 | { 130 | if (!field.Flags().Literal() && !field.Flags().Static()) 131 | { 132 | XLANG_ASSERT(m_underlying_type == ElementType::End); 133 | m_underlying_type = std::get(field.Signature().Type().Type()); 134 | XLANG_ASSERT(ElementType::Boolean <= m_underlying_type && m_underlying_type <= ElementType::U8); 135 | } 136 | } 137 | } 138 | 139 | auto get_enumerator(std::string_view const& name) const 140 | { 141 | auto fields = m_typedef.FieldList(); 142 | 143 | auto field = std::find_if(begin(fields), end(fields), [&](auto&& field) 144 | { 145 | return field.Name() == name; 146 | }); 147 | 148 | XLANG_ASSERT(field != end(fields)); 149 | return field; 150 | } 151 | 152 | TypeDef m_typedef; 153 | ElementType m_underlying_type{}; 154 | 155 | }; 156 | 157 | inline auto TypeDef::get_enum_definition() const 158 | { 159 | return EnumDefinition{ *this }; 160 | } 161 | 162 | template 163 | CustomAttribute get_attribute(T const& row, std::string_view const& type_namespace, std::string_view const& type_name) 164 | { 165 | for (auto&& attribute : row.CustomAttribute()) 166 | { 167 | auto pair = attribute.TypeNamespaceAndName(); 168 | 169 | if (pair.first == type_namespace && pair.second == type_name) 170 | { 171 | return attribute; 172 | } 173 | } 174 | 175 | return {}; 176 | } 177 | 178 | enum class category 179 | { 180 | interface_type, 181 | class_type, 182 | enum_type, 183 | struct_type, 184 | delegate_type 185 | }; 186 | 187 | inline category get_category(TypeDef const& type) 188 | { 189 | if (type.Flags().Semantics() == TypeSemantics::Interface || get_attribute(type, "System.Runtime.InteropServices"sv, "GuidAttribute"sv)) 190 | { 191 | return category::interface_type; 192 | } 193 | 194 | auto const& [extends_namespace, extends_name] = get_base_class_namespace_and_name(type); 195 | 196 | if (extends_name == "Enum"sv && extends_namespace == "System"sv) 197 | { 198 | return category::enum_type; 199 | } 200 | 201 | if (extends_name == "ValueType"sv && extends_namespace == "System"sv) 202 | { 203 | return category::struct_type; 204 | } 205 | 206 | if (extends_name == "MulticastDelegate"sv && extends_namespace == "System"sv) 207 | { 208 | return category::delegate_type; 209 | } 210 | 211 | return category::class_type; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /test/cache.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include 3 | 4 | using namespace winmd::reader; 5 | 6 | std::filesystem::path get_local_winmd_path() 7 | { 8 | std::array local{}; 9 | 10 | #ifdef _WIN64 11 | ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); 12 | #else 13 | ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); 14 | #endif 15 | 16 | return local.data(); 17 | } 18 | 19 | TEST_CASE("cache_add_invalidate") 20 | { 21 | std::filesystem::path winmd_dir = get_local_winmd_path(); 22 | auto file_path = winmd_dir; 23 | file_path.append("Windows.Foundation.winmd"); 24 | 25 | cache c(file_path.string()); 26 | 27 | // Get a type and a database and verify that neither are invalidated by adding a new db 28 | TypeDef IStringable = c.find("Windows.Foundation", "IStringable"); 29 | auto const db = &(c.databases().front()); 30 | 31 | file_path = winmd_dir; 32 | file_path.append("Windows.Data.winmd"); 33 | c.add_database(file_path.string()); 34 | 35 | TypeDef IStringable2 = c.find("Windows.Foundation", "IStringable"); 36 | REQUIRE(IStringable == IStringable2); 37 | 38 | auto const db2 = &(c.databases().front()); 39 | REQUIRE(db == db2); 40 | } 41 | 42 | TEST_CASE("cache_add") 43 | { 44 | std::filesystem::path winmd_dir = get_local_winmd_path(); 45 | auto file_path = winmd_dir; 46 | file_path.append("Windows.Foundation.winmd"); 47 | 48 | cache c(file_path.string()); 49 | 50 | TypeDef JsonValue = c.find("Windows.Data.Json", "JsonValue"); 51 | REQUIRE(!JsonValue); 52 | 53 | file_path = winmd_dir; 54 | file_path.append("Windows.Data.winmd"); 55 | c.add_database(file_path.string()); 56 | 57 | JsonValue = c.find("Windows.Data.Json", "JsonValue"); 58 | REQUIRE(!!JsonValue); 59 | REQUIRE(JsonValue.TypeName() == "JsonValue"); 60 | REQUIRE(JsonValue.TypeNamespace() == "Windows.Data.Json"); 61 | } 62 | 63 | TEST_CASE("cache_add_filter") 64 | { 65 | std::filesystem::path winmd_dir = get_local_winmd_path(); 66 | auto file_path = winmd_dir; 67 | file_path.append("Windows.Foundation.winmd"); 68 | 69 | cache c(file_path.string()); 70 | 71 | TypeDef JsonValue = c.find("Windows.Data.Json", "JsonValue"); 72 | REQUIRE(!JsonValue); 73 | 74 | file_path = winmd_dir; 75 | file_path.append("Windows.Data.winmd"); 76 | c.add_database(file_path.string(), [](TypeDef const& type) 77 | { 78 | return !(type.TypeNamespace() == "Windows.Data.Json" && type.TypeName() == "JsonArray"); 79 | }); 80 | 81 | JsonValue = c.find("Windows.Data.Json", "JsonValue"); 82 | REQUIRE(!!JsonValue); 83 | REQUIRE(JsonValue.TypeName() == "JsonValue"); 84 | REQUIRE(JsonValue.TypeNamespace() == "Windows.Data.Json"); 85 | 86 | REQUIRE(!c.find("Windows.Data.Json", "JsonArray")); 87 | } 88 | 89 | TEST_CASE("cache_add_duplicate") 90 | { 91 | std::filesystem::path winmd_dir = get_local_winmd_path(); 92 | auto file_path = winmd_dir; 93 | file_path.append("Windows.Foundation.winmd"); 94 | 95 | cache c(file_path.string()); 96 | 97 | TypeDef IStringable = c.find("Windows.Foundation", "IStringable"); 98 | 99 | // Add a winmd with duplicate types, and verify the original types aren't invalidated. 100 | c.add_database(file_path.string()); 101 | 102 | TypeDef IStringable2 = c.find("Windows.Foundation", "IStringable"); 103 | REQUIRE(IStringable == IStringable2); 104 | } 105 | 106 | bool caches_equal(cache const& lhs, cache const& rhs) 107 | { 108 | if (lhs.namespaces().size() != rhs.namespaces().size()) 109 | return false; 110 | 111 | auto compare_typedef_names = [](TypeDef const& lhs, TypeDef const& rhs) 112 | { 113 | return lhs.TypeName() == rhs.TypeName() && lhs.TypeNamespace() == rhs.TypeNamespace(); 114 | }; 115 | 116 | auto compare_members = [compare_typedef_names](std::vector const& lhs, std::vector const& rhs) 117 | { 118 | return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), compare_typedef_names); 119 | }; 120 | 121 | for (auto iter1 = lhs.namespaces().begin(), iter2 = rhs.namespaces().begin(); 122 | iter1 != lhs.namespaces().end() && iter2 != rhs.namespaces().end(); 123 | ++iter1, ++iter2) 124 | { 125 | if (iter1->first != iter2->first) 126 | return false; 127 | 128 | if (!(compare_members(iter1->second.attributes, iter2->second.attributes)) && 129 | compare_members(iter1->second.classes, iter2->second.classes) && 130 | compare_members(iter1->second.contracts, iter2->second.contracts) && 131 | compare_members(iter1->second.delegates, iter2->second.delegates) && 132 | compare_members(iter1->second.enums, iter2->second.enums) && 133 | compare_members(iter1->second.interfaces, iter2->second.interfaces) && 134 | compare_members(iter1->second.structs, iter2->second.structs)) 135 | return false; 136 | 137 | 138 | if (!std::equal(iter1->second.types.begin(), iter1->second.types.end(), 139 | iter2->second.types.begin(), iter2->second.types.end(), 140 | [](auto const& lhs, auto const& rhs) 141 | { 142 | return lhs.first == rhs.first; 143 | })) 144 | return false; 145 | } 146 | return true; 147 | } 148 | 149 | TEST_CASE("cache_filter") 150 | { 151 | std::filesystem::path winmd_dir = get_local_winmd_path(); 152 | auto file_path = winmd_dir; 153 | file_path.append("Windows.Foundation.winmd"); 154 | 155 | cache const unfiltered(file_path.string()); 156 | 157 | { 158 | cache allow_all(file_path.string(), [](TypeDef const&) { return true; }); 159 | REQUIRE(caches_equal(unfiltered, allow_all)); 160 | } 161 | 162 | { 163 | cache allow_none(file_path.string(), [](TypeDef const&) { return false; }); 164 | REQUIRE(allow_none.namespaces().empty()); 165 | } 166 | 167 | { 168 | cache allow_winrt(file_path.string(), [](TypeDef const& type) 169 | { 170 | return type.Flags().WindowsRuntime(); 171 | }); 172 | REQUIRE(caches_equal(unfiltered, allow_winrt)); 173 | } 174 | 175 | { 176 | auto const type_namespace = "Windows.Foundation"; 177 | auto const type_name = "HResult"; 178 | cache filter_hresult(file_path.string(), [type_namespace, type_name](TypeDef const& type) 179 | { 180 | return !(type.TypeName() == type_name && type.TypeNamespace() == type_namespace); 181 | }); 182 | 183 | REQUIRE(unfiltered.find(type_namespace, type_name)); 184 | REQUIRE(!filter_hresult.find(type_namespace, type_name)); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /vs/winmd.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {i_TypeNamespace(),sb}.{i_TypeName(),sb} 55 | 56 | i_TypeNamespace() 57 | i_TypeName() 58 | 59 | 60 | 61 | 62 | 63 | 64 | {i_TypeNamespace(),sb}.{i_TypeName(),sb} 65 | 66 | i_TypeNamespace() 67 | i_TypeName() 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | {i_TypeNamespace(),sb}.{i_TypeName(),sb} 90 | 91 | 92 | TypeDef 93 | 94 | 95 | TypeRef 96 | 97 | 98 | TypeSpec 99 | 100 | i_TypeNamespace() 101 | i_TypeName() 102 | 103 | 104 | 105 | 106 | 107 | {i_Name(),sb} 108 | 109 | i_Name() 110 | 111 | 112 | 113 | 114 | 115 | {i_Name(),sb} 116 | 117 | i_Name() 118 | 119 | 120 | 121 | 122 | 123 | {i_Name(),sb} 124 | 125 | i_Name() 126 | 127 | 128 | 129 | 130 | 131 | {i_Name(),sb} 132 | 133 | i_Name() 134 | 135 | 136 | 137 | 138 | 139 | {i_Name(),sb} 140 | 141 | i_Name() 142 | 143 | 144 | 145 | 146 | 147 | {i_Name(),sb} 148 | 149 | i_Name() 150 | 151 | 152 | 153 | 154 | 155 | {i_Name(),sb} 156 | 157 | i_Name() 158 | 159 | 160 | 161 | 162 | 163 | {i_Name(),sb} 164 | 165 | i_Name() 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/enum_traits.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct Module; 5 | struct TypeRef; 6 | struct TypeDef; 7 | struct Field; 8 | struct MethodDef; 9 | struct Param; 10 | struct InterfaceImpl; 11 | struct MemberRef; 12 | struct Constant; 13 | struct CustomAttribute; 14 | struct FieldMarshal; 15 | struct DeclSecurity; 16 | struct ClassLayout; 17 | struct FieldLayout; 18 | struct StandAloneSig; 19 | struct EventMap; 20 | struct Event; 21 | struct PropertyMap; 22 | struct Property; 23 | struct MethodSemantics; 24 | struct MethodImpl; 25 | struct ModuleRef; 26 | struct TypeSpec; 27 | struct ImplMap; 28 | struct FieldRVA; 29 | struct Assembly; 30 | struct AssemblyProcessor; 31 | struct AssemblyOS; 32 | struct AssemblyRef; 33 | struct AssemblyRefProcessor; 34 | struct AssemblyRefOS; 35 | struct File; 36 | struct ExportedType; 37 | struct ManifestResource; 38 | struct NestedClass; 39 | struct GenericParam; 40 | struct MethodSpec; 41 | struct GenericParamConstraint; 42 | 43 | 44 | template 45 | struct index_tag; 46 | 47 | template 48 | inline constexpr auto index_tag_v = index_tag::value; 49 | 50 | template<> 51 | struct index_tag : std::integral_constant {}; 52 | template<> 53 | struct index_tag : std::integral_constant {}; 54 | template<> 55 | struct index_tag : std::integral_constant {}; 56 | 57 | template<> 58 | struct index_tag : std::integral_constant {}; 59 | template<> 60 | struct index_tag : std::integral_constant {}; 61 | template<> 62 | struct index_tag : std::integral_constant {}; 63 | 64 | template<> 65 | struct index_tag : std::integral_constant {}; 66 | template<> 67 | struct index_tag : std::integral_constant {}; 68 | template<> 69 | struct index_tag : std::integral_constant {}; 70 | template<> 71 | struct index_tag : std::integral_constant {}; 72 | template<> 73 | struct index_tag : std::integral_constant {}; 74 | template<> 75 | struct index_tag : std::integral_constant {}; 76 | template<> 77 | struct index_tag : std::integral_constant {}; 78 | template<> 79 | struct index_tag : std::integral_constant {}; 80 | template<> 81 | struct index_tag : std::integral_constant {}; 82 | template<> 83 | struct index_tag : std::integral_constant {}; 84 | template<> 85 | struct index_tag : std::integral_constant {}; 86 | template<> 87 | struct index_tag : std::integral_constant {}; 88 | template<> 89 | struct index_tag : std::integral_constant {}; 90 | template<> 91 | struct index_tag : std::integral_constant {}; 92 | template<> 93 | struct index_tag : std::integral_constant {}; 94 | template<> 95 | struct index_tag : std::integral_constant {}; 96 | template<> 97 | struct index_tag : std::integral_constant {}; 98 | template<> 99 | struct index_tag : std::integral_constant {}; 100 | template<> 101 | struct index_tag : std::integral_constant {}; 102 | template<> 103 | struct index_tag : std::integral_constant {}; 104 | template<> 105 | struct index_tag : std::integral_constant {}; 106 | 107 | template<> 108 | struct index_tag : std::integral_constant {}; 109 | template<> 110 | struct index_tag : std::integral_constant {}; 111 | 112 | template<> 113 | struct index_tag : std::integral_constant {}; 114 | template<> 115 | struct index_tag : std::integral_constant {}; 116 | template<> 117 | struct index_tag : std::integral_constant {}; 118 | 119 | template<> 120 | struct index_tag : std::integral_constant {}; 121 | template<> 122 | struct index_tag : std::integral_constant {}; 123 | template<> 124 | struct index_tag : std::integral_constant {}; 125 | template<> 126 | struct index_tag : std::integral_constant {}; 127 | template<> 128 | struct index_tag : std::integral_constant {}; 129 | 130 | template<> 131 | struct index_tag : std::integral_constant {}; 132 | template<> 133 | struct index_tag : std::integral_constant {}; 134 | 135 | template<> 136 | struct index_tag : std::integral_constant {}; 137 | template<> 138 | struct index_tag : std::integral_constant {}; 139 | 140 | template<> 141 | struct index_tag : std::integral_constant {}; 142 | template<> 143 | struct index_tag : std::integral_constant {}; 144 | 145 | template<> 146 | struct index_tag : std::integral_constant {}; 147 | template<> 148 | struct index_tag : std::integral_constant {}; 149 | template<> 150 | struct index_tag : std::integral_constant {}; 151 | 152 | template<> 153 | struct index_tag : std::integral_constant {}; 154 | template<> 155 | struct index_tag : std::integral_constant {}; 156 | 157 | template<> 158 | struct index_tag : std::integral_constant {}; 159 | template<> 160 | struct index_tag : std::integral_constant {}; 161 | template<> 162 | struct index_tag : std::integral_constant {}; 163 | template<> 164 | struct index_tag : std::integral_constant {}; 165 | 166 | template<> 167 | struct index_tag : std::integral_constant {}; 168 | template<> 169 | struct index_tag : std::integral_constant {}; 170 | } 171 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/cache.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct cache 5 | { 6 | cache() = default; 7 | cache(cache const&) = delete; 8 | cache& operator=(cache const&) = delete; 9 | 10 | template 11 | explicit cache(C const& files, TypeFilter filter) 12 | { 13 | for (auto&& file : files) 14 | { 15 | auto& db = m_databases.emplace_back(file, this); 16 | 17 | for (auto&& type : db.TypeDef) 18 | { 19 | if (type.Flags().value == 0 || is_nested(type) || !filter(type)) 20 | { 21 | continue; 22 | } 23 | 24 | auto& ns = m_namespaces[type.TypeNamespace()]; 25 | ns.types.try_emplace(type.TypeName(), type); 26 | } 27 | 28 | for (auto&& row : db.NestedClass) 29 | { 30 | m_nested_types[row.EnclosingType()].push_back(row.NestedType()); 31 | } 32 | } 33 | 34 | for (auto&&[namespace_name, members] : m_namespaces) 35 | { 36 | for (auto&&[name, type] : members.types) 37 | { 38 | add_type_to_members(type, members); 39 | } 40 | } 41 | } 42 | 43 | template 44 | explicit cache(C const& files) : cache{ files, default_type_filter{} } 45 | { 46 | } 47 | 48 | template 49 | explicit cache(std::string const& file, TypeFilter filter) : cache{ std::vector{ file }, filter } 50 | { 51 | } 52 | 53 | explicit cache(std::string const& file) : cache{ std::vector{ file }, default_type_filter{} } 54 | { 55 | } 56 | 57 | struct default_type_filter 58 | { 59 | bool operator()(TypeDef const&) const noexcept 60 | { 61 | return true; 62 | } 63 | }; 64 | 65 | TypeDef find(std::string_view const& type_namespace, std::string_view const& type_name) const noexcept 66 | { 67 | auto ns = m_namespaces.find(type_namespace); 68 | 69 | if (ns == m_namespaces.end()) 70 | { 71 | return {}; 72 | } 73 | 74 | auto type = ns->second.types.find(type_name); 75 | 76 | if (type == ns->second.types.end()) 77 | { 78 | return {}; 79 | } 80 | 81 | return type->second; 82 | } 83 | 84 | TypeDef find(std::string_view const& type_string) const 85 | { 86 | auto pos = type_string.rfind('.'); 87 | 88 | if (pos == std::string_view::npos) 89 | { 90 | impl::throw_invalid("Type '", type_string, "' is missing a namespace qualifier"); 91 | } 92 | 93 | return find(type_string.substr(0, pos), type_string.substr(pos + 1, type_string.size())); 94 | } 95 | 96 | TypeDef find_required(std::string_view const& type_namespace, std::string_view const& type_name) const 97 | { 98 | auto definition = find(type_namespace, type_name); 99 | 100 | if (!definition) 101 | { 102 | impl::throw_invalid("Type '", type_namespace, ".", type_name, "' could not be found"); 103 | } 104 | 105 | return definition; 106 | } 107 | 108 | TypeDef find_required(std::string_view const& type_string) const 109 | { 110 | auto pos = type_string.rfind('.'); 111 | 112 | if (pos == std::string_view::npos) 113 | { 114 | impl::throw_invalid("Type '", type_string, "' is missing a namespace qualifier"); 115 | } 116 | 117 | return find_required(type_string.substr(0, pos), type_string.substr(pos + 1, type_string.size())); 118 | } 119 | 120 | auto const& databases() const noexcept 121 | { 122 | return m_databases; 123 | } 124 | 125 | auto const& namespaces() const noexcept 126 | { 127 | return m_namespaces; 128 | } 129 | 130 | void remove_type(std::string_view const& ns, std::string_view const& name) 131 | { 132 | auto m = m_namespaces.find(ns); 133 | if (m == m_namespaces.end()) 134 | { 135 | return; 136 | } 137 | auto& members = m->second; 138 | 139 | auto remove = [&](auto&& collection, auto&& name) 140 | { 141 | auto pos = std::find_if(collection.begin(), collection.end(), [&](auto&& type) 142 | { 143 | return type.TypeName() == name; 144 | }); 145 | 146 | if (pos != collection.end()) 147 | { 148 | collection.erase(pos); 149 | } 150 | }; 151 | 152 | remove(members.interfaces, name); 153 | remove(members.classes, name); 154 | remove(members.enums, name); 155 | remove(members.structs, name); 156 | remove(members.delegates, name); 157 | } 158 | 159 | // This won't invalidate any existing database or row_base (e.g. TypeDef) instances 160 | // However, it may invalidate iterators and references to namespace_members, because those are stored in std::vector 161 | template 162 | void add_database(std::string_view const& file, TypeFilter filter) 163 | { 164 | auto& db = m_databases.emplace_back(file, this); 165 | for (auto&& type : db.TypeDef) 166 | { 167 | if (type.Flags().value == 0 || is_nested(type) || !filter(type)) 168 | { 169 | continue; 170 | } 171 | 172 | auto& ns = m_namespaces[type.TypeNamespace()]; 173 | auto[iter, inserted] = ns.types.try_emplace(type.TypeName(), type); 174 | if (inserted) 175 | { 176 | add_type_to_members(type, ns); 177 | } 178 | } 179 | 180 | for (auto&& row : db.NestedClass) 181 | { 182 | m_nested_types[row.EnclosingType()].push_back(row.NestedType()); 183 | } 184 | } 185 | 186 | void add_database(std::string_view const& file) 187 | { 188 | add_database(file, default_type_filter{}); 189 | } 190 | 191 | std::vector const& nested_types(TypeDef const& enclosing_type) const 192 | { 193 | auto it = m_nested_types.find(enclosing_type); 194 | if (it != m_nested_types.end()) 195 | { 196 | return it->second; 197 | } 198 | else 199 | { 200 | static const std::vector empty; 201 | return empty; 202 | } 203 | } 204 | 205 | struct namespace_members 206 | { 207 | std::map types; 208 | std::vector interfaces; 209 | std::vector classes; 210 | std::vector enums; 211 | std::vector structs; 212 | std::vector delegates; 213 | std::vector attributes; 214 | std::vector contracts; 215 | }; 216 | 217 | using namespace_type = std::pair const&; 218 | 219 | private: 220 | 221 | void add_type_to_members(TypeDef const& type, namespace_members& members) 222 | { 223 | switch (get_category(type)) 224 | { 225 | case category::interface_type: 226 | members.interfaces.push_back(type); 227 | return; 228 | case category::class_type: 229 | if (extends_type(type, "System"sv, "Attribute"sv)) 230 | { 231 | members.attributes.push_back(type); 232 | return; 233 | } 234 | members.classes.push_back(type); 235 | return; 236 | case category::enum_type: 237 | members.enums.push_back(type); 238 | return; 239 | case category::struct_type: 240 | if (get_attribute(type, "Windows.Foundation.Metadata"sv, "ApiContractAttribute"sv)) 241 | { 242 | members.contracts.push_back(type); 243 | return; 244 | } 245 | members.structs.push_back(type); 246 | return; 247 | case category::delegate_type: 248 | members.delegates.push_back(type); 249 | return; 250 | } 251 | } 252 | 253 | std::list m_databases; 254 | std::map m_namespaces; 255 | std::map> m_nested_types; 256 | }; 257 | } -------------------------------------------------------------------------------- /src/impl/winmd_reader/view.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | auto const& begin(std::pair const& values) noexcept 6 | { 7 | return values.first; 8 | } 9 | 10 | template 11 | auto const& end(std::pair const& values) noexcept 12 | { 13 | return values.second; 14 | } 15 | 16 | template 17 | auto distance(std::pair const& values) noexcept 18 | { 19 | return values.second - values.first; 20 | } 21 | 22 | template 23 | auto equal_range(Container const& container, T const& value) noexcept 24 | { 25 | return std::equal_range(container.begin(), container.end(), value); 26 | } 27 | 28 | template 29 | auto equal_range(Container const& container, T const& value, Compare compare) noexcept 30 | { 31 | return std::equal_range(container.begin(), container.end(), value, compare); 32 | } 33 | 34 | struct byte_view; 35 | inline int32_t uncompress_signed(byte_view& cursor, uint32_t length); 36 | 37 | struct byte_view 38 | { 39 | byte_view() noexcept = default; 40 | byte_view(byte_view const&) noexcept = default; 41 | byte_view& operator=(byte_view const&) noexcept = default; 42 | 43 | byte_view(byte_view&& other) noexcept : 44 | m_first(std::exchange(other.m_first, {})), 45 | m_last(std::exchange(other.m_last, {})) 46 | { 47 | } 48 | 49 | byte_view& operator=(byte_view&& other) noexcept 50 | { 51 | m_first = std::exchange(other.m_first, {}); 52 | m_last = std::exchange(other.m_last, {}); 53 | return *this; 54 | } 55 | 56 | byte_view(uint8_t const* const first, uint8_t const* const last) noexcept : 57 | m_first(first), 58 | m_last(last) 59 | { 60 | } 61 | 62 | auto begin() const noexcept 63 | { 64 | return m_first; 65 | } 66 | 67 | auto end() const noexcept 68 | { 69 | return m_last; 70 | } 71 | 72 | uint32_t size() const noexcept 73 | { 74 | return static_cast(end() - begin()); 75 | } 76 | 77 | explicit operator bool() const noexcept 78 | { 79 | return size() > 0; 80 | } 81 | 82 | byte_view seek(uint32_t const offset) const 83 | { 84 | check_available(offset); 85 | return{ m_first + offset, m_last }; 86 | } 87 | 88 | byte_view sub(uint32_t const offset, uint32_t const size) const 89 | { 90 | check_available(offset + size); 91 | return{ m_first + offset, m_first + offset + size }; 92 | } 93 | 94 | template 95 | T const& as(uint32_t const offset = 0) const 96 | { 97 | check_available(offset + sizeof(T)); 98 | return reinterpret_cast(*(m_first + offset)); 99 | } 100 | 101 | std::string_view as_string(uint32_t const offset = 0) const 102 | { 103 | static_assert(sizeof(uint8_t) == 1); 104 | check_available(offset + 1); 105 | auto const length = as(offset); 106 | if (length == 0) 107 | { 108 | return ""; 109 | } 110 | else if (length == 0xff) 111 | { 112 | return { nullptr, 0 }; 113 | } 114 | else 115 | { 116 | check_available(offset + 1 + length); 117 | return { reinterpret_cast(m_first + offset + 1), length }; 118 | } 119 | } 120 | 121 | std::u16string_view as_u16string_constant() const 122 | { 123 | return { reinterpret_cast(m_first), size() / 2 }; 124 | } 125 | 126 | template 127 | auto as_array(uint32_t const offset, uint32_t const count) const 128 | { 129 | check_available(offset + count * sizeof(T)); 130 | return reinterpret_cast(m_first + offset); 131 | } 132 | 133 | private: 134 | 135 | void check_available(uint32_t const offset) const 136 | { 137 | if (m_first + offset > m_last) 138 | { 139 | impl::throw_invalid("Buffer too small"); 140 | } 141 | } 142 | 143 | uint8_t const* m_first{}; 144 | uint8_t const* m_last{}; 145 | }; 146 | 147 | struct file_view : byte_view 148 | { 149 | file_view(file_view const&) = delete; 150 | file_view& operator=(file_view const&) = delete; 151 | file_view(file_view&&) noexcept = default; 152 | file_view& operator=(file_view&&) noexcept = default; 153 | 154 | file_view(std::string_view const& path) : byte_view{ open_file(path) }, m_backed_by_file{ true } 155 | { 156 | } 157 | 158 | file_view(uint8_t const* const first, uint8_t const* const last) noexcept : byte_view{ first, last }, m_backed_by_file{ false } 159 | { 160 | } 161 | 162 | ~file_view() noexcept 163 | { 164 | if (m_backed_by_file) 165 | { 166 | #if defined(_WIN32) 167 | UnmapViewOfFile(begin()); 168 | #else 169 | munmap(const_cast(reinterpret_cast(begin())), size()); 170 | #endif 171 | } 172 | } 173 | 174 | private: 175 | 176 | bool m_backed_by_file; 177 | 178 | #if defined(_WIN32) 179 | struct handle 180 | { 181 | HANDLE value{}; 182 | 183 | ~handle() noexcept 184 | { 185 | if (value) 186 | { 187 | CloseHandle(value); 188 | } 189 | } 190 | 191 | explicit operator bool() const noexcept 192 | { 193 | return value != 0; 194 | } 195 | }; 196 | #endif 197 | 198 | struct file_handle 199 | { 200 | #if defined(_WIN32) 201 | using handle_type = HANDLE; 202 | #else 203 | using handle_type = int; 204 | static constexpr handle_type INVALID_HANDLE_VALUE = -1; 205 | #endif 206 | 207 | handle_type value{ INVALID_HANDLE_VALUE }; 208 | 209 | ~file_handle() noexcept 210 | { 211 | if (value != INVALID_HANDLE_VALUE) 212 | { 213 | #if defined(_WIN32) 214 | CloseHandle(value); 215 | #else 216 | close(value); 217 | #endif 218 | } 219 | } 220 | 221 | explicit operator bool() const noexcept 222 | { 223 | return value != INVALID_HANDLE_VALUE; 224 | } 225 | }; 226 | 227 | static byte_view open_file(std::string_view const& path) 228 | { 229 | #if defined(_WIN32) 230 | auto input = impl::c_str(path); 231 | 232 | auto const input_length = static_cast(path.length() + 1); 233 | int buffer_length = MultiByteToWideChar(CP_UTF8, 0, input, input_length, 0, 0); 234 | std::vector output = std::vector(buffer_length); 235 | int result = MultiByteToWideChar(CP_UTF8, 0, input, input_length, output.data(), buffer_length); 236 | 237 | if (result == 0) 238 | { 239 | switch (GetLastError()) 240 | { 241 | case ERROR_INSUFFICIENT_BUFFER: 242 | impl::throw_invalid("Insufficient buffer size"); 243 | case ERROR_NO_UNICODE_TRANSLATION: 244 | impl::throw_invalid("Untranslatable path"); 245 | default: 246 | impl::throw_invalid("Could not convert path"); 247 | } 248 | } 249 | 250 | file_handle file{ CreateFile2(output.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr) }; 251 | 252 | if (!file) 253 | { 254 | impl::throw_invalid("Could not open file '", path, "'"); 255 | } 256 | 257 | LARGE_INTEGER size{}; 258 | GetFileSizeEx(file.value, &size); 259 | 260 | if (!size.QuadPart) 261 | { 262 | return{}; 263 | } 264 | 265 | handle mapping{ CreateFileMappingW(file.value, nullptr, PAGE_READONLY, 0, 0, nullptr) }; 266 | 267 | if (!mapping) 268 | { 269 | impl::throw_invalid("Could not open file '", path, "'"); 270 | } 271 | 272 | auto const first{ static_cast(MapViewOfFile(mapping.value, FILE_MAP_READ, 0, 0, 0)) }; 273 | return{ first, first + size.QuadPart }; 274 | #else 275 | file_handle file{ open(impl::c_str(path), O_RDONLY, 0) }; 276 | if (!file) 277 | { 278 | impl::throw_invalid("Could not open file '", path, "'"); 279 | } 280 | 281 | struct stat st; 282 | int ret = fstat(file.value, &st); 283 | if (ret < 0) 284 | { 285 | impl::throw_invalid("Could not open file '", path, "'"); 286 | } 287 | if (!st.st_size) 288 | { 289 | return{}; 290 | } 291 | 292 | #if defined(__linux__) 293 | auto const flags = MAP_PRIVATE | MAP_POPULATE; 294 | #else 295 | auto const flags = MAP_PRIVATE; 296 | #endif 297 | 298 | auto const first = static_cast(mmap(nullptr, st.st_size, PROT_READ, flags, file.value, 0)); 299 | if (first == MAP_FAILED) 300 | { 301 | impl::throw_invalid("Could not open file '", path, "'"); 302 | } 303 | 304 | return{ first, first + st.st_size }; 305 | #endif 306 | } 307 | }; 308 | } 309 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/enum.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | struct coded_index_bits : std::integral_constant {}; 6 | 7 | template 8 | inline constexpr uint32_t coded_index_bits_v = coded_index_bits::value; 9 | 10 | enum class TypeDefOrRef : uint32_t 11 | { 12 | TypeDef, 13 | TypeRef, 14 | TypeSpec, 15 | }; 16 | template <> 17 | struct coded_index_bits : std::integral_constant {}; 18 | 19 | enum class HasConstant : uint32_t 20 | { 21 | Field, 22 | Param, 23 | Property, 24 | }; 25 | template <> 26 | struct coded_index_bits : std::integral_constant {}; 27 | 28 | enum class HasCustomAttribute : uint32_t 29 | { 30 | MethodDef, 31 | Field, 32 | TypeRef, 33 | TypeDef, 34 | Param, 35 | InterfaceImpl, 36 | MemberRef, 37 | Module, 38 | Permission, 39 | Property, 40 | Event, 41 | StandAloneSig, 42 | ModuleRef, 43 | TypeSpec, 44 | Assembly, 45 | AssemblyRef, 46 | File, 47 | ExportedType, 48 | ManifestResource, 49 | GenericParam, 50 | GenericParamConstraint, 51 | MethodSpec, 52 | }; 53 | template <> 54 | struct coded_index_bits : std::integral_constant {}; 55 | 56 | enum class HasFieldMarshal : uint32_t 57 | { 58 | Field, 59 | Param, 60 | }; 61 | template <> 62 | struct coded_index_bits : std::integral_constant {}; 63 | 64 | enum class HasDeclSecurity : uint32_t 65 | { 66 | TypeDef, 67 | MethodDef, 68 | Assembly, 69 | }; 70 | template <> 71 | struct coded_index_bits : std::integral_constant {}; 72 | 73 | enum class MemberRefParent : uint32_t 74 | { 75 | TypeDef, 76 | TypeRef, 77 | ModuleRef, 78 | MethodDef, 79 | TypeSpec, 80 | }; 81 | template <> 82 | struct coded_index_bits : std::integral_constant {}; 83 | 84 | enum class HasSemantics : uint32_t 85 | { 86 | Event, 87 | Property, 88 | }; 89 | template <> 90 | struct coded_index_bits : std::integral_constant {}; 91 | 92 | enum class MethodDefOrRef : uint32_t 93 | { 94 | MethodDef, 95 | MemberRef, 96 | }; 97 | template <> 98 | struct coded_index_bits : std::integral_constant {}; 99 | 100 | enum class MemberForwarded : uint32_t 101 | { 102 | Field, 103 | MethodDef, 104 | }; 105 | template <> 106 | struct coded_index_bits : std::integral_constant {}; 107 | 108 | enum class Implementation : uint32_t 109 | { 110 | File, 111 | AssemblyRef, 112 | ExportedType, 113 | }; 114 | template <> 115 | struct coded_index_bits : std::integral_constant {}; 116 | 117 | enum class CustomAttributeType : uint32_t 118 | { 119 | MethodDef = 2, 120 | MemberRef, 121 | }; 122 | template <> 123 | struct coded_index_bits : std::integral_constant {}; 124 | 125 | enum class ResolutionScope : uint32_t 126 | { 127 | Module, 128 | ModuleRef, 129 | AssemblyRef, 130 | TypeRef, 131 | }; 132 | template <> 133 | struct coded_index_bits : std::integral_constant {}; 134 | 135 | enum class TypeOrMethodDef : uint32_t 136 | { 137 | TypeDef, 138 | MethodDef, 139 | }; 140 | template <> 141 | struct coded_index_bits : std::integral_constant {}; 142 | 143 | enum class MemberAccess : uint16_t 144 | { 145 | CompilerControlled = 0x0000, // Member not referenceable 146 | Private = 0x0001, 147 | FamAndAssem = 0x0002, // Accessible by subtypes only in this Assembly 148 | Assembly = 0x0003, // Accessible by anyone in this Assembly 149 | Family = 0x0004, // aka Protected 150 | FamOrAssem = 0x0005, // Accessible by subtypes anywhere, plus anyone in this Assembly 151 | Public = 0x0006, 152 | }; 153 | 154 | enum class TypeVisibility : uint32_t 155 | { 156 | NotPublic = 0x00000000, 157 | Public = 0x00000001, 158 | NestedPublic = 0x00000002, 159 | NestedPrivate = 0x00000003, 160 | NestedFamily = 0x00000004, 161 | NestedAssembly = 0x00000005, 162 | NestedFamANDAssem = 0x00000006, 163 | NestedFamORAssem = 0x00000007, 164 | }; 165 | 166 | enum class TypeLayout : uint32_t 167 | { 168 | AutoLayout = 0x00000000, 169 | SequentialLayout = 0x00000008, 170 | ExplicitLayout = 0x00000010, 171 | }; 172 | 173 | enum class TypeSemantics : uint32_t 174 | { 175 | Class = 0x00000000, 176 | Interface = 0x00000020, 177 | }; 178 | 179 | enum class StringFormat : uint32_t 180 | { 181 | AnsiClass = 0x00000000, 182 | UnicodeClass = 0x00010000, 183 | AutoClass = 0x00020000, 184 | CustomFormatClass = 0x00030000, 185 | CustomFormatMask = 0x00C00000, 186 | }; 187 | 188 | enum class CodeType : uint16_t 189 | { 190 | IL = 0x0000, // Method impl is CIL 191 | Native = 0x0001, // Method impl is native 192 | OPTIL = 0x0002, // Reserved: shall be zero in conforming implementations 193 | Runtime = 0x0003, // Method impl is provided by the runtime 194 | }; 195 | 196 | enum class Managed : uint16_t 197 | { 198 | Unmanaged = 0x0004, 199 | Managed = 0x0000, 200 | }; 201 | 202 | enum class VtableLayout : uint16_t 203 | { 204 | ReuseSlot = 0x0000, // Method reuses existing slot in a vtable 205 | NewSlot = 0x0100, // Method always gets a new slot in the vtable 206 | }; 207 | 208 | enum class GenericParamVariance : uint16_t 209 | { 210 | None = 0x0000, 211 | Covariant = 0x0001, 212 | Contravariant = 0x0002 213 | }; 214 | 215 | enum class GenericParamSpecialConstraint : uint16_t 216 | { 217 | ReferenceTypeConstraint = 0x0004, 218 | NotNullableValueTypeConstraint = 0x0008, 219 | DefaultConstructorConstraint = 0x0010 220 | }; 221 | 222 | enum class ConstantType : uint16_t 223 | { 224 | Boolean = 0x02, 225 | Char = 0x03, 226 | Int8 = 0x04, 227 | UInt8 = 0x05, 228 | Int16 = 0x06, 229 | UInt16 = 0x07, 230 | Int32 = 0x08, 231 | UInt32 = 0x09, 232 | Int64 = 0x0a, 233 | UInt64 = 0x0b, 234 | Float32 = 0x0c, 235 | Float64 = 0x0d, 236 | String = 0x0e, 237 | Class = 0x12 238 | }; 239 | 240 | enum class ElementType : uint8_t 241 | { 242 | End = 0x00, // Sentinel value 243 | 244 | Void = 0x01, 245 | Boolean = 0x02, 246 | Char = 0x03, 247 | I1 = 0x04, 248 | U1 = 0x05, 249 | I2 = 0x06, 250 | U2 = 0x07, 251 | I4 = 0x08, 252 | U4 = 0x09, 253 | I8 = 0x0a, 254 | U8 = 0x0b, 255 | R4 = 0x0c, 256 | R8 = 0x0d, 257 | String = 0x0e, 258 | 259 | Ptr = 0x0f, // Followed by TypeSig 260 | ByRef = 0x10, // Followed by TypeSig 261 | ValueType = 0x11, // Followed by TypeDef or TypeRef 262 | Class = 0x12, // Followed by TypeDef or TypeRef 263 | Var = 0x13, // Generic parameter in a type definition, represented as unsigned integer 264 | Array = 0x14, 265 | GenericInst = 0x15, 266 | TypedByRef = 0x16, 267 | 268 | I = 0x18, // System.IntPtr 269 | U = 0x19, // System.UIntPtr 270 | 271 | FnPtr = 0x1b, // Followed by full method signature 272 | Object = 0x1c, // System.Object 273 | SZArray = 0x1d, 274 | MVar = 0x1e, // Generic parameter in a method definition, represented as unsigned integer 275 | CModReqd = 0x1f, // Required modifier, followed by a TypeDef or TypeRef 276 | CModOpt = 0x20, // Optional modifier, followed by a TypeDef or TypeRef 277 | Internal = 0x21, 278 | 279 | Modifier = 0x40, // Or'd with folowing element types 280 | Sentinel = 0x41, // Sentinel for vararg method signature 281 | 282 | Pinned = 0x45, 283 | 284 | Type = 0x50, // System.Type 285 | TaggedObject = 0x51, // Boxed object (in custom attributes) 286 | Field = 0x53, // Custom attribute field 287 | Property = 0x54, // Custom attribute property 288 | Enum = 0x55, // Custom attribute enum 289 | }; 290 | 291 | enum class CallingConvention : uint8_t 292 | { 293 | Default = 0x00, 294 | VarArg = 0x05, 295 | Field = 0x06, 296 | LocalSig = 0x07, 297 | Property = 0x08, 298 | GenericInst = 0x10, 299 | Mask = 0x0f, 300 | 301 | HasThis = 0x20, 302 | ExplicitThis = 0x40, 303 | Generic = 0x10, 304 | }; 305 | 306 | enum class AssemblyHashAlgorithm : uint32_t 307 | { 308 | None = 0x0000, 309 | Reserved_MD5 = 0x8003, 310 | SHA1 = 0x8004, 311 | }; 312 | 313 | enum class AssemblyFlags : uint32_t 314 | { 315 | PublicKey = 0x0001, // The assembly reference holds the full (unhashed) public key 316 | Retargetable = 0x0100, 317 | WindowsRuntime = 0x0200, 318 | DisableJITcompileOptimizer = 0x4000, 319 | EnableJITcompileTracking = 0x8000, 320 | }; 321 | 322 | template 323 | constexpr inline T enum_mask(T value, T mask) noexcept 324 | { 325 | static_assert(std::is_enum_v); 326 | using val = std::underlying_type_t; 327 | return static_cast(static_cast(value) & static_cast(mask)); 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /test/winmd.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | NotUsing 27 | NotUsing 28 | NotUsing 29 | NotUsing 30 | 31 | 32 | Create 33 | Create 34 | Create 35 | Create 36 | 37 | 38 | 39 | 40 | 41 | 42 | 16.0 43 | {50FE79EA-0FCE-489B-B6B4-3303DAE2E9A1} 44 | Win32Proj 45 | winmd 46 | 10.0 47 | 48 | 49 | 50 | Application 51 | true 52 | v142 53 | Unicode 54 | 55 | 56 | Application 57 | false 58 | v142 59 | true 60 | Unicode 61 | 62 | 63 | Application 64 | true 65 | v142 66 | Unicode 67 | 68 | 69 | Application 70 | false 71 | v142 72 | true 73 | Unicode 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | true 95 | $(SolutionDir)x86\$(Configuration)\ 96 | x86\$(Configuration)\ 97 | 98 | 99 | true 100 | 101 | 102 | false 103 | $(SolutionDir)x86\$(Configuration)\ 104 | x86\$(Configuration)\ 105 | 106 | 107 | false 108 | 109 | 110 | 111 | Use 112 | Level4 113 | Disabled 114 | true 115 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 116 | true 117 | pch.h 118 | ..\src 119 | stdcpp17 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Use 129 | Level4 130 | Disabled 131 | true 132 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | pch.h 135 | ..\src 136 | stdcpp17 137 | 138 | 139 | Console 140 | true 141 | 142 | 143 | 144 | 145 | Use 146 | Level4 147 | MaxSpeed 148 | true 149 | true 150 | true 151 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 152 | true 153 | pch.h 154 | ..\src 155 | stdcpp17 156 | 157 | 158 | Console 159 | true 160 | true 161 | true 162 | 163 | 164 | 165 | 166 | Use 167 | Level4 168 | MaxSpeed 169 | true 170 | true 171 | true 172 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 173 | true 174 | pch.h 175 | ..\src 176 | stdcpp17 177 | 178 | 179 | Console 180 | true 181 | true 182 | true 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/table.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct database; 5 | struct cache; 6 | 7 | struct table_base 8 | { 9 | explicit table_base(database const* database) noexcept : m_database(database) 10 | { 11 | } 12 | 13 | database const& get_database() const noexcept 14 | { 15 | return *m_database; 16 | } 17 | 18 | uint32_t size() const noexcept 19 | { 20 | return m_row_count; 21 | } 22 | 23 | uint32_t row_size() const noexcept 24 | { 25 | return m_row_size; 26 | } 27 | 28 | uint32_t column_size(uint32_t const column) const noexcept 29 | { 30 | return m_columns[column].size; 31 | } 32 | 33 | template 34 | T get_value(uint32_t const row, uint32_t const column) const 35 | { 36 | static_assert(std::is_enum_v || std::is_integral_v); 37 | uint32_t const data_size = m_columns[column].size; 38 | XLANG_ASSERT(data_size == 1 || data_size == 2 || data_size == 4 || data_size == 8); 39 | XLANG_ASSERT(data_size <= sizeof(T)); 40 | 41 | if (row > size()) 42 | { 43 | impl::throw_invalid("Invalid row index"); 44 | } 45 | 46 | uint8_t const* ptr = m_data + row * m_row_size + m_columns[column].offset; 47 | switch (data_size) 48 | { 49 | case 1: 50 | { 51 | uint8_t temp = *ptr; 52 | return static_cast(temp); 53 | } 54 | case 2: 55 | { 56 | uint16_t temp = *reinterpret_cast(ptr); 57 | return static_cast(temp); 58 | } 59 | case 4: 60 | { 61 | uint32_t temp = *reinterpret_cast(ptr); 62 | return static_cast(temp); 63 | } 64 | default: 65 | { 66 | uint64_t temp = *reinterpret_cast(ptr); 67 | return static_cast(temp); 68 | } 69 | } 70 | } 71 | 72 | private: 73 | 74 | friend database; 75 | 76 | struct column 77 | { 78 | uint8_t offset; 79 | uint8_t size; 80 | }; 81 | 82 | database const* m_database; 83 | uint8_t const* m_data{}; 84 | uint32_t m_row_count{}; 85 | uint8_t m_row_size{}; 86 | std::array m_columns{}; 87 | 88 | void set_row_count(uint32_t const row_count) noexcept 89 | { 90 | XLANG_ASSERT(!m_row_count); 91 | m_row_count = row_count; 92 | } 93 | 94 | void set_columns(uint8_t const a, uint8_t const b = 0, uint8_t const c = 0, uint8_t const d = 0, uint8_t const e = 0, uint8_t const f = 0) noexcept 95 | { 96 | XLANG_ASSERT(a); 97 | XLANG_ASSERT(a <= 8); 98 | XLANG_ASSERT(b <= 8); 99 | XLANG_ASSERT(c <= 8); 100 | XLANG_ASSERT(d <= 8); 101 | XLANG_ASSERT(e <= 8); 102 | XLANG_ASSERT(f <= 8); 103 | 104 | XLANG_ASSERT(!m_row_size); 105 | m_row_size = a + b + c + d + e + f; 106 | XLANG_ASSERT(m_row_size < UINT8_MAX); 107 | 108 | m_columns[0] = { 0, a }; 109 | if (b) { m_columns[1] = { static_cast(a), b }; } 110 | if (c) { m_columns[2] = { static_cast(a + b), c }; } 111 | if (d) { m_columns[3] = { static_cast(a + b + c), d }; } 112 | if (e) { m_columns[4] = { static_cast(a + b + c + d), e }; } 113 | if (f) { m_columns[5] = { static_cast(a + b + c + d + e), f }; } 114 | } 115 | 116 | void set_data(byte_view& view) noexcept 117 | { 118 | XLANG_ASSERT(!m_data); 119 | 120 | if (m_row_count) 121 | { 122 | XLANG_ASSERT(m_row_size); 123 | m_data = view.begin(); 124 | view = view.seek(m_row_count * m_row_size); 125 | } 126 | } 127 | 128 | uint8_t index_size() const noexcept 129 | { 130 | return m_row_count < (1 << 16) ? 2 : 4; 131 | } 132 | }; 133 | 134 | template 135 | struct index_base 136 | { 137 | index_base() noexcept = default; 138 | 139 | index_base(table_base const* const table, T const type, uint32_t const row) noexcept : 140 | m_table{ table }, 141 | m_value{ ((row + 1) << coded_index_bits_v) | static_cast(type) } 142 | { 143 | } 144 | 145 | index_base(table_base const* const table, uint32_t const value) noexcept : 146 | m_table{ table }, 147 | m_value{ value } 148 | { 149 | } 150 | 151 | explicit operator bool() const noexcept 152 | { 153 | return m_value != 0; 154 | } 155 | 156 | T type() const noexcept 157 | { 158 | return static_cast(m_value & ((1 << coded_index_bits_v) - 1)); 159 | } 160 | 161 | uint32_t index() const noexcept 162 | { 163 | return (m_value >> coded_index_bits_v) - 1; 164 | } 165 | 166 | template 167 | Row get_row() const; 168 | 169 | bool operator==(index_base const& other) const noexcept 170 | { 171 | return m_value == other.m_value; 172 | } 173 | 174 | bool operator!=(index_base const& other) const noexcept 175 | { 176 | return !(*this == other); 177 | } 178 | 179 | bool operator<(index_base const& other) const noexcept 180 | { 181 | return m_value < other.m_value; 182 | } 183 | 184 | database const& get_database() const noexcept 185 | { 186 | return m_table->get_database(); 187 | } 188 | 189 | protected: 190 | 191 | table_base const* m_table{}; 192 | uint32_t m_value{}; 193 | }; 194 | 195 | template 196 | struct typed_index : index_base 197 | { 198 | using index_base::index_base; 199 | }; 200 | 201 | template <> struct typed_index : index_base 202 | { 203 | using index_base::index_base; 204 | 205 | auto TypeRef() const; 206 | auto TypeDef() const; 207 | }; 208 | 209 | template 210 | struct coded_index : typed_index 211 | { 212 | coded_index() noexcept = default; 213 | 214 | coded_index(table_base const* const table, T const type, uint32_t const row) noexcept : 215 | typed_index{ table, type, row } 216 | { 217 | } 218 | 219 | coded_index(table_base const* const table, uint32_t const value) noexcept : 220 | typed_index{ table, value } 221 | { 222 | } 223 | }; 224 | 225 | template 226 | struct row_base 227 | { 228 | using iterator_category = std::random_access_iterator_tag; 229 | using value_type = Row; 230 | using difference_type = int32_t; 231 | using pointer = value_type*; 232 | using reference = value_type&; 233 | using const_reference = value_type const&; 234 | 235 | row_base(table_base const* const table, uint32_t const index) noexcept : m_table(table), m_index(index) 236 | { 237 | } 238 | 239 | uint32_t index() const noexcept 240 | { 241 | return m_index; 242 | } 243 | 244 | template 245 | auto coded_index() const noexcept 246 | { 247 | return reader::coded_index{ m_table, index_tag_v, index() }; 248 | } 249 | 250 | template 251 | T get_value(uint32_t const column) const 252 | { 253 | XLANG_ASSERT(*this); 254 | return m_table->get_value(m_index, column); 255 | } 256 | 257 | template 258 | auto get_list(uint32_t const column) const; 259 | 260 | template 261 | auto get_target_row(uint32_t const column) const; 262 | 263 | template 264 | auto get_parent_row() const; 265 | 266 | database const& get_database() const noexcept 267 | { 268 | return m_table->get_database(); 269 | } 270 | 271 | cache const& get_cache() const noexcept 272 | { 273 | return get_database().get_cache(); 274 | } 275 | 276 | reference operator++() noexcept 277 | { 278 | ++m_index; 279 | return static_cast(*this); 280 | } 281 | 282 | value_type operator++(int) noexcept 283 | { 284 | row_base temp{ *this }; 285 | operator++(); 286 | return temp; 287 | } 288 | 289 | reference operator--() noexcept 290 | { 291 | --m_index; 292 | return static_cast(*this); 293 | } 294 | 295 | value_type operator--(int) noexcept 296 | { 297 | row_base temp{ *this }; 298 | operator--(); 299 | return temp; 300 | } 301 | 302 | reference operator+=(difference_type offset) noexcept 303 | { 304 | m_index += offset; 305 | return static_cast(*this); 306 | } 307 | 308 | value_type operator+(difference_type offset) const noexcept 309 | { 310 | return { m_table, m_index + offset }; 311 | } 312 | 313 | reference operator-=(difference_type offset) noexcept 314 | { 315 | return *this += -offset; 316 | } 317 | 318 | value_type operator-(difference_type offset) const noexcept 319 | { 320 | return *this + -offset; 321 | } 322 | 323 | difference_type operator-(row_base const& other) const noexcept 324 | { 325 | XLANG_ASSERT(m_table == other.m_table); 326 | return m_index - other.m_index; 327 | } 328 | 329 | value_type operator[](difference_type offset) const noexcept 330 | { 331 | return { m_table, m_index + offset }; 332 | } 333 | 334 | bool operator==(row_base const& other) const noexcept 335 | { 336 | return (m_table == other.m_table) && (m_index == other.m_index); 337 | } 338 | 339 | bool operator!=(row_base const& other) const noexcept 340 | { 341 | return !(*this == other); 342 | } 343 | 344 | bool operator<(row_base const& other) const noexcept 345 | { 346 | return m_table < other.m_table || (!(other.m_table < m_table) && m_index < other.m_index); 347 | } 348 | 349 | bool operator>(row_base const& other) const noexcept 350 | { 351 | return other < *this; 352 | } 353 | 354 | bool operator<=(row_base const& other) const noexcept 355 | { 356 | return !(other < *this); 357 | } 358 | 359 | bool operator>=(row_base const& other) const noexcept 360 | { 361 | return !(*this < other); 362 | } 363 | 364 | [[nodiscard]] const_reference operator*() const noexcept 365 | { 366 | return static_cast(*this); 367 | } 368 | 369 | explicit operator bool() const noexcept 370 | { 371 | return m_table != nullptr; 372 | } 373 | 374 | protected: 375 | 376 | row_base() noexcept = default; 377 | 378 | std::string_view get_string(uint32_t const column) const; 379 | byte_view get_blob(uint32_t const column) const; 380 | 381 | template 382 | auto get_coded_index(uint32_t const column) const 383 | { 384 | return reader::coded_index{ m_table, m_table->get_value(m_index, column) }; 385 | } 386 | 387 | table_base const* get_table() const noexcept 388 | { 389 | return m_table; 390 | } 391 | 392 | private: 393 | 394 | table_base const* m_table{}; 395 | uint32_t m_index{}; 396 | }; 397 | 398 | template 399 | struct table : table_base 400 | { 401 | explicit table(database const* const database) noexcept : table_base{ database } 402 | { 403 | } 404 | 405 | T begin() const noexcept 406 | { 407 | return { this, 0 }; 408 | } 409 | 410 | T end() const noexcept 411 | { 412 | return { this, size() }; 413 | } 414 | 415 | T operator[](uint32_t const row) const noexcept 416 | { 417 | return { this, row }; 418 | } 419 | }; 420 | } 421 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/custom_attribute.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | inline auto CustomAttribute::TypeNamespaceAndName() const 5 | { 6 | if (Type().type() == CustomAttributeType::MemberRef) 7 | { 8 | auto const& member_parent = Type().MemberRef().Class(); 9 | switch (member_parent.type()) 10 | { 11 | case MemberRefParent::TypeDef: 12 | { 13 | auto const& def = member_parent.TypeDef(); 14 | return std::pair{ def.TypeNamespace(), def.TypeName() }; 15 | } 16 | 17 | case MemberRefParent::TypeRef: 18 | { 19 | auto const& ref = member_parent.TypeRef(); 20 | return std::pair{ ref.TypeNamespace(), ref.TypeName() }; 21 | } 22 | default: 23 | impl::throw_invalid("A CustomAttribute MemberRef should only be a TypeDef or TypeRef"); 24 | } 25 | } 26 | else 27 | { 28 | auto const& def = Type().MethodDef().Parent(); 29 | return std::pair{ def.TypeNamespace(), def.TypeName() }; 30 | } 31 | } 32 | 33 | struct ElemSig 34 | { 35 | struct SystemType 36 | { 37 | std::string_view name; 38 | }; 39 | 40 | struct EnumValue 41 | { 42 | EnumDefinition type; 43 | using value_type = std::variant; 44 | value_type value; 45 | 46 | bool equals_enumerator(std::string_view const& name) const 47 | { 48 | auto field = type.get_enumerator(name); 49 | auto constant_value = std::visit([](auto&& v) { return Constant::constant_type{ v }; }, value); 50 | return field.Constant().Value() == constant_value; 51 | } 52 | }; 53 | 54 | using value_type = std::variant; 55 | 56 | ElemSig(database const& db, ParamSig const& param, byte_view& data) 57 | : value{ read_element(db, param, data) } 58 | { 59 | } 60 | 61 | ElemSig(SystemType type) 62 | : value(type) 63 | { 64 | } 65 | 66 | ElemSig(EnumDefinition const& enum_def, byte_view& data) 67 | : value{ EnumValue{enum_def, read_enum(enum_def.m_underlying_type, data) } } 68 | { 69 | } 70 | 71 | ElemSig(ElementType type, byte_view& data) 72 | : value{ read_primitive(type, data) } 73 | { 74 | } 75 | 76 | static value_type read_element(database const& db, ParamSig const& param, byte_view& data) 77 | { 78 | auto const& type = param.Type().Type(); 79 | if (auto element_type = std::get_if(&type)) 80 | { 81 | return read_primitive(*element_type, data); 82 | } 83 | else if (auto type_index = std::get_if>(&type)) 84 | { 85 | if ((type_index->type() == TypeDefOrRef::TypeRef && type_index->TypeRef().TypeNamespace() == "System" && type_index->TypeRef().TypeName() == "Type") || 86 | (type_index->type() == TypeDefOrRef::TypeDef && type_index->TypeDef().TypeNamespace() == "System" && type_index->TypeDef().TypeName() == "Type")) 87 | { 88 | return SystemType{ read(data) }; 89 | } 90 | else 91 | { 92 | // Should be an enum. Resolve it. 93 | auto resolve_type = [&db, &type_index]() -> TypeDef 94 | { 95 | if (type_index->type() == TypeDefOrRef::TypeDef) 96 | { 97 | return type_index->TypeDef(); 98 | } 99 | auto const& typeref = type_index->TypeRef(); 100 | return db.get_cache().find_required(typeref.TypeNamespace(), typeref.TypeName()); 101 | }; 102 | TypeDef const& enum_type = resolve_type(); 103 | if (!enum_type.is_enum()) 104 | { 105 | impl::throw_invalid("CustomAttribute params that are TypeDefOrRef must be an enum or System.Type"); 106 | } 107 | 108 | auto const& enum_def = enum_type.get_enum_definition(); 109 | return EnumValue{ enum_def, read_enum(enum_def.m_underlying_type, data) }; 110 | } 111 | } 112 | impl::throw_invalid("Custom attribute params must be primitives, enums, or System.Type"); 113 | } 114 | 115 | static value_type read_primitive(ElementType type, byte_view& data) 116 | { 117 | switch (type) 118 | { 119 | case ElementType::Boolean: 120 | return read(data); 121 | 122 | case ElementType::Char: 123 | return read(data); 124 | 125 | case ElementType::I1: 126 | return read(data); 127 | 128 | case ElementType::U1: 129 | return read(data); 130 | 131 | case ElementType::I2: 132 | return read(data); 133 | 134 | case ElementType::U2: 135 | return read(data); 136 | 137 | case ElementType::I4: 138 | return read(data); 139 | 140 | case ElementType::U4: 141 | return read(data); 142 | 143 | case ElementType::I8: 144 | return read(data); 145 | 146 | case ElementType::U8: 147 | return read(data); 148 | 149 | case ElementType::R4: 150 | return read(data); 151 | 152 | case ElementType::R8: 153 | return read(data); 154 | 155 | case ElementType::String: 156 | return read(data); 157 | 158 | default: 159 | impl::throw_invalid("Non-primitive type encountered"); 160 | } 161 | } 162 | 163 | static EnumValue::value_type read_enum(ElementType type, byte_view& data) 164 | { 165 | switch (type) 166 | { 167 | case ElementType::Boolean: 168 | return read(data); 169 | 170 | case ElementType::Char: 171 | return read(data); 172 | 173 | case ElementType::I1: 174 | return read(data); 175 | 176 | case ElementType::U1: 177 | return read(data); 178 | 179 | case ElementType::I2: 180 | return read(data); 181 | 182 | case ElementType::U2: 183 | return read(data); 184 | 185 | case ElementType::I4: 186 | return read(data); 187 | 188 | case ElementType::U4: 189 | return read(data); 190 | 191 | case ElementType::I8: 192 | return read(data); 193 | 194 | case ElementType::U8: 195 | return read(data); 196 | 197 | default: 198 | impl::throw_invalid("Invalid underling enum type encountered"); 199 | } 200 | } 201 | 202 | value_type value; 203 | }; 204 | 205 | struct FixedArgSig 206 | { 207 | using value_type = std::variant>; 208 | 209 | FixedArgSig(database const& db, ParamSig const& ctor_param, byte_view& data) 210 | : value{ read_arg(db, ctor_param, data) } 211 | {} 212 | 213 | FixedArgSig(ElemSig::SystemType type) 214 | : value{ ElemSig{type} } 215 | {} 216 | 217 | FixedArgSig(EnumDefinition const& enum_def, byte_view& data) 218 | : value{ ElemSig{ enum_def, data } } 219 | {} 220 | 221 | FixedArgSig(ElementType type, bool is_array, byte_view& data) 222 | : value{ read_arg(type, is_array, data) } 223 | {} 224 | 225 | static value_type read_arg(database const& db, ParamSig const& ctor_param, byte_view& data) 226 | { 227 | auto const& type_sig = ctor_param.Type(); 228 | if (type_sig.is_szarray()) 229 | { 230 | std::vector elems; 231 | auto const num_elements = read(data); 232 | if (num_elements != 0xffffffff) 233 | { 234 | if (num_elements > data.size()) 235 | { 236 | impl::throw_invalid("Invalid blob array size"); 237 | } 238 | elems.reserve(num_elements); 239 | for (uint32_t i = 0; i < num_elements; ++i) 240 | { 241 | elems.emplace_back(db, ctor_param, data); 242 | } 243 | } 244 | return elems; 245 | } 246 | else 247 | { 248 | return ElemSig{ db, ctor_param, data }; 249 | } 250 | } 251 | 252 | static value_type read_arg(ElementType type, bool is_array, byte_view& data) 253 | { 254 | if (is_array) 255 | { 256 | std::vector elems; 257 | auto const num_elements = read(data); 258 | if (num_elements != 0xffffffff) 259 | { 260 | if (num_elements > data.size()) 261 | { 262 | impl::throw_invalid("Invalid blob array size"); 263 | } 264 | elems.reserve(num_elements); 265 | for (uint32_t i = 0; i < num_elements; ++i) 266 | { 267 | elems.emplace_back(type, data); 268 | } 269 | } 270 | return elems; 271 | } 272 | else 273 | { 274 | return ElemSig{ type, data }; 275 | } 276 | } 277 | 278 | value_type value; 279 | }; 280 | 281 | struct NamedArgSig 282 | { 283 | NamedArgSig(database const& db, byte_view& data) 284 | : value{ parse_value(db, data) } 285 | {} 286 | 287 | std::string_view name; 288 | FixedArgSig value; 289 | 290 | private: 291 | FixedArgSig parse_value(database const& db, byte_view& data) 292 | { 293 | auto const field_or_prop = read(data); 294 | if (field_or_prop != ElementType::Field && field_or_prop != ElementType::Property) 295 | { 296 | impl::throw_invalid("NamedArg must be either FIELD or PROPERTY"); 297 | } 298 | 299 | auto type = read(data); 300 | switch (type) 301 | { 302 | case ElementType::Type: 303 | name = read(data); 304 | return FixedArgSig{ ElemSig::SystemType{read(data)} }; 305 | 306 | case ElementType::Enum: 307 | { 308 | auto type_string = read(data); 309 | name = read(data); 310 | auto type_def = db.get_cache().find(type_string); 311 | if (!type_def) 312 | { 313 | impl::throw_invalid("CustomAttribute named param referenced unresolved enum type"); 314 | } 315 | if (!type_def.is_enum()) 316 | { 317 | impl::throw_invalid("CustomAttribute named param referenced non-enum type"); 318 | } 319 | 320 | return FixedArgSig{ type_def.get_enum_definition(), data }; 321 | } 322 | 323 | default: 324 | { 325 | bool const is_array = (type == ElementType::SZArray); 326 | if (is_array) 327 | { 328 | type = read(data); 329 | } 330 | if (type < ElementType::Boolean || ElementType::String < type) 331 | { 332 | impl::throw_invalid("CustomAttribute named param must be a primitive, System.Type, or an Enum"); 333 | } 334 | name = read(data); 335 | return FixedArgSig{ type, is_array, data }; 336 | } 337 | } 338 | } 339 | }; 340 | 341 | struct CustomAttributeSig 342 | { 343 | CustomAttributeSig(table_base const* table, byte_view& data, MethodDefSig const& ctor) 344 | { 345 | database const& db = table->get_database(); 346 | auto const prolog = read(data); 347 | if (prolog != 0x0001) 348 | { 349 | impl::throw_invalid("CustomAttribute blobs must start with prolog of 0x0001"); 350 | } 351 | 352 | for (auto const& param : ctor.Params()) 353 | { 354 | m_fixed_args.push_back(FixedArgSig{ db, param, data }); 355 | } 356 | 357 | const auto num_named_args = read(data); 358 | if (num_named_args > data.size()) 359 | { 360 | impl::throw_invalid("Invalid blob array size"); 361 | } 362 | m_named_args.reserve(num_named_args); 363 | 364 | for (uint16_t i = 0; i < num_named_args; ++i) 365 | { 366 | m_named_args.emplace_back(db, data); 367 | } 368 | } 369 | 370 | std::vector const& FixedArgs() const noexcept { return m_fixed_args; } 371 | std::vector const& NamedArgs() const noexcept { return m_named_args; } 372 | 373 | private: 374 | std::vector m_fixed_args; 375 | std::vector m_named_args; 376 | }; 377 | 378 | inline auto CustomAttribute::Value() const 379 | { 380 | auto const ctor = Type(); 381 | MethodDefSig const& method_sig = ctor.type() == CustomAttributeType::MemberRef ? ctor.MemberRef().MethodSignature() : ctor.MethodDef().Signature(); 382 | auto cursor = get_blob(2); 383 | return CustomAttributeSig{ get_table(), cursor, method_sig }; 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/schema.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct TypeRef : row_base 5 | { 6 | using row_base::row_base; 7 | 8 | auto ResolutionScope() const 9 | { 10 | return get_coded_index(0); 11 | } 12 | 13 | auto TypeName() const 14 | { 15 | return get_string(1); 16 | } 17 | 18 | auto TypeNamespace() const 19 | { 20 | return get_string(2); 21 | } 22 | 23 | auto CustomAttribute() const; 24 | }; 25 | 26 | struct CustomAttribute : row_base 27 | { 28 | using row_base::row_base; 29 | 30 | auto Parent() const 31 | { 32 | return get_coded_index(0); 33 | } 34 | 35 | auto Type() const 36 | { 37 | return get_coded_index(1); 38 | } 39 | 40 | auto Value() const; 41 | 42 | auto TypeNamespaceAndName() const; 43 | }; 44 | 45 | struct TypeDef : row_base 46 | { 47 | using row_base::row_base; 48 | 49 | auto Flags() const 50 | { 51 | return TypeAttributes{{ get_value(0) }}; 52 | } 53 | 54 | auto TypeName() const 55 | { 56 | return get_string(1); 57 | } 58 | 59 | auto TypeNamespace() const 60 | { 61 | return get_string(2); 62 | } 63 | 64 | auto Extends() const 65 | { 66 | return get_coded_index(3); 67 | } 68 | 69 | auto FieldList() const; 70 | auto MethodList() const; 71 | 72 | auto CustomAttribute() const; 73 | auto InterfaceImpl() const; 74 | auto GenericParam() const; 75 | auto PropertyList() const; 76 | auto EventList() const; 77 | auto MethodImplList() const; 78 | 79 | auto EnclosingType() const; 80 | 81 | bool is_enum() const; 82 | auto get_enum_definition() const; 83 | }; 84 | 85 | struct MethodDef : row_base 86 | { 87 | using row_base::row_base; 88 | 89 | auto RVA() const 90 | { 91 | return get_value(0); 92 | } 93 | 94 | auto ImplFlags() const 95 | { 96 | return MethodImplAttributes{{ get_value(1) }}; 97 | } 98 | 99 | auto Flags() const 100 | { 101 | return MethodAttributes{{ get_value(2) }}; 102 | } 103 | 104 | auto Name() const 105 | { 106 | return get_string(3); 107 | } 108 | 109 | MethodDefSig Signature() const 110 | { 111 | auto cursor = get_blob(4); 112 | return{ get_table(), cursor }; 113 | } 114 | 115 | auto ParamList() const; 116 | auto CustomAttribute() const; 117 | auto Parent() const; 118 | auto GenericParam() const; 119 | 120 | bool SpecialName() const 121 | { 122 | return Flags().SpecialName(); 123 | } 124 | }; 125 | 126 | struct MemberRef : row_base 127 | { 128 | using row_base::row_base; 129 | 130 | auto Class() const 131 | { 132 | return get_coded_index(0); 133 | } 134 | 135 | auto Name() const 136 | { 137 | return get_string(1); 138 | } 139 | 140 | MethodDefSig MethodSignature() const 141 | { 142 | auto cursor = get_blob(2); 143 | return{ get_table(), cursor }; 144 | } 145 | 146 | auto CustomAttribute() const; 147 | }; 148 | 149 | struct Module : row_base 150 | { 151 | using row_base::row_base; 152 | 153 | auto Name() const 154 | { 155 | return get_string(1); 156 | } 157 | 158 | auto CustomAttribute() const; 159 | }; 160 | 161 | struct Field : row_base 162 | { 163 | using row_base::row_base; 164 | 165 | auto Flags() const 166 | { 167 | return FieldAttributes{{ get_value(0) }}; 168 | } 169 | 170 | auto Name() const 171 | { 172 | return get_string(1); 173 | } 174 | 175 | auto Signature() const 176 | { 177 | auto cursor = get_blob(2); 178 | return FieldSig{ get_table(), cursor }; 179 | } 180 | 181 | auto CustomAttribute() const; 182 | auto Constant() const; 183 | auto Parent() const; 184 | auto FieldMarshal() const; 185 | }; 186 | 187 | struct Param : row_base 188 | { 189 | using row_base::row_base; 190 | 191 | auto Flags() const 192 | { 193 | return ParamAttributes{{ get_value(0) }}; 194 | } 195 | 196 | auto Sequence() const 197 | { 198 | return get_value(1); 199 | } 200 | 201 | auto Name() const 202 | { 203 | return get_string(2); 204 | } 205 | 206 | auto CustomAttribute() const; 207 | auto Constant() const; 208 | auto FieldMarshal() const; 209 | }; 210 | 211 | struct InterfaceImpl : row_base 212 | { 213 | using row_base::row_base; 214 | 215 | auto Class() const; 216 | 217 | auto Interface() const 218 | { 219 | return get_coded_index(1); 220 | } 221 | 222 | auto CustomAttribute() const; 223 | }; 224 | 225 | struct Constant : row_base 226 | { 227 | using row_base::row_base; 228 | 229 | using constant_type = std::variant; 230 | 231 | auto Type() const 232 | { 233 | return get_value(0); 234 | } 235 | 236 | auto Parent() const 237 | { 238 | return get_coded_index(1); 239 | } 240 | 241 | auto ValueBoolean() const; 242 | auto ValueChar() const; 243 | auto ValueInt8() const; 244 | auto ValueUInt8() const; 245 | auto ValueInt16() const; 246 | auto ValueUInt16() const; 247 | auto ValueInt32() const; 248 | auto ValueUInt32() const; 249 | auto ValueInt64() const; 250 | auto ValueUInt64() const; 251 | auto ValueFloat32() const; 252 | auto ValueFloat64() const; 253 | auto ValueString() const; 254 | auto ValueClass() const; 255 | 256 | constant_type Value() const; 257 | }; 258 | 259 | struct FieldMarshal : row_base 260 | { 261 | using row_base::row_base; 262 | 263 | auto Parent() const 264 | { 265 | return get_coded_index(0); 266 | } 267 | }; 268 | 269 | struct TypeSpec : row_base 270 | { 271 | using row_base::row_base; 272 | 273 | TypeSpecSig Signature() const 274 | { 275 | auto cursor = get_blob(0); 276 | return{ get_table(), cursor }; 277 | } 278 | 279 | auto CustomAttribute() const; 280 | }; 281 | 282 | struct DeclSecurity : row_base 283 | { 284 | using row_base::row_base; 285 | }; 286 | 287 | struct ClassLayout : row_base 288 | { 289 | using row_base::row_base; 290 | 291 | auto PackingSize() const 292 | { 293 | return get_value(0); 294 | } 295 | 296 | auto ClassSize() const 297 | { 298 | return get_value(1); 299 | } 300 | 301 | auto Parent() const; 302 | }; 303 | 304 | struct FieldLayout : row_base 305 | { 306 | using row_base::row_base; 307 | }; 308 | 309 | struct StandAloneSig : row_base 310 | { 311 | using row_base::row_base; 312 | 313 | auto CustomAttribute() const; 314 | }; 315 | 316 | struct EventMap : row_base 317 | { 318 | using row_base::row_base; 319 | 320 | auto Parent() const; 321 | auto EventList() const; 322 | }; 323 | 324 | struct Event : row_base 325 | { 326 | using row_base::row_base; 327 | 328 | auto EventFlags() const 329 | { 330 | return EventAttributes{{ get_value(0) }}; 331 | } 332 | 333 | auto Name() const 334 | { 335 | return get_string(1); 336 | } 337 | 338 | auto EventType() const 339 | { 340 | return get_coded_index(2); 341 | } 342 | 343 | auto MethodSemantic() const; 344 | auto Parent() const; 345 | auto CustomAttribute() const; 346 | }; 347 | 348 | struct PropertyMap : row_base 349 | { 350 | using row_base::row_base; 351 | 352 | auto Parent() const; 353 | auto PropertyList() const; 354 | }; 355 | 356 | struct Property : row_base 357 | { 358 | using row_base::row_base; 359 | 360 | auto Flags() const 361 | { 362 | return PropertyAttributes{{ get_value(0) }}; 363 | } 364 | 365 | auto Name() const 366 | { 367 | return get_string(1); 368 | } 369 | 370 | PropertySig Type() const 371 | { 372 | auto cursor = get_blob(2); 373 | return{ get_table(), cursor }; 374 | } 375 | 376 | auto MethodSemantic() const; 377 | auto Parent() const; 378 | auto Constant() const; 379 | auto CustomAttribute() const; 380 | }; 381 | 382 | struct MethodSemantics : row_base 383 | { 384 | using row_base::row_base; 385 | 386 | auto Semantic() const 387 | { 388 | return MethodSemanticsAttributes{{ get_value(0) }}; 389 | } 390 | 391 | auto Method() const; 392 | 393 | auto Association() const 394 | { 395 | return get_coded_index(2); 396 | } 397 | }; 398 | 399 | struct MethodImpl : row_base 400 | { 401 | using row_base::row_base; 402 | 403 | auto Class() const; 404 | 405 | auto MethodBody() const 406 | { 407 | return get_coded_index(1); 408 | } 409 | 410 | auto MethodDeclaration() const 411 | { 412 | return get_coded_index(2); 413 | } 414 | }; 415 | 416 | struct ModuleRef : row_base 417 | { 418 | using row_base::row_base; 419 | 420 | auto CustomAttribute() const; 421 | }; 422 | 423 | struct ImplMap : row_base 424 | { 425 | using row_base::row_base; 426 | }; 427 | 428 | struct FieldRVA : row_base 429 | { 430 | using row_base::row_base; 431 | }; 432 | 433 | struct Assembly : row_base 434 | { 435 | using row_base::row_base; 436 | 437 | auto HashAlgId() const 438 | { 439 | return get_value(0); 440 | } 441 | 442 | auto Version() const; 443 | 444 | auto Flags() const 445 | { 446 | return AssemblyAttributes{{ get_value(2) }}; 447 | } 448 | 449 | auto PublicKey() const 450 | { 451 | return get_blob(3); 452 | } 453 | 454 | auto Name() const 455 | { 456 | return get_string(4); 457 | } 458 | 459 | auto Culture() const 460 | { 461 | return get_string(5); 462 | } 463 | 464 | auto CustomAttribute() const; 465 | }; 466 | 467 | struct AssemblyProcessor : row_base 468 | { 469 | using row_base::row_base; 470 | 471 | auto Processor() const 472 | { 473 | return get_value(0); 474 | } 475 | }; 476 | 477 | struct AssemblyOS : row_base 478 | { 479 | using row_base::row_base; 480 | 481 | auto OSPlatformId() const 482 | { 483 | return get_value(0); 484 | } 485 | 486 | auto OSMajorVersion() const 487 | { 488 | return get_value(1); 489 | } 490 | 491 | auto OSMinorVersion() const 492 | { 493 | return get_value(2); 494 | } 495 | }; 496 | 497 | struct AssemblyRef : row_base 498 | { 499 | using row_base::row_base; 500 | 501 | auto Version() const; 502 | 503 | auto Flags() const 504 | { 505 | return AssemblyAttributes{{ get_value(1) }}; 506 | } 507 | 508 | auto PublicKeyOrToken() const 509 | { 510 | return get_blob(2); 511 | } 512 | 513 | auto Name() const 514 | { 515 | return get_string(3); 516 | } 517 | 518 | auto Culture() const 519 | { 520 | return get_string(4); 521 | } 522 | 523 | auto HashValue() const 524 | { 525 | return get_string(5); 526 | } 527 | 528 | auto CustomAttribute() const; 529 | }; 530 | 531 | struct AssemblyRefProcessor : row_base 532 | { 533 | using row_base::row_base; 534 | 535 | auto Processor() const 536 | { 537 | return get_value(0); 538 | } 539 | 540 | auto AssemblyRef() const; 541 | }; 542 | 543 | struct AssemblyRefOS : row_base 544 | { 545 | using row_base::row_base; 546 | 547 | auto OSPlatformId() const 548 | { 549 | return get_value(0); 550 | } 551 | 552 | auto OSMajorVersion() const 553 | { 554 | return get_value(1); 555 | } 556 | 557 | auto OSMinorVersion() const 558 | { 559 | return get_value(2); 560 | } 561 | 562 | auto AssemblyRef() const; 563 | }; 564 | 565 | struct File : row_base 566 | { 567 | using row_base::row_base; 568 | 569 | auto CustomAttribute() const; 570 | }; 571 | 572 | struct ExportedType : row_base 573 | { 574 | using row_base::row_base; 575 | 576 | auto CustomAttribute() const; 577 | }; 578 | 579 | struct ManifestResource : row_base 580 | { 581 | using row_base::row_base; 582 | 583 | auto CustomAttribute() const; 584 | }; 585 | 586 | struct NestedClass : row_base 587 | { 588 | using row_base::row_base; 589 | 590 | TypeDef NestedType() const; 591 | TypeDef EnclosingType() const; 592 | }; 593 | 594 | struct GenericParam : row_base 595 | { 596 | using row_base::row_base; 597 | 598 | auto Number() const 599 | { 600 | return get_value(0); 601 | } 602 | 603 | auto Flags() const 604 | { 605 | return GenericParamAttributes{{ get_value(1) }}; 606 | } 607 | 608 | auto Owner() const 609 | { 610 | return get_coded_index(2); 611 | } 612 | 613 | auto Name() const 614 | { 615 | return get_string(3); 616 | } 617 | 618 | auto CustomAttribute() const; 619 | }; 620 | 621 | struct MethodSpec : row_base 622 | { 623 | using row_base::row_base; 624 | 625 | auto CustomAttribute() const; 626 | }; 627 | 628 | struct GenericParamConstraint : row_base 629 | { 630 | using row_base::row_base; 631 | 632 | auto CustomAttribute() const; 633 | }; 634 | 635 | inline bool operator<(coded_index const& left, CustomAttribute const& right) noexcept 636 | { 637 | return left < right.Parent(); 638 | } 639 | 640 | inline bool operator<(CustomAttribute const& left, coded_index const& right) noexcept 641 | { 642 | return left.Parent() < right; 643 | } 644 | 645 | inline bool operator<(coded_index const& left, GenericParam const& right) noexcept 646 | { 647 | return left < right.Owner(); 648 | } 649 | 650 | inline bool operator<(GenericParam const& left, coded_index const& right) noexcept 651 | { 652 | return left.Owner() < right; 653 | } 654 | 655 | inline bool operator<(coded_index const& left, Constant const& right) noexcept 656 | { 657 | return left < right.Parent(); 658 | } 659 | 660 | inline bool operator<(Constant const& left, coded_index const& right) noexcept 661 | { 662 | return left.Parent() < right; 663 | } 664 | 665 | inline bool operator<(coded_index const& left, MethodSemantics const& right) noexcept 666 | { 667 | return left < right.Association(); 668 | } 669 | 670 | inline bool operator<(MethodSemantics const& left, coded_index const& right) noexcept 671 | { 672 | return left.Association() < right; 673 | } 674 | 675 | inline bool operator<(NestedClass const& left, TypeDef const& right) noexcept 676 | { 677 | return left.NestedType() < right; 678 | } 679 | 680 | inline bool operator<(TypeDef const& left, NestedClass const& right) noexcept 681 | { 682 | return left < right.NestedType(); 683 | } 684 | 685 | inline bool operator<(coded_index const& left, FieldMarshal const& right) noexcept 686 | { 687 | return left < right.Parent(); 688 | } 689 | 690 | inline bool operator<(FieldMarshal const& left, coded_index const& right) noexcept 691 | { 692 | return left.Parent() < right; 693 | } 694 | } 695 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/column.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | template 6 | auto row_base::get_list(uint32_t const column) const 7 | { 8 | auto const& my_table = get_database().template get_table(); 9 | auto const& target_table = get_database().template get_table(); 10 | 11 | auto first = target_table.begin() + get_value(column) - 1; 12 | auto last = target_table.end(); 13 | if (index() + 1 < my_table.size()) 14 | { 15 | last = target_table.begin() + my_table[index() + 1].template get_value(column) - 1; 16 | } 17 | return std::pair{ first, last }; 18 | } 19 | 20 | template 21 | template 22 | auto row_base::get_target_row(uint32_t const column) const 23 | { 24 | return get_database().template get_table()[get_value(column) - 1]; 25 | } 26 | 27 | template 28 | template 29 | auto row_base::get_parent_row() const 30 | { 31 | struct compare 32 | { 33 | bool operator()(T const& lhs, uint32_t rhs) const noexcept 34 | { 35 | return lhs.template get_value(ParentColumn) < rhs; 36 | } 37 | bool operator()(uint32_t lhs, T const& rhs) const noexcept 38 | { 39 | return lhs < rhs.template get_value(ParentColumn); 40 | } 41 | }; 42 | auto const& map = get_database().template get_table(); 43 | return std::upper_bound(map.begin(), map.end(), index() + 1, compare{}) - 1; 44 | } 45 | 46 | inline auto TypeDef::GenericParam() const 47 | { 48 | return equal_range(get_database().GenericParam, coded_index()); 49 | } 50 | 51 | inline auto MethodDef::GenericParam() const 52 | { 53 | return equal_range(get_database().GenericParam, coded_index()); 54 | } 55 | 56 | inline auto TypeDef::InterfaceImpl() const 57 | { 58 | struct compare 59 | { 60 | bool operator()(uint32_t const left, reader::InterfaceImpl const& right) noexcept 61 | { 62 | return left < right.get_value(0); 63 | } 64 | 65 | bool operator()(reader::InterfaceImpl const& left, uint32_t const right) noexcept 66 | { 67 | return left.get_value(0) < right; 68 | } 69 | }; 70 | 71 | return equal_range(get_database().InterfaceImpl, index() + 1, compare{}); 72 | } 73 | 74 | inline auto TypeDef::FieldList() const 75 | { 76 | return get_list(4); 77 | } 78 | 79 | inline auto TypeDef::MethodList() const 80 | { 81 | return get_list(5); 82 | } 83 | 84 | inline auto MethodDef::ParamList() const 85 | { 86 | return get_list(5); 87 | } 88 | 89 | inline auto MethodDef::Parent() const 90 | { 91 | return get_parent_row(); 92 | } 93 | 94 | inline auto Field::Parent() const 95 | { 96 | return get_parent_row(); 97 | } 98 | 99 | inline auto InterfaceImpl::Class() const 100 | { 101 | return get_target_row(0); 102 | } 103 | 104 | inline auto MethodSemantics::Method() const 105 | { 106 | return get_target_row(1); 107 | } 108 | 109 | inline auto PropertyMap::Parent() const 110 | { 111 | return get_target_row(0); 112 | } 113 | 114 | inline auto Property::MethodSemantic() const 115 | { 116 | return equal_range(get_database().get_table(), coded_index()); 117 | } 118 | 119 | inline auto Property::Parent() const 120 | { 121 | return get_parent_row().Parent(); 122 | } 123 | 124 | inline auto PropertyMap::PropertyList() const 125 | { 126 | return get_list(1); 127 | } 128 | 129 | inline auto EventMap::Parent() const 130 | { 131 | return get_target_row(0); 132 | } 133 | 134 | inline auto EventMap::EventList() const 135 | { 136 | return get_list(1); 137 | } 138 | 139 | inline auto Event::MethodSemantic() const 140 | { 141 | return equal_range(get_database().get_table(), coded_index()); 142 | } 143 | 144 | inline auto Event::Parent() const 145 | { 146 | return get_parent_row().Parent(); 147 | } 148 | 149 | inline auto TypeDef::PropertyList() const 150 | { 151 | auto const& map = get_database().get_table(); 152 | auto index = this->index() + 1; 153 | auto iter = std::find_if(map.begin(), map.end(), [index](PropertyMap const& elem) 154 | { 155 | return elem.get_value(0) == index; 156 | }); 157 | if (iter == map.end()) 158 | { 159 | auto const& props = get_database().get_table(); 160 | return std::pair{ props.end(), props.end() }; 161 | } 162 | else 163 | { 164 | return iter.PropertyList(); 165 | } 166 | } 167 | 168 | inline auto TypeDef::EventList() const 169 | { 170 | auto const& map = get_database().get_table(); 171 | auto index = this->index() + 1; 172 | auto iter = std::find_if(map.begin(), map.end(), [index](EventMap const& elem) 173 | { 174 | return elem.get_value(0) == index; 175 | }); 176 | if (iter == map.end()) 177 | { 178 | auto const& props = get_database().get_table(); 179 | return std::pair{ props.end(), props.end() }; 180 | } 181 | else 182 | { 183 | return iter.EventList(); 184 | } 185 | } 186 | 187 | inline auto TypeDef::MethodImplList() const 188 | { 189 | struct compare 190 | { 191 | bool operator()(MethodImpl const& lhs, uint32_t rhs) const noexcept 192 | { 193 | return lhs.get_value(1) < rhs; 194 | } 195 | bool operator()(uint32_t lhs, MethodImpl const& rhs) const noexcept 196 | { 197 | return lhs < rhs.get_value(1); 198 | } 199 | }; 200 | return equal_range(get_database().get_table(), index() + 1, compare{}); 201 | } 202 | 203 | inline auto Field::Constant() const 204 | { 205 | auto const range = equal_range(get_database().Constant, coded_index()); 206 | reader::Constant result; 207 | if (range.second != range.first) 208 | { 209 | XLANG_ASSERT(range.second - range.first == 1); 210 | result = range.first; 211 | } 212 | return result; 213 | } 214 | 215 | inline auto Param::Constant() const 216 | { 217 | auto const range = equal_range(get_database().Constant, coded_index()); 218 | reader::Constant result; 219 | if (range.second != range.first) 220 | { 221 | XLANG_ASSERT(range.second - range.first == 1); 222 | result = range.first; 223 | } 224 | return result; 225 | } 226 | 227 | inline auto Property::Constant() const 228 | { 229 | auto const range = equal_range(get_database().Constant, coded_index()); 230 | reader::Constant result; 231 | if (range.second != range.first) 232 | { 233 | XLANG_ASSERT(range.second - range.first == 1); 234 | result = range.first; 235 | } 236 | return result; 237 | } 238 | 239 | inline auto MethodImpl::Class() const 240 | { 241 | return get_target_row(0); 242 | } 243 | 244 | inline auto Constant::ValueBoolean() const 245 | { 246 | XLANG_ASSERT(Type() == ConstantType::Boolean); 247 | return get_blob(2).as(); 248 | } 249 | 250 | inline auto Constant::ValueChar() const 251 | { 252 | XLANG_ASSERT(Type() == ConstantType::Char); 253 | return get_blob(2).as(); 254 | } 255 | 256 | inline auto Constant::ValueInt8() const 257 | { 258 | XLANG_ASSERT(Type() == ConstantType::Int8); 259 | return get_blob(2).as(); 260 | } 261 | 262 | inline auto Constant::ValueUInt8() const 263 | { 264 | XLANG_ASSERT(Type() == ConstantType::UInt8); 265 | return get_blob(2).as(); 266 | } 267 | 268 | inline auto Constant::ValueInt16() const 269 | { 270 | XLANG_ASSERT(Type() == ConstantType::Int16); 271 | return get_blob(2).as(); 272 | } 273 | 274 | inline auto Constant::ValueUInt16() const 275 | { 276 | XLANG_ASSERT(Type() == ConstantType::UInt16); 277 | return get_blob(2).as(); 278 | } 279 | 280 | inline auto Constant::ValueInt32() const 281 | { 282 | XLANG_ASSERT(Type() == ConstantType::Int32); 283 | return get_blob(2).as(); 284 | } 285 | 286 | inline auto Constant::ValueUInt32() const 287 | { 288 | XLANG_ASSERT(Type() == ConstantType::UInt32); 289 | return get_blob(2).as(); 290 | } 291 | 292 | inline auto Constant::ValueInt64() const 293 | { 294 | XLANG_ASSERT(Type() == ConstantType::Int64); 295 | return get_blob(2).as(); 296 | } 297 | 298 | inline auto Constant::ValueUInt64() const 299 | { 300 | XLANG_ASSERT(Type() == ConstantType::UInt64); 301 | return get_blob(2).as(); 302 | } 303 | 304 | inline auto Constant::ValueFloat32() const 305 | { 306 | XLANG_ASSERT(Type() == ConstantType::Float32); 307 | return get_blob(2).as(); 308 | } 309 | 310 | inline auto Constant::ValueFloat64() const 311 | { 312 | XLANG_ASSERT(Type() == ConstantType::Float64); 313 | return get_blob(2).as(); 314 | } 315 | 316 | inline auto Constant::ValueString() const 317 | { 318 | XLANG_ASSERT(Type() == ConstantType::String); 319 | return get_blob(2).as_u16string_constant(); 320 | } 321 | 322 | inline auto Constant::ValueClass() const 323 | { 324 | XLANG_ASSERT(Type() == ConstantType::Class); 325 | XLANG_ASSERT(get_blob(2).as() == 0); 326 | return nullptr; 327 | } 328 | 329 | inline Constant::constant_type Constant::Value() const 330 | { 331 | switch (Type()) 332 | { 333 | case ConstantType::Boolean: 334 | return ValueBoolean(); 335 | case ConstantType::Char: 336 | return ValueChar(); 337 | case ConstantType::Int8: 338 | return ValueInt8(); 339 | case ConstantType::UInt8: 340 | return ValueUInt8(); 341 | case ConstantType::Int16: 342 | return ValueInt16(); 343 | case ConstantType::UInt16: 344 | return ValueUInt16(); 345 | case ConstantType::Int32: 346 | return ValueInt32(); 347 | case ConstantType::UInt32: 348 | return ValueUInt32(); 349 | case ConstantType::Int64: 350 | return ValueInt64(); 351 | case ConstantType::UInt64: 352 | return ValueUInt64(); 353 | case ConstantType::Float32: 354 | return ValueFloat32(); 355 | case ConstantType::Float64: 356 | return ValueFloat64(); 357 | case ConstantType::String: 358 | return ValueString(); 359 | case ConstantType::Class: 360 | return ValueClass(); 361 | default: 362 | impl::throw_invalid("Invalid constant type"); 363 | } 364 | } 365 | 366 | inline auto MethodDef::CustomAttribute() const 367 | { 368 | return equal_range(get_database().get_table(), coded_index()); 369 | } 370 | 371 | inline auto Field::CustomAttribute() const 372 | { 373 | return equal_range(get_database().get_table(), coded_index()); 374 | } 375 | 376 | inline auto TypeRef::CustomAttribute() const 377 | { 378 | return equal_range(get_database().get_table(), coded_index()); 379 | } 380 | 381 | inline auto TypeDef::CustomAttribute() const 382 | { 383 | return equal_range(get_database().get_table(), coded_index()); 384 | } 385 | 386 | inline auto Param::CustomAttribute() const 387 | { 388 | return equal_range(get_database().get_table(), coded_index()); 389 | } 390 | 391 | inline auto InterfaceImpl::CustomAttribute() const 392 | { 393 | return equal_range(get_database().get_table(), coded_index()); 394 | } 395 | 396 | inline auto MemberRef::CustomAttribute() const 397 | { 398 | return equal_range(get_database().get_table(), coded_index()); 399 | } 400 | 401 | inline auto Module::CustomAttribute() const 402 | { 403 | return equal_range(get_database().get_table(), coded_index()); 404 | } 405 | 406 | inline auto Property::CustomAttribute() const 407 | { 408 | return equal_range(get_database().get_table(), coded_index()); 409 | } 410 | 411 | inline auto Event::CustomAttribute() const 412 | { 413 | return equal_range(get_database().get_table(), coded_index()); 414 | } 415 | 416 | inline auto StandAloneSig::CustomAttribute() const 417 | { 418 | return equal_range(get_database().get_table(), coded_index()); 419 | } 420 | 421 | inline auto ModuleRef::CustomAttribute() const 422 | { 423 | return equal_range(get_database().get_table(), coded_index()); 424 | } 425 | 426 | inline auto TypeSpec::CustomAttribute() const 427 | { 428 | return equal_range(get_database().get_table(), coded_index()); 429 | } 430 | 431 | inline auto Assembly::CustomAttribute() const 432 | { 433 | return equal_range(get_database().get_table(), coded_index()); 434 | } 435 | 436 | inline auto AssemblyRef::CustomAttribute() const 437 | { 438 | return equal_range(get_database().get_table(), coded_index()); 439 | } 440 | 441 | inline auto File::CustomAttribute() const 442 | { 443 | return equal_range(get_database().get_table(), coded_index()); 444 | } 445 | 446 | inline auto ExportedType::CustomAttribute() const 447 | { 448 | return equal_range(get_database().get_table(), coded_index()); 449 | } 450 | 451 | inline auto ManifestResource::CustomAttribute() const 452 | { 453 | return equal_range(get_database().get_table(), coded_index()); 454 | } 455 | 456 | inline auto GenericParam::CustomAttribute() const 457 | { 458 | return equal_range(get_database().get_table(), coded_index()); 459 | } 460 | 461 | inline auto GenericParamConstraint::CustomAttribute() const 462 | { 463 | return equal_range(get_database().get_table(), coded_index()); 464 | } 465 | 466 | inline auto MethodSpec::CustomAttribute() const 467 | { 468 | return equal_range(get_database().get_table(), coded_index()); 469 | } 470 | 471 | struct AssemblyVersion 472 | { 473 | uint16_t MajorVersion; 474 | uint16_t MinorVersion; 475 | uint16_t BuildNumber; 476 | uint16_t RevisionNumber; 477 | }; 478 | 479 | inline auto Assembly::Version() const 480 | { 481 | auto const temp = get_value(1); 482 | return AssemblyVersion{ static_cast(temp & 0xffff), static_cast((temp >> 16) & 0xffff), static_cast((temp >> 32) & 0xffff), static_cast((temp >> 48) & 0xffff) }; 483 | } 484 | 485 | inline auto AssemblyRef::Version() const 486 | { 487 | auto const temp = get_value(0); 488 | return AssemblyVersion{ static_cast(temp & 0xffff), static_cast((temp >> 16) & 0xffff), static_cast((temp >> 32) & 0xffff), static_cast((temp >> 48) & 0xffff) }; 489 | } 490 | 491 | inline auto AssemblyRefOS::AssemblyRef() const 492 | { 493 | return get_target_row(3); 494 | } 495 | 496 | inline auto AssemblyRefProcessor::AssemblyRef() const 497 | { 498 | return get_target_row(3); 499 | } 500 | 501 | inline auto ClassLayout::Parent() const 502 | { 503 | return get_target_row(2); 504 | } 505 | 506 | inline TypeDef NestedClass::NestedType() const 507 | { 508 | return get_target_row(0); 509 | } 510 | 511 | inline TypeDef NestedClass::EnclosingType() const 512 | { 513 | return get_target_row(1); 514 | } 515 | 516 | inline auto TypeDef::EnclosingType() const 517 | { 518 | auto const range = equal_range(get_database().NestedClass, *this); 519 | TypeDef result; 520 | if (range.first != range.second) 521 | { 522 | XLANG_ASSERT(range.second - range.first == 1); 523 | result = range.first.EnclosingType(); 524 | } 525 | return result; 526 | } 527 | 528 | inline auto Field::FieldMarshal() const 529 | { 530 | auto const range = equal_range(get_database().FieldMarshal, coded_index()); 531 | reader::FieldMarshal result; 532 | if (range.first != range.second) 533 | { 534 | XLANG_ASSERT(range.second - range.first == 1); 535 | result = range.first; 536 | } 537 | return result; 538 | } 539 | 540 | inline auto Param::FieldMarshal() const 541 | { 542 | auto const range = equal_range(get_database().FieldMarshal, coded_index()); 543 | reader::FieldMarshal result; 544 | if (range.first != range.second) 545 | { 546 | XLANG_ASSERT(range.second - range.first == 1); 547 | result = range.first; 548 | } 549 | return result; 550 | } 551 | } 552 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/signature.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | inline uint32_t uncompress_unsigned(byte_view& cursor) 5 | { 6 | auto data = cursor.begin(); 7 | uint32_t value; 8 | uint32_t length; 9 | if ((*data & 0x80) == 0x00) 10 | { 11 | length = 1; 12 | value = *data; 13 | } 14 | else if ((*data & 0xc0) == 0x80) 15 | { 16 | length = 2; 17 | value = (*data++ & 0x3f) << 8; 18 | value |= *data; 19 | } 20 | else if ((*data & 0xe0) == 0xc0) 21 | { 22 | length = 4; 23 | value = (*data++ & 0x1f) << 24; 24 | value |= *data++ << 16; 25 | value |= *data++ << 8; 26 | value |= *data; 27 | } 28 | else 29 | { 30 | impl::throw_invalid("Invalid compressed integer in blob"); 31 | } 32 | cursor = cursor.seek(length); 33 | return value; 34 | } 35 | 36 | template 37 | T uncompress_enum(byte_view& cursor) 38 | { 39 | static_assert(std::is_enum_v); 40 | static_assert(std::is_unsigned_v>); 41 | return static_cast(uncompress_unsigned(cursor)); 42 | } 43 | 44 | template 45 | T read(byte_view& cursor) 46 | { 47 | auto const& result = cursor.as(); 48 | cursor = cursor.seek(sizeof(T)); 49 | return result; 50 | } 51 | 52 | template <> 53 | inline std::string_view read(byte_view& cursor) 54 | { 55 | uint32_t const length = uncompress_unsigned(cursor); 56 | std::string_view result{ reinterpret_cast(cursor.begin()), length }; 57 | cursor = cursor.seek(length); 58 | return result; 59 | } 60 | 61 | struct CustomModSig; 62 | struct FieldSig; 63 | struct GenericTypeInstSig; 64 | struct MethodDefSig; 65 | struct ParamSig; 66 | struct PropertySig; 67 | struct RetTypeSig; 68 | struct TypeSig; 69 | struct TypeSpecSig; 70 | 71 | struct CustomModSig 72 | { 73 | CustomModSig(table_base const* table, byte_view& data) 74 | : m_cmod(uncompress_enum(data)) 75 | , m_type(table, uncompress_unsigned(data)) 76 | { 77 | XLANG_ASSERT(m_cmod == ElementType::CModReqd || m_cmod == ElementType::CModOpt); 78 | } 79 | 80 | ElementType CustomMod() const noexcept 81 | { 82 | return m_cmod; 83 | } 84 | 85 | coded_index Type() const noexcept 86 | { 87 | return m_type; 88 | } 89 | 90 | private: 91 | ElementType m_cmod; 92 | coded_index m_type; 93 | }; 94 | 95 | struct GenericTypeInstSig 96 | { 97 | GenericTypeInstSig(table_base const* table, byte_view& data); 98 | 99 | GenericTypeInstSig(coded_index type, std::vector&& args) 100 | : m_type(type) 101 | , m_generic_arg_count(static_cast(args.size())) 102 | , m_generic_args(std::move(args)) 103 | { 104 | // If constructing directly, probably don't care about m_class_or_value 105 | } 106 | 107 | ElementType ClassOrValueType() const noexcept 108 | { 109 | return m_class_or_value; 110 | } 111 | 112 | coded_index GenericType() const noexcept 113 | { 114 | return m_type; 115 | } 116 | 117 | uint32_t GenericArgCount() const noexcept 118 | { 119 | return m_generic_arg_count; 120 | } 121 | 122 | auto GenericArgs() const noexcept 123 | { 124 | return std::pair{ m_generic_args.cbegin(), m_generic_args.cend() }; 125 | } 126 | 127 | private: 128 | ElementType m_class_or_value{}; 129 | coded_index m_type; 130 | uint32_t m_generic_arg_count; 131 | std::vector m_generic_args; 132 | }; 133 | 134 | inline std::vector parse_cmods(table_base const* table, byte_view& data) 135 | { 136 | std::vector result; 137 | auto cursor = data; 138 | 139 | for (auto element_type = uncompress_enum(cursor); 140 | element_type == ElementType::CModOpt || element_type == ElementType::CModReqd; 141 | element_type = uncompress_enum(cursor)) 142 | { 143 | result.emplace_back(table, data); 144 | cursor = data; 145 | } 146 | return result; 147 | } 148 | 149 | inline bool parse_szarray(table_base const*, byte_view& data) 150 | { 151 | auto cursor = data; 152 | if (uncompress_enum(cursor) == ElementType::SZArray) 153 | { 154 | data = cursor; 155 | return true; 156 | } 157 | return false; 158 | } 159 | 160 | inline bool parse_array(table_base const*, byte_view& data) 161 | { 162 | auto cursor = data; 163 | if (uncompress_enum(cursor) == ElementType::Array) 164 | { 165 | data = cursor; 166 | return true; 167 | } 168 | return false; 169 | } 170 | 171 | inline std::pair> parse_array_sizes(table_base const*, byte_view& data) 172 | { 173 | uint32_t const rank = uncompress_unsigned(data); 174 | uint32_t const num_sizes = uncompress_unsigned(data); 175 | std::vector sizes; 176 | sizes.reserve(num_sizes); 177 | for (uint32_t i = 0; i < num_sizes; ++i) 178 | { 179 | auto size = uncompress_unsigned(data); 180 | sizes.push_back(size); 181 | } 182 | return { rank, sizes }; 183 | } 184 | 185 | inline int parse_ptr(table_base const*, byte_view& data) 186 | { 187 | auto cursor = data; 188 | int result = 0; 189 | while(uncompress_enum(cursor) == ElementType::Ptr) 190 | { 191 | ++result; 192 | data = cursor; 193 | } 194 | return result; 195 | } 196 | 197 | struct GenericTypeIndex 198 | { 199 | uint32_t index; 200 | }; 201 | 202 | struct GenericMethodTypeIndex 203 | { 204 | uint32_t index; 205 | }; 206 | 207 | struct TypeSig 208 | { 209 | using value_type = std::variant, GenericTypeIndex, GenericTypeInstSig, GenericMethodTypeIndex>; 210 | TypeSig(table_base const* table, byte_view& data) 211 | : m_is_szarray(parse_szarray(table, data)) 212 | , m_is_array(parse_array(table, data)) 213 | , m_ptr_count(parse_ptr(table, data)) 214 | , m_cmod(parse_cmods(table, data)) 215 | , m_element_type(parse_element_type(data)) 216 | , m_type(ParseType(table, data)) 217 | { 218 | if (m_is_array) 219 | { 220 | std::tie(m_array_rank, m_array_sizes) = parse_array_sizes(table, data); 221 | } 222 | } 223 | 224 | explicit TypeSig(value_type&& arg) 225 | : m_type(std::move(arg)) 226 | { 227 | // If constructing directly, probably don't actually care about m_element_type. Simply populate m_type 228 | } 229 | 230 | value_type const& Type() const noexcept 231 | { 232 | return m_type; 233 | } 234 | 235 | ElementType element_type() const noexcept 236 | { 237 | return m_element_type; 238 | } 239 | 240 | bool is_szarray() const noexcept 241 | { 242 | return m_is_szarray; 243 | } 244 | 245 | bool is_array() const noexcept 246 | { 247 | return m_is_array; 248 | } 249 | 250 | uint32_t array_rank() const noexcept 251 | { 252 | return m_array_rank; 253 | } 254 | 255 | std::vector const& array_sizes() const noexcept 256 | { 257 | return m_array_sizes; 258 | } 259 | 260 | int ptr_count() const noexcept 261 | { 262 | return m_ptr_count; 263 | } 264 | 265 | private: 266 | static ElementType parse_element_type(byte_view& data) 267 | { 268 | auto cursor = data; 269 | return uncompress_enum(cursor); 270 | } 271 | 272 | static value_type ParseType(table_base const* table, byte_view& data); 273 | bool m_is_szarray{}; 274 | bool m_is_array{}; 275 | int m_ptr_count{}; 276 | std::vector m_cmod; 277 | ElementType m_element_type{}; 278 | value_type m_type; 279 | uint32_t m_array_rank{}; 280 | std::vector m_array_sizes; 281 | }; 282 | 283 | inline bool is_by_ref(byte_view& data) 284 | { 285 | auto cursor = data; 286 | auto element_type = uncompress_enum(cursor); 287 | if (element_type == ElementType::ByRef) 288 | { 289 | data = cursor; 290 | return true; 291 | } 292 | else 293 | { 294 | XLANG_ASSERT(element_type != ElementType::TypedByRef); 295 | return false; 296 | } 297 | } 298 | 299 | struct ParamSig 300 | { 301 | ParamSig(table_base const* table, byte_view& data) 302 | : m_cmod(parse_cmods(table, data)) 303 | , m_byref(is_by_ref(data)) 304 | , m_type(table, data) 305 | { 306 | } 307 | 308 | auto CustomMod() const noexcept 309 | { 310 | return std::pair{ m_cmod.cbegin(), m_cmod.cend() }; 311 | } 312 | 313 | bool ByRef() const noexcept 314 | { 315 | return m_byref; 316 | } 317 | 318 | TypeSig const& Type() const noexcept 319 | { 320 | return m_type; 321 | } 322 | 323 | private: 324 | std::vector m_cmod; 325 | bool m_byref; 326 | TypeSig m_type; 327 | }; 328 | 329 | struct RetTypeSig 330 | { 331 | RetTypeSig(table_base const* table, byte_view& data) 332 | : m_cmod(parse_cmods(table, data)) 333 | , m_byref(is_by_ref(data)) 334 | { 335 | auto cursor = data; 336 | auto element_type = uncompress_enum(cursor); 337 | if (element_type == ElementType::Void) 338 | { 339 | data = cursor; 340 | } 341 | else 342 | { 343 | m_type.emplace(table, data); 344 | } 345 | } 346 | 347 | auto CustomMod() const noexcept 348 | { 349 | return std::pair{ m_cmod.cbegin(), m_cmod.cend() }; 350 | } 351 | 352 | bool ByRef() const noexcept 353 | { 354 | return m_byref; 355 | } 356 | 357 | TypeSig const& Type() const noexcept 358 | { 359 | return *m_type; 360 | } 361 | 362 | explicit operator bool() const noexcept 363 | { 364 | return m_type.has_value(); 365 | } 366 | 367 | private: 368 | std::vector m_cmod; 369 | bool m_byref; 370 | std::optional m_type; 371 | }; 372 | 373 | struct MethodDefSig 374 | { 375 | MethodDefSig(table_base const* table, byte_view& data) 376 | : m_calling_convention(uncompress_enum(data)) 377 | , m_generic_param_count(enum_mask(m_calling_convention, CallingConvention::Generic) == CallingConvention::Generic ? uncompress_unsigned(data) : 0) 378 | , m_param_count(uncompress_unsigned(data)) 379 | , m_ret_type(table, data) 380 | { 381 | if (m_param_count > data.size()) 382 | { 383 | impl::throw_invalid("Invalid blob array size"); 384 | } 385 | m_params.reserve(m_param_count); 386 | for (uint32_t count = 0; count < m_param_count; ++count) 387 | { 388 | m_params.emplace_back(table, data); 389 | } 390 | } 391 | 392 | CallingConvention CallConvention() const noexcept 393 | { 394 | return m_calling_convention; 395 | } 396 | 397 | uint32_t GenericParamCount() const noexcept 398 | { 399 | return m_generic_param_count; 400 | } 401 | 402 | RetTypeSig const& ReturnType() const noexcept 403 | { 404 | return m_ret_type; 405 | } 406 | 407 | auto Params() const noexcept 408 | { 409 | return std::pair{ m_params.cbegin(), m_params.cend() }; 410 | } 411 | 412 | private: 413 | CallingConvention m_calling_convention; 414 | uint32_t m_generic_param_count; 415 | uint32_t m_param_count; 416 | RetTypeSig m_ret_type; 417 | std::vector m_params; 418 | }; 419 | 420 | struct FieldSig 421 | { 422 | FieldSig(table_base const* table, byte_view& data) 423 | : m_calling_convention(check_convention(data)) 424 | , m_cmod(parse_cmods(table, data)) 425 | , m_type(table, data) 426 | {} 427 | 428 | auto CustomMod() const noexcept 429 | { 430 | return std::pair{ m_cmod.cbegin(), m_cmod.cend() }; 431 | } 432 | 433 | TypeSig const& Type() const noexcept 434 | { 435 | return m_type; 436 | } 437 | 438 | private: 439 | static CallingConvention check_convention(byte_view& data) 440 | { 441 | auto conv = read(data); 442 | if (enum_mask(conv, CallingConvention::Field) != CallingConvention::Field) 443 | { 444 | impl::throw_invalid("Invalid calling convention for field blob"); 445 | } 446 | return conv; 447 | } 448 | CallingConvention m_calling_convention; 449 | std::vector m_cmod; 450 | TypeSig m_type; 451 | }; 452 | 453 | struct PropertySig 454 | { 455 | PropertySig(table_base const* table, byte_view& data) 456 | : m_calling_convention(check_convention(data)) 457 | , m_param_count(uncompress_unsigned(data)) 458 | , m_cmod(parse_cmods(table, data)) 459 | , m_type(table, data) 460 | { 461 | if (m_param_count > data.size()) 462 | { 463 | impl::throw_invalid("Invalid blob array size"); 464 | } 465 | m_params.reserve(m_param_count); 466 | for (uint32_t count = 0; count < m_param_count; ++count) 467 | { 468 | m_params.emplace_back(table, data); 469 | } 470 | } 471 | 472 | TypeSig const& Type() const noexcept 473 | { 474 | return m_type; 475 | } 476 | 477 | CallingConvention CallConvention() const noexcept 478 | { 479 | return m_calling_convention; 480 | } 481 | 482 | private: 483 | static CallingConvention check_convention(byte_view& data) 484 | { 485 | auto conv = read(data); 486 | if (enum_mask(conv, CallingConvention::Property) != CallingConvention::Property) 487 | { 488 | impl::throw_invalid("Invalid calling convention for property blob"); 489 | } 490 | return conv; 491 | } 492 | CallingConvention m_calling_convention; 493 | uint32_t m_param_count; 494 | std::vector m_cmod; 495 | TypeSig m_type; 496 | std::vector m_params; 497 | }; 498 | 499 | struct TypeSpecSig 500 | { 501 | TypeSpecSig(table_base const* table, byte_view& data) 502 | : m_type(ParseType(table, data)) 503 | { 504 | } 505 | 506 | GenericTypeInstSig const& GenericTypeInst() const noexcept 507 | { 508 | return m_type; 509 | } 510 | 511 | private: 512 | static GenericTypeInstSig ParseType(table_base const* table, byte_view& data) 513 | { 514 | [[maybe_unused]] auto element_type = uncompress_enum(data); 515 | XLANG_ASSERT(element_type == ElementType::GenericInst); 516 | return { table, data }; 517 | } 518 | GenericTypeInstSig m_type; 519 | }; 520 | 521 | inline GenericTypeInstSig::GenericTypeInstSig(table_base const* table, byte_view& data) 522 | : m_class_or_value(uncompress_enum(data)) 523 | , m_type(table, uncompress_unsigned(data)) 524 | , m_generic_arg_count(uncompress_unsigned(data)) 525 | { 526 | if (!(m_class_or_value == ElementType::Class || m_class_or_value == ElementType::ValueType)) 527 | { 528 | impl::throw_invalid("Generic type instantiation signatures must begin with either ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUE"); 529 | } 530 | 531 | if (m_generic_arg_count > data.size()) 532 | { 533 | impl::throw_invalid("Invalid blob array size"); 534 | } 535 | m_generic_args.reserve(m_generic_arg_count); 536 | for (uint32_t arg = 0; arg < m_generic_arg_count; ++arg) 537 | { 538 | m_generic_args.emplace_back(table, data); 539 | } 540 | } 541 | 542 | inline TypeSig::value_type TypeSig::ParseType(table_base const* table, byte_view& data) 543 | { 544 | auto element_type = uncompress_enum(data); 545 | switch (element_type) 546 | { 547 | case ElementType::Boolean: 548 | case ElementType::Char: 549 | case ElementType::I1: 550 | case ElementType::U1: 551 | case ElementType::I2: 552 | case ElementType::U2: 553 | case ElementType::I4: 554 | case ElementType::U4: 555 | case ElementType::I8: 556 | case ElementType::U8: 557 | case ElementType::R4: 558 | case ElementType::R8: 559 | case ElementType::String: 560 | case ElementType::Object: 561 | case ElementType::U: 562 | case ElementType::I: 563 | case ElementType::Void: 564 | return element_type; 565 | break; 566 | 567 | case ElementType::Class: 568 | case ElementType::ValueType: 569 | return coded_index{ table, uncompress_unsigned(data) }; 570 | break; 571 | 572 | case ElementType::GenericInst: 573 | return GenericTypeInstSig{ table, data }; 574 | break; 575 | 576 | case ElementType::Var: 577 | return GenericTypeIndex{ uncompress_unsigned(data) }; 578 | break; 579 | 580 | case ElementType::MVar: 581 | return GenericMethodTypeIndex{ uncompress_unsigned(data) }; 582 | break; 583 | 584 | default: 585 | impl::throw_invalid("Unrecognized ELEMENT_TYPE encountered"); 586 | break; 587 | } 588 | } 589 | } 590 | -------------------------------------------------------------------------------- /src/impl/winmd_reader/flags.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::impl 3 | { 4 | template 5 | struct AttributesBase 6 | { 7 | T value; 8 | protected: 9 | constexpr T get_mask(T mask) const noexcept 10 | { 11 | return value & mask; 12 | } 13 | void set_mask(T arg, T mask) noexcept 14 | { 15 | value = (value & ~mask) | (arg & mask); 16 | } 17 | template 18 | constexpr U get_enum(T mask) const noexcept 19 | { 20 | static_assert(std::is_enum_v); 21 | static_assert(std::is_same_v>); 22 | return static_cast(get_mask(mask)); 23 | } 24 | template 25 | void set_enum(U arg, T mask) noexcept 26 | { 27 | static_assert(std::is_enum_v); 28 | static_assert(std::is_same_v>); 29 | set_mask(static_cast(arg), mask); 30 | } 31 | constexpr bool get_bit(int bit) const noexcept 32 | { 33 | return get_mask(1 << bit); 34 | } 35 | void set_bit(bool arg, int bit) noexcept 36 | { 37 | set_mask(arg << bit, 1 << bit); 38 | } 39 | }; 40 | } 41 | 42 | namespace winmd::reader 43 | { 44 | struct AssemblyAttributes : impl::AttributesBase 45 | { 46 | constexpr bool WindowsRuntime() const noexcept 47 | { 48 | return get_bit(WindowsRuntime_bit); 49 | } 50 | void WindowsRuntime(bool arg) noexcept 51 | { 52 | set_bit(arg, WindowsRuntime_bit); 53 | } 54 | 55 | private: 56 | static constexpr int WindowsRuntime_bit{ 9 }; 57 | }; 58 | 59 | struct EventAttributes : impl::AttributesBase 60 | { 61 | constexpr bool SpecialName() const noexcept 62 | { 63 | return get_bit(SpecialName_bit); 64 | } 65 | void SpecialName(bool arg) noexcept 66 | { 67 | set_bit(arg, SpecialName_bit); 68 | } 69 | constexpr bool RTSpecialName() const noexcept 70 | { 71 | return get_bit(RTSpecialName_bit); 72 | } 73 | void RTSpecialName(bool arg) noexcept 74 | { 75 | set_bit(arg, RTSpecialName_bit); 76 | } 77 | 78 | private: 79 | static constexpr int SpecialName_bit{ 9 }; 80 | static constexpr int RTSpecialName_bit{ 10 }; 81 | }; 82 | 83 | struct FieldAttributes : impl::AttributesBase 84 | { 85 | constexpr MemberAccess Access() const noexcept 86 | { 87 | return get_enum(Access_mask); 88 | } 89 | void Access(MemberAccess arg) noexcept 90 | { 91 | set_enum(arg, Access_mask); 92 | } 93 | constexpr bool Static() const noexcept 94 | { 95 | return get_bit(Static_bit); 96 | } 97 | constexpr bool InitOnly() const noexcept 98 | { 99 | return get_bit(InitOnly_bit); 100 | } 101 | constexpr bool Literal() const noexcept 102 | { 103 | return get_bit(Literal_bit); 104 | } 105 | constexpr bool NotSerialized() const noexcept 106 | { 107 | return get_bit(NotSerialized_bit); 108 | } 109 | constexpr bool SpecialName() const noexcept 110 | { 111 | return get_bit(SpecialName_bit); 112 | } 113 | constexpr bool PInvokeImpl() const noexcept 114 | { 115 | return get_bit(PInvokeImpl_bit); 116 | } 117 | constexpr bool RTSpecialName() const noexcept 118 | { 119 | return get_bit(RTSpecialName_bit); 120 | } 121 | constexpr bool HasFieldMarshal() const noexcept 122 | { 123 | return get_bit(HasFieldMarshal_bit); 124 | } 125 | constexpr bool HasDefault() const noexcept 126 | { 127 | return get_bit(HasDefault_bit); 128 | } 129 | constexpr bool HasFieldRVA() const noexcept 130 | { 131 | return get_bit(HasFieldRVA_bit); 132 | } 133 | 134 | private: 135 | static constexpr uint16_t Access_mask{ 0x0007 }; 136 | static constexpr int Static_bit{ 4 }; 137 | static constexpr int InitOnly_bit{ 5 }; 138 | static constexpr int Literal_bit{ 6 }; 139 | static constexpr int NotSerialized_bit{ 7 }; 140 | static constexpr int SpecialName_bit{ 9 }; 141 | static constexpr int PInvokeImpl_bit{ 13 }; 142 | static constexpr int RTSpecialName_bit{ 10 }; 143 | static constexpr int HasFieldMarshal_bit{ 12 }; 144 | static constexpr int HasDefault_bit{ 15 }; 145 | static constexpr int HasFieldRVA_bit{ 8 }; 146 | }; 147 | 148 | struct GenericParamAttributes : impl::AttributesBase 149 | { 150 | constexpr GenericParamVariance Variance() const noexcept 151 | { 152 | return get_enum(Variance_mask); 153 | } 154 | void Variance(GenericParamVariance arg) noexcept 155 | { 156 | set_enum(arg, Variance_mask); 157 | } 158 | constexpr GenericParamSpecialConstraint SpecialConstraint() const noexcept 159 | { 160 | return get_enum(SpecialConstraint_mask); 161 | } 162 | void SpecialConstraint(GenericParamSpecialConstraint arg) noexcept 163 | { 164 | set_enum(arg, SpecialConstraint_mask); 165 | } 166 | 167 | private: 168 | static constexpr uint16_t Variance_mask{ 0x0003 }; 169 | static constexpr uint16_t SpecialConstraint_mask{ 0x001c }; 170 | }; 171 | 172 | struct MethodAttributes : impl::AttributesBase 173 | { 174 | constexpr MemberAccess Access() const noexcept 175 | { 176 | return get_enum(Access_mask); 177 | } 178 | void Access(MemberAccess arg) noexcept 179 | { 180 | set_enum(arg, Access_mask); 181 | } 182 | constexpr bool Static() const noexcept 183 | { 184 | return get_bit(Static_bit); 185 | } 186 | void Static(bool arg) noexcept 187 | { 188 | set_bit(arg, Static_bit); 189 | } 190 | constexpr bool Final() const noexcept 191 | { 192 | return get_bit(Final_bit); 193 | } 194 | void Final(bool arg) noexcept 195 | { 196 | set_bit(arg, Final_bit); 197 | } 198 | constexpr bool Virtual() const noexcept 199 | { 200 | return get_bit(Virtual_bit); 201 | } 202 | void Virtual(bool arg) noexcept 203 | { 204 | set_bit(arg, Virtual_bit); 205 | } 206 | constexpr bool HideBySig() const noexcept 207 | { 208 | return get_bit(HideBySig_bit); 209 | } 210 | void HideBySig(bool arg) noexcept 211 | { 212 | set_bit(arg, HideBySig_bit); 213 | } 214 | constexpr VtableLayout Layout() const noexcept 215 | { 216 | return get_enum(VtableLayout_mask); 217 | } 218 | void Layout(VtableLayout arg) noexcept 219 | { 220 | set_enum(arg, VtableLayout_mask); 221 | } 222 | constexpr bool Strict() const noexcept 223 | { 224 | return get_bit(Strict_bit); 225 | } 226 | void Strict(bool arg) noexcept 227 | { 228 | set_bit(arg, Strict_bit); 229 | } 230 | constexpr bool Abstract() const noexcept 231 | { 232 | return get_bit(Abstract_bit); 233 | } 234 | void Abstract(bool arg) noexcept 235 | { 236 | set_bit(arg, Abstract_bit); 237 | } 238 | constexpr bool SpecialName() const noexcept 239 | { 240 | return get_bit(SpecialName_bit); 241 | } 242 | void SpecialName(bool arg) noexcept 243 | { 244 | set_bit(arg, SpecialName_bit); 245 | } 246 | constexpr bool PInvokeImpl() const noexcept 247 | { 248 | return get_bit(PInvokeImpl_bit); 249 | } 250 | void PInvokeImpl(bool arg) noexcept 251 | { 252 | set_bit(arg, PInvokeImpl_bit); 253 | } 254 | constexpr bool UnmanagedExport() const noexcept 255 | { 256 | return get_bit(UnmanagedExport_bit); 257 | } 258 | void UnmanagedExport(bool arg) noexcept 259 | { 260 | set_bit(arg, UnmanagedExport_bit); 261 | } 262 | constexpr bool RTSpecialName() const noexcept 263 | { 264 | return get_bit(RTSpecialName_bit); 265 | } 266 | void RTSpecialName(bool arg) noexcept 267 | { 268 | set_bit(arg, RTSpecialName_bit); 269 | } 270 | constexpr bool HasSecurity() const noexcept 271 | { 272 | return get_bit(HasSecurity_bit); 273 | } 274 | void HasSecurity(bool arg) noexcept 275 | { 276 | set_bit(arg, HasSecurity_bit); 277 | } 278 | constexpr bool RequireSecObject() const noexcept 279 | { 280 | return get_bit(RequireSecObject_bit); 281 | } 282 | void RequireSecObject(bool arg) noexcept 283 | { 284 | set_bit(arg, RequireSecObject_bit); 285 | } 286 | 287 | private: 288 | static constexpr uint16_t Access_mask{ 0x0007 }; 289 | static constexpr int Static_bit{ 4 }; 290 | static constexpr int Final_bit{ 5 }; 291 | static constexpr int Virtual_bit{ 6 }; 292 | static constexpr int HideBySig_bit{ 7 }; 293 | static constexpr uint16_t VtableLayout_mask{ 0x0100 }; 294 | static constexpr int Strict_bit{ 9 }; 295 | static constexpr int Abstract_bit{ 10 }; 296 | static constexpr int SpecialName_bit{ 11 }; 297 | static constexpr int PInvokeImpl_bit{ 13 }; 298 | static constexpr int UnmanagedExport_bit{ 3 }; 299 | static constexpr int RTSpecialName_bit{ 12 }; 300 | static constexpr int HasSecurity_bit{ 14 }; 301 | static constexpr int RequireSecObject_bit{ 15 }; 302 | }; 303 | 304 | struct MethodImplAttributes : impl::AttributesBase 305 | { 306 | constexpr reader::CodeType CodeType() const noexcept 307 | { 308 | return get_enum(CodeType_mask); 309 | } 310 | void CodeType(reader::CodeType arg) noexcept 311 | { 312 | set_enum(arg, CodeType_mask); 313 | } 314 | constexpr reader::Managed Managed() const noexcept 315 | { 316 | return get_enum(Managed_mask); 317 | } 318 | void Managed(reader::Managed arg) noexcept 319 | { 320 | set_enum(arg, Managed_mask); 321 | } 322 | constexpr bool ForwardRef() const noexcept 323 | { 324 | return get_bit(ForwardRef_bit); 325 | } 326 | void ForwardRef(bool arg) noexcept 327 | { 328 | set_bit(arg, ForwardRef_bit); 329 | } 330 | constexpr bool PreserveSig() const noexcept 331 | { 332 | return get_bit(PreserveSig_bit); 333 | } 334 | void PreserveSig(bool arg) noexcept 335 | { 336 | set_bit(arg, PreserveSig_bit); 337 | } 338 | constexpr bool InternalCall() const noexcept 339 | { 340 | return get_bit(InternalCall_bit); 341 | } 342 | void InternalCall(bool arg) noexcept 343 | { 344 | set_bit(arg, InternalCall_bit); 345 | } 346 | constexpr bool Synchronized() const noexcept 347 | { 348 | return get_bit(Synchronized_bit); 349 | } 350 | void Synchronized(bool arg) noexcept 351 | { 352 | set_bit(arg, Synchronized_bit); 353 | } 354 | constexpr bool NoInlining() const noexcept 355 | { 356 | return get_bit(NoInlining_bit); 357 | } 358 | void NoInlining(bool arg) noexcept 359 | { 360 | set_bit(arg, NoInlining_bit); 361 | } 362 | constexpr bool NoOptimization() const noexcept 363 | { 364 | return get_bit(NoOptimization_bit); 365 | } 366 | void NoOptimization(bool arg) noexcept 367 | { 368 | set_bit(arg, NoOptimization_bit); 369 | } 370 | 371 | private: 372 | static constexpr uint16_t CodeType_mask{ 0x0003 }; 373 | static constexpr uint16_t Managed_mask{ 0x0004 }; 374 | static constexpr int ForwardRef_bit{ 4 }; // Method is defined; used primarily in merge scenarios 375 | static constexpr int PreserveSig_bit{ 7 }; // Reserved 376 | static constexpr int InternalCall_bit{ 12 }; // Reserved 377 | static constexpr int Synchronized_bit{ 5 }; // Method is single threaded through the body 378 | static constexpr int NoInlining_bit{ 3 }; // Method cannot be inlined 379 | static constexpr int NoOptimization_bit{ 6 }; // Method will not be optimized when generatinv native code 380 | static constexpr uint16_t MaxMethodImplVal{ 0xffff }; // Range check value 381 | }; 382 | 383 | struct MethodSemanticsAttributes : impl::AttributesBase 384 | { 385 | constexpr bool Setter() const noexcept 386 | { 387 | return get_bit(Setter_bit); 388 | } 389 | void Setter(bool arg) noexcept 390 | { 391 | set_bit(arg, Setter_bit); 392 | } 393 | constexpr bool Getter() const noexcept 394 | { 395 | return get_bit(Getter_bit); 396 | } 397 | void Getter(bool arg) noexcept 398 | { 399 | set_bit(arg, Getter_bit); 400 | } 401 | constexpr bool Other() const noexcept 402 | { 403 | return get_bit(Other_bit); 404 | } 405 | void Other(bool arg) noexcept 406 | { 407 | set_bit(arg, Other_bit); 408 | } 409 | constexpr bool AddOn() const noexcept 410 | { 411 | return get_bit(AddOn_bit); 412 | } 413 | void AddOn(bool arg) noexcept 414 | { 415 | set_bit(arg, AddOn_bit); 416 | } 417 | constexpr bool RemoveOn() const noexcept 418 | { 419 | return get_bit(RemoveOn_bit); 420 | } 421 | void RemoveOn(bool arg) noexcept 422 | { 423 | set_bit(arg, RemoveOn_bit); 424 | } 425 | constexpr bool Fire() const noexcept 426 | { 427 | return get_bit(Fire_bit); 428 | } 429 | void Fire(bool arg) noexcept 430 | { 431 | set_bit(arg, Fire_bit); 432 | } 433 | 434 | private: 435 | static constexpr int Setter_bit{ 0 }; 436 | static constexpr int Getter_bit{ 1 }; 437 | static constexpr int Other_bit{ 2 }; 438 | static constexpr int AddOn_bit{ 3 }; 439 | static constexpr int RemoveOn_bit{ 4 }; 440 | static constexpr int Fire_bit{ 5 }; 441 | }; 442 | 443 | struct ParamAttributes : impl::AttributesBase 444 | { 445 | constexpr bool In() const noexcept 446 | { 447 | return get_bit(In_bit); 448 | } 449 | void In(bool arg) noexcept 450 | { 451 | set_bit(arg, In_bit); 452 | } 453 | constexpr bool Out() const noexcept 454 | { 455 | return get_bit(Out_bit); 456 | } 457 | void Out(bool arg) noexcept 458 | { 459 | set_bit(arg, Out_bit); 460 | } 461 | constexpr bool Optional() const noexcept 462 | { 463 | return get_bit(Optional_bit); 464 | } 465 | void Optional(bool arg) noexcept 466 | { 467 | set_bit(arg, Optional_bit); 468 | } 469 | constexpr bool HasDefault() const noexcept 470 | { 471 | return get_bit(HasDefault_bit); 472 | } 473 | void HasDefault(bool arg) noexcept 474 | { 475 | set_bit(arg, HasDefault_bit); 476 | } 477 | constexpr bool HasFieldMarshal() const noexcept 478 | { 479 | return get_bit(HasFieldMarshal_bit); 480 | } 481 | void HasFieldMarshal(bool arg) noexcept 482 | { 483 | set_bit(arg, HasFieldMarshal_bit); 484 | } 485 | 486 | private: 487 | static constexpr int In_bit{ 0 }; 488 | static constexpr int Out_bit{ 1 }; 489 | static constexpr int Optional_bit{ 4 }; 490 | static constexpr int HasDefault_bit{ 12 }; 491 | static constexpr int HasFieldMarshal_bit{ 13 }; 492 | static constexpr uint16_t Unused_mask{ 0xcfe0 }; 493 | }; 494 | 495 | struct PropertyAttributes : impl::AttributesBase 496 | { 497 | constexpr bool SpecialName() const noexcept 498 | { 499 | return get_bit(SpecialName_bit); 500 | } 501 | void SpecialName(bool arg) noexcept 502 | { 503 | set_bit(arg, SpecialName_bit); 504 | } 505 | constexpr bool RTSpecialName() const noexcept 506 | { 507 | return get_bit(RTSpecialName_bit); 508 | } 509 | void RTSpecialName(bool arg) noexcept 510 | { 511 | set_bit(arg, RTSpecialName_bit); 512 | } 513 | constexpr bool HasDefault() const noexcept 514 | { 515 | return get_bit(HasDefault_bit); 516 | } 517 | void HasDefault(bool arg) noexcept 518 | { 519 | set_bit(arg, HasDefault_bit); 520 | } 521 | 522 | private: 523 | static constexpr int SpecialName_bit{ 9 }; 524 | static constexpr int RTSpecialName_bit{ 10 }; 525 | static constexpr int HasDefault_bit{ 12 }; 526 | static constexpr uint16_t Unused_mask{ 0xe9ff }; 527 | }; 528 | 529 | struct TypeAttributes : impl::AttributesBase 530 | { 531 | constexpr TypeVisibility Visibility() const noexcept 532 | { 533 | return get_enum(Visibility_mask); 534 | } 535 | void Visibility(TypeVisibility arg) noexcept 536 | { 537 | set_enum(arg, Visibility_mask); 538 | } 539 | constexpr TypeLayout Layout() const noexcept 540 | { 541 | return get_enum(Layout_mask); 542 | } 543 | void Layout(TypeLayout arg) noexcept 544 | { 545 | set_enum(arg, Layout_mask); 546 | } 547 | constexpr TypeSemantics Semantics() const noexcept 548 | { 549 | return get_enum(Semantics_mask); 550 | } 551 | void Semantics(TypeSemantics arg) noexcept 552 | { 553 | set_enum(arg, Semantics_mask); 554 | } 555 | constexpr bool Abstract() const noexcept 556 | { 557 | return get_bit(Abstract_bit); 558 | } 559 | void Abstract(bool arg) noexcept 560 | { 561 | set_bit(arg, Abstract_bit); 562 | } 563 | constexpr bool Sealed() const noexcept 564 | { 565 | return get_bit(Sealed_bit); 566 | } 567 | void Sealed(bool arg) noexcept 568 | { 569 | set_bit(arg, Sealed_bit); 570 | } 571 | constexpr bool SpecialName() const noexcept 572 | { 573 | return get_bit(SpecialName_bit); 574 | } 575 | void SpecialName(bool arg) noexcept 576 | { 577 | set_bit(arg, SpecialName_bit); 578 | } 579 | constexpr bool Import() const noexcept 580 | { 581 | return get_bit(Import_bit); 582 | } 583 | void Import(bool arg) noexcept 584 | { 585 | set_bit(arg, Import_bit); 586 | } 587 | constexpr bool Serializable() const noexcept 588 | { 589 | return get_bit(Serializable_bit); 590 | } 591 | void Serializable(bool arg) noexcept 592 | { 593 | set_bit(arg, Serializable_bit); 594 | } 595 | constexpr bool WindowsRuntime() const noexcept 596 | { 597 | return get_bit(WindowsRuntime_bit); 598 | } 599 | void WindowsRuntime(bool arg) noexcept 600 | { 601 | set_bit(arg, WindowsRuntime_bit); 602 | } 603 | constexpr reader::StringFormat StringFormat() const noexcept 604 | { 605 | return get_enum(StringFormat_mask); 606 | } 607 | void StringFormat(reader::StringFormat arg) noexcept 608 | { 609 | set_enum(arg, StringFormat_mask); 610 | } 611 | constexpr bool BeforeFieldInit() const noexcept 612 | { 613 | return get_bit(BeforeFieldInit_bit); 614 | } 615 | void BeforeFieldInit(bool arg) noexcept 616 | { 617 | set_bit(arg, BeforeFieldInit_bit); 618 | } 619 | constexpr bool RTSpecialName() const noexcept 620 | { 621 | return get_bit(RTSpecialName_bit); 622 | } 623 | void RTSpecialName(bool arg) noexcept 624 | { 625 | set_bit(arg, RTSpecialName_bit); 626 | } 627 | constexpr bool HasSecurity() const noexcept 628 | { 629 | return get_bit(HasSecurity_bit); 630 | } 631 | void HasSecurity(bool arg) noexcept 632 | { 633 | set_bit(arg, HasSecurity_bit); 634 | } 635 | constexpr bool IsTypeForwarder() const noexcept 636 | { 637 | return get_bit(IsTypeForwarder_bit); 638 | } 639 | void IsTypeForwarder(bool arg) noexcept 640 | { 641 | set_bit(arg, IsTypeForwarder_bit); 642 | } 643 | 644 | private: 645 | static constexpr uint32_t Visibility_mask{ 0x00000007 }; 646 | static constexpr uint32_t Layout_mask{ 0x00000018 }; 647 | static constexpr uint32_t Semantics_mask{ 0x00000020 }; 648 | static constexpr int Abstract_bit{ 7 }; 649 | static constexpr int Sealed_bit{ 8 }; 650 | static constexpr int SpecialName_bit{ 10 }; 651 | static constexpr int Import_bit{ 12 }; 652 | static constexpr int Serializable_bit{ 13 }; 653 | static constexpr int WindowsRuntime_bit{ 14 }; 654 | static constexpr uint32_t StringFormat_mask{ 0x00030000 }; 655 | static constexpr int BeforeFieldInit_bit{ 20 }; 656 | static constexpr int RTSpecialName_bit{ 11 }; 657 | static constexpr int HasSecurity_bit{ 18 }; 658 | static constexpr int IsTypeForwarder_bit{ 21 }; 659 | }; 660 | } 661 | --------------------------------------------------------------------------------