blob: 80c6a1d4352b71ec3d6b8a85b46b65ec46a491ab [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.ArchiveResourceProviderUtils;
import com.android.tools.r8.utils.ArchiveResourceProviderUtils.ProgramResourceFactory;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.OneShotByteResource;
import com.android.tools.r8.utils.ZipUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.zip.ZipFile;
/** Provider for archives of program resources. */
@KeepForApi
public class ArchiveProgramResourceProvider implements ProgramResourceProvider {
@KeepForApi
public interface ZipFileSupplier {
ZipFile open() throws IOException;
}
public static boolean includeClassFileEntries(String entry) {
return ZipUtils.isClassFile(entry);
}
public static boolean includeDexEntries(String entry) {
return ZipUtils.isDexFile(entry);
}
public static boolean includeClassFileOrDexEntries(String entry) {
return ZipUtils.isClassFile(entry) || ZipUtils.isDexFile(entry);
}
private final Origin origin;
private final ZipFileSupplier supplier;
private final Predicate<String> include;
public static ArchiveProgramResourceProvider fromArchive(Path archive) {
return fromArchive(archive, ArchiveProgramResourceProvider::includeClassFileOrDexEntries);
}
public static ArchiveProgramResourceProvider fromArchive(
Path archive, Predicate<String> include) {
return fromSupplier(
new PathOrigin(archive),
() -> FileUtils.createZipFile(archive.toFile(), StandardCharsets.UTF_8),
include);
}
public static ArchiveProgramResourceProvider fromSupplier(
Origin origin, ZipFileSupplier supplier) {
return fromSupplier(
origin, supplier, ArchiveProgramResourceProvider::includeClassFileOrDexEntries);
}
public static ArchiveProgramResourceProvider fromSupplier(
Origin origin, ZipFileSupplier supplier, Predicate<String> include) {
return new ArchiveProgramResourceProvider(origin, supplier, include);
}
private ArchiveProgramResourceProvider(
Origin origin, ZipFileSupplier supplier, Predicate<String> include) {
assert origin != null;
assert supplier != null;
assert include != null;
this.origin = origin;
this.supplier = supplier;
this.include = include;
}
@Deprecated
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
List<ProgramResource> programResources = new ArrayList<>();
internalGetProgramResources(programResources::add, ProgramResource::fromBytes);
return programResources;
}
@Override
public void getProgramResources(Consumer<ProgramResource> consumer) throws ResourceException {
internalGetProgramResources(consumer, OneShotByteResource::create);
}
private void internalGetProgramResources(
Consumer<ProgramResource> consumer, ProgramResourceFactory programResourceFactory)
throws ResourceException {
List<Kind> seenKinds;
try {
seenKinds =
ArchiveResourceProviderUtils.readArchive(
supplier,
origin,
(name, kind) -> include.test(name),
consumer,
programResourceFactory);
} catch (IOException e) {
throw new ResourceException(origin, e);
}
if (seenKinds.size() == 2) {
assert seenKinds.contains(Kind.CF);
assert seenKinds.contains(Kind.DEX);
throw new CompilationError(
"Cannot create android app from an archive containing both DEX and Java-bytecode "
+ "content.",
origin);
}
}
}