From daefa7f4eac02f05ef63f176aba177e6e466fa12 Mon Sep 17 00:00:00 2001 From: Graham Date: Sat, 2 May 2020 22:06:14 +0100 Subject: [PATCH] Remove streams from LibraryReader and LibraryWriter constructors This will provide a few benefits: - Some of the implementations can now be turned into objects, reducing memory allocation. - A single Resource.compressLibrary() method will be able to take a LibraryWriter, reducing duplication. Signed-off-by: Graham --- .../dev/openrs2/asm/io/JarLibraryReader.kt | 23 +++++---- .../dev/openrs2/asm/io/JarLibraryWriter.kt | 48 +++++++++++-------- .../dev/openrs2/asm/io/Js5LibraryWriter.kt | 4 +- .../java/dev/openrs2/asm/io/LibraryReader.kt | 3 +- .../java/dev/openrs2/asm/io/LibraryWriter.kt | 3 +- .../asm/io/ManifestJarLibraryWriter.kt | 12 +++++ .../openrs2/asm/io/Pack200LibraryReader.kt | 9 ++-- .../openrs2/asm/io/Pack200LibraryWriter.kt | 9 ++-- .../openrs2/asm/io/SignedJarLibraryWriter.kt | 11 ++--- .../main/java/dev/openrs2/bundler/Bundler.kt | 20 ++++---- .../main/java/dev/openrs2/bundler/Resource.kt | 10 ++-- .../java/dev/openrs2/deob/Deobfuscator.kt | 12 ++--- 12 files changed, 89 insertions(+), 75 deletions(-) create mode 100644 asm/src/main/java/dev/openrs2/asm/io/ManifestJarLibraryWriter.kt diff --git a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt index 187e53d9b8..9566c63b5c 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt @@ -5,22 +5,25 @@ import dev.openrs2.asm.classpath.Library import dev.openrs2.util.io.entries import org.objectweb.asm.ClassReader import org.objectweb.asm.tree.ClassNode +import java.io.InputStream import java.util.jar.JarInputStream -class JarLibraryReader(private val input: JarInputStream) : LibraryReader { - override fun read(): Library { +class JarLibraryReader : LibraryReader { + override fun read(input: InputStream): Library { val library = Library() - for (entry in input.entries) { - if (!entry.name.endsWith(CLASS_SUFFIX)) { - continue - } + JarInputStream(input).use { jar -> + for (entry in jar.entries) { + if (!entry.name.endsWith(CLASS_SUFFIX)) { + continue + } - val clazz = ClassNode() - val reader = ClassReader(input) - reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) + val clazz = ClassNode() + val reader = ClassReader(jar) + reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) - library.add(clazz) + library.add(clazz) + } } return library diff --git a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt index a3a4a91acc..b1f91114ec 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt @@ -5,39 +5,47 @@ import dev.openrs2.asm.NopClassVisitor import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.StackFrameClassWriter +import dev.openrs2.util.io.DeterministicJarOutputStream import org.objectweb.asm.ClassWriter import org.objectweb.asm.Opcodes import org.objectweb.asm.util.CheckClassAdapter +import java.io.OutputStream import java.util.jar.JarEntry import java.util.jar.JarOutputStream -class JarLibraryWriter(private val output: JarOutputStream) : LibraryWriter { - override fun write(classPath: ClassPath, library: Library) { - for (clazz in library) { - val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) { - StackFrameClassWriter(classPath) - } else { - ClassWriter(ClassWriter.COMPUTE_MAXS) - } +open class JarLibraryWriter : LibraryWriter { + override fun write(output: OutputStream, classPath: ClassPath, library: Library) { + createJarOutputStream(output).use { jar -> + for (clazz in library) { + val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) { + StackFrameClassWriter(classPath) + } else { + ClassWriter(ClassWriter.COMPUTE_MAXS) + } - clazz.accept(writer) + clazz.accept(writer) - output.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) - output.write(writer.toByteArray()) + jar.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) + jar.write(writer.toByteArray()) - /* - * XXX(gpe): CheckClassAdapter breaks the Label offset - * calculation in the OriginalPcTable's write method, so we do - * a second pass without any attributes to check the class, - * feeding the callbacks into a no-op visitor. - */ - for (method in clazz.methods) { - method.attrs?.clear() + /* + * XXX(gpe): CheckClassAdapter breaks the Label offset + * calculation in the OriginalPcTable's write method, so we do + * a second pass without any attributes to check the class, + * feeding the callbacks into a no-op visitor. + */ + for (method in clazz.methods) { + method.attrs?.clear() + } + clazz.accept(CheckClassAdapter(NopClassVisitor, true)) } - clazz.accept(CheckClassAdapter(NopClassVisitor, true)) } } + protected open fun createJarOutputStream(output: OutputStream): JarOutputStream { + return DeterministicJarOutputStream(output) + } + private companion object { private const val CLASS_SUFFIX = ".class" } diff --git a/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt index 6a70e51167..5e49969e9b 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt @@ -4,8 +4,8 @@ import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library import java.io.OutputStream -class Js5LibraryWriter(private val output: OutputStream) : LibraryWriter { - override fun write(classPath: ClassPath, library: Library) { +class Js5LibraryWriter : LibraryWriter { + override fun write(output: OutputStream, classPath: ClassPath, library: Library) { // TODO(gpe): implement } } diff --git a/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt index 05b9638bcc..444c462448 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt @@ -1,7 +1,8 @@ package dev.openrs2.asm.io import dev.openrs2.asm.classpath.Library +import java.io.InputStream interface LibraryReader { - fun read(): Library + fun read(input: InputStream): Library } diff --git a/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt index b04ee79f34..0b15095059 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt @@ -2,7 +2,8 @@ package dev.openrs2.asm.io import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library +import java.io.OutputStream interface LibraryWriter { - fun write(classPath: ClassPath, library: Library) + fun write(output: OutputStream, classPath: ClassPath, library: Library) } diff --git a/asm/src/main/java/dev/openrs2/asm/io/ManifestJarLibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/ManifestJarLibraryWriter.kt new file mode 100644 index 0000000000..98676d1d7d --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/ManifestJarLibraryWriter.kt @@ -0,0 +1,12 @@ +package dev.openrs2.asm.io + +import dev.openrs2.util.io.DeterministicJarOutputStream +import java.io.OutputStream +import java.util.jar.JarOutputStream +import java.util.jar.Manifest + +class ManifestJarLibraryWriter(private val manifest: Manifest) : JarLibraryWriter() { + override fun createJarOutputStream(output: OutputStream): JarOutputStream { + return DeterministicJarOutputStream(output, manifest) + } +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt index 477c2e2804..b0504beb31 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt @@ -4,12 +4,11 @@ import dev.openrs2.asm.classpath.Library import dev.openrs2.compress.gzip.Gzip import java.io.InputStream import java.nio.file.Files -import java.util.jar.JarInputStream import java.util.jar.JarOutputStream import java.util.jar.Pack200 -class Pack200LibraryReader(private val input: InputStream) : LibraryReader { - override fun read(): Library { +class Pack200LibraryReader : LibraryReader { + override fun read(input: InputStream): Library { val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) try { Gzip.createHeaderlessInputStream(input).use { gzipInput -> @@ -18,8 +17,8 @@ class Pack200LibraryReader(private val input: InputStream) : LibraryReader { } } - return JarInputStream(Files.newInputStream(temp)).use { tempInput -> - JarLibraryReader(tempInput).read() + return Files.newInputStream(temp).use { tempInput -> + JarLibraryReader().read(tempInput) } } finally { Files.deleteIfExists(temp) diff --git a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt index a8dbea86ef..cbf89d923b 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt @@ -3,18 +3,17 @@ package dev.openrs2.asm.io import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library import dev.openrs2.compress.gzip.Gzip -import dev.openrs2.util.io.DeterministicJarOutputStream import java.io.OutputStream import java.nio.file.Files import java.util.jar.JarInputStream import java.util.jar.Pack200 -class Pack200LibraryWriter(private val output: OutputStream) : LibraryWriter { - override fun write(classPath: ClassPath, library: Library) { +class Pack200LibraryWriter : LibraryWriter { + override fun write(output: OutputStream, classPath: ClassPath, library: Library) { val tempJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) try { - DeterministicJarOutputStream(Files.newOutputStream(tempJar)).use { tempOutput -> - JarLibraryWriter(tempOutput).write(classPath, library) + Files.newOutputStream(tempJar).use { tempOutput -> + JarLibraryWriter().write(tempOutput, classPath, library) } JarInputStream(Files.newInputStream(tempJar)).use { input -> diff --git a/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt index b6ed65072e..37da5d3e1a 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt @@ -12,21 +12,20 @@ import java.util.jar.JarInputStream import java.util.jar.Manifest class SignedJarLibraryWriter( - private val output: OutputStream, private val manifest: Manifest, private val keyStore: Pkcs12KeyStore ) : LibraryWriter { - override fun write(classPath: ClassPath, library: Library) { + override fun write(output: OutputStream, classPath: ClassPath, library: Library) { val unsignedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) try { - DeterministicJarOutputStream(Files.newOutputStream(unsignedJar), manifest).use { unsignedOutput -> - JarLibraryWriter(unsignedOutput).write(classPath, library) + Files.newOutputStream(unsignedJar).use { unsignedOutput -> + ManifestJarLibraryWriter(manifest).write(unsignedOutput, classPath, library) } val signedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) try { keyStore.signJar(unsignedJar, signedJar) - repack(signedJar) + repack(signedJar, output) } finally { Files.deleteIfExists(signedJar) } @@ -35,7 +34,7 @@ class SignedJarLibraryWriter( } } - private fun repack(signedJar: Path) { + private fun repack(signedJar: Path, output: OutputStream) { JarInputStream(Files.newInputStream(signedJar)).use { input -> DeterministicJarOutputStream(output, input.manifest).use { output -> for (entry in input.entries) { diff --git a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt index 998da1e712..a23f06bc50 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt @@ -3,20 +3,18 @@ package dev.openrs2.bundler import com.github.michaelbull.logging.InlineLogger import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library -import dev.openrs2.asm.transform.Transformer import dev.openrs2.asm.io.JarLibraryReader -import dev.openrs2.asm.io.JarLibraryWriter +import dev.openrs2.asm.io.ManifestJarLibraryWriter import dev.openrs2.asm.io.Pack200LibraryReader import dev.openrs2.asm.io.SignedJarLibraryWriter +import dev.openrs2.asm.transform.Transformer import dev.openrs2.bundler.transform.ResourceTransformer import dev.openrs2.conf.Config import dev.openrs2.crypto.Pkcs12KeyStore -import dev.openrs2.util.io.DeterministicJarOutputStream import java.nio.file.Files import java.nio.file.Path import java.util.jar.Attributes import java.util.jar.Attributes.Name.MANIFEST_VERSION -import java.util.jar.JarInputStream import java.util.jar.Manifest import javax.inject.Inject import javax.inject.Singleton @@ -134,8 +132,8 @@ class Bundler @Inject constructor( private fun readJar(path: Path): Library { logger.info { "Reading jar $path" } - return JarInputStream(Files.newInputStream(path)).use { input -> - JarLibraryReader(input).read() + return Files.newInputStream(path).use { input -> + JarLibraryReader().read(input) } } @@ -143,23 +141,23 @@ class Bundler @Inject constructor( logger.info { "Reading pack $path" } return Files.newInputStream(path).use { input -> - Pack200LibraryReader(input).read() + Pack200LibraryReader().read(input) } } private fun writeJar(classPath: ClassPath, library: Library, path: Path) { logger.info { "Writing jar $path" } - DeterministicJarOutputStream(Files.newOutputStream(path), unsignedManifest).use { output -> - JarLibraryWriter(output).write(classPath, library) + Files.newOutputStream(path).use { output -> + ManifestJarLibraryWriter(unsignedManifest).write(output, classPath, library) } } private fun writeSignedJar(classPath: ClassPath, library: Library, path: Path, keyStore: Pkcs12KeyStore) { logger.info { "Writing signed jar $path" } - Files.newOutputStream(path).use { - SignedJarLibraryWriter(it, signedManifest, keyStore).write(classPath, library) + Files.newOutputStream(path).use { output -> + SignedJarLibraryWriter(signedManifest, keyStore).write(output, classPath, library) } } diff --git a/bundler/src/main/java/dev/openrs2/bundler/Resource.kt b/bundler/src/main/java/dev/openrs2/bundler/Resource.kt index d49a3b9453..515e087b80 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Resource.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Resource.kt @@ -6,7 +6,6 @@ import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.io.JarLibraryWriter import dev.openrs2.asm.io.Js5LibraryWriter import dev.openrs2.asm.io.Pack200LibraryWriter -import dev.openrs2.util.io.DeterministicJarOutputStream import java.io.ByteArrayOutputStream import java.nio.file.Files import java.nio.file.Path @@ -71,24 +70,21 @@ class Resource( fun compressJar(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { output -> - DeterministicJarOutputStream(output).use { jarOutput -> - JarLibraryWriter(jarOutput).write(classPath, library) - } - + JarLibraryWriter().write(output, classPath, library) return compress(source, destination, output.toByteArray()) } } fun compressPack(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { output -> - Pack200LibraryWriter(output).write(classPath, library) + Pack200LibraryWriter().write(output, classPath, library) return compress(source, destination, output.toByteArray()) } } fun compressJs5(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { output -> - Js5LibraryWriter(output).write(classPath, library) + Js5LibraryWriter().write(output, classPath, library) return compress(source, destination, output.toByteArray()) } } diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt index 4af984b389..8d0e115994 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt @@ -8,10 +8,8 @@ import dev.openrs2.asm.io.JarLibraryWriter import dev.openrs2.asm.io.Pack200LibraryReader import dev.openrs2.asm.transform.Transformer import dev.openrs2.deob.remap.PrefixRemapper -import dev.openrs2.util.io.DeterministicJarOutputStream import java.nio.file.Files import java.nio.file.Path -import java.util.jar.JarInputStream import javax.inject.Inject import javax.inject.Singleton @@ -124,8 +122,8 @@ class Deobfuscator @Inject constructor( private fun readJar(path: Path): Library { logger.info { "Reading jar $path" } - return JarInputStream(Files.newInputStream(path)).use { input -> - JarLibraryReader(input).read() + return Files.newInputStream(path).use { input -> + JarLibraryReader().read(input) } } @@ -133,15 +131,15 @@ class Deobfuscator @Inject constructor( logger.info { "Reading pack $path" } return Files.newInputStream(path).use { input -> - Pack200LibraryReader(input).read() + Pack200LibraryReader().read(input) } } private fun writeJar(classPath: ClassPath, library: Library, path: Path) { logger.info { "Writing jar $path" } - DeterministicJarOutputStream(Files.newOutputStream(path)).use { output -> - JarLibraryWriter(output).write(classPath, library) + Files.newOutputStream(path).use { output -> + JarLibraryWriter().write(output, classPath, library) } }