All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.java.decompiler.struct.DirectoryContextSource Maven / Gradle / Ivy

Go to download

Modern Java & JVM language decompiler aiming to be as accurate as possible, with an emphasis on output quality.

The newest version!
// Copyright 2000-2022 JetBrains s.r.o. and ForgeFlower contributors Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;

import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.main.extern.IContextSource;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IResultSaver;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;

public class DirectoryContextSource implements IContextSource {
  @SuppressWarnings("deprecation")
  private final IBytecodeProvider legacyProvider;
  private final File baseDirectory;

  @SuppressWarnings("deprecation")
  public DirectoryContextSource(final IBytecodeProvider legacyProvider, final File baseDirectory) {
    this.legacyProvider = legacyProvider;
    this.baseDirectory = baseDirectory;
  }

  @Override
  public String getName() {
    return "directory " + this.baseDirectory.getAbsolutePath();
  }

  @Override
  public Entries getEntries() {
    final List classes = new ArrayList<>();
    final List directories = new ArrayList<>();
    final List others = new ArrayList<>();
    final List jarChildren = new ArrayList<>();
    this.collectEntries(this.baseDirectory.getAbsolutePath(), this.baseDirectory, classes, directories, others, jarChildren);
    return new Entries(classes, directories, others, jarChildren);
  }

  void collectEntries(
    final String base,
    final File current,
    final List classes,
    final List directories,
    final List others,
    final List jarChildren
  ) {
    final String relativePath = relativize(base, current);
    if (current.isDirectory()) {
      directories.add(relativePath);
      final File[] children = current.listFiles();
      for (final File child : children) {
        collectEntries(base, child, classes, directories, others, jarChildren);
      }
    } else {
      if (relativePath.endsWith(CLASS_SUFFIX)) {
        classes.add(sanitize(relativePath.substring(0, relativePath.length() - CLASS_SUFFIX.length())));
      } else if (relativePath.endsWith(".jar") || relativePath.endsWith(".zip")) {
        final String relativeTo = current.getParentFile().getAbsolutePath().substring(base.length());
        try {
          jarChildren.add(new JarContextSource(this.legacyProvider, current, relativeTo));
        } catch (final IOException ex) {
          final String message = "Invalid archive " + current;
          DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR, ex);
          throw new UncheckedIOException(message, ex);
        }
      } else {
        others.add(sanitize(relativePath));
      }
    }
  }

  private String relativize(final String base, final File current) {
    final String relativePath = current.getAbsolutePath().substring(base.length());
    return relativePath.startsWith("/") || relativePath.startsWith("\\") ? relativePath.substring(1) : relativePath;
  }

  private Entry sanitize(final String path) {
    return Entry.atBase(path.replace(File.separatorChar, '/'));
  }

  @Override
  @SuppressWarnings("deprecation")
  public InputStream getInputStream(String resource) throws IOException {
    final File targetFile = new File(this.baseDirectory, resource);
    if (this.legacyProvider != null) {
      return new ByteArrayInputStream(this.legacyProvider.getBytecode(targetFile.getAbsolutePath(), null));
    } else {
      return new FileInputStream(targetFile);
    }
  }

  @Override
  public IOutputSink createOutputSink(IResultSaver saver) {
    final File base = this.baseDirectory;
    final String basePath = this.baseDirectory.getAbsolutePath();
    return new IOutputSink() {
      @Override
      public void begin() {
        // FIXME: ugly but needs to exist for folder->jar saving to work properly
        if (!(saver instanceof ConsoleDecompiler)) {
          saver.createArchive(basePath, "", null);
        }
        saver.saveFolder("");
      }

      @Override
      public void acceptOther(String path) {
        saver.copyFile(new File(base, path).getAbsolutePath(), "", path);
      }

      @Override
      public void acceptDirectory(String directory) {
        saver.saveFolder(directory);
      }

      @Override
      public void acceptClass(String qualifiedName, String fileName, String content, int[] mapping) {
        saver.saveClassFile("", qualifiedName, fileName, content, mapping);
      }

      @Override
      public void close() throws IOException {
        saver.closeArchive("", base.getName() + ".jar");
      }
    };
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy