diff options
Diffstat (limited to 'dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java')
-rw-r--r-- | dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java new file mode 100644 index 00000000..fd654de5 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java @@ -0,0 +1,109 @@ +package org.jf.dexlib2.analysis; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.jf.dexlib2.DexFileFactory; +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.dexbacked.OatFile; +import org.jf.dexlib2.iface.MultiDexContainer; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +public class PathEntryLoader { + Opcodes opcodes; + + public Opcodes getOpcodes() { + return opcodes; + } + + final Set<File> loadedFiles = Sets.newHashSet(); + final List<ClassProvider> classProviders = Lists.newArrayList(); + + public List<ClassProvider> getClassProviders() { + return classProviders; + } + + public PathEntryLoader(Opcodes opcodes) { + this.opcodes = opcodes; + } + + @Nonnull + public List<ClassProvider> getResolvedClassProviders() { + return classProviders; + } + + public void loadEntry(@Nonnull File entryFile, boolean loadOatDependencies) + throws IOException, NoDexException { + if (loadedFiles.contains(entryFile)) { + return; + } + + MultiDexContainer<? extends DexBackedDexFile> container; + try { + container = DexFileFactory.loadDexContainer(entryFile, opcodes); + } catch (DexFileFactory.UnsupportedFileTypeException ex) { + throw new ClassPathResolver.ResolveException(ex); + } + + List<String> entryNames = container.getDexEntryNames(); + + if (entryNames.isEmpty()) { + throw new NoDexException("%s contains no dex file", entryFile); + } + + loadedFiles.add(entryFile); + + for (String entryName : entryNames) { + classProviders.add(new DexClassProvider(container.getEntry(entryName))); + } + + if (loadOatDependencies && container instanceof OatFile) { + List<String> oatDependencies = ((OatFile) container).getBootClassPath(); + if (!oatDependencies.isEmpty()) { + try { + loadOatDependencies(entryFile.getParentFile(), oatDependencies); + } catch (ClassPathResolver.NotFoundException ex) { + throw new ClassPathResolver.ResolveException(ex, "Error while loading oat file %s", entryFile); + } catch (NoDexException ex) { + throw new ClassPathResolver.ResolveException(ex, "Error while loading dependencies for oat file %s", entryFile); + } + } + } + } + + private void loadOatDependencies(@Nonnull File directory, @Nonnull List<String> oatDependencies) + throws IOException, NoDexException, ClassPathResolver.NotFoundException { + // We assume that all oat dependencies are located in the same directory as the oat file + for (String oatDependency : oatDependencies) { + String oatDependencyName = getFilenameForOatDependency(oatDependency); + File file = new File(directory, oatDependencyName); + if (!file.exists()) { + throw new ClassPathResolver.NotFoundException("Cannot find dependency %s in %s", oatDependencyName, directory); + } + + loadEntry(file, false); + } + } + + @Nonnull + private String getFilenameForOatDependency(String oatDependency) { + int index = oatDependency.lastIndexOf('/'); + + String dependencyLeaf = oatDependency.substring(index + 1); + if (dependencyLeaf.endsWith(".art")) { + return dependencyLeaf.substring(0, dependencyLeaf.length() - 4) + ".oat"; + } + return dependencyLeaf; + } + + static class NoDexException extends Exception { + public NoDexException(String message, Object... formatArgs) { + super(String.format(message, formatArgs)); + } + } +}
\ No newline at end of file |