Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make better patch #45

Merged
merged 1 commit into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import org.gradle.api.DefaultTask
import org.gradle.api.file.FileTree
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import java.io.File
import java.security.MessageDigest

open class MakeBsdiffPatch : DefaultTask() {
open class MakeClassBsdiffPatch : DefaultTask() {
@InputFiles var oldFiles: FileTree = project.files().asFileTree
@InputFiles var newFiles: FileTree = project.files().asFileTree
@OutputDirectory var outTo: File? = null
Expand All @@ -19,6 +21,9 @@ open class MakeBsdiffPatch : DefaultTask() {
val outTo = outTo ?: error("outTo not inited")
val patchPrefix = patchPrefix ?: error("patchPrefix not inited")

check ((oldFiles.keys - newFiles.keys).isEmpty()) { "some files are deleted: ${oldFiles.keys - newFiles.keys}" }
check ((newFiles.keys - oldFiles.keys).isEmpty()) { "some files are added: ${newFiles.keys - oldFiles.keys}" }

val patchDir = outTo.resolve(patchPrefix)
val sha1 = MessageDigest.getInstance("SHA-1")

Expand All @@ -28,19 +33,20 @@ open class MakeBsdiffPatch : DefaultTask() {
val oldBytes = oldFile.readBytes()
val newBytes = newFile.readBytes()

val oldHashFile = patchDir.resolve("$newPath.old.sha1")
oldHashFile.parentFile.mkdirs()
oldHashFile.writeBytes(sha1.digest(oldBytes))

if (oldBytes.contentEquals(newBytes))
continue

val bsDiffFile = patchDir.resolve("$newPath.bsdiff")
val newHashFile = patchDir.resolve("$newPath.new.sha1")
val oldHashFile = patchDir.resolve("$newPath.old.sha1")

bsDiffFile.parentFile.mkdirs()
newHashFile.parentFile.mkdirs()
oldHashFile.parentFile.mkdirs()

Diff.diff(oldBytes, newBytes, bsDiffFile.outputStream())
oldHashFile.writeBytes(sha1.digest(oldBytes))
newHashFile.writeBytes(sha1.digest(newBytes))
}
}
Expand Down
53 changes: 53 additions & 0 deletions buildSrc/src/main/kotlin/RemakeClassWithConstantPool.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import io.sigpipe.jbsdiff.Diff
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileTree
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import java.io.File
import java.security.MessageDigest

open class RemakeClassWithConstantPool : DefaultTask() {
@InputFiles var oldFiles: FileTree = project.files().asFileTree
@InputFiles var newFiles: FileTree = project.files().asFileTree
@OutputDirectory var outTo: File? = null

@TaskAction
fun run() {
val oldFiles = getAllFiles(oldFiles)
val newFiles = getAllFiles(newFiles)
val outTo = outTo ?: error("outTo not inited")

check ((oldFiles.keys - newFiles.keys).isEmpty()) { "some files are deleted: ${oldFiles.keys - newFiles.keys}" }
check ((newFiles.keys - oldFiles.keys).isEmpty()) { "some files are added: ${newFiles.keys - oldFiles.keys}" }

for ((newPath, newFile) in newFiles) {
val oldFile = oldFiles[newPath]

outTo.resolve(newPath).parentFile.mkdirs()

if (oldFile == null) {
newFile.copyTo(outTo.resolve(newPath), overwrite = true)
continue
}

outTo.resolve(newPath).writeBytes(remakeClass(oldFile.readBytes(), newFile.readBytes()))
}
}

private fun remakeClass(oldBytes: ByteArray, readBytes: ByteArray): ByteArray {
return ClassWriter(ClassReader(oldBytes), 0)
.also { ClassReader(readBytes).accept(it, 0) }
.toByteArray()
}

private fun getAllFiles(fileTree: FileTree): Map<String, File> {
val files = mutableMapOf<String, File>()
fileTree.visit {
if (it.isDirectory) return@visit
files[it.path] = it.file
}
return files
}
}
32 changes: 24 additions & 8 deletions makePatch.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,34 @@ def fixRtmBuiltJar = jar.archivePath
def patchesDir = file("${buildDir}/resources/patches")
def unzippedJarDir = file("$buildDir/unzipped")
def fixRtmOutputDir = file("$buildDir/libs")
def remadeClassesDir = file("$buildDir/remade-classes")
def unzippedNgtsDir = file("$buildDir/unzipped-ngts")

task makeRtmPatch(type: MakeBsdiffPatch) {
task unzipNgtsDir(type: Copy) {
from (zipTree(oldRTM) + zipTree(oldNGTLib)) {
include ("**/*.class")
}
into unzippedNgtsDir
}

task remakeClasses(type: RemakeClassWithConstantPool) {
dependsOn build
dependsOn unzipNgtsDir

oldFiles = zipTree(oldRTM) + zipTree(oldNGTLib)
oldFiles = fileTree(unzippedNgtsDir)
newFiles = zipTree(fixRtmBuiltJar).matching {
include ("**/*.class")
include ("jp/ngt/**/*.class")
}
outTo = remadeClassesDir
}

task makeRtmPatch(type: MakeClassBsdiffPatch) {
dependsOn remakeClasses
dependsOn unzipNgtsDir
dependsOn build

oldFiles = fileTree(unzippedNgtsDir)
newFiles = fileTree(remadeClassesDir)

outTo = patchesDir
patchPrefix = "com/anatawa12/fixRtm/asm/patches"
Expand All @@ -25,11 +45,7 @@ task unzipFixRTM(type: Copy) {
dependsOn build

from (zipTree(fixRtmBuiltJar)){
include "com/anatawa12/**/*"
include "kotlin/**/*"
include "kotlinx/**/*"
include "org/**/*"
include "io/sigpipe/**/*"
exclude ("jp/ngt/**/*")
}

destinationDir = unzippedJarDir
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/com/anatawa12/fixRtm/asm/PatchApplier.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,36 @@ class PatchApplier : IClassTransformer {
}
logger.trace("patch found for $name")

checkSha(patch.oldSha1, basicClass) {"sha1 diget not match for class: $name. please check your mod version"}
checkSha(patch.oldSha1, basicClass) {"sha1 digest not match for class: $name. please check your mod version"}

if (patch.jbsdiff == null) return basicClass

val out = ByteArrayOutputStream()
Patch.patch(basicClass, patch.jbsdiff, out)
val patched = out.toByteArray()

checkSha(patch.newSha1, patched) {"patched sha1 diget not match for class: $name. please check your mod version"}

logger.trace("patched: $name")

if (patch.newSha1 == null) return basicClass

checkSha(patch.newSha1, patched) {"patched sha1 digest not match for class: $name. please check your mod version"}

return patched
}

private fun getPatchAndSha1(className: String): PatchAndSha1? {
val classFilePath = "${className.replace('.', '/')}.class"
return PatchAndSha1(
jbsdiff = getStream("$classFilePath.bsdiff")?.readBytes() ?: return null,
jbsdiff = getStream("$classFilePath.bsdiff")?.readBytes(),
oldSha1 = getStream("$classFilePath.old.sha1")?.readBytes() ?: return null,
newSha1 = getStream("$classFilePath.new.sha1")?.readBytes() ?: return null
newSha1 = getStream("$classFilePath.new.sha1")?.readBytes()
)
}

private class PatchAndSha1(
val jbsdiff: ByteArray,
val jbsdiff: ByteArray?,
val oldSha1: ByteArray,
val newSha1: ByteArray
val newSha1: ByteArray?
)

private inline fun checkSha(sha: ByteArray, file: ByteArray, message: () -> String) {
Expand Down