| // Copyright (c) 2019, 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.utils; |
| |
| import static com.android.tools.r8.utils.FileUtils.isArchive; |
| |
| import com.android.tools.r8.DataResourceProvider; |
| import com.android.tools.r8.ProgramResource; |
| import com.android.tools.r8.ProgramResource.Kind; |
| import com.android.tools.r8.ProgramResourceProvider; |
| import com.android.tools.r8.ResourceException; |
| import com.android.tools.r8.errors.CompilationError; |
| import com.android.tools.r8.origin.ArchiveEntryOrigin; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.origin.PathOrigin; |
| import com.google.common.io.ByteStreams; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Path; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipException; |
| import java.util.zip.ZipFile; |
| import java.util.zip.ZipInputStream; |
| |
| public class AarArchiveResourceProvider implements ProgramResourceProvider { |
| |
| private final Origin origin; |
| private final Path archive; |
| |
| public static AarArchiveResourceProvider fromArchive(Path archive) { |
| return new AarArchiveResourceProvider(archive); |
| } |
| |
| AarArchiveResourceProvider(Path archive) { |
| assert isArchive(archive); |
| origin = new ArchiveEntryOrigin("classes.jar", new PathOrigin(archive)); |
| this.archive = archive; |
| } |
| |
| private List<ProgramResource> readClassesJar(ZipInputStream stream) throws IOException { |
| ZipEntry entry; |
| List<ProgramResource> resources = new ArrayList<>(); |
| while (null != (entry = stream.getNextEntry())) { |
| String name = entry.getName(); |
| if (ZipUtils.isClassFile(name)) { |
| Origin entryOrigin = new ArchiveEntryOrigin(name, origin); |
| String descriptor = DescriptorUtils.guessTypeDescriptor(name); |
| ProgramResource resource = |
| OneShotByteResource.create( |
| Kind.CF, |
| entryOrigin, |
| ByteStreams.toByteArray(stream), |
| Collections.singleton(descriptor)); |
| resources.add(resource); |
| } |
| } |
| return resources; |
| } |
| |
| private List<ProgramResource> readArchive() throws IOException { |
| List<ProgramResource> classResources = null; |
| try (ZipFile zipFile = FileUtils.createZipFile(archive.toFile(), StandardCharsets.UTF_8)) { |
| final Enumeration<? extends ZipEntry> entries = zipFile.entries(); |
| while (entries.hasMoreElements()) { |
| ZipEntry entry = entries.nextElement(); |
| try (InputStream stream = zipFile.getInputStream(entry)) { |
| String name = entry.getName(); |
| if (name.equals("classes.jar")) { |
| try (ZipInputStream classesStream = new ZipInputStream(stream)) { |
| classResources = readClassesJar(classesStream); |
| } |
| break; |
| } |
| } |
| } |
| } catch (ZipException e) { |
| throw new CompilationError("Zip error while reading '" + archive + "': " + e.getMessage(), e); |
| } |
| return classResources == null ? Collections.emptyList() : classResources; |
| } |
| |
| @Override |
| public Collection<ProgramResource> getProgramResources() throws ResourceException { |
| try { |
| return readArchive(); |
| } catch (IOException e) { |
| throw new ResourceException(origin, e); |
| } |
| } |
| |
| @Override |
| public DataResourceProvider getDataResourceProvider() { |
| return null; |
| } |
| } |