/* * 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.writer; import static blue.lapis.nocturne.util.Constants.CLASS_PATH_SEPARATOR_PATTERN; import static blue.lapis.nocturne.util.Constants.ENIGMA_ROOT_PACKAGE_PREFIX; 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.FieldMapping; import blue.lapis.nocturne.mapping.model.InnerClassMapping; import blue.lapis.nocturne.mapping.model.MethodMapping; import blue.lapis.nocturne.mapping.model.MethodParameterMapping; import blue.lapis.nocturne.mapping.model.TopLevelClassMapping; import java.io.PrintWriter; /** * The mappings writer, for the Enigma format. */ public class EnigmaWriter extends MappingsWriter { /** * Constructs a new {@link EnigmaWriter} which outputs to the given * {@link PrintWriter}. * * @param outputWriter The {@link PrintWriter} to output to */ public EnigmaWriter(PrintWriter outputWriter) { super(outputWriter); } @Override public void write(MappingContext mappings) { for (TopLevelClassMapping classMapping : mappings.getMappings().values()) { this.writeClassMapping(classMapping, 0); } out.close(); } protected void writeClassMapping(ClassMapping classMapping, int depth) { boolean inner = classMapping instanceof InnerClassMapping; if (classMapping.getDeobfuscatedName().equals(classMapping.getObfuscatedName())) { if (!classMapping.getInnerClassMappings().isEmpty()) { out.println(getIndentForDepth(depth) + "CLASS " + (inner ? classMapping.getObfuscatedName() : addNonePrefix(classMapping.getObfuscatedName()))); } } else { out.println(getIndentForDepth(depth) + "CLASS " + (inner ? classMapping.getFullObfuscatedName() : addNonePrefix(classMapping.getObfuscatedName())) + " " + (inner ? classMapping.getDeobfuscatedName() : addNonePrefix(classMapping.getDeobfuscatedName()))); } classMapping.getInnerClassMappings().values().forEach(m -> this.writeClassMapping(m, depth + 1)); classMapping.getFieldMappings().values().stream().filter(NOT_USELESS) .forEach(m -> this.writeFieldMapping(m, depth + 1)); classMapping.getMethodMappings().values().stream().filter(NOT_USELESS) .forEach(m -> this.writeMethodMapping(m, depth + 1)); } protected void writeFieldMapping(FieldMapping fieldMapping, int depth) { out.println(getIndentForDepth(depth) + "FIELD " + fieldMapping.getObfuscatedName() + " " + fieldMapping.getDeobfuscatedName() + " " + addNonePrefix(fieldMapping.getObfuscatedType()).toString()); } protected void writeMethodMapping(MethodMapping methodMapping, int depth) { if (methodMapping.getDeobfuscatedName().equals(methodMapping.getObfuscatedName())) { out.println(getIndentForDepth(depth) + "METHOD " + methodMapping.getObfuscatedName() + " " + addNonePrefixes(methodMapping.getObfuscatedDescriptor()).toString()); } else { out.println(getIndentForDepth(depth) + "METHOD " + methodMapping.getObfuscatedName() + " " + methodMapping.getDeobfuscatedName() + " " + addNonePrefixes(methodMapping.getObfuscatedDescriptor()).toString()); } for (MethodParameterMapping methodParameterMapping : methodMapping.getParamMappings().values()) { writeArgumentMapping(methodParameterMapping, depth + 1); } } protected void writeArgumentMapping(MethodParameterMapping argMapping, int depth) { out.println(getIndentForDepth(depth) + "ARG " + argMapping.getIndex() + " " + argMapping.getDeobfuscatedName()); } private String getIndentForDepth(int depth) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < depth; i++) { builder.append("\t"); } return builder.toString(); } private String addNonePrefix(String str) { if (!CLASS_PATH_SEPARATOR_PATTERN.matcher(str).find()) { return ENIGMA_ROOT_PACKAGE_PREFIX + str; } return str; } private Type addNonePrefix(Type type) { return type.isPrimitive() ? type : Type.fromString("L" + addNonePrefix(type.getClassName()) + ";"); } private MethodDescriptor addNonePrefixes(MethodDescriptor desc) { Type[] params = new Type[desc.getParamTypes().length]; for (int i = 0; i < params.length; i++) { params[i] = addNonePrefix(desc.getParamTypes()[i]); } Type returnType = addNonePrefix(desc.getReturnType()); return new MethodDescriptor(returnType, params); } }