forked from openrs2/openrs2
parent
b40eedfb3b
commit
26348b8a2e
@ -0,0 +1,44 @@ |
||||
package dev.openrs2.asm.io |
||||
|
||||
import dev.openrs2.asm.ClassVersionUtils |
||||
import dev.openrs2.asm.NopClassVisitor |
||||
import dev.openrs2.asm.classpath.ClassPath |
||||
import dev.openrs2.asm.classpath.Library |
||||
import dev.openrs2.asm.classpath.StackFrameClassWriter |
||||
import org.objectweb.asm.ClassWriter |
||||
import org.objectweb.asm.Opcodes |
||||
import org.objectweb.asm.util.CheckClassAdapter |
||||
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) |
||||
} |
||||
|
||||
clazz.accept(writer) |
||||
|
||||
output.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) |
||||
output.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() |
||||
} |
||||
clazz.accept(CheckClassAdapter(NopClassVisitor, true)) |
||||
} |
||||
} |
||||
|
||||
private companion object { |
||||
private const val CLASS_SUFFIX = ".class" |
||||
} |
||||
} |
@ -0,0 +1,11 @@ |
||||
package dev.openrs2.asm.io |
||||
|
||||
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) { |
||||
// TODO(gpe): implement |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
package dev.openrs2.asm.io |
||||
|
||||
import dev.openrs2.asm.classpath.ClassPath |
||||
import dev.openrs2.asm.classpath.Library |
||||
|
||||
interface LibraryWriter { |
||||
fun write(classPath: ClassPath, library: Library) |
||||
} |
@ -0,0 +1,34 @@ |
||||
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) { |
||||
val tempJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) |
||||
try { |
||||
DeterministicJarOutputStream(Files.newOutputStream(tempJar)).use { tempOutput -> |
||||
JarLibraryWriter(tempOutput).write(classPath, library) |
||||
} |
||||
|
||||
JarInputStream(Files.newInputStream(tempJar)).use { input -> |
||||
Gzip.createHeaderlessOutputStream(output).use { gzip -> |
||||
Pack200.newPacker().pack(input, gzip) |
||||
} |
||||
} |
||||
} finally { |
||||
Files.deleteIfExists(tempJar) |
||||
} |
||||
} |
||||
|
||||
private companion object { |
||||
private const val TEMP_PREFIX = "tmp" |
||||
private const val JAR_SUFFIX = ".jar" |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
package dev.openrs2.asm.io |
||||
|
||||
import dev.openrs2.asm.classpath.ClassPath |
||||
import dev.openrs2.asm.classpath.Library |
||||
import dev.openrs2.crypto.Pkcs12KeyStore |
||||
import dev.openrs2.util.io.DeterministicJarOutputStream |
||||
import java.io.OutputStream |
||||
import java.nio.file.Files |
||||
import java.nio.file.Path |
||||
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) { |
||||
val unsignedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) |
||||
try { |
||||
DeterministicJarOutputStream(Files.newOutputStream(unsignedJar), manifest).use { unsignedOutput -> |
||||
JarLibraryWriter(unsignedOutput).write(classPath, library) |
||||
} |
||||
|
||||
val signedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) |
||||
try { |
||||
keyStore.signJar(unsignedJar, signedJar) |
||||
repack(signedJar) |
||||
} finally { |
||||
Files.deleteIfExists(signedJar) |
||||
} |
||||
} finally { |
||||
Files.deleteIfExists(unsignedJar) |
||||
} |
||||
} |
||||
|
||||
private fun repack(signedJar: Path) { |
||||
JarInputStream(Files.newInputStream(signedJar)).use { input -> |
||||
DeterministicJarOutputStream(output, input.manifest).use { output -> |
||||
generateSequence { input.nextJarEntry }.forEach { |
||||
output.putNextEntry(it) |
||||
input.copyTo(output) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private companion object { |
||||
private const val TEMP_PREFIX = "tmp" |
||||
private const val JAR_SUFFIX = ".jar" |
||||
} |
||||
} |
Loading…
Reference in new issue