From 88df33d38e45c999af56d65ef8dc605b76682495 Mon Sep 17 00:00:00 2001 From: JakubPruzinec <39880563+JakubPruzinec@users.noreply.github.com> Date: Sat, 10 Nov 2018 15:39:45 +0100 Subject: [PATCH] Implemented .NET TypeRef hashes and presentation of .NET imported types (#386) * plain and json getters * plain json presentations * dotnet class and reconstructor * fileformat and related * fileinfo and cmake * minor changes - cleanup and docs * DotnetClass linking fixed * child nodes libname derivation fixed * hash names type postfix added * typeref index presentation removed * hashes fixed * std::variant alternative for cpp 11/14/17 * type check for DotnetClass * Removed submodule file * veriant as non gitmodule * variant completely removed * Variant reinstalled as non submodule * Another deletion of submodule * Another addition of non submodule variant * variant single header * branch rebase - variant single header * variant hidden files deleted * Cosmetic changes --- LICENSE-THIRD-PARTY | 2 +- deps/CMakeLists.txt | 1 + deps/variant/CMakeLists.txt | 2 + deps/variant/include/mpark/variant.hpp | 2462 +++++++++++++++++ .../fileformat/file_format/pe/pe_format.h | 7 + .../types/dotnet_types/dotnet_class.h | 24 +- .../dotnet_types/dotnet_type_reconstructor.h | 8 +- src/fileformat/file_format/pe/pe_format.cpp | 160 ++ .../types/dotnet_types/dotnet_class.cpp | 142 +- .../dotnet_type_reconstructor.cpp | 145 +- src/fileinfo/CMakeLists.txt | 2 + src/fileinfo/file_detector/pe_detector.cpp | 3 + .../file_information/file_information.cpp | 112 + .../file_information/file_information.h | 12 + .../file_information_types/dotnet_info.cpp | 129 + .../file_information_types/dotnet_info.h | 16 + .../typeref_table_plain_getter.cpp | 100 + .../typeref_table_plain_getter.h | 31 + .../typeref_table_json_getter.cpp | 91 + .../typeref_table_json_getter.h | 30 + .../file_presentation/getters/json_getters.h | 1 + .../file_presentation/getters/plain_getters.h | 1 + .../file_presentation/json_presentation.cpp | 2 + .../file_presentation/plain_presentation.cpp | 1 + src/utils/CMakeLists.txt | 1 + 25 files changed, 3461 insertions(+), 24 deletions(-) create mode 100644 deps/variant/CMakeLists.txt create mode 100644 deps/variant/include/mpark/variant.hpp create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h diff --git a/LICENSE-THIRD-PARTY b/LICENSE-THIRD-PARTY index cb635cb9c..50bcfe781 100644 --- a/LICENSE-THIRD-PARTY +++ b/LICENSE-THIRD-PARTY @@ -2275,4 +2275,4 @@ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index c950ed6c1..101385545 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(pelib) add_subdirectory(yaracpp) add_subdirectory(yaramod) add_subdirectory(whereami) +add_subdirectory(variant) if(RETDEC_TESTS) add_subdirectory(googletest) diff --git a/deps/variant/CMakeLists.txt b/deps/variant/CMakeLists.txt new file mode 100644 index 000000000..6bb4c5049 --- /dev/null +++ b/deps/variant/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(mpark_variant INTERFACE) +target_include_directories(mpark_variant INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/deps/variant/include/mpark/variant.hpp b/deps/variant/include/mpark/variant.hpp new file mode 100644 index 000000000..6ed9c833b --- /dev/null +++ b/deps/variant/include/mpark/variant.hpp @@ -0,0 +1,2462 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_VARIANT_HPP +#define MPARK_VARIANT_HPP + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + T& emplace(Args&&...); + + template + T& emplace(initializer_list, Args&&...); + + template + variant_alternative& emplace(Args&&...); + + template + variant_alternative& emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_CONFIG_HPP +#define MPARK_CONFIG_HPP + +// MSVC 2015 Update 3. +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) +#error "MPark.Variant requires C++11 support." +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_include +#define __has_include(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_builtin(__builtin_addressof) || \ + (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) +#define MPARK_BUILTIN_ADDRESSOF +#endif + +#if __has_builtin(__builtin_unreachable) +#define MPARK_BUILTIN_UNREACHABLE +#endif + +#if __has_builtin(__type_pack_element) +#define MPARK_TYPE_PACK_ELEMENT +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 && \ + !(defined(_MSC_VER) && _MSC_VER <= 1915) +#define MPARK_CPP14_CONSTEXPR +#endif + +#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND)) +#define MPARK_EXCEPTIONS +#endif + +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define MPARK_GENERIC_LAMBDAS +#endif + +#if defined(__cpp_lib_integer_sequence) +#define MPARK_INTEGER_SEQUENCE +#endif + +#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) +#define MPARK_RETURN_TYPE_DEDUCTION +#endif + +#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) +#define MPARK_TRANSPARENT_OPERATORS +#endif + +#if defined(__cpp_variable_templates) || defined(_MSC_VER) +#define MPARK_VARIABLE_TEMPLATES +#endif + +#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 +#define MPARK_TRIVIALITY_TYPE_TRAITS +#endif + +#endif // MPARK_CONFIG_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_IN_PLACE_HPP +#define MPARK_IN_PLACE_HPP + + +namespace mpark { + + struct in_place_t { explicit in_place_t() = default; }; + + template + struct in_place_index_t { explicit in_place_index_t() = default; }; + + template + struct in_place_type_t { explicit in_place_type_t() = default; }; + +#ifdef MPARK_VARIABLE_TEMPLATES + constexpr in_place_t in_place{}; + + template constexpr in_place_index_t in_place_index{}; + + template constexpr in_place_type_t in_place_type{}; +#endif + +} // namespace mpark + +#endif // MPARK_IN_PLACE_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_LIB_HPP +#define MPARK_LIB_HPP + + +#define RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +namespace mpark { + namespace lib { + template + struct identity { using type = T; }; + + inline namespace cpp14 { + template + struct array { + constexpr const T &operator[](std::size_t index) const { + return data[index]; + } + + T data[N == 0 ? 1 : N]; + }; + + template + using add_pointer_t = typename std::add_pointer::type; + + template + using common_type_t = typename std::common_type::type; + + template + using decay_t = typename std::decay::type; + + template + using enable_if_t = typename std::enable_if::type; + + template + using remove_const_t = typename std::remove_const::type; + + template + using remove_reference_t = typename std::remove_reference::type; + + template + inline constexpr T &&forward(remove_reference_t &t) noexcept { + return static_cast(t); + } + + template + inline constexpr T &&forward(remove_reference_t &&t) noexcept { + static_assert(!std::is_lvalue_reference::value, + "can not forward an rvalue as an lvalue"); + return static_cast(t); + } + + template + inline constexpr remove_reference_t &&move(T &&t) noexcept { + return static_cast &&>(t); + } + +#ifdef MPARK_INTEGER_SEQUENCE + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::index_sequence_for; +#else + template + struct integer_sequence { + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; + + template + using index_sequence = integer_sequence; + + template + struct make_index_sequence_concat; + + template + struct make_index_sequence_concat, + index_sequence> + : identity> {}; + + template + struct make_index_sequence_impl; + + template + using make_index_sequence = typename make_index_sequence_impl::type; + + template + struct make_index_sequence_impl + : make_index_sequence_concat, + make_index_sequence> {}; + + template <> + struct make_index_sequence_impl<0> : identity> {}; + + template <> + struct make_index_sequence_impl<1> : identity> {}; + + template + using index_sequence_for = make_index_sequence; +#endif + + // +#ifdef MPARK_TRANSPARENT_OPERATORS + using equal_to = std::equal_to<>; +#else + struct equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) == lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using not_equal_to = std::not_equal_to<>; +#else + struct not_equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) != lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less = std::less<>; +#else + struct less { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) < lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater = std::greater<>; +#else + struct greater { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) > lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less_equal = std::less_equal<>; +#else + struct less_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) <= lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater_equal = std::greater_equal<>; +#else + struct greater_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + RETURN(lib::forward(lhs) >= lib::forward(rhs)) + }; +#endif + } // namespace cpp14 + + inline namespace cpp17 { + + // + template + using bool_constant = std::integral_constant; + + template + struct voider : identity {}; + + template + using void_t = typename voider::type; + + namespace detail { + namespace swappable { + + using std::swap; + + template + struct is_swappable { + private: + template (), + std::declval()))> + inline static std::true_type test(int); + + template + inline static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template ::value> + struct is_nothrow_swappable { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + static constexpr bool value = + noexcept(swap(std::declval(), std::declval())); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + }; + + template + struct is_nothrow_swappable : std::false_type {}; + + } // namespace swappable + } // namespace detail + + using detail::swappable::is_swappable; + using detail::swappable::is_nothrow_swappable; + + // +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline constexpr auto invoke(F &&f, As &&... as) + RETURN(lib::forward(f)(lib::forward(as)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + inline constexpr auto invoke(T B::*pmv, D &&d) + RETURN(lib::forward(d).*pmv) + + template + inline constexpr auto invoke(Pmv pmv, Ptr &&ptr) + RETURN((*lib::forward(ptr)).*pmv) + + template + inline constexpr auto invoke(T B::*pmf, D &&d, As &&... as) + RETURN((lib::forward(d).*pmf)(lib::forward(as)...)) + + template + inline constexpr auto invoke(Pmf pmf, Ptr &&ptr, As &&... as) + RETURN(((*lib::forward(ptr)).*pmf)(lib::forward(as)...)) + + namespace detail { + + template + struct invoke_result {}; + + template + struct invoke_result(), std::declval()...))>, + F, + Args...> + : identity(), std::declval()...))> {}; + + } // namespace detail + + template + using invoke_result = detail::invoke_result; + + template + using invoke_result_t = typename invoke_result::type; + + namespace detail { + + template + struct is_invocable : std::false_type {}; + + template + struct is_invocable>, F, Args...> + : std::true_type {}; + + template + struct is_invocable_r : std::false_type {}; + + template + struct is_invocable_r>, + R, + F, + Args...> + : std::is_convertible, R> {}; + + } // namespace detail + + template + using is_invocable = detail::is_invocable; + + template + using is_invocable_r = detail::is_invocable_r; + + // +#ifdef MPARK_BUILTIN_ADDRESSOF + template + inline constexpr T *addressof(T &arg) noexcept { + return __builtin_addressof(arg); + } +#else + namespace detail { + + namespace has_addressof_impl { + + struct fail; + + template + inline fail operator&(T &&); + + template + inline static constexpr bool impl() { + return (std::is_class::value || std::is_union::value) && + !std::is_same()), fail>::value; + } + + } // namespace has_addressof_impl + + template + using has_addressof = bool_constant()>; + + template + inline constexpr T *addressof(T &arg, std::true_type) noexcept { + return std::addressof(arg); + } + + template + inline constexpr T *addressof(T &arg, std::false_type) noexcept { + return &arg; + } + + } // namespace detail + + template + inline constexpr T *addressof(T &arg) noexcept { + return detail::addressof(arg, detail::has_addressof{}); + } +#endif + + template + inline constexpr T *addressof(const T &&) = delete; + + } // namespace cpp17 + + template + struct remove_all_extents : identity {}; + + template + struct remove_all_extents> : remove_all_extents {}; + + template + using remove_all_extents_t = typename remove_all_extents::type; + + template + using size_constant = std::integral_constant; + + template + struct indexed_type : size_constant, identity {}; + + template + using all = std::is_same, + integer_sequence>; + +#ifdef MPARK_TYPE_PACK_ELEMENT + template + using type_pack_element_t = __type_pack_element; +#else + template + struct type_pack_element_impl { + private: + template + struct set; + + template + struct set> : indexed_type... {}; + + template + inline static std::enable_if impl(indexed_type); + + inline static std::enable_if impl(...); + + public: + using type = decltype(impl(set>{})); + }; + + template + using type_pack_element = typename type_pack_element_impl::type; + + template + using type_pack_element_t = typename type_pack_element::type; +#endif + +#ifdef MPARK_TRIVIALITY_TYPE_TRAITS + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; +#else + template + struct is_trivially_copy_constructible + : bool_constant< + std::is_copy_constructible::value && __has_trivial_copy(T)> {}; + + template + struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; + + template + struct is_trivially_copy_assignable + : bool_constant< + std::is_copy_assignable::value && __has_trivial_assign(T)> {}; + + template + struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; +#endif + + template + struct dependent_type : T {}; + + template + struct push_back; + + template + using push_back_t = typename push_back::type; + + template + struct push_back, J> { + using type = index_sequence; + }; + + } // namespace lib +} // namespace mpark + +#undef RETURN + +#endif // MPARK_LIB_HPP + +namespace mpark { + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + +#define AUTO auto +#define AUTO_RETURN(...) { return __VA_ARGS__; } + +#define AUTO_REFREF auto && +#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } + +#define DECLTYPE_AUTO decltype(auto) +#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } + +#else + +#define AUTO auto +#define AUTO_RETURN(...) \ + -> lib::decay_t { return __VA_ARGS__; } + +#define AUTO_REFREF auto +#define AUTO_REFREF_RETURN(...) \ + -> decltype((__VA_ARGS__)) { \ + static_assert(std::is_reference::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO auto +#define DECLTYPE_AUTO_RETURN(...) \ + -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +#endif + + class bad_variant_access : public std::exception { + public: + virtual const char *what() const noexcept override { return "bad_variant_access"; } + }; + + [[noreturn]] inline void throw_bad_variant_access() { +#ifdef MPARK_EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); +#ifdef MPARK_BUILTIN_UNREACHABLE + __builtin_unreachable(); +#endif +#endif + } + + template + class variant; + + template + struct variant_size; + +#ifdef MPARK_VARIABLE_TEMPLATES + template + constexpr std::size_t variant_size_v = variant_size::value; +#endif + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size> : lib::size_constant {}; + + template + struct variant_alternative; + + template + using variant_alternative_t = typename variant_alternative::type; + + template + struct variant_alternative + : std::add_const> {}; + + template + struct variant_alternative + : std::add_volatile> {}; + + template + struct variant_alternative + : std::add_cv> {}; + + template + struct variant_alternative> { + static_assert(I < sizeof...(Ts), + "Index out of bounds in std::variant_alternative<>"); + using type = lib::type_pack_element_t; + }; + + constexpr std::size_t variant_npos = static_cast(-1); + + namespace detail { + + constexpr std::size_t not_found = static_cast(-1); + constexpr std::size_t ambiguous = static_cast(-2); + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr std::size_t find_index() { + constexpr lib::array matches = { + {std::is_same::value...} + }; + std::size_t result = not_found; + for (std::size_t i = 0; i < sizeof...(Ts); ++i) { + if (matches[i]) { + if (result != not_found) { + return ambiguous; + } + result = i; + } + } + return result; + } +#else + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t) { + return result; + } + + template + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t idx, + bool b, + Bs... bs) { + return b ? (result != not_found ? ambiguous + : find_index_impl(idx, idx + 1, bs...)) + : find_index_impl(result, idx + 1, bs...); + } + + template + inline constexpr std::size_t find_index() { + return find_index_impl(not_found, 0, std::is_same::value...); + } +#endif + + template + using find_index_sfinae_impl = + lib::enable_if_t>; + + template + using find_index_sfinae = find_index_sfinae_impl()>; + + template + struct find_index_checked_impl : lib::size_constant { + static_assert(I != not_found, "the specified type is not found."); + static_assert(I != ambiguous, "the specified type is ambiguous."); + }; + + template + using find_index_checked = find_index_checked_impl()>; + + struct valueless_t {}; + + enum class Trait { TriviallyAvailable, Available, Unavailable }; + + template class IsTriviallyAvailable, + template class IsAvailable> + inline constexpr Trait trait() { + return IsTriviallyAvailable::value + ? Trait::TriviallyAvailable + : IsAvailable::value ? Trait::Available + : Trait::Unavailable; + } + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr Trait common_trait(Traits... traits) { + Trait result = Trait::TriviallyAvailable; + for (Trait t : {traits...}) { + if (static_cast(t) > static_cast(result)) { + result = t; + } + } + return result; + } +#else + inline constexpr Trait common_trait_impl(Trait result) { return result; } + + template + inline constexpr Trait common_trait_impl(Trait result, + Trait t, + Traits... ts) { + return static_cast(t) > static_cast(result) + ? common_trait_impl(t, ts...) + : common_trait_impl(result, ts...); + } + + template + inline constexpr Trait common_trait(Traits... ts) { + return common_trait_impl(Trait::TriviallyAvailable, ts...); + } +#endif + + template + struct traits { + static constexpr Trait copy_constructible_trait = + common_trait(trait()...); + + static constexpr Trait move_constructible_trait = + common_trait(trait()...); + + static constexpr Trait copy_assignable_trait = + common_trait(copy_constructible_trait, + trait()...); + + static constexpr Trait move_assignable_trait = + common_trait(move_constructible_trait, + trait()...); + + static constexpr Trait destructible_trait = + common_trait(trait()...); + }; + + namespace access { + + struct recursive_union { +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { + return lib::forward(v).head_; + } + + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { + return get_alt(lib::forward(v).tail_, in_place_index_t{}); + } +#else + template + struct get_alt_impl { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) + }; + + template + struct get_alt_impl<0, Dummy> { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(lib::forward(v).head_) + }; + + template + inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) +#endif + }; + + struct base { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(recursive_union::get_alt( + data(lib::forward(v)), in_place_index_t{})) + }; + + struct variant { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) + }; + + } // namespace access + + namespace visitation { + + struct base { + template + inline static constexpr const T &at(const T &elem) noexcept { + return elem; + } + + template + inline static constexpr const lib::remove_all_extents_t &at( + const lib::array &elems, std::size_t i, Is... is) noexcept { + return at(elems[i], is...); + } + + template + inline static constexpr int visit_visitor_return_type_check() { + static_assert(lib::all::value...>::value, + "`mpark::visit` requires the visitor to have a single " + "return type."); + return 0; + } + + template + inline static constexpr lib::array< + lib::common_type_t...>, + sizeof...(Fs)> + make_farray(Fs &&... fs) { + using result = lib::array...>, + sizeof...(Fs)>; + return visit_visitor_return_type_check...>(), + result{{lib::forward(fs)...}}; + } + + template + struct dispatcher { + template + struct impl { + inline static constexpr DECLTYPE_AUTO dispatch(F f, Vs... vs) + DECLTYPE_AUTO_RETURN(lib::invoke( + static_cast(f), + access::base::get_alt(static_cast(vs))...)) + }; + }; + + template + inline static constexpr AUTO make_dispatch(lib::index_sequence) + AUTO_RETURN(&dispatcher::template impl::dispatch) + + template + inline static constexpr AUTO make_fdiagonal_impl() + AUTO_RETURN(make_dispatch( + lib::index_sequence::value...>{})) + + template + inline static constexpr AUTO make_fdiagonal_impl( + lib::index_sequence) + AUTO_RETURN(make_farray(make_fdiagonal_impl()...)) + + template + inline static constexpr /* auto * */ auto make_fdiagonal() + -> decltype(make_fdiagonal_impl( + lib::make_index_sequence::size()>{})) { + static_assert(lib::all<(lib::decay_t::size() == + lib::decay_t::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl( + lib::make_index_sequence::size()>{}); + } + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto make_fmatrix_impl(Is is) { + return make_dispatch(is); + } + + template + inline static constexpr auto make_fmatrix_impl( + Is, lib::index_sequence, Ls... ls) { + return make_farray(make_fmatrix_impl( + lib::push_back_t{}, ls...)...); + } + + template + inline static constexpr auto make_fmatrix() { + return make_fmatrix_impl( + lib::index_sequence<>{}, + lib::make_index_sequence::size()>{}...); + } +#else + template + struct make_fmatrix_impl { + template + struct impl; + + template + struct impl { + inline constexpr AUTO operator()() const + AUTO_RETURN(make_dispatch(Is{})) + }; + + template + struct impl, Ls...> { + inline constexpr AUTO operator()() const + AUTO_RETURN( + make_farray(impl, Ls...>{}()...)) + }; + }; + + template + inline static constexpr AUTO make_fmatrix() + AUTO_RETURN( + typename make_fmatrix_impl::template impl< + lib::index_sequence<>, + lib::make_index_sequence::size()>...>{}()) +#endif + }; // namespace base + + template + using FDiagonal = decltype(base::make_fdiagonal()); + + template + struct fdiagonal { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FDiagonal value = + base::make_fdiagonal(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FDiagonal fdiagonal::value; + + template + using FMatrix = decltype(base::make_fmatrix()); + + template + struct fmatrix { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FMatrix value = + base::make_fmatrix(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FMatrix fmatrix::value; + + struct alt { + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fdiagonal(vs)))...>::value, + index)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fmatrix(vs)))...>::value, + vs.index()...)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + }; + + struct variant { + private: + template + struct visit_exhaustive_visitor_check { + static_assert( + lib::is_invocable::value, + "`mpark::visit` requires the visitor to be exhaustive."); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + inline constexpr DECLTYPE_AUTO operator()(Visitor &&visitor, + Values &&... values) const + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), + lib::forward(values)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + struct value_visitor { + Visitor &&visitor_; + + template + inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const + DECLTYPE_AUTO_RETURN( + visit_exhaustive_visitor_check< + Visitor, + decltype((lib::forward(alts).value))...>{}( + lib::forward(visitor_), + lib::forward(alts).value...)) + }; + + template + inline static constexpr AUTO make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor{lib::forward(visitor)}) + + public: + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + alt::visit_alt_at(index, + lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt_at(index, + make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + }; + + } // namespace visitation + + template + struct alt { + using value_type = T; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + template + inline explicit constexpr alt(in_place_t, Args &&... args) + : value(lib::forward(args)...) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + T value; + }; + + template + union recursive_union; + + template + union recursive_union {}; + +#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ + template \ + union recursive_union { \ + public: \ + inline explicit constexpr recursive_union(valueless_t) noexcept \ + : dummy_{} {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t<0>, \ + Args &&... args) \ + : head_(in_place_t{}, lib::forward(args)...) {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t, \ + Args &&... args) \ + : tail_(in_place_index_t{}, lib::forward(args)...) {} \ + \ + recursive_union(const recursive_union &) = default; \ + recursive_union(recursive_union &&) = default; \ + \ + destructor \ + \ + recursive_union &operator=(const recursive_union &) = default; \ + recursive_union &operator=(recursive_union &&) = default; \ + \ + private: \ + char dummy_; \ + alt head_; \ + recursive_union tail_; \ + \ + friend struct access::recursive_union; \ + } + + MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, + ~recursive_union() = default;); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, + ~recursive_union() {}); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, + ~recursive_union() = delete;); + +#undef MPARK_VARIANT_RECURSIVE_UNION + + using index_t = unsigned int; + + template + class base { + public: + inline explicit constexpr base(valueless_t tag) noexcept + : data_(tag), index_(static_cast(-1)) {} + + template + inline explicit constexpr base(in_place_index_t, Args &&... args) + : data_(in_place_index_t{}, lib::forward(args)...), + index_(I) {} + + inline constexpr bool valueless_by_exception() const noexcept { + return index_ == static_cast(-1); + } + + inline constexpr std::size_t index() const noexcept { + return valueless_by_exception() ? variant_npos : index_; + } + + protected: + using data_t = recursive_union; + + friend inline constexpr base &as_base(base &b) { return b; } + friend inline constexpr const base &as_base(const base &b) { return b; } + friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } + + friend inline constexpr data_t &data(base &b) { return b.data_; } + friend inline constexpr const data_t &data(const base &b) { return b.data_; } + friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } + + inline static constexpr std::size_t size() { return sizeof...(Ts); } + + data_t data_; + index_t index_; + + friend struct access::base; + friend struct visitation::base; + }; + + struct dtor { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + +#if defined(_MSC_VER) && _MSC_VER < 1910 +#define INHERITING_CTOR(type, base) \ + template \ + inline explicit constexpr type(Args &&... args) \ + : base(lib::forward(args)...) {} +#else +#define INHERITING_CTOR(type, base) using base::base; +#endif + + template + class destructor; + +#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template \ + class destructor, destructible_trait> \ + : public base { \ + using super = base; \ + \ + public: \ + INHERITING_CTOR(destructor, super) \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition \ + destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + + MPARK_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, + ~destructor() = default;, + inline void destroy() noexcept { + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Available, + ~destructor() { destroy(); }, + inline void destroy() noexcept { + if (!this->valueless_by_exception()) { + visitation::alt::visit_alt(dtor{}, *this); + } + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Unavailable, + ~destructor() = delete;, + inline void destroy() noexcept = delete;); + +#undef MPARK_VARIANT_DESTRUCTOR + + template + class constructor : public destructor { + using super = destructor; + + public: + INHERITING_CTOR(constructor, super) + using super::operator=; + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + struct ctor { + template + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { + constructor::construct_alt(lhs_alt, + lib::forward(rhs_alt).value); + } + }; +#endif + + template + inline static T &construct_alt(alt &a, Args &&... args) { + ::new (static_cast(lib::addressof(a))) + alt(in_place_t{}, lib::forward(args)...); + return a.value; + } + + template + inline static void generic_construct(constructor &lhs, Rhs &&rhs) { + lhs.destroy(); + if (!rhs.valueless_by_exception()) { + visitation::alt::visit_alt_at( + rhs.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &lhs_alt, auto &&rhs_alt) { + constructor::construct_alt( + lhs_alt, lib::forward(rhs_alt).value); + } +#else + ctor{} +#endif + , + lhs, + lib::forward(rhs)); + lhs.index_ = rhs.index_; + } + } + }; + + template + class move_constructor; + +#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template \ + class move_constructor, move_constructible_trait> \ + : public constructor> { \ + using super = constructor>; \ + \ + public: \ + INHERITING_CTOR(move_constructor, super) \ + using super::operator=; \ + \ + move_constructor(const move_constructor &) = default; \ + definition \ + ~move_constructor() = default; \ + move_constructor &operator=(const move_constructor &) = default; \ + move_constructor &operator=(move_constructor &&) = default; \ + } + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + lib::all::value...>::value) + : move_constructor(valueless_t{}) { + this->generic_construct(*this, lib::move(that)); + }); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef MPARK_VARIANT_MOVE_CONSTRUCTOR + + template + class copy_constructor; + +#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template \ + class copy_constructor, copy_constructible_trait> \ + : public move_constructor> { \ + using super = move_constructor>; \ + \ + public: \ + INHERITING_CTOR(copy_constructor, super) \ + using super::operator=; \ + \ + definition \ + copy_constructor(copy_constructor &&) = default; \ + ~copy_constructor() = default; \ + copy_constructor &operator=(const copy_constructor &) = default; \ + copy_constructor &operator=(copy_constructor &&) = default; \ + } + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, + copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { + this->generic_construct(*this, that); + }); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef MPARK_VARIANT_COPY_CONSTRUCTOR + + template + class assignment : public copy_constructor { + using super = copy_constructor; + + public: + INHERITING_CTOR(assignment, super) + using super::operator=; + + template + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...)) { + this->destroy(); + auto &result = this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...); + this->index_ = I; + return result; + } + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + template + struct assigner { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { + self->assign_alt(this_alt, lib::forward(that_alt).value); + } + assignment *self; + }; +#endif + + template + inline void assign_alt(alt &a, Arg &&arg) { + if (this->index() == I) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + a.value = lib::forward(arg); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + struct { + void operator()(std::true_type) const { + this_->emplace(lib::forward(arg_)); + } + void operator()(std::false_type) const { + this_->emplace(T(lib::forward(arg_))); + } + assignment *this_; + Arg &&arg_; + } impl{this, lib::forward(arg)}; + impl(lib::bool_constant< + std::is_nothrow_constructible::value || + !std::is_nothrow_move_constructible::value>{}); + } + } + + template + inline void generic_assign(That &&that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (that.valueless_by_exception()) { + this->destroy(); + } else { + visitation::alt::visit_alt_at( + that.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [this](auto &this_alt, auto &&that_alt) { + this->assign_alt( + this_alt, lib::forward(that_alt).value); + } +#else + assigner{this} +#endif + , + *this, + lib::forward(that)); + } + } + }; + + template + class move_assignment; + +#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template \ + class move_assignment, move_assignable_trait> \ + : public assignment> { \ + using super = assignment>; \ + \ + public: \ + INHERITING_CTOR(move_assignment, super) \ + using super::operator=; \ + \ + move_assignment(const move_assignment &) = default; \ + move_assignment(move_assignment &&) = default; \ + ~move_assignment() = default; \ + move_assignment &operator=(const move_assignment &) = default; \ + definition \ + } + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, + move_assignment &operator=(move_assignment &&that) = default;); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value)...>::value) { + this->generic_assign(lib::move(that)); + return *this; + }); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef MPARK_VARIANT_MOVE_ASSIGNMENT + + template + class copy_assignment; + +#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template \ + class copy_assignment, copy_assignable_trait> \ + : public move_assignment> { \ + using super = move_assignment>; \ + \ + public: \ + INHERITING_CTOR(copy_assignment, super) \ + using super::operator=; \ + \ + copy_assignment(const copy_assignment &) = default; \ + copy_assignment(copy_assignment &&) = default; \ + ~copy_assignment() = default; \ + definition \ + copy_assignment &operator=(copy_assignment &&) = default; \ + } + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, + copy_assignment &operator=(const copy_assignment &that) = default;); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment &operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, + copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef MPARK_VARIANT_COPY_ASSIGNMENT + + template + class impl : public copy_assignment> { + using super = copy_assignment>; + + public: + INHERITING_CTOR(impl, super) + using super::operator=; + + template + inline void assign(Arg &&arg) { + this->assign_alt(access::base::get_alt(*this), + lib::forward(arg)); + } + + inline void swap(impl &that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == that.index()) { + visitation::alt::visit_alt_at(this->index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &this_alt, auto &that_alt) { + using std::swap; + swap(this_alt.value, + that_alt.value); + } +#else + swapper{} +#endif + , + *this, + that); + } else { + impl *lhs = this; + impl *rhs = lib::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) { + std::swap(lhs, rhs); + } + impl tmp(lib::move(*rhs)); +#ifdef MPARK_EXCEPTIONS + // EXTENSION: When the move construction of `lhs` into `rhs` throws + // and `tmp` is nothrow move constructible then we move `tmp` back + // into `rhs` and provide the strong exception safety guarantee. + try { + this->generic_construct(*rhs, lib::move(*lhs)); + } catch (...) { + if (tmp.move_nothrow()) { + this->generic_construct(*rhs, lib::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, lib::move(*lhs)); +#endif + this->generic_construct(*lhs, lib::move(tmp)); + } + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct swapper { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; +#endif + + inline constexpr bool move_nothrow() const { + return this->valueless_by_exception() || + lib::array{ + {std::is_nothrow_move_constructible::value...} + }[this->index()]; + } + }; + + template + struct overload_leaf { + using F = lib::size_constant (*)(T); + operator F() const { return nullptr; } + }; + + template + struct overload_impl { + private: + template + struct impl; + + template + struct impl> : overload_leaf... {}; + + public: + using type = impl>; + }; + + template + using overload = typename overload_impl::type; + + template + using best_match = lib::invoke_result_t, T &&>; + + template + struct is_in_place_index : std::false_type {}; + + template + struct is_in_place_index> : std::true_type {}; + + template + struct is_in_place_type : std::false_type {}; + + template + struct is_in_place_type> : std::true_type {}; + + } // detail + + template + class variant { + static_assert(0 < sizeof...(Ts), + "variant must consist of at least one alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a void type as an alternative."); + + public: + template < + typename Front = lib::type_pack_element_t<0, Ts...>, + lib::enable_if_t::value, int> = 0> + inline constexpr variant() noexcept( + std::is_nothrow_default_constructible::value) + : impl_(in_place_index_t<0>{}) {} + + variant(const variant &) = default; + variant(variant &&) = default; + + template < + typename Arg, + typename Decayed = lib::decay_t, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept( + std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(arg)) {} + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_index_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_index_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_type_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_type_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template , variant>::value, + int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t<(std::is_assignable::value && + std::is_constructible::value), + int> = 0> + inline variant &operator=(Arg &&arg) noexcept( + (std::is_nothrow_assignable::value && + std::is_nothrow_constructible::value)) { + impl_.template assign(lib::forward(arg)); + return *this; + } + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + inline constexpr bool valueless_by_exception() const noexcept { + return impl_.valueless_by_exception(); + } + + inline constexpr std::size_t index() const noexcept { + return impl_.index(); + } + + template , + Dummy>::value && + lib::dependent_type, + Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + lib::is_nothrow_swappable::value)...>::value) { + impl_.swap(that.impl_); + } + + private: + detail::impl impl_; + + friend struct detail::access::variant; + friend struct detail::visitation::variant; + }; + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return v.index() == I; + } + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return holds_alternative::value>(v); + } + + namespace detail { + template + struct generic_get_impl { + constexpr generic_get_impl(int) noexcept {} + + constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN( + access::variant::get_alt(lib::forward(v)).value) + }; + + template + inline constexpr AUTO_REFREF generic_get(V &&v) + AUTO_REFREF_RETURN(generic_get_impl( + holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( + lib::forward(v))) + } // namespace detail + + template + inline constexpr variant_alternative_t> &get( + variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr variant_alternative_t> &&get( + variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr const variant_alternative_t> &get( + const variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr const variant_alternative_t> &&get( + const variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr T &get(variant &v) { + return get::value>(v); + } + + template + inline constexpr T &&get(variant &&v) { + return get::value>(lib::move(v)); + } + + template + inline constexpr const T &get(const variant &v) { + return get::value>(v); + } + + template + inline constexpr const T &&get(const variant &&v) { + return get::value>(lib::move(v)); + } + + namespace detail { + + template + inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept + AUTO_RETURN(v && holds_alternative(*v) + ? lib::addressof(access::variant::get_alt(*v).value) + : nullptr) + + } // namespace detail + + template + inline constexpr lib::add_pointer_t>> + get_if(variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t< + const variant_alternative_t>> + get_if(const variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(const variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr bool operator==(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::equal_to; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return false; + if (lhs.valueless_by_exception()) return true; + return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); +#else + return lhs.index() == rhs.index() && + (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator!=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::not_equal_to; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); +#else + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator<(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::less; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); +#else + return !rhs.valueless_by_exception() && + (lhs.valueless_by_exception() || lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator>(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::greater; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return false; + if (rhs.valueless_by_exception()) return true; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); +#else + return !lhs.valueless_by_exception() && + (rhs.valueless_by_exception() || lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator<=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::less_equal; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); +#else + return lhs.valueless_by_exception() || + (!rhs.valueless_by_exception() && + (lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); +#endif + } + + template + inline constexpr bool operator>=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using lib::greater_equal; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return true; + if (lhs.valueless_by_exception()) return false; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); +#else + return rhs.valueless_by_exception() || + (!lhs.valueless_by_exception() && + (lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at( + lhs.index(), greater_equal{}, lhs, rhs)))); +#endif + } + + struct monostate {}; + + inline constexpr bool operator<(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator>(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator<=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator>=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator==(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator!=(monostate, monostate) noexcept { + return false; + } + +#ifdef MPARK_CPP14_CONSTEXPR + namespace detail { + + inline constexpr bool all(std::initializer_list bs) { + for (bool b : bs) { + if (!b) { + return false; + } + } + return true; + } + + } // namespace detail + + template + inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { + return (detail::all({!vs.valueless_by_exception()...}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value( + lib::forward(visitor), lib::forward(vs)...); + } +#else + namespace detail { + + template + inline constexpr bool all_impl(const lib::array &bs, + std::size_t idx) { + return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); + } + + template + inline constexpr bool all(const lib::array &bs) { + return all_impl(bs, 0); + } + + } // namespace detail + + template + inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + (detail::all( + lib::array{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(lib::forward(visitor), + lib::forward(vs)...)) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + template + inline auto swap(variant &lhs, + variant &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) { + lhs.swap(rhs); + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + namespace detail { + + template + using enabled_type = T; + + namespace hash { + + template + constexpr bool meets_requirements() noexcept { + return std::is_copy_constructible::value && + std::is_move_constructible::value && + lib::is_invocable_r::value; + } + + template + constexpr bool is_enabled() noexcept { + using H = std::hash; + return meets_requirements() && + std::is_default_constructible::value && + std::is_copy_assignable::value && + std::is_move_assignable::value; + } + + } // namespace hash + + } // namespace detail + +#undef AUTO +#undef AUTO_RETURN + +#undef AUTO_REFREF +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO +#undef DECLTYPE_AUTO_RETURN + +} // namespace mpark + +namespace std { + + template + struct hash, + mpark::lib::enable_if_t>()...>::value>>> { + using argument_type = mpark::variant; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &v) const { + using mpark::detail::visitation::variant; + std::size_t result = + v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : variant::visit_alt( +#ifdef MPARK_GENERIC_LAMBDAS + [](const auto &alt) { + using alt_type = mpark::lib::decay_t; + using value_type = mpark::lib::remove_const_t< + typename alt_type::value_type>; + return hash{}(alt.value); + } +#else + hasher{} +#endif + , + v); + return hash_combine(result, hash{}(v.index())); + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct hasher { + template + inline std::size_t operator()(const Alt &alt) const { + using alt_type = mpark::lib::decay_t; + using value_type = + mpark::lib::remove_const_t; + return hash{}(alt.value); + } + }; +#endif + + static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { + return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + } + }; + + template <> + struct hash { + using argument_type = mpark::monostate; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } + }; + +} // namespace std + +#endif // MPARK_VARIANT_HPP diff --git a/include/retdec/fileformat/file_format/pe/pe_format.h b/include/retdec/fileformat/file_format/pe/pe_format.h index cd11a5f50..0bb009330 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format.h +++ b/include/retdec/fileformat/file_format/pe/pe_format.h @@ -41,6 +41,9 @@ class PeFormat : public FileFormat std::string typeLibId; ///< .NET type lib ID std::vector> definedClasses; ///< .NET defined class list std::vector> importedClasses; ///< .NET imported class list + std::string typeRefHashCrc32; ///< .NET typeref table hash as CRC32 + std::string typeRefHashMd5; ///< .NET typeref table hash as MD5 + std::string typeRefHashSha256; ///< .NET typeref table hash as SHA256 /// @name Initialization methods /// @{ @@ -88,6 +91,7 @@ class PeFormat : public FileFormat void detectTypeLibId(); void detectDotnetTypes(); std::uint64_t detectPossibleMetadataHeaderAddress() const; + void computeTypeRefHashes(); /// @} protected: PeLib::PeFile *file; ///< PeLib representation of PE file @@ -171,6 +175,9 @@ class PeFormat : public FileFormat const std::string& getTypeLibId() const; const std::vector>& getDefinedDotnetClasses() const; const std::vector>& getImportedDotnetClasses() const; + const std::string& getTypeRefhashCrc32() const; + const std::string& getTypeRefhashMd5() const; + const std::string& getTypeRefhashSha256() const; /// @} }; diff --git a/include/retdec/fileformat/types/dotnet_types/dotnet_class.h b/include/retdec/fileformat/types/dotnet_types/dotnet_class.h index 1ee79db4d..4defb1ade 100644 --- a/include/retdec/fileformat/types/dotnet_types/dotnet_class.h +++ b/include/retdec/fileformat/types/dotnet_types/dotnet_class.h @@ -10,6 +10,9 @@ #include #include +#include + +#include "retdec/utils/conversion.h" #include "retdec/fileformat/types/dotnet_types/dotnet_field.h" #include "retdec/fileformat/types/dotnet_types/dotnet_method.h" #include "retdec/fileformat/types/dotnet_types/dotnet_property.h" @@ -24,7 +27,9 @@ namespace fileformat { class DotnetClass : public DotnetType { private: - const TypeDef* rawRecord; + mpark::variant rawRecord; + const DotnetClass* parent; + std::size_t index; std::size_t declaredFieldsCount; std::size_t declaredMethodsCount; std::size_t declaredGenericParametersCount; @@ -33,17 +38,27 @@ class DotnetClass : public DotnetType std::vector> methods; std::vector genericParameters; std::vector> baseTypes; + std::string libName; bool classOrInterface; bool abstract; bool sealed; + MetadataTableType recordType; std::string getGenericParametersString() const; public: + DotnetClass(MetadataTableType rType, std::size_t idx); + /// @name Getters /// @{ - const TypeDef* getRawRecord() const; + const TypeDef* getRawTypeDef() const; + const TypeRef* getRawTypeRef() const; + const DotnetClass* getParent() const; std::string getNameWithGenericParameters() const; std::string getFullyQualifiedNameWithGenericParameters() const; + std::string getNameWithParentClassIndex() const; + std::string getNestedName() const; + const std::string& getLibName() const; + std::size_t getIndex() const; std::size_t getDeclaredFieldsCount() const; std::size_t getDeclaredMethodsCount() const; std::size_t getDeclaredGenericParametersCount() const; @@ -57,14 +72,17 @@ class DotnetClass : public DotnetType std::size_t getMethodsCount() const; std::size_t getGenericParametersCount() const; std::string getTypeString() const; + MetadataTableType getRecordType() const; /// @} /// @name Setters /// @{ - void setRawRecord(const TypeDef* classTypeDef); + void setRawRecord(mpark::variant rRecord); + void setParent(const DotnetClass* par); void setDeclaredFieldsCount(std::size_t classFieldsCount); void setDeclaredMethodsCount(std::size_t classMethodsCount); void setDeclaredGenericParametersCount(std::size_t classGenericParamsCount); + void setLibName(const std::string &lName); void setIsInterface(bool set); void setIsAbstract(bool set); void setIsSealed(bool set); diff --git a/include/retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h b/include/retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h index 38aaf6305..e716a384f 100644 --- a/include/retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h +++ b/include/retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h @@ -41,8 +41,12 @@ class DotnetTypeReconstructor bool reconstructNestedClasses(); bool reconstructBaseTypes(); - std::unique_ptr createClassDefinition(const TypeDef* typeDef, std::size_t fieldsCount, std::size_t methodsCount); - std::unique_ptr createClassReference(const TypeRef* typeRef); + void linkReconstructedClasses(); + void linkReconstructedClassesDo(size_t i, std::vector &visited, std::vector &stack, ClassList &refClasses, const MetadataTable* typeRefTable); + + std::unique_ptr createClassDefinition(const TypeDef* typeDef, std::size_t fieldsCount, + std::size_t methodsCount, std::size_t typeDefIndex); + std::unique_ptr createClassReference(const TypeRef* typeRef, std::size_t typeRefIndex); std::unique_ptr createField(const Field* field, const DotnetClass* ownerClass); std::unique_ptr createProperty(const Property* property, const DotnetClass* ownerClass); std::unique_ptr createMethod(const MethodDef* methodDef, const DotnetClass* ownerClass); diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 351bfc8bd..86edd1c6a 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -26,6 +26,7 @@ #include "retdec/fileformat/utils/asn1.h" #include "retdec/fileformat/utils/conversions.h" #include "retdec/fileformat/utils/file_io.h" +#include "retdec/crypto/crypto.h" using namespace retdec::utils; using namespace PeLib; @@ -1861,6 +1862,8 @@ void PeFormat::detectDotnetTypes() definedClasses = reconstructor.getDefinedClasses(); importedClasses = reconstructor.getReferencedClasses(); } + + computeTypeRefHashes(); } /** @@ -1919,6 +1922,147 @@ std::uint64_t PeFormat::detectPossibleMetadataHeaderAddress() const return metadataHeaderFound ? address : 0; } +/** + * Compute typeref hashes - CRC32, MD5, SHA256. + */ +void PeFormat::computeTypeRefHashes() +{ + if (!metadataStream || !stringStream) + { + return; + } + + std::vector typeRefHashBytes; + std::string typeName; + std::string nameSpace; + std::string referencedName; + MetadataTableType resolutionScopeType; + + auto typeRefTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::TypeRef)); + auto moduleTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::Module)); + auto moduleRefTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::ModuleRef)); + auto assemblyRefTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::AssemblyRef)); + + if (!typeRefTable) + { + return; + } + + for (std::size_t i = 1; i <= typeRefTable->getNumberOfRows(); ++i) + { + bool validTypeName = false; + bool validNameSpace = false; + bool validReferencedName = false; + + auto typeRefRow = typeRefTable->getRow(i); + + if (stringStream->getString(typeRefRow->typeName.getIndex(), typeName) && !typeName.empty()) + { + validTypeName = true; + } + if (stringStream->getString(typeRefRow->typeNamespace.getIndex(), nameSpace) && !nameSpace.empty()) + { + validNameSpace = true; + } + + if (typeRefRow->resolutionScope.getTable(resolutionScopeType)) + { + switch (resolutionScopeType) + { + case MetadataTableType::TypeRef: + { + auto typeRef = typeRefTable->getRow(typeRefRow->resolutionScope.getIndex()); + if (typeRef && stringStream->getString(typeRef->typeName.getIndex(), referencedName) && !referencedName.empty()) + { + referencedName += "TR"; + validReferencedName = true; + } + break; + } + case MetadataTableType::Module: + { + if (moduleTable) + { + auto module = moduleTable->getRow(typeRefRow->resolutionScope.getIndex()); + if (module && stringStream->getString(module->name.getIndex(), referencedName) && !referencedName.empty()) + { + referencedName += "M"; + validReferencedName = true; + } + } + break; + } + case MetadataTableType::ModuleRef: + { + if (moduleRefTable) + { + auto moduleRef = moduleRefTable->getRow(typeRefRow->resolutionScope.getIndex()); + if (moduleRef && stringStream->getString(moduleRef->name.getIndex(), referencedName) && !referencedName.empty()) + { + referencedName += "MR"; + validReferencedName = true; + } + } + break; + } + case MetadataTableType::AssemblyRef: + { + if (assemblyRefTable) + { + auto assemblyRef = assemblyRefTable->getRow(typeRefRow->resolutionScope.getIndex()); + if (assemblyRef && stringStream->getString(assemblyRef->name.getIndex(), referencedName) && !referencedName.empty()) + { + referencedName += "AR"; + validReferencedName = true; + } + } + break; + } + default: + break; + } + + if (!typeRefHashBytes.empty()) + { + typeRefHashBytes.push_back(static_cast(',')); + } + + std::string fullName; + if (validTypeName) + { + fullName = typeName; + } + if (validNameSpace) + { + if (!fullName.empty()) + { + fullName += "."; + } + + fullName += nameSpace; + } + if (validReferencedName) + { + if (!fullName.empty()) + { + fullName += "."; + } + + fullName += referencedName; + } + + for(const auto c : fullName) + { + typeRefHashBytes.push_back(static_cast(c)); + } + } + } + + typeRefHashCrc32 = retdec::crypto::getCrc32(typeRefHashBytes.data(), typeRefHashBytes.size()); + typeRefHashMd5 = retdec::crypto::getMd5(typeRefHashBytes.data(), typeRefHashBytes.size()); + typeRefHashSha256 = retdec::crypto::getSha256(typeRefHashBytes.data(), typeRefHashBytes.size()); +} + retdec::utils::Endianness PeFormat::getEndianness() const { switch(formatParser->getMachineType()) @@ -2535,5 +2679,21 @@ const std::vector>& PeFormat::getImportedDotnetClas return importedClasses; } + +const std::string& PeFormat::getTypeRefhashCrc32() const +{ + return typeRefHashCrc32; +} + +const std::string& PeFormat::getTypeRefhashMd5() const +{ + return typeRefHashMd5; +} + +const std::string& PeFormat::getTypeRefhashSha256() const +{ + return typeRefHashSha256; +} + } // namespace fileformat } // namespace retdec diff --git a/src/fileformat/types/dotnet_types/dotnet_class.cpp b/src/fileformat/types/dotnet_types/dotnet_class.cpp index f607e5748..c93410f1f 100644 --- a/src/fileformat/types/dotnet_types/dotnet_class.cpp +++ b/src/fileformat/types/dotnet_types/dotnet_class.cpp @@ -7,9 +7,22 @@ #include "retdec/utils/string.h" #include "retdec/fileformat/types/dotnet_types/dotnet_class.h" +using namespace retdec::utils; + namespace retdec { namespace fileformat { +/** + * Constructor + */ +DotnetClass::DotnetClass(MetadataTableType rType, std::size_t idx) : rawRecord{static_cast(nullptr)}, + parent(nullptr), index(idx), declaredFieldsCount(0), declaredMethodsCount(0), + declaredGenericParametersCount(0), classOrInterface(false), abstract(false), + sealed(false), recordType(rType) +{ + +} + /** * Returns string containing all the generic pamaters. Returned string is in the format * @return Generic parameter string. @@ -25,11 +38,39 @@ std::string DotnetClass::getGenericParametersString() const /** * Returns the raw metadata table record for this class. - * @return Raw type record. + * @return Raw typeDef record. + */ +const TypeDef* DotnetClass::getRawTypeDef() const +{ + if (recordType != MetadataTableType::TypeDef) + { + return nullptr; + } + + return mpark::get(rawRecord); +} + +/** + * Returns the raw metadata table record for this class. + * @return Raw typeRef record. + */ +const TypeRef* DotnetClass::getRawTypeRef() const +{ + if (recordType != MetadataTableType::TypeRef) + { + return nullptr; + } + + return mpark::get(rawRecord); +} + +/** + * Returns this classes parent. + * @return Parent. */ -const TypeDef* DotnetClass::getRawRecord() const +const DotnetClass* DotnetClass::getParent() const { - return rawRecord; + return parent; } /** @@ -50,6 +91,68 @@ std::string DotnetClass::getFullyQualifiedNameWithGenericParameters() const return getFullyQualifiedName() + getGenericParametersString(); } +/** + * Returns the name of the class appended with parent class presentation index. + * @return Name with parent class presentation index. + */ +std::string DotnetClass::getNameWithParentClassIndex() const +{ + if (name.empty() || !parent) + { + return name; + } + + return name + "." + numToStr(parent->getIndex() - 1); +} + +/** + * Returns the nested name of the class. + * @return Nested name. + */ +std::string DotnetClass::getNestedName() const +{ + auto nestedName = name; + + if (nestedName.empty()) + { + return ""; + } + + for (auto p = parent; p; p = p->getParent()) + { + nestedName += "." + p->getName(); + } + + return nestedName; +} + +/** + * Returns library name of the referencing class + * @return Library name of the referencing class. + */ +const std::string& DotnetClass::getLibName() const +{ + if (recordType == MetadataTableType::AssemblyRef) + { + return libName; + } + if (parent) + { + return parent->getLibName(); + } + + return libName; +} + +/** + * Returns index of the class + * @return Index of the class + */ +std::size_t DotnetClass::getIndex() const +{ + return index; +} + /** * Returns the declared number of fields according to metadata tables. * @return Declared number of fields. @@ -167,13 +270,31 @@ std::string DotnetClass::getTypeString() const return isClass() ? "class" : "interface"; } +/** + * Returns the record type of the class + * @return Record type of the class + */ +MetadataTableType DotnetClass::getRecordType() const +{ + return recordType; +} + /** * Sets the raw metadata table record for this class. - * @param classRawRecord Raw metadata table record. + * @param rRecord Raw metadata table record. + */ +void DotnetClass::setRawRecord(mpark::variant rRecord) +{ + rawRecord = rRecord; +} + +/** + * Sets this classes parent. + * @param par Parent. */ -void DotnetClass::setRawRecord(const TypeDef* classRawRecord) +void DotnetClass::setParent(const DotnetClass* par) { - rawRecord = classRawRecord; + parent = par; } /** @@ -203,6 +324,15 @@ void DotnetClass::setDeclaredGenericParametersCount(std::size_t classGenericPara declaredGenericParametersCount = classGenericParamsCount; } +/** + * Sets the library name of referencing class. + * @param lName Library name. + */ +void DotnetClass::setLibName(const std::string &lName) +{ + libName = lName; +} + /** * Sets whether the class is actual class or interface. * @param set @c true for interface, otherwise class. diff --git a/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp b/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp index 5b8e57c2c..a2962faec 100644 --- a/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp +++ b/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp @@ -252,6 +252,98 @@ DotnetTypeReconstructor::ClassList DotnetTypeReconstructor::getReferencedClasses return classesFromTable(refClassTable); } +/** + * Links referenced (imported) classes. + */ +void DotnetTypeReconstructor::linkReconstructedClasses() +{ + std::vector visited (refClassTable.size(), false); + std::vector stack (refClassTable.size(), false); + + auto typeRefTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::TypeRef)); + + if (!typeRefTable) + { + return; + } + + auto refClasses = getReferencedClasses(); + + for (size_t i = 1; i < refClasses.size(); i++) + { + linkReconstructedClassesDo(i, visited, stack, refClasses, typeRefTable); + } + + for (size_t i = 1; i < refClasses.size(); i++) + { + auto t = refClasses[i]; + } +} + +/** + * Helper function for linkReconstructedClasses() + * @param i Index of a class to be linked. + * @param visited Visited flags for cyclic linkage detection. + * @param stack Recent traversal stack for cyclic linkage detection. + * @param typeRefTable Typeref table. + */ +void DotnetTypeReconstructor::linkReconstructedClassesDo(size_t i, std::vector &visited, std::vector &stack, + ClassList &refClasses, const MetadataTable* typeRefTable) +{ + if (visited[i]) + { + return; + } + + visited[i] = true; + + auto typeRef = refClasses[i]; + auto typeRefRaw = typeRef->getRawTypeRef(); + MetadataTableType resolutionScopeType; + + if (!typeRefRaw || !typeRefRaw->resolutionScope.getTable(resolutionScopeType) || + resolutionScopeType != MetadataTableType::TypeRef) + { + return; + } + + auto parentRaw = typeRefTable->getRow(typeRefRaw->resolutionScope.getIndex()); + + if (!parentRaw) + { + return; + } + + const DotnetClass *parent = nullptr; + + size_t parentI = 1; + while (parentI < refClasses.size()) + { + auto parentInRefClasses = refClasses[parentI]; + + if (parentInRefClasses->getRawTypeRef() == parentRaw) + { + parent = parentInRefClasses.get(); + break; + } + + parentI++; + } + + stack[i] = true; + + if (!parent || stack[parentI]) + { + stack[i] = false; + return; + } + + typeRef->setParent(parent); + + linkReconstructedClassesDo(parentI, visited, stack, refClasses, typeRefTable); + stack[i] = false; +} + /** * Reconstructs defined and referenced (imported) classes and interfaces. * @return @c true if reconstruction successful, otherwise @c false. @@ -268,7 +360,7 @@ bool DotnetTypeReconstructor::reconstructClasses() // Reconstruct defined classes from TypeDef table for (std::size_t i = 1; i <= typeDefTable->getNumberOfRows(); ++i) { - auto typeDef = typeDefTable->getRow(i); + auto typeDef = static_cast(typeDefTable->getRow(i)); std::size_t fieldsCount = 0; std::size_t methodsCount = 0; @@ -293,7 +385,7 @@ bool DotnetTypeReconstructor::reconstructClasses() : methodDefTable->getSize() - typeDef->methodList.getIndex() + 1; } - auto newClass = createClassDefinition(typeDef, fieldsCount, methodsCount); + auto newClass = createClassDefinition(typeDef, fieldsCount, methodsCount, i); if (newClass == nullptr) continue; @@ -305,13 +397,15 @@ bool DotnetTypeReconstructor::reconstructClasses() { auto typeRef = typeRefTable->getRow(i); - auto newClass = createClassReference(typeRef); + auto newClass = createClassReference(typeRef, i); if (newClass == nullptr) continue; refClassTable.emplace(i, std::move(newClass)); } + linkReconstructedClasses(); + return true; } @@ -329,7 +423,7 @@ bool DotnetTypeReconstructor::reconstructMethods() { // Obtain TypeDef from the class const auto& classType = kv.second; - auto typeDef = classType->getRawRecord(); + auto typeDef = classType->getRawTypeDef(); auto methodStartIndex = typeDef->methodList.getIndex(); for (auto i = methodStartIndex; i < methodStartIndex + classType->getDeclaredMethodsCount(); ++i) @@ -467,7 +561,7 @@ bool DotnetTypeReconstructor::reconstructFields() for (const auto& kv : defClassTable) { const auto& classType = kv.second; - auto typeDef = classType->getRawRecord(); + auto typeDef = classType->getRawTypeDef(); auto fieldStartIndex = typeDef->fieldList.getIndex(); for (auto i = fieldStartIndex; i < fieldStartIndex + classType->getDeclaredFieldsCount(); ++i) @@ -585,7 +679,7 @@ bool DotnetTypeReconstructor::reconstructBaseTypes() std::unique_ptr baseType; - auto typeDef = classType->getRawRecord(); + auto typeDef = classType->getRawTypeDef(); MetadataTableType extendsTable; if (!typeDef->extends.getTable(extendsTable)) @@ -690,7 +784,8 @@ bool DotnetTypeReconstructor::reconstructBaseTypes() * @param methodsCount Declared number of methods. * @return New class definition or @c nullptr in case of failure. */ -std::unique_ptr DotnetTypeReconstructor::createClassDefinition(const TypeDef* typeDef, std::size_t fieldsCount, std::size_t methodsCount) +std::unique_ptr DotnetTypeReconstructor::createClassDefinition(const TypeDef* typeDef, std::size_t fieldsCount, + std::size_t methodsCount, std::size_t typeDefIndex) { std::string className, classNameSpace; if (!stringStream->getString(typeDef->typeName.getIndex(), className) || !stringStream->getString(typeDef->typeNamespace.getIndex(), classNameSpace)) @@ -704,7 +799,7 @@ std::unique_ptr DotnetTypeReconstructor::createClassDefinition(cons if (className.empty() || className == "") return nullptr; - auto newClass = std::make_unique(); + auto newClass = std::make_unique(MetadataTableType::TypeDef, typeDefIndex); newClass->setRawRecord(typeDef); newClass->setName(className); newClass->setNameSpace(classNameSpace); @@ -722,24 +817,50 @@ std::unique_ptr DotnetTypeReconstructor::createClassDefinition(cons /** * Creates new class reference from TypeRef table record. * @param typeRef TypeRef table record. + * @param typeRefIndex Index of typeRef table record. * @return New class reference or @c nullptr in case of failure. */ -std::unique_ptr DotnetTypeReconstructor::createClassReference(const TypeRef* typeRef) +std::unique_ptr DotnetTypeReconstructor::createClassReference(const TypeRef* typeRef, std::size_t typeRefIndex) { - std::string className, classNameSpace; - if (!stringStream->getString(typeRef->typeName.getIndex(), className) || !stringStream->getString(typeRef->typeNamespace.getIndex(), classNameSpace)) + std::string className, classNameSpace, classLibName; + MetadataTableType resolutionScopeType; + if (!stringStream->getString(typeRef->typeName.getIndex(), className) || + !stringStream->getString(typeRef->typeNamespace.getIndex(), classNameSpace)) + { return nullptr; + } + + if (!typeRef->resolutionScope.getTable(resolutionScopeType) || resolutionScopeType != MetadataTableType::AssemblyRef) + { + classLibName = ""; + } + + else + { + auto assemblyRefTable = static_cast*>(metadataStream->getMetadataTable(MetadataTableType::AssemblyRef)); + auto assemblyRef = assemblyRefTable->getRow(typeRef->resolutionScope.getIndex()); + + if (!assemblyRef || !stringStream->getString(assemblyRef->name.getIndex(), classLibName)) + { + classLibName = ""; + } + } className = retdec::utils::replaceNonprintableChars(className); classNameSpace = retdec::utils::replaceNonprintableChars(classNameSpace); + classLibName = retdec::utils::replaceNonprintableChars(classLibName); auto genericParamsCount = extractGenericParamsCountAndFixClassName(className); if (className.empty()) + { return nullptr; + } - auto newClass = std::make_unique(); + auto newClass = std::make_unique(MetadataTableType::TypeRef, typeRefIndex); + newClass->setRawRecord(typeRef); newClass->setName(className); newClass->setNameSpace(classNameSpace); + newClass->setLibName(classLibName); newClass->setDeclaredGenericParametersCount(genericParamsCount); return newClass; diff --git a/src/fileinfo/CMakeLists.txt b/src/fileinfo/CMakeLists.txt index fce2878ee..a66f232df 100644 --- a/src/fileinfo/CMakeLists.txt +++ b/src/fileinfo/CMakeLists.txt @@ -55,6 +55,7 @@ set(FILEINFO_SOURCES file_presentation/getters/iterative_getter/iterative_distribution_getter/segment_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/strings_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/symbol_tables_plain_getter.cpp + file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_getter.cpp file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_simple_getter/iterative_simple_getter.cpp @@ -72,6 +73,7 @@ set(FILEINFO_SOURCES file_presentation/getters/iterative_getter/iterative_subtitle_getter/segment_json_getter.cpp file_presentation/getters/iterative_getter/iterative_subtitle_getter/strings_json_getter.cpp file_presentation/getters/iterative_getter/iterative_subtitle_getter/symbol_tables_json_getter.cpp + file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp file_presentation/getters/pattern_config_getter/pattern_config_getter.cpp file_presentation/getters/simple_getter/basic_json_getter.cpp file_presentation/getters/simple_getter/basic_plain_getter.cpp diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 15ea23871..4085ebff4 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -332,6 +332,9 @@ void PeDetector::getDotnetInfo() fileInfo.setDotnetTypeLibId(peParser->getTypeLibId()); fileInfo.setDotnetDefinedClassList(peParser->getDefinedDotnetClasses()); fileInfo.setDotnetImportedClassList(peParser->getImportedDotnetClasses()); + fileInfo.setDotnetTypeRefhashCrc32(peParser->getTypeRefhashCrc32()); + fileInfo.setDotnetTypeRefhashMd5(peParser->getTypeRefhashMd5()); + fileInfo.setDotnetTypeRefhashSha256(peParser->getTypeRefhashSha256()); } void PeDetector::detectFileClass() diff --git a/src/fileinfo/file_information/file_information.cpp b/src/fileinfo/file_information/file_information.cpp index 563fd794b..468c8990c 100644 --- a/src/fileinfo/file_information/file_information.cpp +++ b/src/fileinfo/file_information/file_information.cpp @@ -2806,6 +2806,82 @@ const std::string& FileInformation::getDotnetRuntimeVersion() const return dotnetInfo.getRuntimeVersion(); } +/** + * Get imported class name + * @param position Index of selected imported class (indexed from 0) + * @return Name of selected imported class + */ +std::string FileInformation::getDotnetImportedClassName(std::size_t position) const +{ + return dotnetInfo.getImportedClassName(position); +} + +/** + * Get imported class nested name + * @param position Index of selected imported class (indexed from 0) + * @return Nested name of selected imported class + */ +std::string FileInformation::getDotnetImportedClassNestedName(std::size_t position) const +{ + return dotnetInfo.getImportedClassNestedName(position); +} + +/** + * Get imported class name with parent class presentation index + * @param position Index of selected imported class (indexed from 0) + * @return Name of selected imported class with parent class presentation index + */ +std::string FileInformation::getDotnetImportedClassNameWithParentClassIndex(std::size_t position) const +{ + return dotnetInfo.getImportedClassNameWithParentClassIndex(position); +} + +/** + * Get imported class library name + * @param position Index of selected imported class (indexed from 0) + * @return Library name of selected imported class + */ +std::string FileInformation::getDotnetImportedClassLibName(std::size_t position) const +{ + return dotnetInfo.getImportedClassLibName(position); +} + +/** + * Get dotnet typeref hash as CRC32 + * @return Typeref hash as CRC32 + */ +std::string FileInformation::getDotnetTypeRefhashCrc32() const +{ + return dotnetInfo.getTypeRefhashCrc32(); +} + +/** + * Get dotnet typeref hash as MD5 + * @return Typeref hash as MD5 + */ +std::string FileInformation::getDotnetTypeRefhashMd5() const +{ + return dotnetInfo.getTypeRefhashMd5(); +} + +/** + * Get dotnet typeref hash as SHA256 + * @return Typeref hash as SHA256 + */ +std::string FileInformation::getDotnetTypeRefhashSha256() const +{ + return dotnetInfo.getTypeRefhashSha256(); +} + +/** + * Get number of stored imported dotnet classes + * @return Number of stored imported dotnet classes + */ +std::size_t FileInformation::getNumberOfStoredDotnetImportedClasses() const +{ + return dotnetInfo.getNumberOfImportedClasses(); +} + /** * Returns .NET metadata header address in string representation in specified format. * @param format Format. @@ -3006,6 +3082,15 @@ bool FileInformation::hasDotnetTypeLibId() const return dotnetInfo.hasTypeLibId(); } +/** + * Find out if there are any records in typeref table + * @return @c true if typeref is not empty, @c false otherwise + */ +bool FileInformation::hasDotnetTypeRefTableRecords() const +{ + return dotnetInfo.hasImportedClassListRecords(); +} + /** * Set instance status * @param state New status of this instance @@ -3678,6 +3763,33 @@ void FileInformation::setDotnetImportedClassList(const std::vector>& dotnetClassList); void setDotnetImportedClassList(const std::vector>& dotnetClassList); + void setDotnetTypeRefhashCrc32(const std::string& crc32); + void setDotnetTypeRefhashMd5(const std::string& md5); + void setDotnetTypeRefhashSha256(const std::string& sha256); /// @} /// @name Other methods diff --git a/src/fileinfo/file_information/file_information_types/dotnet_info.cpp b/src/fileinfo/file_information/file_information_types/dotnet_info.cpp index ef2f6c59d..78275f6a8 100644 --- a/src/fileinfo/file_information/file_information_types/dotnet_info.cpp +++ b/src/fileinfo/file_information/file_information_types/dotnet_info.cpp @@ -26,6 +26,99 @@ const std::string& DotnetInfo::getRuntimeVersion() const return runtimeVersion; } +/** + * Get number of imported classes in typeref table + * @return Number of imported classes in typeref table + */ +std::size_t DotnetInfo::getNumberOfImportedClasses() const +{ + return importedClassList.size(); +} + +/** + * Get imported class name + * @param position Index of selected imported class from typeref table (indexed from 0) + * @return Imported class name + */ +std::string DotnetInfo::getImportedClassName(std::size_t position) const +{ + return (position < getNumberOfImportedClasses()) ? importedClassList[position]->getName() : ""; +} + +/** + * Get imported class nested name + * @param position Index of selected imported class from typeref table (indexed from 0) + * @return Imported class nested name + */ +std::string DotnetInfo::getImportedClassNestedName(std::size_t position) const +{ + return (position < getNumberOfImportedClasses()) ? importedClassList[position]->getNestedName() : ""; +} + +/** + * Get imported class name with parent class presentation index + * @param position Index of selected imported class from typeref table (indexed from 0) + * @return Imported class name with parent class presentation index + */ +std::string DotnetInfo::getImportedClassNameWithParentClassIndex(std::size_t position) const +{ + return (position < getNumberOfImportedClasses()) ? importedClassList[position]->getNameWithParentClassIndex() : ""; +} + +/** + * Get imported class library name + * @param position Index of selected imported class from typeref table (indexed from 0) + * @return Imported class library name + */ +std::string DotnetInfo::getImportedClassLibName(std::size_t position) const +{ + return (position < getNumberOfImportedClasses()) ? importedClassList[position]->getLibName() : ""; +} + +/** + * Get imported class typeref index + * @param position Index of selected imported class from typeref table (indexed from 0) + * @param result Variable to store the result to + * @return @c true if result is valid, otherwise @c false. + */ +bool DotnetInfo::getImportedClassIndex(std::size_t position, std::size_t &result) const +{ + if (position >= getNumberOfImportedClasses()) + { + return false; + } + + result = importedClassList[position]->getIndex(); + return true; +} + +/** + * Get typeRefhash as CRC32 + * @return TypeRefhash as CRC32 + */ +const std::string& DotnetInfo::getTypeRefhashCrc32() const +{ + return typeRefHashCrc32; +} + +/** + * Get typeRefhash as MD5 + * @return TypeRefhash as MD5 + */ +const std::string& DotnetInfo::getTypeRefhashMd5() const +{ + return typeRefHashMd5; +} + +/** + * Get typeRefhash as SHA256 + * @return TypeRefhash as SHA256 + */ +const std::string& DotnetInfo::getTypeRefhashSha256() const +{ + return typeRefHashSha256; +} + /** * Returns the metadata header address in string representation with specified format. * @param format Format. @@ -293,6 +386,33 @@ void DotnetInfo::setImportedClassList(const std::vector> definedClassList; std::vector> importedClassList; + std::string typeRefHashCrc32; + std::string typeRefHashMd5; + std::string typeRefHashSha256; public: DotnetInfo(); /// @name Getters /// @{ const std::string& getRuntimeVersion() const; + std::size_t getNumberOfImportedClasses() const; + std::string getImportedClassName(std::size_t position) const; + std::string getImportedClassNestedName(std::size_t position) const; + std::string getImportedClassNameWithParentClassIndex(std::size_t position) const; + std::string getImportedClassLibName(std::size_t position) const; + bool getImportedClassIndex(std::size_t position, std::size_t &result) const; + const std::string& getTypeRefhashCrc32() const; + const std::string& getTypeRefhashMd5() const; + const std::string& getTypeRefhashSha256() const; std::string getMetadataHeaderAddressStr(std::ios_base &(* format)(std::ios_base &)) const; std::string getMetadataStreamOffsetStr(std::ios_base &(* format)(std::ios_base &)) const; std::string getMetadataStreamSizeStr(std::ios_base &(* format)(std::ios_base &)) const; @@ -76,6 +88,9 @@ class DotnetInfo void setTypeLibId(const std::string& id); void setDefinedClassList(const std::vector>& dotnetClassList); void setImportedClassList(const std::vector>& dotnetClassList); + void setTypeRefhashCrc32(const std::string& crc32); + void setTypeRefhashMd5(const std::string& md5); + void setTypeRefhashSha256(const std::string& sha256); /// @} /// @name Detection @@ -87,6 +102,7 @@ class DotnetInfo bool hasGuidStream() const; bool hasUserStringStream() const; bool hasTypeLibId() const; + bool hasImportedClassListRecords() const; /// @} }; diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp new file mode 100644 index 000000000..52c854ce9 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp @@ -0,0 +1,100 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.cpp + * @brief Methods of TypeRefTablePlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/utils/conversion.h" +#include "retdec/utils/string.h" +#include "retdec/fileformat/utils/conversions.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +namespace +{ + +const std::size_t distributionArray[] = {6, 40, 40, 6}; +const std::string headerArray[] = {"i", "name", "libName"}; +const std::string headerDesc[] = {"index", "name of dotnet import", "name of library from which is import imported"}; + +} // anonymous namespace + +/** + * Constructor + * @param fileInfo Information about file + */ +TypeRefTablePlainGetter::TypeRefTablePlainGetter(FileInformation &fileInfo) : IterativeDistributionGetter(fileInfo) +{ + numberOfStructures = 1; + numberOfStoredRecords.push_back(fileinfo.getNumberOfStoredDotnetImportedClasses()); + numberOfExtraElements.push_back(0); + title = "TypeRef table"; + distribution.insert(distribution.begin(), std::begin(distributionArray), std::end(distributionArray)); + commonHeaderElements.insert(commonHeaderElements.begin(), std::begin(headerArray), std::end(headerArray)); + commonHeaderDesc.insert(commonHeaderDesc.begin(), std::begin(headerDesc), std::end(headerDesc)); + loadRecords(); +} + +/** + * Destructor + */ +TypeRefTablePlainGetter::~TypeRefTablePlainGetter() +{ + +} + +std::size_t TypeRefTablePlainGetter::getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const +{ + if(structIndex >= numberOfStructures || !fileinfo.hasDotnetTypeRefTableRecords()) + { + return 0; + } + + desc.clear(); + info.clear(); + + desc.push_back("Number of dotnet imports: "); + desc.push_back("CRC32 : "); + desc.push_back("MD5 : "); + desc.push_back("SHA256 : "); + info.push_back(numToStr(fileinfo.getNumberOfStoredDotnetImportedClasses())); + info.push_back(fileinfo.getDotnetTypeRefhashCrc32()); + info.push_back(fileinfo.getDotnetTypeRefhashMd5()); + info.push_back(fileinfo.getDotnetTypeRefhashSha256()); + + return info.size(); +} + +bool TypeRefTablePlainGetter::loadRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) +{ + if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex]) + { + return false; + } + + record.clear(); + record.push_back(numToStr(recIndex)); + record.push_back(replaceNonprintableChars(fileinfo.getDotnetImportedClassNameWithParentClassIndex(recIndex))); + record.push_back(replaceNonprintableChars(fileinfo.getDotnetImportedClassLibName(recIndex))); + + return true; +} + +bool TypeRefTablePlainGetter::getFlagDescriptors(std::size_t structIndex, std::vector &desc, std::vector &abbv) const +{ + if(structIndex >= numberOfStructures) + { + return false; + } + + desc.clear(); + abbv.clear(); + + return true; +} + +} // namespace fileinfo diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h new file mode 100644 index 000000000..c3bbf9b9e --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h @@ -0,0 +1,31 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h + * @brief Definition of TypeRefTablePlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_DISTRIBUTION_GETTER_TYPEREF_TABLE_PLAIN_GETTER_H +#define FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_DISTRIBUTION_GETTER_TYPEREF_TABLE_PLAIN_GETTER_H + +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/iterative_distribution_getter.h" + +namespace fileinfo { + +/** + * Getter for typeref table + */ +class TypeRefTablePlainGetter : public IterativeDistributionGetter +{ + protected: + virtual bool loadRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) override; + public: + TypeRefTablePlainGetter(FileInformation &fileInfo); + virtual ~TypeRefTablePlainGetter() override; + + virtual std::size_t getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const override; + virtual bool getFlagDescriptors(std::size_t structIndex, std::vector &desc, std::vector &abbv) const override; +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp new file mode 100644 index 000000000..099841713 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp @@ -0,0 +1,91 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.cpp + * @brief Methods of TypeRefTableJsonGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/utils/conversion.h" +#include "retdec/utils/string.h" +#include "retdec/fileformat/utils/conversions.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +/** + * Constructor + * @param fileInfo Information about file + */ +TypeRefTableJsonGetter::TypeRefTableJsonGetter(FileInformation &fileInfo) : IterativeSubtitleGetter(fileInfo) +{ + numberOfStructures = 1; + numberOfStoredRecords.push_back(fileinfo.getNumberOfStoredDotnetImportedClasses()); + numberOfExtraElements.push_back(0); + title = "typeRefTable"; + subtitle = "types"; + commonHeaderElements.push_back("index"); + commonHeaderElements.push_back("name"); + commonHeaderElements.push_back("libraryName"); +} + +/** + * Destructor + */ +TypeRefTableJsonGetter::~TypeRefTableJsonGetter() +{ + +} + +std::size_t TypeRefTableJsonGetter::getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const +{ + if(structIndex >= numberOfStructures || !fileinfo.hasDotnetTypeRefTableRecords()) + { + return 0; + } + + desc.clear(); + info.clear(); + + desc.push_back("numberOfTypes"); + desc.push_back("crc32"); + desc.push_back("md5"); + desc.push_back("sha256"); + info.push_back(numToStr(fileinfo.getNumberOfStoredDotnetImportedClasses())); + info.push_back(fileinfo.getDotnetTypeRefhashCrc32()); + info.push_back(fileinfo.getDotnetTypeRefhashMd5()); + info.push_back(fileinfo.getDotnetTypeRefhashSha256()); + + return info.size(); +} + +bool TypeRefTableJsonGetter::getRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) const +{ + if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex]) + { + return false; + } + + record.clear(); + record.push_back(numToStr(recIndex)); + record.push_back(replaceNonprintableChars(fileinfo.getDotnetImportedClassNestedName(recIndex))); + record.push_back(replaceNonprintableChars(fileinfo.getDotnetImportedClassLibName(recIndex))); + + return true; +} + +bool TypeRefTableJsonGetter::getFlags(std::size_t structIndex, std::size_t recIndex, std::string &flagsValue, std::vector &desc) const +{ + if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex]) + { + return false; + } + + flagsValue.clear(); + desc.clear(); + + return true; +} + +} // namespace fileinfo diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h new file mode 100644 index 000000000..3c54443a0 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h @@ -0,0 +1,30 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h + * @brief Definition of TypRefTableJsonGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_SUBTITLE_GETTER_TYPEREF_TABLE_JSON_GETTER_H +#define FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_SUBTITLE_GETTER_TYPEREF_TABLE_JSON_GETTER_H + +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/iterative_subtitle_getter.h" + +namespace fileinfo { + +/** + * Getter for typeref table + */ +class TypeRefTableJsonGetter : public IterativeSubtitleGetter +{ + public: + TypeRefTableJsonGetter(FileInformation &fileInfo); + virtual ~TypeRefTableJsonGetter() override; + + virtual std::size_t getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const override; + virtual bool getRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) const override; + virtual bool getFlags(std::size_t structIndex, std::size_t recIndex, std::string &flagsValue, std::vector &desc) const override; +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/getters/json_getters.h b/src/fileinfo/file_presentation/getters/json_getters.h index 2c008398a..8737b05e8 100644 --- a/src/fileinfo/file_presentation/getters/json_getters.h +++ b/src/fileinfo/file_presentation/getters/json_getters.h @@ -20,6 +20,7 @@ #include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/segment_json_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/strings_json_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/symbol_tables_json_getter.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_subtitle_getter/typeref_table_json_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/basic_json_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/dotnet_json_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/entry_point_json_getter.h" diff --git a/src/fileinfo/file_presentation/getters/plain_getters.h b/src/fileinfo/file_presentation/getters/plain_getters.h index 41c28f0e6..25cc964b0 100644 --- a/src/fileinfo/file_presentation/getters/plain_getters.h +++ b/src/fileinfo/file_presentation/getters/plain_getters.h @@ -23,6 +23,7 @@ #include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/segment_plain_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/strings_plain_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/symbol_tables_plain_getter.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/basic_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/dotnet_plain_getter.h" diff --git a/src/fileinfo/file_presentation/json_presentation.cpp b/src/fileinfo/file_presentation/json_presentation.cpp index 9f294bfed..6b987f7a9 100644 --- a/src/fileinfo/file_presentation/json_presentation.cpp +++ b/src/fileinfo/file_presentation/json_presentation.cpp @@ -475,6 +475,8 @@ void JsonPresentation::presentDotnetInfo(Json::Value &root) const jDotnet["classes"].append(jClass); } + presentIterativeSubtitle(jDotnet, TypeRefTableJsonGetter(fileinfo)); + root["dotnetInfo"] = jDotnet; } diff --git a/src/fileinfo/file_presentation/plain_presentation.cpp b/src/fileinfo/file_presentation/plain_presentation.cpp index e8a9ec2a0..d8ebeb02f 100644 --- a/src/fileinfo/file_presentation/plain_presentation.cpp +++ b/src/fileinfo/file_presentation/plain_presentation.cpp @@ -703,6 +703,7 @@ bool PlainPresentation::present() presentIterativeDistribution(SymbolTablesPlainGetter(fileinfo), explanatory); presentIterativeDistribution(ImportTablePlainGetter(fileinfo), explanatory); presentIterativeDistribution(ExportTablePlainGetter(fileinfo), explanatory); + presentIterativeDistribution(TypeRefTablePlainGetter(fileinfo), explanatory); presentIterativeDistribution(RelocationTablesPlainGetter(fileinfo), explanatory); presentIterativeDistribution(DynamicSectionsPlainGetter(fileinfo), explanatory); presentIterativeDistribution(ResourcePlainGetter(fileinfo), explanatory); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index a3a828241..c76985d81 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries(retdec-utils whereami) if(MSVC) target_link_libraries(retdec-utils whereami shlwapi) # shlwapi.dll for PathRemoveFileSpec() endif() +target_link_libraries(retdec-utils mpark_variant) target_include_directories(retdec-utils PUBLIC ${PROJECT_SOURCE_DIR}/include/) target_include_directories(retdec-utils PUBLIC ${PROJECT_SOURCE_DIR}/deps/)