/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.util.container;
import org.jd.gui.api.model.Container;
import org.jd.gui.model.container.ContainerEntryComparator;
import org.jd.gui.util.exception.ExceptionUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class JarContainerEntryUtil {
public static Collection<Container.Entry> removeInnerTypeEntries(Collection<Container.Entry> entries) {
HashSet<String> potentialOuterTypePaths = new HashSet<>();
Collection<Container.Entry> filtredSubEntries;
for (Container.Entry e : entries) {
if (!e.isDirectory()) {
String p = e.getPath();
if (p.toLowerCase().endsWith(".class")) {
int lastSeparatorIndex = p.lastIndexOf('/');
int dollarIndex = p.substring(lastSeparatorIndex+1).indexOf('$');
if (dollarIndex != -1) {
potentialOuterTypePaths.add(p.substring(0, lastSeparatorIndex+1+dollarIndex) + ".class");
}
}
}
}
if (potentialOuterTypePaths.size() == 0) {
filtredSubEntries = entries;
} else {
HashSet<String> innerTypePaths = new HashSet<>();
for (Container.Entry e : entries) {
if (!e.isDirectory() && potentialOuterTypePaths.contains(e.getPath())) {
populateInnerTypePaths(innerTypePaths, e);
}
}
filtredSubEntries = new ArrayList<>();
for (Container.Entry e : entries) {
if (!e.isDirectory()) {
String p = e.getPath();
if (p.toLowerCase().endsWith(".class")) {
int indexDollar = p.lastIndexOf('$');
if (indexDollar != -1) {
int indexSeparator = p.lastIndexOf('/');
if (indexDollar > indexSeparator) {
if (innerTypePaths.contains(p)) {
// Inner class found -> Skip
continue;
} else {
populateInnerTypePaths(innerTypePaths, e);
if (innerTypePaths.contains(p)) {
// Inner class found -> Skip
continue;
}
}
}
}
}
}
// Valid path
filtredSubEntries.add(e);
}
}
List<Container.Entry> list = new ArrayList<>(filtredSubEntries);
list.sort(ContainerEntryComparator.COMPARATOR);
return list;
}
protected static void populateInnerTypePaths(final HashSet<String> innerTypePaths, Container.Entry entry) {
try (InputStream is = entry.getInputStream()) {
ClassReader classReader = new ClassReader(is);
String p = entry.getPath();
final String prefixPath = p.substring(0, p.length() - classReader.getClassName().length() - 6);
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM7) {
public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) {
innerTypePaths.add(prefixPath + name + ".class");
}
};
classReader.accept(classVisitor, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
} catch (Exception e) {
assert ExceptionUtil.printStackTrace(e);
}
}
}