summaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/mapper/tools/ClassData.java
blob: a9fbcecbad6855dfcc92c7d5dfd979939de5b2b7 (plain) (blame)
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
94
95
96
97
98
99
100
package ftbsc.lll.mapper.tools;

import ftbsc.lll.exceptions.AmbiguousMappingException;
import ftbsc.lll.exceptions.MappingNotFoundException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Container class used to store information about classes.
 */
public class ClassData {
   /**
    * The unobfuscated name (FQN with '/' instad of '.') of the class.
    */
   public final String unobf;

   /**
    * The obfuscated internal name (FQN with '/' instad of '.') of the class.
    */
   public final String obf;

   /**
    * A {@link Map} tying each member's name or signature to its
    * obfuscated counterpart.
    */
   public final Map<String, String> members;

   /**
    * The constructor. It takes in the names (obfuscated and non-obfuscated)
    * of a class.
    * @param unobf the unobfuscated name
    * @param obf the obfuscated name
    */
   public ClassData(String unobf, String obf) {
      this.unobf = unobf;
      this.obf = obf;
      this.members = new HashMap<>();
   }

   /**
    * Adds a member to the target class.
    * For fields only the names are required; for methods,
    * this takes in the full signature ({@code name + " " + space}).
    * @param s the String representing the declaration line
    */
   public void addMember(String s) {
      String[] split = s.trim().split(" ");
      if(split.length == 2) //field
         members.put(split[0], split[1]);
      else if (split.length == 3) //method
         members.put(split[0] + " " + split[1], split[2]);
   }

   /**
    * Gets an obfuscated member given the method name and a method descriptor,
    * which may be partial (i.e. not include return type) or null if the member
    * is not a method.
    * @param memberName member name
    * @param methodDescriptor the method descriptor, or null if it's not a method
    * @return the requested obfuscated name, or null if nothing was found
    * @throws AmbiguousMappingException if not enough data was given to uniquely identify a mapping
    */
   public String get(String memberName, String methodDescriptor) {

      //find all keys that start with the name
      List<String> candidates = members.keySet().stream().filter(
         m -> m.split(" ")[0].equals(memberName)
      ).collect(Collectors.toList());

      if(methodDescriptor != null) {
         String signature = String.format("%s %s", memberName, methodDescriptor);
         candidates = candidates.stream().filter(
            m -> m.equals(signature)
         ).collect(Collectors.toList());
      }

      switch(candidates.size()) {
         case 0:
            throw new MappingNotFoundException(String.format(
               "%s.%s%s",
               this.unobf,
               memberName,
               methodDescriptor == null ? "" : "()"
            ));
         case 1:
            return members.get(candidates.get(0));
         default:
            throw new AmbiguousMappingException(String.format(
               "Mapper could not uniquely identify member %s.%s%s, found %d!",
               this.unobf,
               memberName,
               methodDescriptor == null ? "" : "()",
               candidates.size()
            ));
      }
   }
}