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>
Graham 5 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 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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save