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 <gpe@openrs2.dev>
bzip2
Graham 4 years ago
parent 46d8af509c
commit daefa7f4ea
  1. 23
      asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt
  2. 48
      asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt
  3. 4
      asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt
  4. 3
      asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt
  5. 3
      asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt
  6. 12
      asm/src/main/java/dev/openrs2/asm/io/ManifestJarLibraryWriter.kt
  7. 9
      asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt
  8. 9
      asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt
  9. 11
      asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt
  10. 20
      bundler/src/main/java/dev/openrs2/bundler/Bundler.kt
  11. 10
      bundler/src/main/java/dev/openrs2/bundler/Resource.kt
  12. 12
      deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt

@ -5,22 +5,25 @@ import dev.openrs2.asm.classpath.Library
import dev.openrs2.util.io.entries import dev.openrs2.util.io.entries
import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.ClassNode
import java.io.InputStream
import java.util.jar.JarInputStream import java.util.jar.JarInputStream
class JarLibraryReader(private val input: JarInputStream) : LibraryReader { class JarLibraryReader : LibraryReader {
override fun read(): Library { override fun read(input: InputStream): Library {
val library = Library() val library = Library()
for (entry in input.entries) { JarInputStream(input).use { jar ->
if (!entry.name.endsWith(CLASS_SUFFIX)) { for (entry in jar.entries) {
continue if (!entry.name.endsWith(CLASS_SUFFIX)) {
} continue
}
val clazz = ClassNode() val clazz = ClassNode()
val reader = ClassReader(input) val reader = ClassReader(jar)
reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
library.add(clazz) library.add(clazz)
}
} }
return library return library

@ -5,39 +5,47 @@ import dev.openrs2.asm.NopClassVisitor
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.classpath.StackFrameClassWriter import dev.openrs2.asm.classpath.StackFrameClassWriter
import dev.openrs2.util.io.DeterministicJarOutputStream
import org.objectweb.asm.ClassWriter import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import org.objectweb.asm.util.CheckClassAdapter import org.objectweb.asm.util.CheckClassAdapter
import java.io.OutputStream
import java.util.jar.JarEntry import java.util.jar.JarEntry
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
class JarLibraryWriter(private val output: JarOutputStream) : LibraryWriter { open class JarLibraryWriter : LibraryWriter {
override fun write(classPath: ClassPath, library: Library) { override fun write(output: OutputStream, classPath: ClassPath, library: Library) {
for (clazz in library) { createJarOutputStream(output).use { jar ->
val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) { for (clazz in library) {
StackFrameClassWriter(classPath) val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) {
} else { StackFrameClassWriter(classPath)
ClassWriter(ClassWriter.COMPUTE_MAXS) } else {
} ClassWriter(ClassWriter.COMPUTE_MAXS)
}
clazz.accept(writer) clazz.accept(writer)
output.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) jar.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX))
output.write(writer.toByteArray()) jar.write(writer.toByteArray())
/* /*
* XXX(gpe): CheckClassAdapter breaks the Label offset * XXX(gpe): CheckClassAdapter breaks the Label offset
* calculation in the OriginalPcTable's write method, so we do * calculation in the OriginalPcTable's write method, so we do
* a second pass without any attributes to check the class, * a second pass without any attributes to check the class,
* feeding the callbacks into a no-op visitor. * feeding the callbacks into a no-op visitor.
*/ */
for (method in clazz.methods) { for (method in clazz.methods) {
method.attrs?.clear() 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 companion object {
private const val CLASS_SUFFIX = ".class" private const val CLASS_SUFFIX = ".class"
} }

@ -4,8 +4,8 @@ import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import java.io.OutputStream import java.io.OutputStream
class Js5LibraryWriter(private val output: OutputStream) : LibraryWriter { class Js5LibraryWriter : LibraryWriter {
override fun write(classPath: ClassPath, library: Library) { override fun write(output: OutputStream, classPath: ClassPath, library: Library) {
// TODO(gpe): implement // TODO(gpe): implement
} }
} }

@ -1,7 +1,8 @@
package dev.openrs2.asm.io package dev.openrs2.asm.io
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import java.io.InputStream
interface LibraryReader { interface LibraryReader {
fun read(): Library fun read(input: InputStream): Library
} }

@ -2,7 +2,8 @@ package dev.openrs2.asm.io
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import java.io.OutputStream
interface LibraryWriter { interface LibraryWriter {
fun write(classPath: ClassPath, library: Library) fun write(output: OutputStream, classPath: ClassPath, library: Library)
} }

@ -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)
}
}

@ -4,12 +4,11 @@ import dev.openrs2.asm.classpath.Library
import dev.openrs2.compress.gzip.Gzip import dev.openrs2.compress.gzip.Gzip
import java.io.InputStream import java.io.InputStream
import java.nio.file.Files import java.nio.file.Files
import java.util.jar.JarInputStream
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
import java.util.jar.Pack200 import java.util.jar.Pack200
class Pack200LibraryReader(private val input: InputStream) : LibraryReader { class Pack200LibraryReader : LibraryReader {
override fun read(): Library { override fun read(input: InputStream): Library {
val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX)
try { try {
Gzip.createHeaderlessInputStream(input).use { gzipInput -> Gzip.createHeaderlessInputStream(input).use { gzipInput ->
@ -18,8 +17,8 @@ class Pack200LibraryReader(private val input: InputStream) : LibraryReader {
} }
} }
return JarInputStream(Files.newInputStream(temp)).use { tempInput -> return Files.newInputStream(temp).use { tempInput ->
JarLibraryReader(tempInput).read() JarLibraryReader().read(tempInput)
} }
} finally { } finally {
Files.deleteIfExists(temp) Files.deleteIfExists(temp)

@ -3,18 +3,17 @@ package dev.openrs2.asm.io
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import dev.openrs2.compress.gzip.Gzip import dev.openrs2.compress.gzip.Gzip
import dev.openrs2.util.io.DeterministicJarOutputStream
import java.io.OutputStream import java.io.OutputStream
import java.nio.file.Files import java.nio.file.Files
import java.util.jar.JarInputStream import java.util.jar.JarInputStream
import java.util.jar.Pack200 import java.util.jar.Pack200
class Pack200LibraryWriter(private val output: OutputStream) : LibraryWriter { class Pack200LibraryWriter : LibraryWriter {
override fun write(classPath: ClassPath, library: Library) { override fun write(output: OutputStream, classPath: ClassPath, library: Library) {
val tempJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) val tempJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX)
try { try {
DeterministicJarOutputStream(Files.newOutputStream(tempJar)).use { tempOutput -> Files.newOutputStream(tempJar).use { tempOutput ->
JarLibraryWriter(tempOutput).write(classPath, library) JarLibraryWriter().write(tempOutput, classPath, library)
} }
JarInputStream(Files.newInputStream(tempJar)).use { input -> JarInputStream(Files.newInputStream(tempJar)).use { input ->

@ -12,21 +12,20 @@ import java.util.jar.JarInputStream
import java.util.jar.Manifest import java.util.jar.Manifest
class SignedJarLibraryWriter( class SignedJarLibraryWriter(
private val output: OutputStream,
private val manifest: Manifest, private val manifest: Manifest,
private val keyStore: Pkcs12KeyStore private val keyStore: Pkcs12KeyStore
) : LibraryWriter { ) : 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) val unsignedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX)
try { try {
DeterministicJarOutputStream(Files.newOutputStream(unsignedJar), manifest).use { unsignedOutput -> Files.newOutputStream(unsignedJar).use { unsignedOutput ->
JarLibraryWriter(unsignedOutput).write(classPath, library) ManifestJarLibraryWriter(manifest).write(unsignedOutput, classPath, library)
} }
val signedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) val signedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX)
try { try {
keyStore.signJar(unsignedJar, signedJar) keyStore.signJar(unsignedJar, signedJar)
repack(signedJar) repack(signedJar, output)
} finally { } finally {
Files.deleteIfExists(signedJar) 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 -> JarInputStream(Files.newInputStream(signedJar)).use { input ->
DeterministicJarOutputStream(output, input.manifest).use { output -> DeterministicJarOutputStream(output, input.manifest).use { output ->
for (entry in input.entries) { for (entry in input.entries) {

@ -3,20 +3,18 @@ package dev.openrs2.bundler
import com.github.michaelbull.logging.InlineLogger import com.github.michaelbull.logging.InlineLogger
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.transform.Transformer
import dev.openrs2.asm.io.JarLibraryReader 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.Pack200LibraryReader
import dev.openrs2.asm.io.SignedJarLibraryWriter import dev.openrs2.asm.io.SignedJarLibraryWriter
import dev.openrs2.asm.transform.Transformer
import dev.openrs2.bundler.transform.ResourceTransformer import dev.openrs2.bundler.transform.ResourceTransformer
import dev.openrs2.conf.Config import dev.openrs2.conf.Config
import dev.openrs2.crypto.Pkcs12KeyStore import dev.openrs2.crypto.Pkcs12KeyStore
import dev.openrs2.util.io.DeterministicJarOutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.util.jar.Attributes import java.util.jar.Attributes
import java.util.jar.Attributes.Name.MANIFEST_VERSION import java.util.jar.Attributes.Name.MANIFEST_VERSION
import java.util.jar.JarInputStream
import java.util.jar.Manifest import java.util.jar.Manifest
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -134,8 +132,8 @@ class Bundler @Inject constructor(
private fun readJar(path: Path): Library { private fun readJar(path: Path): Library {
logger.info { "Reading jar $path" } logger.info { "Reading jar $path" }
return JarInputStream(Files.newInputStream(path)).use { input -> return Files.newInputStream(path).use { input ->
JarLibraryReader(input).read() JarLibraryReader().read(input)
} }
} }
@ -143,23 +141,23 @@ class Bundler @Inject constructor(
logger.info { "Reading pack $path" } logger.info { "Reading pack $path" }
return Files.newInputStream(path).use { input -> return Files.newInputStream(path).use { input ->
Pack200LibraryReader(input).read() Pack200LibraryReader().read(input)
} }
} }
private fun writeJar(classPath: ClassPath, library: Library, path: Path) { private fun writeJar(classPath: ClassPath, library: Library, path: Path) {
logger.info { "Writing jar $path" } logger.info { "Writing jar $path" }
DeterministicJarOutputStream(Files.newOutputStream(path), unsignedManifest).use { output -> Files.newOutputStream(path).use { output ->
JarLibraryWriter(output).write(classPath, library) ManifestJarLibraryWriter(unsignedManifest).write(output, classPath, library)
} }
} }
private fun writeSignedJar(classPath: ClassPath, library: Library, path: Path, keyStore: Pkcs12KeyStore) { private fun writeSignedJar(classPath: ClassPath, library: Library, path: Path, keyStore: Pkcs12KeyStore) {
logger.info { "Writing signed jar $path" } logger.info { "Writing signed jar $path" }
Files.newOutputStream(path).use { Files.newOutputStream(path).use { output ->
SignedJarLibraryWriter(it, signedManifest, keyStore).write(classPath, library) SignedJarLibraryWriter(signedManifest, keyStore).write(output, classPath, library)
} }
} }

@ -6,7 +6,6 @@ import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.io.JarLibraryWriter import dev.openrs2.asm.io.JarLibraryWriter
import dev.openrs2.asm.io.Js5LibraryWriter import dev.openrs2.asm.io.Js5LibraryWriter
import dev.openrs2.asm.io.Pack200LibraryWriter import dev.openrs2.asm.io.Pack200LibraryWriter
import dev.openrs2.util.io.DeterministicJarOutputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
@ -71,24 +70,21 @@ class Resource(
fun compressJar(source: String, destination: String, classPath: ClassPath, library: Library): Resource { fun compressJar(source: String, destination: String, classPath: ClassPath, library: Library): Resource {
ByteArrayOutputStream().use { output -> ByteArrayOutputStream().use { output ->
DeterministicJarOutputStream(output).use { jarOutput -> JarLibraryWriter().write(output, classPath, library)
JarLibraryWriter(jarOutput).write(classPath, library)
}
return compress(source, destination, output.toByteArray()) return compress(source, destination, output.toByteArray())
} }
} }
fun compressPack(source: String, destination: String, classPath: ClassPath, library: Library): Resource { fun compressPack(source: String, destination: String, classPath: ClassPath, library: Library): Resource {
ByteArrayOutputStream().use { output -> ByteArrayOutputStream().use { output ->
Pack200LibraryWriter(output).write(classPath, library) Pack200LibraryWriter().write(output, classPath, library)
return compress(source, destination, output.toByteArray()) return compress(source, destination, output.toByteArray())
} }
} }
fun compressJs5(source: String, destination: String, classPath: ClassPath, library: Library): Resource { fun compressJs5(source: String, destination: String, classPath: ClassPath, library: Library): Resource {
ByteArrayOutputStream().use { output -> ByteArrayOutputStream().use { output ->
Js5LibraryWriter(output).write(classPath, library) Js5LibraryWriter().write(output, classPath, library)
return compress(source, destination, output.toByteArray()) return compress(source, destination, output.toByteArray())
} }
} }

@ -8,10 +8,8 @@ import dev.openrs2.asm.io.JarLibraryWriter
import dev.openrs2.asm.io.Pack200LibraryReader import dev.openrs2.asm.io.Pack200LibraryReader
import dev.openrs2.asm.transform.Transformer import dev.openrs2.asm.transform.Transformer
import dev.openrs2.deob.remap.PrefixRemapper import dev.openrs2.deob.remap.PrefixRemapper
import dev.openrs2.util.io.DeterministicJarOutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.util.jar.JarInputStream
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -124,8 +122,8 @@ class Deobfuscator @Inject constructor(
private fun readJar(path: Path): Library { private fun readJar(path: Path): Library {
logger.info { "Reading jar $path" } logger.info { "Reading jar $path" }
return JarInputStream(Files.newInputStream(path)).use { input -> return Files.newInputStream(path).use { input ->
JarLibraryReader(input).read() JarLibraryReader().read(input)
} }
} }
@ -133,15 +131,15 @@ class Deobfuscator @Inject constructor(
logger.info { "Reading pack $path" } logger.info { "Reading pack $path" }
return Files.newInputStream(path).use { input -> return Files.newInputStream(path).use { input ->
Pack200LibraryReader(input).read() Pack200LibraryReader().read(input)
} }
} }
private fun writeJar(classPath: ClassPath, library: Library, path: Path) { private fun writeJar(classPath: ClassPath, library: Library, path: Path) {
logger.info { "Writing jar $path" } logger.info { "Writing jar $path" }
DeterministicJarOutputStream(Files.newOutputStream(path)).use { output -> Files.newOutputStream(path).use { output ->
JarLibraryWriter(output).write(classPath, library) JarLibraryWriter().write(output, classPath, library)
} }
} }

Loading…
Cancel
Save