/*
* Nocturne
* Copyright (c) 2015-2016, Lapis <https://github.com/LapisBlue>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package blue.lapis.nocturne.mapping.io.reader;
import static blue.lapis.nocturne.util.Constants.SPACE_PATTERN;
import blue.lapis.nocturne.Main;
import blue.lapis.nocturne.jar.model.attribute.MethodDescriptor;
import blue.lapis.nocturne.jar.model.attribute.Type;
import blue.lapis.nocturne.mapping.MappingContext;
import blue.lapis.nocturne.mapping.model.ClassMapping;
import blue.lapis.nocturne.mapping.model.MethodMapping;
import blue.lapis.nocturne.processor.index.model.signature.FieldSignature;
import blue.lapis.nocturne.processor.index.model.signature.MethodSignature;
import blue.lapis.nocturne.util.helper.MappingsHelper;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* The mappings reader, for the SRG format.
*/
public class JamReader extends MappingsReader {
private static final String CLASS_MAPPING_KEY = "CL";
private static final String FIELD_MAPPING_KEY = "FD";
private static final String METHOD_MAPPING_KEY = "MD";
private static final String PARAM_MAPPING_KEY = "MP";
private static final int CLASS_MAPPING_ELEMENT_COUNT = 3;
private static final int FIELD_MAPPING_ELEMENT_COUNT = 5;
private static final int METHOD_MAPPING_ELEMENT_COUNT = 5;
private static final int PARAM_MAPPING_ELEMENT_COUNT = 7;
public JamReader(BufferedReader reader) {
super(reader);
}
@Override
public MappingContext read() {
MappingContext mappings = new MappingContext();
Pattern spacePattern = Pattern.compile(" ", Pattern.LITERAL);
List<String> rawClassMappings = new ArrayList<>();
List<String> rawFieldMappings = new ArrayList<>();
List<String> rawMethodMappings = new ArrayList<>();
List<String> rawParamMappings = new ArrayList<>();
for (String line : reader.lines().collect(Collectors.toList())) {
String trim = line.trim();
if (trim.charAt(0) == '#' || trim.isEmpty()) {
continue;
}
if (line.length() < 4) {
Main.getLogger().warning("Found bogus line in mappings file - ignoring");
continue;
}
int len = spacePattern.split(line).length;
String key = line.substring(0, 2);
if (key.equals(CLASS_MAPPING_KEY) && len == CLASS_MAPPING_ELEMENT_COUNT) {
rawClassMappings.add(line);
} else if (key.equals(FIELD_MAPPING_KEY) && len == FIELD_MAPPING_ELEMENT_COUNT) {
rawFieldMappings.add(line);
} else if (key.equals(METHOD_MAPPING_KEY) && len == METHOD_MAPPING_ELEMENT_COUNT) {
rawMethodMappings.add(line);
} else if (key.equals(PARAM_MAPPING_KEY) && len == PARAM_MAPPING_ELEMENT_COUNT) {
rawParamMappings.add(line);
} else {
Main.getLogger().warning("Discovered unrecognized key \"" + key + "\" in mappings file - ignoring");
}
}
// we need to sort the class mappings in order of ascending nesting level
rawClassMappings.sort((s1, s2) -> getClassNestingLevel(s1) - getClassNestingLevel(s2));
genClassMappings(mappings, rawClassMappings);
genFieldMappings(mappings, rawFieldMappings);
genMethodMappings(mappings, rawMethodMappings);
genMethodParamMappings(mappings, rawParamMappings);
return mappings;
}
private void genClassMappings(MappingContext context, List<String> classMappings) {
for (String mapping : classMappings) {
String[] arr = SPACE_PATTERN.split(mapping);
String obf = arr[1];
String deobf = arr[2];
MappingsHelper.genClassMapping(context, obf, deobf, false);
}
}
private void genFieldMappings(MappingContext context, List<String> fieldMappings) {
for (String mapping : fieldMappings) {
String[] arr = SPACE_PATTERN.split(mapping);
String owningClass = arr[1];
String obf = arr[2];
String desc = arr[3];
String deobf = arr[4];
MappingsHelper.genFieldMapping(context, owningClass, new FieldSignature(obf, Type.fromString(desc)), deobf);
}
}
private void genMethodMappings(MappingContext context, List<String> methodMappings) {
for (String mapping : methodMappings) {
String[] arr = SPACE_PATTERN.split(mapping);
String owningClass = arr[1];
String obf = arr[2];
String desc = arr[3];
String deobf = arr[4];
MappingsHelper.genMethodMapping(context, owningClass,
new MethodSignature(obf, MethodDescriptor.fromString(desc)), deobf, false);
}
}
private void genMethodParamMappings(MappingContext context, List<String> paramMappings) {
for (String mapping : paramMappings) {
String[] arr = SPACE_PATTERN.split(mapping);
String owningClass = arr[1];
String owningMethod = arr[2];
String owningMethodDesc = arr[3]; //TODO: *stretching collar* oooooh...
Optional<ClassMapping> classMapping = MappingsHelper.getClassMapping(context, owningClass);
if (!classMapping.isPresent()) {
Main.getLogger().warning("Discovered orphaned method parameter mapping (class) - ignoring");
continue;
}
MethodMapping methodMapping = classMapping.get().getMethodMappings()
.get(new MethodSignature(owningMethod, MethodDescriptor.fromString(owningMethodDesc)));
if (methodMapping == null) {
methodMapping = new MethodMapping(classMapping.get(),
new MethodSignature(owningMethod, MethodDescriptor.fromString(owningMethodDesc)), owningMethod,
false);
}
int index;
try {
index = Integer.parseInt(arr[4]);
} catch (NumberFormatException ex) {
Main.getLogger().warning("Discovered invalid method parameter mapping (index) - ignoring");
continue;
}
String deobf = arr[5];
MappingsHelper.genArgumentMapping(context, methodMapping, index, deobf);
}
}
}