#include "il2cpp-config.h" 
 | 
  
 | 
#include <string> 
 | 
#include <cstring> 
 | 
#include <algorithm> 
 | 
#include <ctype.h> 
 | 
  
 | 
#include "metadata/Il2CppTypeCompare.h" 
 | 
#include "utils/StringUtils.h" 
 | 
#include "vm/Assembly.h" 
 | 
#include "vm/AssemblyName.h" 
 | 
#include "vm/Class.h" 
 | 
#include "vm/GenericClass.h" 
 | 
#include "vm/GenericContainer.h" 
 | 
#include "vm/MetadataCache.h" 
 | 
#include "vm/Reflection.h" 
 | 
#include "vm/String.h" 
 | 
#include "vm/Type.h" 
 | 
#include "vm-utils/VmStringUtils.h" 
 | 
#include "il2cpp-class-internals.h" 
 | 
#include "il2cpp-object-internals.h" 
 | 
#include "il2cpp-tabledefs.h" 
 | 
#include "vm/Array.h" 
 | 
  
 | 
static char* copy_name(const char* name) 
 | 
{ 
 | 
    const size_t len = strlen(name); 
 | 
    char* cname = new char[len + 1]; 
 | 
  
 | 
    strncpy(cname, name, len); 
 | 
  
 | 
    cname[len] = '\0'; 
 | 
  
 | 
    return cname; 
 | 
} 
 | 
  
 | 
namespace il2cpp 
 | 
{ 
 | 
namespace vm 
 | 
{ 
 | 
    TypeNameParser::TypeNameParser(const std::string &name, TypeNameParseInfo &info, bool is_nested) : 
 | 
        _info(info), 
 | 
        _is_nested(is_nested), 
 | 
        _accept_assembly_name(true), 
 | 
        _p(name.begin()), 
 | 
        _end(name.end()) 
 | 
    { 
 | 
    } 
 | 
  
 | 
    TypeNameParser::TypeNameParser(std::string::const_iterator &begin, std::string::const_iterator &end, TypeNameParseInfo &info, bool is_nested) : 
 | 
        _info(info), 
 | 
        _is_nested(is_nested), 
 | 
        _accept_assembly_name(true), 
 | 
        _p(begin), 
 | 
        _end(end) 
 | 
    { 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::Parse(bool acceptAssemblyName) 
 | 
    { 
 | 
        _accept_assembly_name = acceptAssemblyName; 
 | 
  
 | 
        int32_t arity = 0; 
 | 
  
 | 
        InitializeParser(); 
 | 
  
 | 
        if (IsEOL()) 
 | 
            return false; 
 | 
        if (!ParseTypeName(arity)) 
 | 
            return false; 
 | 
        if (!ParseNestedTypeOptional(arity)) 
 | 
            return false; 
 | 
        if (!ParseTypeArgumentsOptional(arity)) 
 | 
            return false; 
 | 
        if (!ParsePointerModifiersOptional()) 
 | 
            return false; 
 | 
        if (!ParseArrayModifierOptional()) 
 | 
            return false; 
 | 
        if (!ParseByRefModifiersOptional()) 
 | 
            return false; 
 | 
        if (!ParseAssemblyNameOptional()) 
 | 
            return false; 
 | 
  
 | 
        return (_p == _end) || _is_nested; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseAssembly() 
 | 
    { 
 | 
        InitializeParser(); 
 | 
  
 | 
        if (IsEOL()) 
 | 
            return false; 
 | 
        if (!ParseAssemblyName()) 
 | 
            return false; 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseTypeName(int32_t &arity) 
 | 
    { 
 | 
        std::string::const_iterator begin = _p; 
 | 
        std::string::const_iterator last_dot = _end; 
 | 
  
 | 
        while (true) 
 | 
        { 
 | 
            ConsumeIdentifier(); 
 | 
  
 | 
            if (!CurrentIs('.')) 
 | 
                break; 
 | 
  
 | 
            last_dot = _p; 
 | 
  
 | 
            if (!Next()) 
 | 
                return false; // Invalid format 
 | 
        } 
 | 
  
 | 
        if (CurrentIs('`')) 
 | 
        { 
 | 
            if (!Next()) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            if (!ConsumeNumber(arity)) 
 | 
                return false; // Invalid format 
 | 
        } 
 | 
  
 | 
        if (last_dot == _end) 
 | 
        { 
 | 
            _info._name.assign(begin, _p); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            _info._namespace.assign(begin, last_dot); 
 | 
            _info._name.assign(last_dot + 1, _p); 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseNestedTypeOptional(int32_t &arity) 
 | 
    { 
 | 
        while (CurrentIs('+')) 
 | 
        { 
 | 
            if (!Next()) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            std::string::const_iterator begin = _p; 
 | 
  
 | 
            ConsumeIdentifier(); 
 | 
  
 | 
            if (CurrentIs('`')) 
 | 
            { 
 | 
                if (!Next()) 
 | 
                    return false; // Invalid format 
 | 
  
 | 
                int32_t nested_arity = 0; 
 | 
  
 | 
                if (!ConsumeNumber(nested_arity)) 
 | 
                    return false; // Invalid format 
 | 
  
 | 
                arity += nested_arity; 
 | 
            } 
 | 
  
 | 
            _info._nested.push_back(std::string(begin, _p)); 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParsePointerModifiersOptional() 
 | 
    { 
 | 
        if (IsEOL()) 
 | 
            return true; 
 | 
  
 | 
        while (CurrentIs('*')) 
 | 
        { 
 | 
            _info._modifiers.push_back(-1); 
 | 
            if (!Next(true)) 
 | 
                break; 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseByRefModifiersOptional() 
 | 
    { 
 | 
        if (IsEOL()) 
 | 
            return true; 
 | 
  
 | 
        if (CurrentIs('&')) 
 | 
        { 
 | 
            if (std::find(_info._modifiers.begin(), _info._modifiers.end(), 0) != _info._modifiers.end()) 
 | 
                return false; // Invalid format, already marked as reference 
 | 
  
 | 
            _info._modifiers.push_back(0); 
 | 
  
 | 
            Next(true); 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseTypeArgumentsOptional(int32_t &arity) 
 | 
    { 
 | 
        SkipWhites(); 
 | 
  
 | 
        if (IsEOL()) 
 | 
            return true; 
 | 
  
 | 
        if (!CurrentIs('[')) 
 | 
            return true; 
 | 
  
 | 
        if (NextWillBe(']', true) || NextWillBe(',', true) || NextWillBe('*', true)) 
 | 
            return true; 
 | 
  
 | 
        if (!Next(true)) 
 | 
            return false; // Invalid format 
 | 
  
 | 
        _info._type_arguments.reserve(arity); 
 | 
  
 | 
        while (true) 
 | 
        { 
 | 
            bool acceptAssemblyName = false; 
 | 
  
 | 
            if (CurrentIs('[')) 
 | 
            { 
 | 
                acceptAssemblyName = true; 
 | 
  
 | 
                if (!Next(true)) 
 | 
                    return false; // Invalid format 
 | 
            } 
 | 
  
 | 
            TypeNameParseInfo info; 
 | 
            TypeNameParser parser(_p, _end, info, true); 
 | 
  
 | 
            if (!parser.Parse(acceptAssemblyName)) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            _p = parser._p; 
 | 
  
 | 
            _info._type_arguments.push_back(info); 
 | 
  
 | 
            SkipWhites(); 
 | 
  
 | 
            if (IsEOL()) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            if (acceptAssemblyName) 
 | 
            { 
 | 
                if (!CurrentIs(']')) 
 | 
                    return false; // Invalid format 
 | 
  
 | 
                if (!Next(true)) 
 | 
                    return false; // Invalid format 
 | 
            } 
 | 
  
 | 
            if (CurrentIs(']')) 
 | 
                break; 
 | 
  
 | 
            if (CurrentIs(',')) 
 | 
            { 
 | 
                if (!Next(true)) 
 | 
                    return false; // Invalid format 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                return false; // Invalid format 
 | 
            } 
 | 
        } 
 | 
  
 | 
        if (_info._type_arguments.size() != arity) 
 | 
            return false; // Invalid format 
 | 
  
 | 
        Next(true); 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseArrayModifierOptional() 
 | 
    { 
 | 
        SkipWhites(); 
 | 
  
 | 
        if (IsEOL()) 
 | 
            return true; 
 | 
  
 | 
        if (!CurrentIs('[')) 
 | 
            return true; 
 | 
  
 | 
        if (!NextWillBe(']', true) && !NextWillBe(',', true) && !NextWillBe('*', true)) 
 | 
            return true; 
 | 
  
 | 
        if (!Next(true)) 
 | 
            return false; // Invalid format 
 | 
  
 | 
        int32_t rank = 1; 
 | 
  
 | 
        while (true) 
 | 
        { 
 | 
            if (CurrentIs(']')) 
 | 
            { 
 | 
                Next(true); 
 | 
                break; 
 | 
            } 
 | 
            else if (CurrentIs(',')) 
 | 
            { 
 | 
                ++rank; 
 | 
                if (!Next(true)) 
 | 
                    return false; // invalid format 
 | 
            } 
 | 
            else if (CurrentIs('*')) 
 | 
            { 
 | 
                _info._modifiers.push_back(-2); 
 | 
  
 | 
                if (!Next(true)) 
 | 
                    return false; // invalid format 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                return false; // invalid format 
 | 
            } 
 | 
        } 
 | 
  
 | 
        _info._modifiers.push_back(rank); 
 | 
  
 | 
        // This is to support arrays of array 
 | 
        return ParseArrayModifierOptional(); 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseAssemblyNameOptional() 
 | 
    { 
 | 
        if (!_accept_assembly_name) 
 | 
            return true; 
 | 
  
 | 
        if (!CurrentIs(',')) 
 | 
            return true; 
 | 
  
 | 
        if (!Next()) 
 | 
            return false; // Invalid format 
 | 
  
 | 
        SkipWhites(); 
 | 
  
 | 
        return ParseAssemblyName(); 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseAssemblyName() 
 | 
    { 
 | 
        std::string::const_iterator begin = _p; 
 | 
  
 | 
        ConsumeAssemblyIdentifier(); 
 | 
  
 | 
        _info._assembly_name.name.assign(begin, _p); 
 | 
  
 | 
        SkipWhites(); 
 | 
  
 | 
        ParsePropertiesOptional(); 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParsePropertiesOptional() 
 | 
    { 
 | 
        while (CurrentIs(',')) 
 | 
        { 
 | 
            if (!Next(true)) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            std::string::const_iterator begin = _p; 
 | 
            ConsumePropertyIdentifier(); 
 | 
            std::string propertyName(begin, _p); 
 | 
            utils::VmStringUtils::CaseInsensitiveComparer propertyNameComparer; 
 | 
  
 | 
            if (!CurrentIs('=')) 
 | 
                return false; 
 | 
  
 | 
            if (!Next()) 
 | 
                return false; // Invalid format 
 | 
  
 | 
            begin = _p; 
 | 
            ConsumePropertyValue(); 
 | 
            std::string propertyValue(begin, _p); 
 | 
  
 | 
            if (propertyNameComparer(propertyName, "version")) 
 | 
            { 
 | 
                if (!ParseVersion(propertyValue, _info._assembly_name.major, _info._assembly_name.minor, _info._assembly_name.build, _info._assembly_name.revision)) 
 | 
                    return false; 
 | 
            } 
 | 
            else if (propertyNameComparer(propertyName.c_str(), "publickey")) 
 | 
            { 
 | 
                if (!propertyNameComparer(propertyValue, "null")) 
 | 
                    _info._assembly_name.public_key = propertyValue; 
 | 
            } 
 | 
            else if (propertyNameComparer(propertyName.c_str(), "publickeytoken")) 
 | 
            { 
 | 
                if (!propertyNameComparer(propertyValue, "null")) 
 | 
                { 
 | 
                    if ((kPublicKeyTokenLength - 1) != propertyValue.size()) 
 | 
                        return false; 
 | 
                    strncpy(_info._assembly_name.public_key_token, propertyValue.c_str(), kPublicKeyTokenLength); 
 | 
                } 
 | 
            } 
 | 
            else if (propertyNameComparer(propertyName.c_str(), "culture")) 
 | 
            { 
 | 
                _info._assembly_name.culture = propertyValue; 
 | 
            } 
 | 
            else if (propertyNameComparer(propertyName.c_str(), "contenttype")) 
 | 
            { 
 | 
                // If content type is WindowsRuntime, coerse assembly name into WindowsRuntimeMetadata if it's not that (otherwise preserve its casing) 
 | 
                if (propertyNameComparer(propertyValue, "windowsruntime") && !propertyNameComparer(_info._assembly_name.name.c_str(), "windowsruntimemetadata")) 
 | 
                    _info._assembly_name.name = "WindowsRuntimeMetadata"; 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                return false; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ParseVersion(const std::string& version, uint16_t& major, uint16_t& minor, uint16_t& build, uint16_t& revision) 
 | 
    { 
 | 
        size_t start = 0; 
 | 
        size_t index = version.find('.'); 
 | 
        if (-1 == index) 
 | 
            return false; 
 | 
        std::string component = version.substr(start, index - start); 
 | 
        major = atoi(component.c_str()); 
 | 
  
 | 
        start = index + 1; 
 | 
        index = version.find('.', start); 
 | 
        if (-1 == index) 
 | 
            return false; 
 | 
        component = version.substr(start, index - start); 
 | 
        minor = atoi(component.c_str()); 
 | 
  
 | 
        start = index + 1; 
 | 
        index = version.find('.', start); 
 | 
        if (-1 == index) 
 | 
            return false; 
 | 
        component = version.substr(start, index - start); 
 | 
        build = atoi(component.c_str()); 
 | 
  
 | 
        start = index + 1; 
 | 
        component = version.substr(start, version.size() - start); 
 | 
        revision = atoi(component.c_str()); 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::NextWillBe(char v, bool skipWhites) const 
 | 
    { 
 | 
        if (IsEOL()) 
 | 
            return false; 
 | 
  
 | 
        int32_t i = 1; 
 | 
        if (skipWhites) 
 | 
        { 
 | 
            if ((*(_p + i) == ' ') || (*(_p + i) == '\t')) 
 | 
                ++i; 
 | 
  
 | 
            if ((_p + i) >= _end) 
 | 
                return false; 
 | 
        } 
 | 
  
 | 
        return *(_p + i) == v; 
 | 
    } 
 | 
  
 | 
    bool TypeNameParser::ConsumeNumber(int32_t &value) 
 | 
    { 
 | 
        if (!isdigit(*_p)) 
 | 
            return false; 
 | 
  
 | 
        std::string::const_iterator begin = _p; 
 | 
  
 | 
        while (isdigit(*_p)) 
 | 
        { 
 | 
            if (!Next()) 
 | 
                break; 
 | 
        } 
 | 
  
 | 
        value = (int32_t)strtol(&(*begin), NULL, 10); 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::ConsumeAssemblyIdentifier() 
 | 
    { 
 | 
        do 
 | 
        { 
 | 
            switch (*_p) 
 | 
            { 
 | 
                case ',': 
 | 
                case '+': 
 | 
                case '&': 
 | 
                case '*': 
 | 
                case '[': 
 | 
                case ']': 
 | 
                case '=': 
 | 
                case '"': 
 | 
                case '`': 
 | 
                    return; 
 | 
  
 | 
                case '\\': 
 | 
                    Next(); 
 | 
                    break; 
 | 
            } 
 | 
        } 
 | 
        while (Next()); 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::ConsumePropertyIdentifier() 
 | 
    { 
 | 
        do 
 | 
        { 
 | 
            switch (*_p) 
 | 
            { 
 | 
                case '=': 
 | 
                    return; 
 | 
            } 
 | 
        } 
 | 
        while (Next()); 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::ConsumePropertyValue() 
 | 
    { 
 | 
        do 
 | 
        { 
 | 
            switch (*_p) 
 | 
            { 
 | 
                case ',': 
 | 
                case ']': 
 | 
                    return; 
 | 
            } 
 | 
        } 
 | 
        while (Next()); 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::ConsumeIdentifier() 
 | 
    { 
 | 
        do 
 | 
        { 
 | 
            switch (*_p) 
 | 
            { 
 | 
                case ',': 
 | 
                case '+': 
 | 
                case '&': 
 | 
                case '*': 
 | 
                case '[': 
 | 
                case ']': 
 | 
                case '.': 
 | 
                case '=': 
 | 
                case '"': 
 | 
                case '`': 
 | 
                    return; 
 | 
  
 | 
                case '\\': 
 | 
                    Next(); 
 | 
                    break; 
 | 
            } 
 | 
        } 
 | 
        while (Next()); 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::InitializeParser() 
 | 
    { 
 | 
        SkipWhites(); 
 | 
    } 
 | 
  
 | 
    void TypeNameParser::SkipWhites() 
 | 
    { 
 | 
        while ((CurrentIs(' ') || CurrentIs('\t')) && !IsEOL()) 
 | 
            ++_p; 
 | 
    } 
 | 
  
 | 
    TypeNameParseInfo::TypeNameParseInfo() 
 | 
    { 
 | 
    } 
 | 
  
 | 
    TypeNameParseInfo::~TypeNameParseInfo() 
 | 
    { 
 | 
        _type_arguments.clear(); 
 | 
        _modifiers.clear(); 
 | 
        _nested.clear(); 
 | 
    } 
 | 
  
 | 
    int Type::GetType(const Il2CppType *type) 
 | 
    { 
 | 
        return type->type; 
 | 
    } 
 | 
  
 | 
    void Type::GetNameInternal(std::string &str, const Il2CppType *type, Il2CppTypeNameFormat format, bool is_nested) 
 | 
    { 
 | 
        switch (type->type) 
 | 
        { 
 | 
            case IL2CPP_TYPE_ARRAY: 
 | 
            { 
 | 
                Il2CppClass* arrayClass = Class::FromIl2CppType(type); 
 | 
                Il2CppClass* elementClass = Class::GetElementClass(arrayClass); 
 | 
                Type::GetNameInternal( 
 | 
                    str, 
 | 
                    &elementClass->byval_arg, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false); 
 | 
  
 | 
                str += '['; 
 | 
  
 | 
                if (arrayClass->rank == 1) 
 | 
                    str += '*'; 
 | 
  
 | 
                for (int32_t i = 1; i < arrayClass->rank; i++) 
 | 
                    str += ','; 
 | 
  
 | 
                str += ']'; 
 | 
  
 | 
                if (type->byref) 
 | 
                    str += '&'; 
 | 
  
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = elementClass->image->assembly; 
 | 
                    str += ", " + vm::AssemblyName::AssemblyNameToString(ta->aname); 
 | 
                } 
 | 
  
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_SZARRAY: 
 | 
            { 
 | 
                Il2CppClass* elementClass = Class::FromIl2CppType(type->data.type); 
 | 
                Type::GetNameInternal( 
 | 
                    str, 
 | 
                    &elementClass->byval_arg, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false); 
 | 
  
 | 
                str += "[]"; 
 | 
  
 | 
                if (type->byref) 
 | 
                    str += '&'; 
 | 
  
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = elementClass->image->assembly; 
 | 
                    str += ", " + vm::AssemblyName::AssemblyNameToString(ta->aname); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_PTR: 
 | 
            { 
 | 
                Type::GetNameInternal( 
 | 
                    str, 
 | 
                    type->data.type, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false); 
 | 
  
 | 
                str += '*'; 
 | 
  
 | 
                if (type->byref) 
 | 
                    str += '&'; 
 | 
  
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = Class::FromIl2CppType(type->data.type)->image->assembly; 
 | 
                    str += ", " + vm::AssemblyName::AssemblyNameToString(ta->aname); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_VAR: 
 | 
            case IL2CPP_TYPE_MVAR: 
 | 
                str += MetadataCache::GetStringFromIndex(Type::GetGenericParameter(type)->nameIndex); 
 | 
  
 | 
                if (type->byref) 
 | 
                    str += '&'; 
 | 
                break; 
 | 
  
 | 
            default: 
 | 
            { 
 | 
                Il2CppClass *klass = Class::FromIl2CppType(type); 
 | 
                Class::Init(klass); 
 | 
  
 | 
                Il2CppClass* declaringType = Class::GetDeclaringType(klass); 
 | 
                if (declaringType) 
 | 
                { 
 | 
                    Type::GetNameInternal(str, &declaringType->byval_arg, format, true); 
 | 
                    str += (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '.' : '+'); 
 | 
                } 
 | 
                else if (*klass->namespaze) 
 | 
                { 
 | 
                    str += klass->namespaze; 
 | 
                    str += '.'; 
 | 
                } 
 | 
  
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_IL) 
 | 
                { 
 | 
                    const char *s = strchr(klass->name, '`'); 
 | 
                    str += (s ? std::string(klass->name, s) : klass->name); 
 | 
                } 
 | 
                else 
 | 
                    str += klass->name; 
 | 
  
 | 
                if (is_nested) 
 | 
                    break; 
 | 
  
 | 
                if (klass->generic_class) 
 | 
                { 
 | 
                    Il2CppGenericClass *gclass = klass->generic_class; 
 | 
                    const Il2CppGenericInst *inst = gclass->context.class_inst; 
 | 
                    Il2CppTypeNameFormat nested_format; 
 | 
  
 | 
                    nested_format = format == IL2CPP_TYPE_NAME_FORMAT_FULL_NAME ? IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format; 
 | 
  
 | 
                    str += (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '<' : '['); 
 | 
  
 | 
                    for (uint32_t i = 0; i < inst->type_argc; i++) 
 | 
                    { 
 | 
                        const Il2CppType *t = inst->type_argv[i]; 
 | 
  
 | 
                        if (i) 
 | 
                            str += ','; 
 | 
  
 | 
                        if ((nested_format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (t->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                            str += '['; 
 | 
  
 | 
                        Type::GetNameInternal(str, inst->type_argv[i], nested_format, false); 
 | 
  
 | 
                        if ((nested_format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (t->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                            str += ']'; 
 | 
                    } 
 | 
  
 | 
                    str += (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '>' : ']'); 
 | 
                } 
 | 
                else if (Class::IsGeneric(klass) && (format != IL2CPP_TYPE_NAME_FORMAT_FULL_NAME) && (format != IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) 
 | 
                { 
 | 
                    const Il2CppGenericContainer* container = Class::GetGenericContainer(klass); 
 | 
  
 | 
                    str += (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '<' : '['); 
 | 
  
 | 
                    for (int32_t i = 0; i < container->type_argc; i++) 
 | 
                    { 
 | 
                        if (i) 
 | 
                            str += ','; 
 | 
                        str += MetadataCache::GetStringFromIndex(GenericContainer::GetGenericParameter(container, i)->nameIndex); 
 | 
                    } 
 | 
  
 | 
                    str += (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '>' : ']'); 
 | 
                } 
 | 
  
 | 
                if (type->byref) 
 | 
                    str += '&'; 
 | 
  
 | 
                if ((format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (type->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = klass->image->assembly; 
 | 
                    str += ", " + vm::AssemblyName::AssemblyNameToString(ta->aname); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    std::string Type::GetName(const Il2CppType *type, Il2CppTypeNameFormat format) 
 | 
    { 
 | 
        std::string str; 
 | 
        Type::GetNameInternal(str, type, format, false); 
 | 
        return str; 
 | 
    } 
 | 
  
 | 
    enum 
 | 
    { 
 | 
        //max digits on uint16 is 5(used to convert the number of generic args) + max 3 other slots taken; 
 | 
        kNameChunkBufferSize = 8 
 | 
    }; 
 | 
  
 | 
    static inline char* flushChunkBuffer(char* buffer, void(*chunkReportFunc)(void*data, void* userData), void* userData) 
 | 
    { 
 | 
        chunkReportFunc(buffer, userData); 
 | 
        memset(buffer, 0x00, kNameChunkBufferSize); 
 | 
  
 | 
        return buffer; 
 | 
    } 
 | 
  
 | 
    void Type::GetNameChunkedRecurseInternal(const Il2CppType *type, Il2CppTypeNameFormat format, bool is_nested, void(*chunkReportFunc)(void*data, void* userData), void* userData) 
 | 
    { 
 | 
        char buffer[kNameChunkBufferSize + 1]; //null terminate the buffer 
 | 
        memset(buffer, 0x00, kNameChunkBufferSize + 1); 
 | 
        char* bufferPtr = buffer; 
 | 
        char* bufferIter = bufferPtr; 
 | 
  
 | 
        switch (type->type) 
 | 
        { 
 | 
            case IL2CPP_TYPE_ARRAY: 
 | 
            { 
 | 
                Il2CppClass* arrayClass = Class::FromIl2CppType(type); 
 | 
                Il2CppClass* elementClass = Class::GetElementClass(arrayClass); 
 | 
                Type::GetNameChunkedRecurseInternal( 
 | 
                    &elementClass->byval_arg, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false, chunkReportFunc, userData); 
 | 
  
 | 
                *bufferIter++ = '['; 
 | 
  
 | 
                if (arrayClass->rank == 1) 
 | 
                    *bufferIter++ = '*'; 
 | 
  
 | 
                for (int32_t i = 1; i < arrayClass->rank; i++) 
 | 
                { 
 | 
                    *bufferIter++ = ','; 
 | 
                    if (kNameChunkBufferSize - (bufferIter - bufferPtr) < 2) 
 | 
                    { 
 | 
                        bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                *bufferIter++ = ']'; 
 | 
  
 | 
                if (type->byref) 
 | 
                    *bufferIter++ = '&'; 
 | 
  
 | 
                bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = elementClass->image->assembly; 
 | 
                    *bufferIter++ = ','; 
 | 
                    chunkReportFunc(bufferPtr, userData); 
 | 
  
 | 
                    //change this to call the callback 
 | 
                    vm::AssemblyName::AssemblyNameReportChunked(ta->aname, chunkReportFunc, userData); 
 | 
                } 
 | 
  
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_SZARRAY: 
 | 
            { 
 | 
                Il2CppClass* elementClass = Class::FromIl2CppType(type->data.type); 
 | 
                Type::GetNameChunkedRecurseInternal( 
 | 
                    &elementClass->byval_arg, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false, chunkReportFunc, userData); 
 | 
  
 | 
                *bufferIter++ = '['; 
 | 
                *bufferIter++ = ']'; 
 | 
  
 | 
                if (type->byref) 
 | 
                    *bufferIter++ = '&'; 
 | 
  
 | 
                bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = elementClass->image->assembly; 
 | 
                    *bufferIter++ = ','; 
 | 
                    chunkReportFunc(bufferPtr, userData); 
 | 
                    //change this to call the callback 
 | 
                    vm::AssemblyName::AssemblyNameReportChunked(ta->aname, chunkReportFunc, userData); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_PTR: 
 | 
            { 
 | 
                Type::GetNameChunkedRecurseInternal( 
 | 
                    type->data.type, 
 | 
                    format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? IL2CPP_TYPE_NAME_FORMAT_FULL_NAME : format, 
 | 
                    false, chunkReportFunc, userData); 
 | 
  
 | 
                *bufferIter++ = '*'; 
 | 
  
 | 
                if (type->byref) 
 | 
                    *bufferIter++ = '&'; 
 | 
  
 | 
                bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = Class::FromIl2CppType(type->data.type)->image->assembly; 
 | 
                    *bufferIter++ = ','; 
 | 
                    chunkReportFunc(bufferPtr, userData); 
 | 
                    //change this to call the callback 
 | 
                    vm::AssemblyName::AssemblyNameReportChunked(ta->aname, chunkReportFunc, userData); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            case IL2CPP_TYPE_VAR: 
 | 
            case IL2CPP_TYPE_MVAR: 
 | 
                chunkReportFunc(const_cast<char*>(MetadataCache::GetStringFromIndex(Type::GetGenericParameter(type)->nameIndex)), userData); 
 | 
  
 | 
                if (type->byref) 
 | 
                { 
 | 
                    *bufferIter++ = '&'; 
 | 
                    chunkReportFunc(bufferPtr, userData); 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            default: 
 | 
            { 
 | 
                Il2CppClass *klass = Class::FromIl2CppType(type); 
 | 
                Class::Init(klass); 
 | 
  
 | 
                Il2CppClass* declaringType = Class::GetDeclaringType(klass); 
 | 
                if (declaringType) 
 | 
                { 
 | 
                    Type::GetNameChunkedRecurseInternal(&declaringType->byval_arg, format, true, chunkReportFunc, userData); 
 | 
                    *bufferIter++ = (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '.' : '+'); 
 | 
                } 
 | 
                else if (*klass->namespaze) 
 | 
                { 
 | 
                    chunkReportFunc(const_cast<char*>(klass->namespaze), userData); 
 | 
                    *bufferIter++ = '.'; 
 | 
                } 
 | 
  
 | 
                if (format == IL2CPP_TYPE_NAME_FORMAT_IL) 
 | 
                { 
 | 
                    const char *s = strchr(klass->name, '`'); 
 | 
                    size_t len = s ? s - klass->name : strlen(klass->name); 
 | 
  
 | 
                    for (size_t i = 0; i < len; ++i) 
 | 
                    { 
 | 
                        *bufferIter++ = *(klass->name + i); 
 | 
                        if (kNameChunkBufferSize - (bufferIter - bufferPtr) == 0) 
 | 
                        { 
 | 
                            bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
                else 
 | 
                    chunkReportFunc(const_cast<char*>(klass->name), userData); 
 | 
  
 | 
                if (bufferPtr != bufferIter) 
 | 
                { 
 | 
                    bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                } 
 | 
  
 | 
                if (is_nested) 
 | 
                    break; 
 | 
  
 | 
                if (klass->generic_class) 
 | 
                { 
 | 
                    Il2CppGenericClass *gclass = klass->generic_class; 
 | 
                    const Il2CppGenericInst *inst = gclass->context.class_inst; 
 | 
                    Il2CppTypeNameFormat nested_format; 
 | 
  
 | 
                    nested_format = format == IL2CPP_TYPE_NAME_FORMAT_FULL_NAME ? IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format; 
 | 
  
 | 
                    *bufferIter++ = (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '<' : '['); 
 | 
  
 | 
                    for (uint32_t i = 0; i < inst->type_argc; i++) 
 | 
                    { 
 | 
                        const Il2CppType *t = inst->type_argv[i]; 
 | 
  
 | 
                        if (i) 
 | 
                            *bufferIter++ = ','; 
 | 
  
 | 
                        if ((nested_format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (t->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                            *bufferIter++ = '['; 
 | 
                        bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                        Type::GetNameChunkedRecurseInternal(inst->type_argv[i], nested_format, false, chunkReportFunc, userData); 
 | 
  
 | 
                        if ((nested_format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (t->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                            *bufferIter++ = ']'; 
 | 
                    } 
 | 
  
 | 
                    *bufferIter++ = (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '>' : ']'); 
 | 
                } 
 | 
                else if (Class::IsGeneric(klass) && (format != IL2CPP_TYPE_NAME_FORMAT_FULL_NAME) && (format != IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) 
 | 
                { 
 | 
                    const Il2CppGenericContainer* container = Class::GetGenericContainer(klass); 
 | 
  
 | 
                    *bufferIter++ = (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '<' : '['); 
 | 
  
 | 
                    for (int32_t i = 0; i < container->type_argc; ++i) 
 | 
                    { 
 | 
                        if (i) 
 | 
                            *bufferIter++ = ','; 
 | 
                        const char* idxStr = MetadataCache::GetStringFromIndex(GenericContainer::GetGenericParameter(container, i)->nameIndex); 
 | 
                        size_t len = strlen(idxStr); 
 | 
                        for (size_t l = 0; l < len; ++l) 
 | 
                        { 
 | 
                            *bufferIter++ = *(idxStr + l); 
 | 
                            if (kNameChunkBufferSize - (bufferIter - bufferPtr) < 2) 
 | 
                            //make sure there's at least 2 slots empty to 
 | 
                            //accommodate the worst case scenario until we flush 
 | 
                            { 
 | 
                                bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    *bufferIter++ = (format == IL2CPP_TYPE_NAME_FORMAT_IL ? '>' : ']'); 
 | 
                } 
 | 
  
 | 
                if (type->byref) 
 | 
                    *bufferIter++ = '&'; 
 | 
  
 | 
                bufferIter = flushChunkBuffer(bufferPtr, chunkReportFunc, userData); 
 | 
                if ((format == IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) && (type->type != IL2CPP_TYPE_VAR) && (type->type != IL2CPP_TYPE_MVAR)) 
 | 
                { 
 | 
                    const Il2CppAssembly *ta = klass->image->assembly; 
 | 
                    *bufferIter++ = ','; 
 | 
                    chunkReportFunc(bufferPtr, userData); 
 | 
                    //change this to call the callback 
 | 
                    vm::AssemblyName::AssemblyNameReportChunked(ta->aname, chunkReportFunc, userData); 
 | 
                } 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    void Type::GetNameChunkedRecurse(const Il2CppType *type, Il2CppTypeNameFormat format, void(*reportFunc)(void*data, void* userData), void* userData) 
 | 
    { 
 | 
        GetNameChunkedRecurseInternal(type, format, false, reportFunc, userData); 
 | 
    } 
 | 
  
 | 
    Il2CppClass* Type::GetClassOrElementClass(const Il2CppType *type) 
 | 
    { 
 | 
        // This is a weird function to mimic old mono behaviour. 
 | 
        // We incorrectly used the analogous mono function in Unity. 
 | 
        // Expectations: Return class if type is not an array. Return element type if it is an array. 
 | 
        if (type->type == IL2CPP_TYPE_ARRAY) 
 | 
            return Class::FromIl2CppType(type->data.array->etype); 
 | 
  
 | 
        if (type->type == IL2CPP_TYPE_SZARRAY) 
 | 
            return Class::FromIl2CppType(type->data.type); 
 | 
  
 | 
        // IL2CPP_TYPE_SZARRAY stores element class in klass 
 | 
        return il2cpp::vm::MetadataCache::GetIl2CppClassFromTypeDefinition(type->data.typeHandle); 
 | 
    } 
 | 
  
 | 
    const Il2CppType* Type::GetUnderlyingType(const Il2CppType *type) 
 | 
    { 
 | 
        if (type->type == IL2CPP_TYPE_VALUETYPE && MetadataCache::GetIl2CppClassFromTypeDefinition(type->data.typeHandle)->enumtype && !type->byref) 
 | 
            return Class::GetEnumBaseType(MetadataCache::GetIl2CppClassFromTypeDefinition(type->data.typeHandle)); 
 | 
        if (IsGenericInstance(type)) 
 | 
        { 
 | 
            Il2CppClass* definition = GenericClass::GetTypeDefinition(type->data.generic_class); 
 | 
            if (definition != NULL && definition->enumtype && !type->byref) 
 | 
                return Class::GetEnumBaseType(definition); 
 | 
        } 
 | 
        return type; 
 | 
    } 
 | 
  
 | 
    bool Type::IsGenericInstance(const Il2CppType* type) 
 | 
    { 
 | 
        return type->type == IL2CPP_TYPE_GENERICINST; 
 | 
    } 
 | 
  
 | 
    Il2CppReflectionType* Type::GetDeclaringType(const Il2CppType* type) 
 | 
    { 
 | 
        Il2CppClass *typeInfo = NULL; 
 | 
  
 | 
        if (type->byref) 
 | 
            return NULL; 
 | 
        if (type->type == IL2CPP_TYPE_VAR || type->type == IL2CPP_TYPE_MVAR) 
 | 
        { 
 | 
            const Il2CppGenericParameter* genericParameter = GetGenericParameter(type); 
 | 
            const Il2CppGenericContainer* container = MetadataCache::GetGenericContainerFromIndex(genericParameter->ownerIndex); 
 | 
            typeInfo = GenericContainer::GetDeclaringType(container); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            typeInfo = Class::GetDeclaringType(Class::FromIl2CppType(type)); 
 | 
        } 
 | 
  
 | 
        return typeInfo ? Reflection::GetTypeObject(&typeInfo->byval_arg) : NULL; 
 | 
    } 
 | 
  
 | 
    Il2CppArray* Type::GetGenericArgumentsInternal(Il2CppReflectionType* type, bool runtimeArray) 
 | 
    { 
 | 
        Il2CppArray *res; 
 | 
        Il2CppClass *klass, *pklass; 
 | 
  
 | 
        klass = Class::FromIl2CppType(type->type); 
 | 
  
 | 
        Il2CppClass *arrType = runtimeArray ? il2cpp_defaults.runtimetype_class : il2cpp_defaults.systemtype_class; 
 | 
  
 | 
        if (Class::IsGeneric(klass)) 
 | 
        { 
 | 
            const Il2CppGenericContainer *container = MetadataCache::GetGenericContainerFromIndex(klass->genericContainerIndex); 
 | 
            res = Array::New(arrType, container->type_argc); 
 | 
            for (int32_t i = 0; i < container->type_argc; ++i) 
 | 
            { 
 | 
                pklass = Class::FromGenericParameter(GenericContainer::GetGenericParameter(container, i)); 
 | 
                il2cpp_array_setref(res, i, Reflection::GetTypeObject(&pklass->byval_arg)); 
 | 
            } 
 | 
        } 
 | 
        else if (klass->generic_class) 
 | 
        { 
 | 
            const Il2CppGenericInst *inst = klass->generic_class->context.class_inst; 
 | 
            res = Array::New(arrType, inst->type_argc); 
 | 
            for (uint32_t i = 0; i < inst->type_argc; ++i) 
 | 
                il2cpp_array_setref(res, i, Reflection::GetTypeObject(inst->type_argv[i])); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            res = Array::New(arrType, 0); 
 | 
        } 
 | 
        return res; 
 | 
    } 
 | 
  
 | 
    bool Type::IsEqualToType(const Il2CppType *type, const Il2CppType *otherType) 
 | 
    { 
 | 
        return ::il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(type, otherType); 
 | 
    } 
 | 
  
 | 
    Il2CppReflectionType* Type::GetTypeFromHandle(intptr_t handle) 
 | 
    { 
 | 
        const Il2CppType* type = (const Il2CppType*)handle; 
 | 
        Il2CppClass *klass = vm::Class::FromIl2CppType(type); 
 | 
  
 | 
        return il2cpp::vm::Reflection::GetTypeObject(&klass->byval_arg); 
 | 
    } 
 | 
  
 | 
    uint32_t Type::GetToken(const Il2CppType *type) 
 | 
    { 
 | 
        if (IsGenericInstance(type)) 
 | 
            return GenericClass::GetTypeDefinition(type->data.generic_class)->token; 
 | 
        return GetClass(type)->token; 
 | 
    } 
 | 
  
 | 
    bool Type::IsReference(const Il2CppType* type) 
 | 
    { 
 | 
        if (!type) 
 | 
            return false; 
 | 
  
 | 
        if (type->type == IL2CPP_TYPE_STRING || 
 | 
            type->type == IL2CPP_TYPE_SZARRAY || 
 | 
            type->type == IL2CPP_TYPE_CLASS || 
 | 
            type->type == IL2CPP_TYPE_OBJECT || 
 | 
            type->type == IL2CPP_TYPE_ARRAY) 
 | 
            return true; 
 | 
  
 | 
        if (IsGenericInstance(type) && !GenericClass::IsValueType(type->data.generic_class)) 
 | 
            return true; 
 | 
  
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    bool Type::IsStruct(const Il2CppType* type) 
 | 
    { 
 | 
        if (type->byref) 
 | 
            return false; 
 | 
  
 | 
        if (type->type == IL2CPP_TYPE_VALUETYPE && !MetadataCache::GetIl2CppClassFromTypeDefinition(type->data.typeHandle)->enumtype) 
 | 
            return true; 
 | 
  
 | 
        if (type->type == IL2CPP_TYPE_TYPEDBYREF) 
 | 
            return true; 
 | 
  
 | 
        if (IsGenericInstance(type) && 
 | 
            GenericClass::IsValueType(type->data.generic_class) && 
 | 
            !GenericClass::IsEnum(type->data.generic_class)) 
 | 
            return true; 
 | 
  
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    bool Type::GenericInstIsValuetype(const Il2CppType* type) 
 | 
    { 
 | 
        IL2CPP_ASSERT(IsGenericInstance(type)); 
 | 
        return GenericClass::IsValueType(type->data.generic_class); 
 | 
    } 
 | 
  
 | 
    bool Type::IsEnum(const Il2CppType *type) 
 | 
    { 
 | 
        if (type->type != IL2CPP_TYPE_VALUETYPE) 
 | 
            return false; 
 | 
  
 | 
        Il2CppClass* klass = GetClass(type); 
 | 
        return klass->enumtype; 
 | 
    } 
 | 
  
 | 
    bool Type::IsValueType(const Il2CppType *type) 
 | 
    { 
 | 
        Il2CppClass* klass = GetClass(type); 
 | 
        return klass->valuetype; 
 | 
    } 
 | 
  
 | 
    bool Type::IsEmptyType(const Il2CppType *type) 
 | 
    { 
 | 
        return IsGenericInstance(type) && type->data.generic_class->type == nullptr; 
 | 
    } 
 | 
  
 | 
    bool Type::IsSystemDBNull(const Il2CppType *type) 
 | 
    { 
 | 
        Il2CppClass* klass = GetClass(type); 
 | 
        return (klass->image == il2cpp_defaults.corlib && strcmp(klass->namespaze, "System") == 0 && strcmp(klass->name, "DBNull") == 0); 
 | 
    } 
 | 
  
 | 
    bool Type::IsSystemDateTime(const Il2CppType *type) 
 | 
    { 
 | 
        Il2CppClass* klass = GetClass(type); 
 | 
        return (klass->image == il2cpp_defaults.corlib && strcmp(klass->namespaze, "System") == 0 && strcmp(klass->name, "DateTime") == 0); 
 | 
    } 
 | 
  
 | 
    bool Type::IsSystemDecimal(const Il2CppType *type) 
 | 
    { 
 | 
        Il2CppClass* klass = GetClass(type); 
 | 
        return (klass->image == il2cpp_defaults.corlib && strcmp(klass->namespaze, "System") == 0 && strcmp(klass->name, "Decimal") == 0); 
 | 
    } 
 | 
  
 | 
    Il2CppClass* Type::GetClass(const Il2CppType *type) 
 | 
    { 
 | 
        IL2CPP_ASSERT(type->type == IL2CPP_TYPE_CLASS || type->type == IL2CPP_TYPE_VALUETYPE); 
 | 
        return MetadataCache::GetIl2CppClassFromTypeDefinition(type->data.typeHandle); 
 | 
    } 
 | 
  
 | 
    const Il2CppGenericParameter* Type::GetGenericParameter(const Il2CppType *type) 
 | 
    { 
 | 
        IL2CPP_ASSERT(type->type == IL2CPP_TYPE_VAR || type->type == IL2CPP_TYPE_MVAR); 
 | 
        return type->data.genericParameterHandle; 
 | 
    } 
 | 
  
 | 
    const Il2CppType* Type::GetGenericTypeDefintion(const Il2CppType* type) 
 | 
    { 
 | 
        IL2CPP_ASSERT(IsGenericInstance(type)); 
 | 
        return Class::GetType(GenericClass::GetTypeDefinition(type->data.generic_class)); 
 | 
    } 
 | 
  
 | 
/** 
 | 
* Type::ConstructDelegate: 
 | 
* @delegate: pointer to an uninitialized delegate object 
 | 
* @target: target object 
 | 
* @addr: pointer to native code 
 | 
* @method: method 
 | 
* 
 | 
* Initialize a delegate and set a specific method, not the one 
 | 
* associated with addr. This is useful when sharing generic code. 
 | 
* In that case addr will most probably not be associated with the 
 | 
* correct instantiation of the method. 
 | 
*/ 
 | 
    void Type::ConstructDelegate(Il2CppDelegate* delegate, Il2CppObject* target, Il2CppMethodPointer addr, const MethodInfo* method) 
 | 
    { 
 | 
#if IL2CPP_TINY 
 | 
        IL2CPP_ASSERT(0 && "Type::ConstructDelegatee should not be called with the Tiny profile."); 
 | 
#else 
 | 
        IL2CPP_ASSERT(delegate); 
 | 
  
 | 
        if (method) 
 | 
            delegate->method = method; 
 | 
  
 | 
        delegate->method_ptr = addr; 
 | 
        if (target != NULL) 
 | 
            IL2CPP_OBJECT_SETREF(delegate, target, target); 
 | 
  
 | 
        delegate->invoke_impl = method->invoker_method; //TODO:figure out if this is needed at all 
 | 
#endif 
 | 
    } 
 | 
  
 | 
    Il2CppString* Type::AppendAssemblyNameIfNecessary(Il2CppString* typeName, const char* assemblyName) 
 | 
    { 
 | 
        if (typeName != NULL) 
 | 
        { 
 | 
            std::string name = utils::StringUtils::Utf16ToUtf8(utils::StringUtils::GetChars(typeName)); 
 | 
  
 | 
            il2cpp::vm::TypeNameParseInfo info; 
 | 
            il2cpp::vm::TypeNameParser parser(name, info, false); 
 | 
  
 | 
            if (parser.Parse()) 
 | 
            { 
 | 
                if (info.assembly_name().name.empty()) 
 | 
                { 
 | 
                    std::string assemblyQualifiedName; 
 | 
                    assemblyQualifiedName = name + ", " + assemblyName; 
 | 
                    return vm::String::New(assemblyQualifiedName.c_str()); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return typeName; 
 | 
    } 
 | 
} /* namespace vm */ 
 | 
} /* namespace il2cpp */ 
 |