|  | // 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.graph; | 
|  |  | 
|  | import com.android.tools.r8.dex.Marker; | 
|  | import com.android.tools.r8.naming.ClassNameMapper; | 
|  | import com.android.tools.r8.utils.DescriptorUtils; | 
|  | import com.android.tools.r8.utils.InternalOptions; | 
|  | import java.io.File; | 
|  | import java.io.IOException; | 
|  | import java.io.PrintStream; | 
|  | import java.nio.file.Files; | 
|  | import java.nio.file.Path; | 
|  | import java.util.Collection; | 
|  | import java.util.function.Consumer; | 
|  |  | 
|  | public abstract class DexByteCodeWriter { | 
|  |  | 
|  | public interface OutputStreamProvider { | 
|  | PrintStream get(DexClass clazz) throws IOException; | 
|  | } | 
|  |  | 
|  | final DexApplication application; | 
|  | final InternalOptions options; | 
|  |  | 
|  | DexByteCodeWriter(DexApplication application, | 
|  | InternalOptions options) { | 
|  | this.application = application; | 
|  | this.options = options; | 
|  | } | 
|  |  | 
|  | private static void ensureParentExists(Path path) throws IOException { | 
|  | Path parent = path.getParent(); | 
|  | if (parent != null) { | 
|  | Files.createDirectories(parent); | 
|  | } | 
|  | } | 
|  |  | 
|  | public static OutputStreamProvider oneFilePerClass( | 
|  | ClassNameMapper classNameMapper, Path path, String fileEnding) { | 
|  | return (clazz) -> { | 
|  | String className = | 
|  | DescriptorUtils.descriptorToJavaType(clazz.type.toDescriptorString(), classNameMapper); | 
|  | Path classOutput = path.resolve(className.replace('.', File.separatorChar) + fileEnding); | 
|  | ensureParentExists(classOutput); | 
|  | return new PrintStream(Files.newOutputStream(classOutput)); | 
|  | }; | 
|  | } | 
|  |  | 
|  | public void writeMarkers(PrintStream output) { | 
|  | Collection<Marker> markers = application.dexItemFactory.extractMarkers(); | 
|  | System.out.println("Number of markers: " + markers.size()); | 
|  | for (Marker marker : markers) { | 
|  | output.println(marker.toString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | public void write(PrintStream output) throws IOException { | 
|  | writeMarkers(output); | 
|  | write(x -> output, x -> {}); | 
|  | } | 
|  |  | 
|  | public void write(OutputStreamProvider outputStreamProvider, Consumer<PrintStream> closer) | 
|  | throws IOException { | 
|  | Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder(); | 
|  | for (DexProgramClass clazz : classes) { | 
|  | if (anyMethodMatches(clazz)) { | 
|  | PrintStream ps = outputStreamProvider.get(clazz); | 
|  | try { | 
|  | writeClass(clazz, ps); | 
|  | } finally { | 
|  | closer.accept(ps); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private boolean anyMethodMatches(DexClass clazz) { | 
|  | return !options.hasMethodsFilter() | 
|  | || clazz.getMethodCollection().hasMethods(options::methodMatchesFilter); | 
|  | } | 
|  |  | 
|  | private void writeClass(DexProgramClass clazz, PrintStream ps) { | 
|  | writeClassHeader(clazz, ps); | 
|  | writeFieldsHeader(clazz, ps); | 
|  | clazz.forEachField(field -> writeField(field, ps)); | 
|  | writeFieldsFooter(clazz, ps); | 
|  | writeMethodsHeader(clazz, ps); | 
|  | clazz.forEachProgramMethod(method -> writeMethod(method, ps)); | 
|  | writeMethodsFooter(clazz, ps); | 
|  | writeClassFooter(clazz, ps); | 
|  | } | 
|  |  | 
|  | abstract void writeClassHeader(DexProgramClass clazz, PrintStream ps); | 
|  |  | 
|  | void writeFieldsHeader(DexProgramClass clazz, PrintStream ps) { | 
|  | // Do nothing. | 
|  | } | 
|  |  | 
|  | abstract void writeField(DexEncodedField field, PrintStream ps); | 
|  |  | 
|  | void writeFieldsFooter(DexProgramClass clazz, PrintStream ps) { | 
|  | // Do nothing. | 
|  | } | 
|  |  | 
|  | void writeMethodsHeader(DexProgramClass clazz, PrintStream ps) { | 
|  | // Do nothing. | 
|  | } | 
|  |  | 
|  | abstract void writeMethod(ProgramMethod method, PrintStream ps); | 
|  |  | 
|  | void writeMethodsFooter(DexProgramClass clazz, PrintStream ps) { | 
|  | // Do nothing. | 
|  | } | 
|  |  | 
|  | abstract void writeClassFooter(DexProgramClass clazz, PrintStream ps); | 
|  | } |