Skip to content

Commit

Permalink
Ability to create Bytes shader function
Browse files Browse the repository at this point in the history
  • Loading branch information
joan38 committed Aug 20, 2020
1 parent c811882 commit 8ae6e73
Showing 1 changed file with 62 additions and 45 deletions.
107 changes: 62 additions & 45 deletions core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ object Shader {
mappings: Iterable[(Path, String)],
verbose: Boolean
): Unit = {
val inputStreams = mappings.filter(x => !Files.isDirectory(x._1)).map(x => Files.newInputStream(x._1) -> x._2)
val newMappings = shadeInputStreams(rules, inputStreams, verbose)
val mappingBytes = mappings.filter(x => !Files.isDirectory(x._1)).map(x => Files.readAllBytes(x._1) -> x._2)
val shader = bytcodeShader(rules, verbose)
val newMappings = mappingBytes.flatMap(mapping => shader(mapping._1, mapping._2))
mappings.filterNot(_._1.toFile.isDirectory).foreach(f => Files.delete(f._1))
newMappings.foreach { case (inputStream, mapping) =>
newMappings.foreach { case (bytes, mapping) =>
val out = dir.resolve(mapping)
if (!Files.exists(out.getParent)) Files.createDirectories(out.getParent)
Files.write(out, readAllBytes(inputStream), StandardOpenOption.CREATE)
Files.write(out, bytes, StandardOpenOption.CREATE)
}
}

Expand All @@ -28,52 +29,68 @@ object Shader {
mappings: Iterable[(InputStream, String)],
verbose: Boolean
): Iterable[(InputStream, String)] = {
val jjrules = rules.flatMap { r =>
r.shadePattern match {
case ShadePattern.Rename(patterns) =>
patterns.map { case (from, to) =>
val jrule = new Rule()
jrule.setPattern(from)
jrule.setResult(to)
jrule
}
case ShadePattern.Zap(patterns) =>
patterns.map { pattern =>
val jrule = new Zap()
jrule.setPattern(pattern)
jrule
}
case ShadePattern.Keep(patterns) =>
patterns.map { pattern =>
val jrule = new Keep()
jrule.setPattern(pattern)
jrule
}
case _ => Nil
val shader = bytcodeShader(rules, verbose)
mappings.flatMap { case (inputStream, mapping) =>
shader(readAllBytes(inputStream), mapping).map { case (bytes, newMapping) =>
new ByteArrayInputStream(bytes) {
override def close(): Unit = inputStream.close()
} -> newMapping
}
}
}

def bytcodeShader(
rules: Seq[ShadeRule],
verbose: Boolean
): (Array[Byte], String) => Option[(Array[Byte], String)] =
if (rules.isEmpty) (bytes, mapping) => Some(bytes -> mapping)
else {
val jjrules = rules.flatMap { r =>
r.shadePattern match {
case ShadePattern.Rename(patterns) =>
patterns.map { case (from, to) =>
val jrule = new Rule()
jrule.setPattern(from)
jrule.setResult(to)
jrule
}
case ShadePattern.Zap(patterns) =>
patterns.map { pattern =>
val jrule = new Zap()
jrule.setPattern(pattern)
jrule
}
case ShadePattern.Keep(patterns) =>
patterns.map { pattern =>
val jrule = new Keep()
jrule.setPattern(pattern)
jrule
}
case _ => Nil
}
}

val proc = new JJProcessor(jjrules, verbose, true, null)
val proc = new JJProcessor(jjrules, verbose, true, null)
val excludes = proc.getExcludes

/*
jarjar MisplacedClassProcessor class transforms byte[] to a class using org.objectweb.asm.ClassReader.getClassName
which always translates class names containing '.' into '/', regardless of OS platform.
We need to transform any windows file paths in order for jarjar to match them properly and not omit them.
*/
val sanitizedMappings =
mappings.map(f => if (f._2.contains('\\')) (f._1, f._2.replace('\\', '/')) else f)
val shadedInputStreams = sanitizedMappings.flatMap { f =>
val entry = new EntryStruct
entry.data = readAllBytes(f._1)
entry.name = f._2
entry.time = -1
entry.skipTransform = false
if (proc.process(entry)) Some(new ByteArrayInputStream(entry.data) -> entry.name)
else None
{ (bytes, mapping) =>
/*
jarjar MisplacedClassProcessor class transforms byte[] to a class using org.objectweb.asm.ClassReader.getClassName
which always translates class names containing '.' into '/', regardless of OS platform.
We need to transform any windows file paths in order for jarjar to match them properly and not omit them.
*/
val sanitizedMapping = if (mapping.contains('\\')) mapping.replace('\\', '/') else mapping
val entry = new EntryStruct
entry.data = bytes
entry.name = sanitizedMapping
entry.time = -1
entry.skipTransform = false
val shadedInputStream =
if (proc.process(entry)) Some(entry.data -> entry.name)
else None
shadedInputStream.filterNot(a => excludes.contains(a._2))
}
}
val excludes = proc.getExcludes
shadedInputStreams.filterNot(mapping => excludes.contains(mapping._2))
}
}

sealed trait ShadePattern {
Expand Down

0 comments on commit 8ae6e73

Please sign in to comment.