public void writeMessage(String message, Throwable t) { writeMessage(message, Severity.ERROR, t); }
public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException { byte[] bytes = provider.getBytecode(externalPath, internalPath); return new DataInputFullStream(bytes); }
case TYPE_FOLDER: resultSaver.saveFolder(filename); resultSaver.copyFile(pair[0], filename, pair[1]); mapping = DecompilerContext.getBytecodeSourceMapper().getOriginalLinesMapping(); resultSaver.saveClassFile(filename, cl.qualifiedName, entryName, content, mapping); case TYPE_ZIP: resultSaver.saveFolder(archivePath); resultSaver.createArchive(archivePath, filename, manifest); resultSaver.saveDirEntry(archivePath, filename, dirEntry); resultSaver.copyEntry(pair[0], archivePath, filename, pair[1]); if (entryName != null) { String content = decompiledData.getClassContent(cl); resultSaver.saveClassEntry(archivePath, filename, cl.qualifiedName, entryName, content); resultSaver.closeArchive(archivePath, filename);
private void renameClass(StructClass cl) { if (!cl.isOwn()) { return; } String classOldFullName = cl.qualifiedName; // TODO: rename packages String clSimpleName = ConverterHelper.getSimpleClassName(classOldFullName); if (helper.toBeRenamed(IIdentifierRenamer.Type.ELEMENT_CLASS, clSimpleName, null, null)) { String classNewFullName; do { String classname = helper.getNextClassName(classOldFullName, ConverterHelper.getSimpleClassName(classOldFullName)); classNewFullName = ConverterHelper.replaceSimpleClassName(classOldFullName, classname); } while (context.getClasses().containsKey(classNewFullName)); interceptor.addName(classOldFullName, classNewFullName); } }
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> customProperties, IFernflowerLogger logger) { Map<String, Object> properties = new HashMap<>(IFernflowerPreferences.DEFAULTS); if (customProperties != null) { properties.putAll(customProperties); } String level = (String)properties.get(IFernflowerPreferences.LOG_LEVEL); if (level != null) { try { logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.US))); } catch (IllegalArgumentException ignore) { } } structContext = new StructContext(saver, this, new LazyLoader(provider)); classProcessor = new ClassesProcessor(structContext); PoolInterceptor interceptor = null; if ("1".equals(properties.get(IFernflowerPreferences.RENAME_ENTITIES))) { helper = loadHelper((String)properties.get(IFernflowerPreferences.USER_RENAMER_CLASS), logger); interceptor = new PoolInterceptor(); converter = new IdentifierConverter(structContext, helper, interceptor); } else { helper = null; converter = null; } DecompilerContext context = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor); DecompilerContext.setCurrentContext(context); }
defaults.put(VERIFY_ANONYMOUS_CLASSES, "0"); defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name()); defaults.put(MAX_PROCESSING_METHOD, "0"); defaults.put(RENAME_ENTITIES, "0");
private static void doTest(Type elementType, String className, String element, String descriptor, boolean shallBeRenamed) { boolean result = new ConverterHelper().toBeRenamed(elementType, className, element, descriptor); String assertionMessage = shallBeRenamed ? "Identifier { %s, %s, %s, %s } shall be renamed" : "Identifier { %s, %s, %s, %s } shall not be renamed"; assertTrue(String.format(assertionMessage, elementType.toString(), className, element, descriptor), result == shallBeRenamed); } }
private boolean checkEntry(String entryName, String file) { Set<String> set = mapArchiveEntries.computeIfAbsent(file, k -> new HashSet<>()); boolean added = set.add(entryName); if (!added) { String message = "Zip entry " + entryName + " already exists in " + file; DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); } return added; }
private static IIdentifierRenamer loadHelper(String className, IFernflowerLogger logger) { if (className != null) { try { Class<?> renamerClass = Fernflower.class.getClassLoader().loadClass(className); return (IIdentifierRenamer) renamerClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { logger.writeMessage("Cannot load renamer '" + className + "'", IFernflowerLogger.Severity.WARN, e); } } return new ConverterHelper(); }
@Override public void closeArchive(String path, String archiveName) { String file = new File(getAbsolutePath(path), archiveName).getPath(); try { mapArchiveEntries.remove(file); mapArchiveStreams.remove(file).close(); } catch (IOException ex) { DecompilerContext.getLogger().writeMessage("Cannot close " + file, IFernflowerLogger.Severity.WARN); } } }
@Override public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) { File file = new File(getAbsolutePath(path), entryName); try (Writer out = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) { out.write(content); } catch (IOException ex) { DecompilerContext.getLogger().writeMessage("Cannot write class file " + file, ex); } }
@Override public void copyFile(String source, String path, String entryName) { try { InterpreterUtil.copyFile(new File(source), new File(getAbsolutePath(path), entryName)); } catch (IOException ex) { DecompilerContext.getLogger().writeMessage("Cannot copy " + source + " to " + entryName, ex); } }
@Override public void createArchive(String path, String archiveName, Manifest manifest) { File file = new File(getAbsolutePath(path), archiveName); try { if (!(file.createNewFile() || file.isFile())) { throw new IOException("Cannot create file " + file); } FileOutputStream fileStream = new FileOutputStream(file); ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream); mapArchiveStreams.put(file.getPath(), zipStream); } catch (IOException ex) { DecompilerContext.getLogger().writeMessage("Cannot create archive " + file, ex); } }
@Override public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) { String file = new File(getAbsolutePath(path), archiveName).getPath(); if (!checkEntry(entryName, file)) { return; } try { ZipOutputStream out = mapArchiveStreams.get(file); out.putNextEntry(new ZipEntry(entryName)); if (content != null) { out.write(content.getBytes(StandardCharsets.UTF_8)); } } catch (IOException ex) { String message = "Cannot write entry " + entryName + " to " + file; DecompilerContext.getLogger().writeMessage(message, ex); } }
public static GenericFieldDescriptor parseFieldSignature(String signature) { try { return new GenericFieldDescriptor(new GenericType(signature)); } catch (RuntimeException e) { DecompilerContext.getLogger().writeMessage("Invalid signature: " + signature, IFernflowerLogger.Severity.WARN); return null; } }
@Override public void copyEntry(String source, String path, String archiveName, String entryName) { String file = new File(getAbsolutePath(path), archiveName).getPath(); if (!checkEntry(entryName, file)) { return; } try (ZipFile srcArchive = new ZipFile(new File(source))) { ZipEntry entry = srcArchive.getEntry(entryName); if (entry != null) { try (InputStream in = srcArchive.getInputStream(entry)) { ZipOutputStream out = mapArchiveStreams.get(file); out.putNextEntry(new ZipEntry(entryName)); InterpreterUtil.copyStream(in, out); } } } catch (IOException ex) { String message = "Cannot copy entry " + entryName + " from " + source + " to " + file; DecompilerContext.getLogger().writeMessage(message, ex); } }
public static GenericClassDescriptor parseClassSignature(String signature) { String original = signature; try { GenericClassDescriptor descriptor = new GenericClassDescriptor(); signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); String superCl = GenericType.getNextType(signature); descriptor.superclass = new GenericType(superCl); signature = signature.substring(superCl.length()); while (signature.length() > 0) { String superIf = GenericType.getNextType(signature); descriptor.superinterfaces.add(new GenericType(superIf)); signature = signature.substring(superIf.length()); } return descriptor; } catch (RuntimeException e) { DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN); return null; } }
private static boolean splitExceptionRange(ExceptionRangeCFG range, Set<BasicBlock> setEntries, ControlFlowGraph graph, GenericDominatorEngine engine) { for (BasicBlock entry : setEntries) { List<BasicBlock> lstSubrangeBlocks = getReachableBlocksRestricted(entry, range, engine); if (!lstSubrangeBlocks.isEmpty() && lstSubrangeBlocks.size() < range.getProtectedRange().size()) { // add new range ExceptionRangeCFG subRange = new ExceptionRangeCFG(lstSubrangeBlocks, range.getHandler(), range.getExceptionTypes()); graph.getExceptions().add(subRange); // shrink the original range range.getProtectedRange().removeAll(lstSubrangeBlocks); return true; } else { // should not happen DecompilerContext.getLogger().writeMessage("Inconsistency found while splitting protected range", IFernflowerLogger.Severity.WARN); } } return false; }
@Override public String getClassContent(StructClass cl) { try { TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE); buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString()); classProcessor.writeClass(cl, buffer); return buffer.toString(); } catch (Throwable t) { DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", t); return null; } } }