blob: 9b010b48d640512bf4d160dbd1e9bf2e49014162 [file] [log] [blame]
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.jetbrains.org.objectweb.asm.*
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.jar.JarFile
import java.util.zip.ZipOutputStream
/**
* Removes metadata annotations from Kotlin classes
*/
fun main(args: Array<String>) {
if (args.size != 4) {
error("Usage: kotlinc -script strip-kotlin-annotations.kts <annotation-internal-name-regex> <class-internal-name-regex> <path-to-in-jar> <path-to-out-jar>")
}
val annotationRegex = args[0].toRegex()
val classRegex = args[1].toRegex()
val inFile = File(args[2])
val outFile = File(args[3])
assert(inFile.exists()) { "Input file not found at $inFile" }
println("Stripping annotations from all classes in $inFile")
println("Input file size: ${inFile.length()} bytes")
fun transform(entryName: String, bytes: ByteArray): ByteArray {
if (!entryName.endsWith(".class")) return bytes
if (!classRegex.matches(entryName.removeSuffix(".class"))) return bytes
var changed = false
val classWriter = ClassWriter(0)
val classVisitor = object : ClassVisitor(Opcodes.ASM5, classWriter) {
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
if (annotationRegex.matches(Type.getType(desc).getInternalName())) {
changed = true
return null
}
return super.visitAnnotation(desc, visible)
}
}
ClassReader(bytes).accept(classVisitor, 0)
if (!changed) return bytes
return classWriter.toByteArray()
}
ZipOutputStream(BufferedOutputStream(FileOutputStream(outFile))).use {
outJar ->
JarFile(inFile).use { inJar ->
for (entry in inJar.entries()) {
val inBytes = inJar.getInputStream(entry).readBytes()
val outBytes = transform(entry.name, inBytes)
if (inBytes.size < outBytes.size) {
error("Size increased for ${entry.name}: was ${inBytes.size} bytes, became ${outBytes.size} bytes")
}
entry.compressedSize = -1L
outJar.putNextEntry(entry)
outJar.write(outBytes)
outJar.closeEntry()
}
}
}
println("Output written to $outFile")
println("Output file size: ${outFile.length()} bytes")
}
main(args)