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