Skip to content

Commit cf1a4e0

Browse files
committed
Generalize FoxLoaderPatches.patchBuildConfig() to make a catto happy.
1 parent 7678ef6 commit cf1a4e0

File tree

3 files changed

+70
-33
lines changed

3 files changed

+70
-33
lines changed

patching/generate.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ static void generateBuildConfig0(File buildConfigSrc, Project project) {
7373
printStream.println("// Auto generated class, do not modify.")
7474
printStream.println("package com.fox2code.foxloader.launcher;")
7575
printStream.println()
76+
printStream.println("import com.fox2code.foxloader.patching.TransformerUtils;")
77+
printStream.println("import org.objectweb.asm.tree.ClassNode;")
78+
printStream.println()
7679
printStream.println("/**")
7780
printStream.println(" * Class used to get info about FoxLoader, unlike regular final constants,")
7881
printStream.println(" * the one in this class won't get inlined due to a FoxLoader specific ASM hack.")
82+
printStream.println(" *")
83+
printStream.println(" * @see TransformerUtils#deInlineFieldConstants(ClassNode, boolean)")
7984
printStream.println(" */")
8085
printStream.println("public final class BuildConfig {")
8186
printStream.println(" private BuildConfig() {}")

patching/src/main/java/com/fox2code/foxloader/patching/FoxLoaderPatches.java

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public static void patchFoxLoaderFinalJar(File foxloaderJar) throws IOException
6868
if (!foxloaderJar.renameTo(backup)) {
6969
throw new IOException("Failed to rename loader jar");
7070
}
71+
boolean patchedBuildConfig = false;
7172
try (ZipInputStream zipInputStream = new ZipInputStream(
7273
new BufferedInputStream(Files.newInputStream(backup.toPath())));
7374
ZipOutputStream zipOutputStream = new ZipOutputStream(
@@ -83,6 +84,7 @@ public static void patchFoxLoaderFinalJar(File foxloaderJar) throws IOException
8384
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
8485
IOUtils.copy(zipInputStream, byteArrayOutputStream);
8586
zipOutputStream.write(patchBuildConfig(byteArrayOutputStream.toByteArray()));
87+
patchedBuildConfig = true;
8688
} else {
8789
IOUtils.copy(zipInputStream, zipOutputStream);
8890
}
@@ -91,6 +93,9 @@ public static void patchFoxLoaderFinalJar(File foxloaderJar) throws IOException
9193
}
9294
zipOutputStream.finish();
9395
}
96+
if (!patchedBuildConfig) {
97+
throw new IOException("Patching BuildConfig failed.");
98+
}
9499
if (backup.exists() && !backup.delete()) {
95100
throw new IOException("Failed to delete backup jar");
96101
}
@@ -99,40 +104,10 @@ public static void patchFoxLoaderFinalJar(File foxloaderJar) throws IOException
99104
private static byte[] patchBuildConfig(byte[] buildConfig) {
100105
ClassNode classNode = new ClassNode();
101106
new ClassReader(buildConfig).accept(classNode, 0);
102-
if (TransformerUtils.findMethod(classNode, "<clinit>") != null) {
103-
throw new RuntimeException("<clinit>()V detected in BuildConfig!");
104-
}
105-
MethodNode clInit = new MethodNode(ACC_STATIC, "<clinit>", "()V", null, null);
106-
for (FieldNode fieldNode : classNode.fields) {
107-
if (fieldNode.access != (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) {
108-
throw new RuntimeException("Invalid field access: " + fieldNode.access);
109-
}
110-
AbstractInsnNode constInsn;
111-
switch (fieldNode.desc) {
112-
case "Ljava/lang/String;":
113-
constInsn = new LdcInsnNode(fieldNode.value);
114-
break;
115-
case "I":
116-
case "Z":
117-
if (fieldNode.value instanceof Integer) {
118-
constInsn = TransformerUtils.getNumberInsn((Integer) fieldNode.value);
119-
} else if (fieldNode.value instanceof Boolean) {
120-
constInsn = TransformerUtils.getBooleanInsn((Boolean) fieldNode.value);
121-
} else {
122-
throw new RuntimeException("WTF???");
123-
}
124-
break;
125-
default:
126-
throw new RuntimeException("Unsupported desc: \"" + fieldNode.desc + "\"");
127-
}
128-
fieldNode.value = null;
129-
clInit.instructions.add(constInsn);
130-
clInit.instructions.add(new FieldInsnNode(PUTSTATIC,
131-
"com/fox2code/foxloader/launcher/BuildConfig",
132-
fieldNode.name, fieldNode.desc));
107+
TransformerUtils.deInlineFieldConstants(classNode, true);
108+
if (classNode.methods.size() != 2) {
109+
throw new RuntimeException("WHAT? " + classNode.methods.size());
133110
}
134-
clInit.instructions.add(new InsnNode(RETURN));
135-
classNode.methods.add(clInit);
136111
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
137112
classNode.accept(classWriter);
138113
return classWriter.toByteArray();

patching/src/main/java/com/fox2code/foxloader/patching/TransformerUtils.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,4 +1024,61 @@ public static AbstractInsnNode getConsumingInstruction(InsnList insnList, Abstra
10241024
}
10251025
return null;
10261026
}
1027+
1028+
public static void deInlineFieldConstants(ClassNode classNode) {
1029+
deInlineFieldConstants(classNode, false);
1030+
}
1031+
1032+
public static void deInlineFieldConstants(ClassNode classNode, boolean strict) {
1033+
InsnList addedNodes = new InsnList();
1034+
for (FieldNode fieldNode : classNode.fields) {
1035+
if ((fieldNode.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) !=
1036+
(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) {
1037+
if (strict) {
1038+
throw new RuntimeException("Invalid field access: " + fieldNode.access);
1039+
}
1040+
continue;
1041+
}
1042+
if (fieldNode.value == null) {
1043+
continue;
1044+
}
1045+
AbstractInsnNode constInsn;
1046+
switch (fieldNode.desc) {
1047+
case "Ljava/lang/String;":
1048+
constInsn = new LdcInsnNode(fieldNode.value);
1049+
break;
1050+
case "I":
1051+
case "Z":
1052+
case "S":
1053+
case "B":
1054+
case "C":
1055+
if (fieldNode.value instanceof Integer) {
1056+
constInsn = TransformerUtils.getNumberInsn((Integer) fieldNode.value);
1057+
} else if (fieldNode.value instanceof Boolean) {
1058+
constInsn = TransformerUtils.getBooleanInsn((Boolean) fieldNode.value);
1059+
} else {
1060+
throw new RuntimeException("WTF???");
1061+
}
1062+
break;
1063+
default:
1064+
throw new RuntimeException("Unsupported desc: \"" + fieldNode.desc + "\"");
1065+
}
1066+
fieldNode.value = null;
1067+
addedNodes.add(constInsn);
1068+
addedNodes.add(new FieldInsnNode(Opcodes.PUTSTATIC,
1069+
classNode.name, fieldNode.name, fieldNode.desc));
1070+
}
1071+
if (addedNodes.getFirst() == null) {
1072+
return;
1073+
}
1074+
MethodNode clInit = TransformerUtils.findMethod(classNode, "<clinit>");
1075+
if (clInit == null) {
1076+
clInit = new MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
1077+
clInit.instructions.add(new InsnNode(Opcodes.RETURN));
1078+
classNode.methods.add(clInit);
1079+
} else if (strict) {
1080+
throw new RuntimeException("<clinit>()V detected in BuildConfig!");
1081+
}
1082+
insertToEndOfCode(clInit, addedNodes);
1083+
}
10271084
}

0 commit comments

Comments
 (0)