| // Copyright (c) 2018, 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 static com.android.tools.r8.utils.internal.StringUtils.UNIX_LINE_SEPARATOR; | |
| import com.android.tools.r8.keepanno.annotations.KeepForApi; | |
| import com.android.tools.r8.origin.ArchiveEntryOrigin; | |
| import com.android.tools.r8.origin.Origin; | |
| import com.android.tools.r8.origin.PathOrigin; | |
| import java.io.ByteArrayInputStream; | |
| import java.io.File; | |
| import java.io.FileInputStream; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.zip.ZipEntry; | |
| import java.util.zip.ZipFile; | |
| @KeepForApi | |
| public interface DataEntryResource extends DataResource { | |
| /** Get the bytes of the data entry resource. */ | |
| InputStream getByteStream() throws ResourceException; | |
| @SuppressWarnings("DefaultCharset") | |
| static DataEntryResource fromBytes(byte[] bytes, String name, Origin origin) { | |
| return new ByteDataEntryResource(bytes, name, origin); | |
| } | |
| @SuppressWarnings("DefaultCharset") | |
| static DataEntryResource fromString(String name, Origin origin, String... lines) { | |
| StringBuilder sb = new StringBuilder(); | |
| for (String line : lines) { | |
| sb.append(line); | |
| sb.append(UNIX_LINE_SEPARATOR); | |
| } | |
| return new ByteDataEntryResource(sb.toString().getBytes(), name, origin); | |
| } | |
| static DataEntryResource fromFile(Path dir, Path file) { | |
| return new LocalDataEntryResource( | |
| dir.resolve(file).toFile(), file.toString().replace(File.separatorChar, SEPARATOR)); | |
| } | |
| static DataEntryResource fromZip(ZipFile zip, ZipEntry entry) { | |
| return new ZipDataEntryResource(zip, entry); | |
| } | |
| static DataEntryResource fromZip(ZipFile zip, ZipEntry entry, Origin zipOrigin) { | |
| return new ZipDataEntryResource(zip, entry, zipOrigin); | |
| } | |
| default DataEntryResource withName(String name) { | |
| return new NestedDataEntryResource(name, null, this); | |
| } | |
| class ByteDataEntryResource implements DataEntryResource { | |
| private final byte[] bytes; | |
| private final String name; | |
| private final Origin origin; | |
| public ByteDataEntryResource(byte[] bytes, String name, Origin origin) { | |
| this.bytes = bytes; | |
| this.name = name; | |
| this.origin = origin; | |
| } | |
| @Override | |
| public InputStream getByteStream() { | |
| return new ByteArrayInputStream(bytes); | |
| } | |
| @Override | |
| public String getName() { | |
| return name; | |
| } | |
| @Override | |
| public Origin getOrigin() { | |
| return origin; | |
| } | |
| } | |
| class ZipDataEntryResource implements DataEntryResource { | |
| private final ZipFile zip; | |
| private final ZipEntry entry; | |
| private final Origin zipOrigin; | |
| private ZipDataEntryResource(ZipFile zip, ZipEntry entry) { | |
| this(zip, entry, new PathOrigin(Paths.get(zip.getName()))); | |
| } | |
| private ZipDataEntryResource(ZipFile zip, ZipEntry entry, Origin zipOrigin) { | |
| assert zip != null; | |
| assert entry != null; | |
| this.zip = zip; | |
| this.entry = entry; | |
| this.zipOrigin = zipOrigin; | |
| } | |
| @Override | |
| public Origin getOrigin() { | |
| return new ArchiveEntryOrigin(entry.getName(), zipOrigin); | |
| } | |
| @Override | |
| public String getName() { | |
| return entry.getName(); | |
| } | |
| @Override | |
| public InputStream getByteStream() throws ResourceException { | |
| try { | |
| return zip.getInputStream(entry); | |
| } catch (IOException e) { | |
| throw new ResourceException(getOrigin(), e); | |
| } | |
| } | |
| } | |
| class LocalDataEntryResource implements DataEntryResource { | |
| private final File file; | |
| private final String relativePath; | |
| private LocalDataEntryResource(File file, String relativePath) { | |
| assert file != null; | |
| assert relativePath != null; | |
| this.file = file; | |
| this.relativePath = relativePath; | |
| } | |
| @Override | |
| public Origin getOrigin() { | |
| return new PathOrigin(file.toPath()); | |
| } | |
| @Override | |
| public String getName() { | |
| return relativePath; | |
| } | |
| @Override | |
| public InputStream getByteStream() throws ResourceException { | |
| try { | |
| return new FileInputStream(file); | |
| } catch (IOException e) { | |
| throw new ResourceException(getOrigin(), e); | |
| } | |
| } | |
| } | |
| /** | |
| * A resource that has the same contents as another resource, but with a different name or origin. | |
| */ | |
| class NestedDataEntryResource implements DataEntryResource { | |
| private final String name; | |
| private final Origin origin; | |
| private final DataEntryResource resource; | |
| public NestedDataEntryResource(String name, Origin origin, DataEntryResource resource) { | |
| this.name = name; | |
| this.origin = origin; | |
| this.resource = resource; | |
| } | |
| @Override | |
| public InputStream getByteStream() throws ResourceException { | |
| return resource.getByteStream(); | |
| } | |
| @Override | |
| public String getName() { | |
| return name != null ? name : resource.getName(); | |
| } | |
| @Override | |
| public Origin getOrigin() { | |
| return origin != null ? origin : resource.getOrigin(); | |
| } | |
| } | |
| } |