aboutsummaryrefslogtreecommitdiff
path: root/codegen/lib/mappings.py
blob: 9c39fc2b8a414cf2986233560b3949dd26ef15da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from typing import Optional


class Mappings:
    __slots__ = ('classes', 'fields', 'methods', 'field_types', 'method_types')

    def __init__(self, classes, fields, methods, field_types, method_types):
        self.classes = classes
        self.fields = fields
        self.methods = methods
        self.field_types = field_types
        self.method_types = method_types

    @staticmethod
    def parse(mappings_txt):
        classes = {}
        fields = {}
        methods = {}
        field_types = {}
        method_types = {}

        current_obfuscated_class_name = None

        for line in mappings_txt.splitlines():
            if line.startswith('#') or line == '':
                continue

            if line.startswith('    '):
                # if a line starts with 4 spaces, that means it's a method or a field
                if '(' in line:
                    # if it has an opening parenthesis, it's a method
                    real_name_with_parameters_and_line, obfuscated_name = line.strip().split(' -> ')
                    real_name_with_parameters = real_name_with_parameters_and_line.split(
                        ':')[-1]

                    real_type, real_name = real_name_with_parameters.split('(')[
                        0].split(' ')
                    parameters = real_name_with_parameters.split('(')[1].split(')')[
                        0]

                    if current_obfuscated_class_name not in methods:
                        methods[current_obfuscated_class_name] = {}
                        method_types[current_obfuscated_class_name] = {}
                    methods[current_obfuscated_class_name][
                        f'{obfuscated_name}({parameters})'] = real_name
                    method_types[current_obfuscated_class_name][
                        f'{obfuscated_name}({parameters})'] = real_type
                else:
                    # otherwise, it's a field
                    real_name_with_type, obfuscated_name = line.strip().split(' -> ')
                    real_type, real_name = real_name_with_type.split(' ')

                    if current_obfuscated_class_name not in fields:
                        fields[current_obfuscated_class_name] = {}
                        field_types[current_obfuscated_class_name] = {}
                    fields[current_obfuscated_class_name][obfuscated_name] = real_name
                    field_types[current_obfuscated_class_name][obfuscated_name] = real_type
            else:
                # otherwise it's a class
                real_name, obfuscated_name = line.strip(':').split(' -> ')
                current_obfuscated_class_name = obfuscated_name

                classes[obfuscated_name] = real_name

        return Mappings(classes, fields, methods, field_types, method_types)

    def get_field(self, obfuscated_class_name, obfuscated_field_name):
        return self.fields.get(obfuscated_class_name, {}).get(obfuscated_field_name)

    def get_class(self, obfuscated_class_name):
        if '<' in obfuscated_class_name:
            first_part, args = obfuscated_class_name.split('<')
            args = args.rstrip('>').strip(';').split(';')
            print(args)
            assert len(args) == 1
            arg = self.get_class(args[0][1:])
            return f'{first_part}<{arg}>'
        return self.classes[obfuscated_class_name]

    def get_method(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature):
        return self.methods[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})']

    def get_field_type(self, obfuscated_class_name, obfuscated_field_name) -> str:
        return self.field_types[obfuscated_class_name][obfuscated_field_name]

    def get_method_type(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature) -> str:
        return self.method_types[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})']

    def get_class_from_deobfuscated_name(self, deobfuscated_name) -> Optional[str]:
        for obfuscated_name, real_name in self.classes.items():
            if real_name == deobfuscated_name:
                return obfuscated_name
        return None