| // Copyright (c) 2023, 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 com.android.tools.r8.DiagnosticsHandler; |
| import com.android.tools.r8.PartitionMapConsumer; |
| import com.android.tools.r8.retrace.MappingPartition; |
| import com.android.tools.r8.retrace.MappingPartitionMetadata; |
| import com.android.tools.r8.retrace.PartitionMappingSupplier; |
| import com.android.tools.r8.retrace.RetracePartitionException; |
| import com.android.tools.r8.utils.ZipUtils.ZipBuilder; |
| import com.google.common.io.ByteStreams; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| |
| public class PartitionMapZipContainer { |
| |
| private static final byte[] EMPTY_RESULT = new byte[0]; |
| private static final String METADATA_NAME = "METADATA"; |
| |
| public static PartitionMappingSupplier createPartitionMapZipContainerSupplier(Path path) |
| throws Exception { |
| ZipFile zipFile = new ZipFile(path.toFile()); |
| byte[] metadata = |
| ByteStreams.toByteArray(zipFile.getInputStream(zipFile.getEntry(METADATA_NAME))); |
| return PartitionMappingSupplier.builder() |
| .setMetadata(metadata) |
| .setMappingPartitionFromKeySupplier( |
| key -> { |
| try { |
| ZipEntry entry = zipFile.getEntry(key); |
| return entry == null |
| ? EMPTY_RESULT |
| : ByteStreams.toByteArray(zipFile.getInputStream(entry)); |
| } catch (IOException e) { |
| throw new RetracePartitionException(e); |
| } |
| }) |
| .setFinishedPartitionMappingCallback( |
| diagnosticsHandler -> { |
| try { |
| zipFile.close(); |
| } catch (IOException e) { |
| throw new RetracePartitionException(e); |
| } |
| }) |
| .build(); |
| } |
| |
| public static PartitionMapConsumer createPartitionMapZipContainerConsumer(Path path) { |
| return new Consumer(path); |
| } |
| |
| public static class Consumer implements PartitionMapConsumer { |
| |
| private final Box<ZipBuilder> zipBuilderBox = new Box<>(); |
| private final Path path; |
| |
| private Consumer(Path path) { |
| this.path = path; |
| } |
| |
| @Override |
| public void acceptMappingPartition(MappingPartition mappingPartition) { |
| try { |
| zipBuilderBox |
| .computeIfAbsentThrowing(() -> ZipBuilder.builder(path)) |
| .addBytes(mappingPartition.getKey(), mappingPartition.getPayload()); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public void acceptMappingPartitionMetadata(MappingPartitionMetadata mappingPartitionMetadata) { |
| try { |
| zipBuilderBox |
| .computeIfAbsentThrowing(() -> ZipBuilder.builder(path)) |
| .addBytes(METADATA_NAME, mappingPartitionMetadata.getBytes()); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public void finished(DiagnosticsHandler handler) { |
| try { |
| zipBuilderBox.computeIfAbsentThrowing(() -> ZipBuilder.builder(path)).build(); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| } |