Java tutorial
/* * Copyright (c) 2018 Yrom Wang * * 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. */ package net.yrom.tools; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.util.Map; /** * @author yrom * @version 2018/1/9 */ final class WriteStyleablesProcessor implements Processor { private RSymbols symbols; private File dir; WriteStyleablesProcessor(RSymbols symbols, File dir) { this.symbols = symbols; this.dir = dir; } @Override public void proceed() { ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); writer.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_SUPER, RSymbols.R_STYLEABLES_CLASS_NAME, null, "java/lang/Object", null); for (String name : symbols.getStyleables().keySet()) { writer.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, "[I", null, null); } writeClinit(writer); writer.visitEnd(); byte[] bytes = writer.toByteArray(); try { if (!dir.isDirectory() && !dir.mkdirs()) { throw new RuntimeException("Cannot mkdir " + dir); } Files.write(dir.toPath().resolve(RSymbols.R_STYLEABLES_CLASS_NAME + ".class"), bytes); } catch (IOException e) { throw new UncheckedIOException(e); } } private void writeClinit(ClassWriter writer) { Map<String, int[]> styleables = symbols.getStyleables(); MethodVisitor clinit = writer.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null); clinit.visitCode(); for (Map.Entry<String, int[]> entry : styleables.entrySet()) { final String field = entry.getKey(); final int[] value = entry.getValue(); final int length = value.length; pushInt(clinit, length); clinit.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT); for (int i = 0; i < length; i++) { clinit.visitInsn(Opcodes.DUP); // dup pushInt(clinit, i); pushInt(clinit, value[i]); clinit.visitInsn(Opcodes.IASTORE); // iastore } clinit.visitFieldInsn(Opcodes.PUTSTATIC, RSymbols.R_STYLEABLES_CLASS_NAME, field, "[I"); } clinit.visitInsn(Opcodes.RETURN); clinit.visitMaxs(0, 0); // auto compute clinit.visitEnd(); } private static void pushInt(MethodVisitor mv, int i) { if (0 <= i && i <= 5) { mv.visitInsn(Opcodes.ICONST_0 + i); // ICONST_0 ~ ICONST_5 } else if (i <= Byte.MAX_VALUE) { mv.visitIntInsn(Opcodes.BIPUSH, i); } else if (i <= Short.MAX_VALUE) { mv.visitIntInsn(Opcodes.SIPUSH, i); } else { mv.visitLdcInsn(i); } } }