├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── classfile-core ├── README.md ├── build.gradle └── src │ ├── main │ └── java │ │ └── dev │ │ └── xdark │ │ └── classfile │ │ ├── AccessFlag.java │ │ ├── AttributeWriter.java │ │ ├── ClassAdapter.java │ │ ├── ClassContext.java │ │ ├── ClassIO.java │ │ ├── ClassVersion.java │ │ ├── ClassVisitor.java │ │ ├── ClassWriter.java │ │ ├── FieldWriter.java │ │ ├── FilterClassVisitor.java │ │ ├── InvalidClassException.java │ │ ├── MethodWriter.java │ │ ├── annotation │ │ ├── AnnotationArrayVisitor.java │ │ ├── AnnotationIO.java │ │ ├── AnnotationVisitor.java │ │ ├── ElementType.java │ │ ├── ElementValue.java │ │ ├── ElementValueAnnotation.java │ │ ├── ElementValueArray.java │ │ ├── ElementValueBoolean.java │ │ ├── ElementValueByte.java │ │ ├── ElementValueChar.java │ │ ├── ElementValueClass.java │ │ ├── ElementValueConstant.java │ │ ├── ElementValueDouble.java │ │ ├── ElementValueEnum.java │ │ ├── ElementValueFloat.java │ │ ├── ElementValueInt.java │ │ ├── ElementValueLong.java │ │ ├── ElementValueShort.java │ │ ├── ElementValueString.java │ │ ├── FilterAnnotationArrayVisitor.java │ │ ├── FilterAnnotationVisitor.java │ │ └── InvalidAnnotationException.java │ │ ├── attribute │ │ ├── AnnotationDefaultAttribute.java │ │ ├── Attribute.java │ │ ├── AttributeAdapter.java │ │ ├── AttributeCollector.java │ │ ├── AttributeIO.java │ │ ├── AttributeInfo.java │ │ ├── AttributeLocation.java │ │ ├── AttributeUtil.java │ │ ├── AttributeVisitor.java │ │ ├── BootstrapMethodsAttribute.java │ │ ├── CodeAttribute.java │ │ ├── ConstantValueAttribute.java │ │ ├── DeprecatedAttribute.java │ │ ├── EnclosingMethodAttribute.java │ │ ├── ExceptionsAttribute.java │ │ ├── FilterAttributeVisitor.java │ │ ├── InnerClassesAttribute.java │ │ ├── InvalidAttributeException.java │ │ ├── KnownInfo.java │ │ ├── LineNumberTableAttribute.java │ │ ├── LocalVariableTableAttribute.java │ │ ├── LocalVariableTypeTableAttribute.java │ │ ├── MethodParametersAttribute.java │ │ ├── ModuleAttribute.java │ │ ├── ModuleMainClassAttribute.java │ │ ├── ModulePackagesAttribute.java │ │ ├── NamedAttributeInstance.java │ │ ├── NestHostAttribute.java │ │ ├── NestMembersAttribute.java │ │ ├── PermittedSubclassesAttribute.java │ │ ├── RecordAttribute.java │ │ ├── RuntimeAnnotationsAttribute.java │ │ ├── RuntimeInvisibleAnnotationsAttribute.java │ │ ├── RuntimeInvisibleRuntimeParameterAnnotationsAttribute.java │ │ ├── RuntimeParameterAnnotationsAttribute.java │ │ ├── RuntimeVisibleAnnotationsAttribute.java │ │ ├── RuntimeVisibleRuntimeParameterAnnotationsAttribute.java │ │ ├── SignatureAttribute.java │ │ ├── SourceDebugExtensionAttribute.java │ │ ├── SourceFileAttribute.java │ │ ├── SyntheticAttribute.java │ │ ├── UnknownAttribute.java │ │ ├── code │ │ │ ├── CodeAdapter.java │ │ │ ├── CodeBuilder.java │ │ │ ├── CodeIO.java │ │ │ ├── CodeVisitor.java │ │ │ ├── CodeWriter.java │ │ │ ├── FilterCodeVisitor.java │ │ │ ├── FilterInstructionVisitor.java │ │ │ ├── InstructionIO.java │ │ │ ├── InstructionVisitor.java │ │ │ └── InvalidInstructionException.java │ │ ├── stackmap │ │ │ ├── StackMapTableAttribute.java │ │ │ ├── frame │ │ │ │ ├── AppendFrame.java │ │ │ │ ├── ChopFrame.java │ │ │ │ ├── FrameTypeRange.java │ │ │ │ ├── FullFrame.java │ │ │ │ ├── SameExtendedFrame.java │ │ │ │ ├── SameFrame.java │ │ │ │ ├── SameLocalsOneStackItemExtendedFrame.java │ │ │ │ ├── SameLocalsOneStackItemFrame.java │ │ │ │ ├── StackMapFrame.java │ │ │ │ └── StackMapFrameType.java │ │ │ └── type │ │ │ │ ├── DoubleVerificationTypeInfo.java │ │ │ │ ├── FloatVerificationTypeInfo.java │ │ │ │ ├── IntegerVerificationTypeInfo.java │ │ │ │ ├── LongVerificationTypeInfo.java │ │ │ │ ├── NullVerificationTypeInfo.java │ │ │ │ ├── ObjectVariableVerificationTypeInfo.java │ │ │ │ ├── TopVerificationTypeInfo.java │ │ │ │ ├── UninitializedThisVerificationTypeInfo.java │ │ │ │ ├── UninitializedVariableVerificationTypeInfo.java │ │ │ │ ├── VerificationType.java │ │ │ │ └── VerificationTypeInfo.java │ │ └── type │ │ │ ├── CatchTargetInfo.java │ │ │ ├── EmptyTargetInfo.java │ │ │ ├── FormalParameterTargetInfo.java │ │ │ ├── LocalVariableTargetInfo.java │ │ │ ├── OffsetTargetInfo.java │ │ │ ├── ParameterBoundTargetInfo.java │ │ │ ├── ParameterTargetInfo.java │ │ │ ├── RuntimeInvisibleTypeAnnotationsAttribute.java │ │ │ ├── RuntimeTypeAnnotationsAttribute.java │ │ │ ├── RuntimeVisibleTypeAnnotationsAttribute.java │ │ │ ├── SuperTypeTargetInfo.java │ │ │ ├── TargetInfo.java │ │ │ ├── TargetType.java │ │ │ ├── ThrowsTargetInfo.java │ │ │ ├── TypeAnnotation.java │ │ │ ├── TypeArgumentInfo.java │ │ │ └── TypePath.java │ │ ├── constantpool │ │ ├── BuiltConstantPool.java │ │ ├── ConstantClass.java │ │ ├── ConstantDouble.java │ │ ├── ConstantEntry.java │ │ ├── ConstantFieldReference.java │ │ ├── ConstantFloat.java │ │ ├── ConstantInteger.java │ │ ├── ConstantInterfaceMethodReference.java │ │ ├── ConstantInvokeDynamic.java │ │ ├── ConstantLong.java │ │ ├── ConstantMethodReference.java │ │ ├── ConstantMethodType.java │ │ ├── ConstantModule.java │ │ ├── ConstantNameAndType.java │ │ ├── ConstantPackage.java │ │ ├── ConstantPool.java │ │ ├── ConstantPoolBuilder.java │ │ ├── ConstantPoolCollector.java │ │ ├── ConstantPoolIO.java │ │ ├── ConstantPoolVisitor.java │ │ ├── ConstantReference.java │ │ ├── ConstantString.java │ │ ├── ConstantUtf8.java │ │ ├── ConstantethodHandle.java │ │ ├── FilterConstantPoolVisitor.java │ │ ├── Tag.java │ │ └── ValueEntry.java │ │ ├── dynamic │ │ ├── MethodHandle.java │ │ └── ReferenceKind.java │ │ ├── field │ │ ├── FieldAdapter.java │ │ ├── FieldVisitor.java │ │ └── FilterFieldVisitor.java │ │ ├── io │ │ ├── Codec.java │ │ ├── ContextCodec.java │ │ ├── ContextDecoder.java │ │ ├── ContextEncoder.java │ │ ├── ContextSkip.java │ │ ├── Decoder.java │ │ ├── Encoder.java │ │ ├── Input.java │ │ ├── Output.java │ │ ├── Seekable.java │ │ ├── Skip.java │ │ └── buffer │ │ │ ├── ByteBufferAllocator.java │ │ │ ├── ByteBufferInput.java │ │ │ ├── ByteBufferOutput.java │ │ │ └── ImmediateAllocator.java │ │ ├── method │ │ ├── FilterMethodVisitor.java │ │ ├── MethodAdapter.java │ │ └── MethodVisitor.java │ │ └── opcode │ │ ├── AbstractInstruction.java │ │ ├── EmptyInstruction.java │ │ ├── FieldInstruction.java │ │ ├── FlowInstruction.java │ │ ├── IincInstruction.java │ │ ├── Instruction.java │ │ ├── IntJumpInstruction.java │ │ ├── JumpInstruction.java │ │ ├── JvmOpcodes.java │ │ ├── Label.java │ │ ├── LookupSwitchInstruction.java │ │ ├── MethodInstruction.java │ │ ├── Opcode.java │ │ ├── ShortJumpInstruction.java │ │ ├── SignedShortInstruction.java │ │ ├── SingedByteInstruction.java │ │ ├── TableSwitchInstruction.java │ │ ├── TwoUnsignedShortInstruction.java │ │ ├── UnsignedByteInstruction.java │ │ ├── UnsignedShortInstruction.java │ │ └── WideInstruction.java │ └── test │ └── java │ └── dev │ └── xdark │ └── classfile │ ├── ClassIOTest.java │ ├── ClassWriteTest.java │ └── ConstantTest.java ├── classfile-patcher ├── README.md ├── build.gradle └── src │ └── main │ └── java │ └── dev │ └── xdark │ └── classfile │ ├── ForeignAttributeFilter.java │ ├── OakVersionPatcher.java │ └── UnknownAttributeFilter.java ├── classfile-tree ├── README.md ├── build.gradle └── src │ ├── main │ └── java │ │ └── dev │ │ └── xdark │ │ └── classfile │ │ ├── ClassNode.java │ │ ├── FieldNode.java │ │ ├── MethodNode.java │ │ ├── NodeUtil.java │ │ ├── UnknownAttributeCollector.java │ │ ├── UnknownStoredAttribute.java │ │ └── pseuo │ │ ├── DoublePushInstructionNode.java │ │ ├── FieldInstructionNode.java │ │ ├── FloatPushInstructionNode.java │ │ ├── IncrementInstructionNode.java │ │ ├── InstructionNode.java │ │ ├── IntPushInstructionNode.java │ │ ├── LdcInstructionNode.java │ │ ├── LongPushInstructionNode.java │ │ ├── MethodInstructionNode.java │ │ └── TypeInstructionNode.java │ └── test │ └── java │ └── dev │ └── xdark │ └── classfile │ └── ClassNodeTest.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | out/ 3 | .idea/ 4 | .idea_modules/ 5 | *.iws 6 | *.iml 7 | 8 | # Eclipse 9 | .settings/ 10 | .classpath 11 | .checkstyle 12 | .project 13 | 14 | # Gradle 15 | build/ 16 | generated/ 17 | gradle-app.setting 18 | .gradle 19 | .gradletasknamecache 20 | !gradle-wrapper.jar 21 | **/build/ 22 | 23 | # Misc 24 | hs_err_pid* 25 | *.log 26 | *.ctxt 27 | temp/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xxDark 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # classfile 2 | ASM-like obfuscation-resistant classfile library. 3 | 4 | ## WIP -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | group 'dev.xdark' 3 | version '1.0' 4 | } 5 | 6 | subprojects { 7 | apply plugin: 'java' 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compileOnly 'org.jetbrains:annotations:23.0.0' 14 | testCompileOnly 'org.jetbrains:annotations:23.0.0' 15 | 16 | def junitVersion = '5.9.0' 17 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" 18 | testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" 19 | testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" 20 | } 21 | 22 | test { 23 | useJUnitPlatform() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/README.md: -------------------------------------------------------------------------------- 1 | # classfile-core 2 | Contains core functionality of the library 3 | -------------------------------------------------------------------------------- /classfile-core/build.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxDark/classfile/37d134a81b62c1194223858a8cb8a9464babb4c1/classfile-core/build.gradle -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/AttributeWriter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.attribute.Attribute; 4 | import dev.xdark.classfile.attribute.AttributeIO; 5 | import dev.xdark.classfile.attribute.AttributeVisitor; 6 | import dev.xdark.classfile.io.Output; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.io.IOException; 10 | import java.io.UncheckedIOException; 11 | 12 | final class AttributeWriter implements AttributeVisitor { 13 | private final Output output; 14 | private final ClassContext classContext; 15 | private int count; 16 | private int position; 17 | 18 | AttributeWriter(Output output, ClassContext classContext) { 19 | this.output = output; 20 | this.classContext = classContext; 21 | } 22 | 23 | @Override 24 | public void visitAttributes() { 25 | position = output.position(); 26 | try { 27 | output.writeShort(0); 28 | } catch (IOException ex) { 29 | throw new UncheckedIOException(ex); 30 | } 31 | } 32 | 33 | @Override 34 | public void visitAttribute(int nameIndex, @NotNull Attribute attribute) { 35 | try { 36 | AttributeIO.write(output, nameIndex, classContext, attribute); 37 | } catch (IOException ex) { 38 | throw new UncheckedIOException(ex); 39 | } 40 | count++; 41 | } 42 | 43 | @Override 44 | public void visitEnd() { 45 | try { 46 | Output output = this.output; 47 | int position = output.position(); 48 | output.position(this.position); 49 | output.writeShort(count); 50 | output.position(position); 51 | } catch (IOException ex) { 52 | throw new UncheckedIOException(ex); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/ClassContext.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.constantpool.ConstantPool; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Class context for context-aware codecs. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ClassContext { 12 | private final ClassVersion classVersion; 13 | private final ConstantPool constantPool; 14 | 15 | public ClassContext(ClassVersion classVersion, ConstantPool constantPool) { 16 | this.classVersion = classVersion; 17 | this.constantPool = constantPool; 18 | } 19 | 20 | /** 21 | * @return Class version. 22 | */ 23 | @NotNull 24 | public ClassVersion getClassVersion() { 25 | return classVersion; 26 | } 27 | 28 | /** 29 | * @return Constant pool. 30 | */ 31 | @NotNull 32 | public ConstantPool getConstantPool() { 33 | return constantPool; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/ClassVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.attribute.AttributeVisitor; 4 | import dev.xdark.classfile.constantpool.ConstantPoolVisitor; 5 | import dev.xdark.classfile.field.FieldVisitor; 6 | import dev.xdark.classfile.method.MethodVisitor; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * Class visitor. 12 | * 13 | * @author xDark 14 | * @apiNote Some classes may call methods out of order, 15 | * for example, some class may call {@link ClassVisitor#visitMethod(AccessFlag, int, int)} or any other method 16 | * before calling {@link ClassVisitor#visit(ClassVersion, AccessFlag, int, int, int[])}. 17 | */ 18 | public interface ClassVisitor { 19 | 20 | /** 21 | * Called before this class is visited. 22 | */ 23 | void visitClass(); 24 | 25 | /** 26 | * Visits constant pool. 27 | * 28 | * @return Constant pool visitor or {@code null}, 29 | * if constant pool can be skipped. 30 | */ 31 | @Nullable ConstantPoolVisitor visitConstantPool(); 32 | 33 | /** 34 | * @param version Class version. 35 | * @param access Access flags. 36 | * @param thisClass Class name index. 37 | * @param superClass Super name index. 38 | * @param interfaces Interface name indices. 39 | */ 40 | void visit(@NotNull ClassVersion version, @NotNull AccessFlag access, int thisClass, int superClass, int[] interfaces); 41 | 42 | /** 43 | * Visits new field. 44 | * 45 | * @param access Field access. 46 | * @param nameIndex Field name index. 47 | * @param descriptorIndex Field descriptor index. 48 | * @return New field visitor or {@code null}, 49 | * if field should not be visited. 50 | */ 51 | @Nullable FieldVisitor visitField(@NotNull AccessFlag access, int nameIndex, int descriptorIndex); 52 | 53 | /** 54 | * Visits new method. 55 | * 56 | * @param access Method access. 57 | * @param nameIndex Method name index. 58 | * @param descriptorIndex Method descriptor index. 59 | * @return New method visitor or {@code null}, 60 | * if method should not be visited. 61 | */ 62 | @Nullable MethodVisitor visitMethod(@NotNull AccessFlag access, int nameIndex, int descriptorIndex); 63 | 64 | /** 65 | * @return New attribute visitor or {@code null}, 66 | * if attributes should not be visited. 67 | */ 68 | @Nullable AttributeVisitor visitAttributes(); 69 | 70 | /** 71 | * Called after class has been visited. 72 | */ 73 | void visitEnd(); 74 | } 75 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/FieldWriter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.attribute.AttributeCollector; 4 | import dev.xdark.classfile.attribute.AttributeIO; 5 | import dev.xdark.classfile.attribute.AttributeVisitor; 6 | import dev.xdark.classfile.attribute.NamedAttributeInstance; 7 | import dev.xdark.classfile.field.FieldVisitor; 8 | import dev.xdark.classfile.io.Output; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | final class FieldWriter implements FieldVisitor { 16 | private final List> attributes = new ArrayList<>(); 17 | private AccessFlag access; 18 | private int nameIndex; 19 | private int descriptorIndex; 20 | 21 | @Override 22 | public void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 23 | this.access = access; 24 | this.nameIndex = nameIndex; 25 | this.descriptorIndex = descriptorIndex; 26 | } 27 | 28 | @Override 29 | public @NotNull AttributeVisitor visitAttributes() { 30 | return new AttributeCollector(attributes); 31 | } 32 | 33 | @Override 34 | public void visitEnd() { 35 | } 36 | 37 | void writeTo(Output output, ClassContext classContext) throws IOException { 38 | output.writeShort(access.mask()); 39 | output.writeShort(nameIndex); 40 | output.writeShort(descriptorIndex); 41 | AttributeIO.write(output, attributes, classContext); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/FilterClassVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.attribute.AttributeVisitor; 4 | import dev.xdark.classfile.constantpool.ConstantPool; 5 | import dev.xdark.classfile.constantpool.ConstantPoolVisitor; 6 | import dev.xdark.classfile.field.FieldVisitor; 7 | import dev.xdark.classfile.method.MethodVisitor; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Class visitor that forwards to another visitor. 13 | * 14 | * @author xDark 15 | */ 16 | public class FilterClassVisitor implements ClassVisitor { 17 | @Nullable 18 | protected ClassVisitor cv; 19 | 20 | public FilterClassVisitor(@Nullable ClassVisitor cv) { 21 | this.cv = cv; 22 | } 23 | 24 | public FilterClassVisitor() { 25 | } 26 | 27 | @Override 28 | public void visitClass() { 29 | ClassVisitor cv = this.cv; 30 | if (cv != null) { 31 | cv.visitClass(); 32 | } 33 | } 34 | 35 | @Override 36 | public ConstantPoolVisitor visitConstantPool() { 37 | ClassVisitor cv = this.cv; 38 | return cv == null ? null : cv.visitConstantPool(); 39 | } 40 | 41 | @Override 42 | public void visit(@NotNull ClassVersion version, @NotNull AccessFlag access, int thisClass, int superClass, int[] interfaces) { 43 | ClassVisitor cv = this.cv; 44 | if (cv != null) { 45 | cv.visit(version, access, thisClass, superClass, interfaces); 46 | } 47 | } 48 | 49 | @Override 50 | public FieldVisitor visitField(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 51 | ClassVisitor cv = this.cv; 52 | if (cv != null) { 53 | return cv.visitField(access, nameIndex, descriptorIndex); 54 | } 55 | return null; 56 | } 57 | 58 | @Override 59 | public MethodVisitor visitMethod(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 60 | ClassVisitor cv = this.cv; 61 | if (cv != null) { 62 | return cv.visitMethod(access, nameIndex, descriptorIndex); 63 | } 64 | return null; 65 | } 66 | 67 | @Override 68 | public AttributeVisitor visitAttributes() { 69 | ClassVisitor cv = this.cv; 70 | return cv == null ? null : cv.visitAttributes(); 71 | } 72 | 73 | @Override 74 | public void visitEnd() { 75 | ClassVisitor cv = this.cv; 76 | if (cv != null) { 77 | cv.visitEnd(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/InvalidClassException.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Thrown when class contains invalid data. 7 | * 8 | * @author xDark 9 | */ 10 | public class InvalidClassException extends IOException { 11 | 12 | public InvalidClassException() { 13 | } 14 | 15 | public InvalidClassException(String message) { 16 | super(message); 17 | } 18 | 19 | public InvalidClassException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/MethodWriter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile; 2 | 3 | import dev.xdark.classfile.attribute.AttributeCollector; 4 | import dev.xdark.classfile.attribute.AttributeIO; 5 | import dev.xdark.classfile.attribute.AttributeVisitor; 6 | import dev.xdark.classfile.attribute.NamedAttributeInstance; 7 | import dev.xdark.classfile.io.Output; 8 | import dev.xdark.classfile.method.MethodVisitor; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | final class MethodWriter implements MethodVisitor { 16 | private final List> attributes = new ArrayList<>(); 17 | private AccessFlag access; 18 | private int nameIndex; 19 | private int descriptorIndex; 20 | 21 | @Override 22 | public void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 23 | this.access = access; 24 | this.nameIndex = nameIndex; 25 | this.descriptorIndex = descriptorIndex; 26 | } 27 | 28 | @Override 29 | public @NotNull AttributeVisitor visitAttributes() { 30 | return new AttributeCollector(attributes); 31 | } 32 | 33 | @Override 34 | public void visitEnd() { 35 | } 36 | 37 | void writeTo(Output output, ClassContext classContext) throws IOException { 38 | output.writeShort(access.mask()); 39 | output.writeShort(nameIndex); 40 | output.writeShort(descriptorIndex); 41 | AttributeIO.write(output, attributes, classContext); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/AnnotationArrayVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Annotation array visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public interface AnnotationArrayVisitor { 12 | 13 | /** 14 | * Called before array is visited. 15 | * 16 | * @param length Array length. 17 | */ 18 | void visitArray(int length); 19 | 20 | /** 21 | * @param value Element constant. 22 | */ 23 | void visitConstant(@NotNull ElementValueConstant value); 24 | 25 | /** 26 | * @param value Enum element. 27 | */ 28 | void visitEnum(@NotNull ElementValueEnum value); 29 | 30 | /** 31 | * @return Nested annotation visitor or {@code null}, 32 | * if annotation can be skipped. 33 | */ 34 | @Nullable AnnotationVisitor visitAnnotation(); 35 | 36 | /** 37 | * Called after the array has been visited. 38 | */ 39 | void visitEnd(); 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/AnnotationVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Annotation visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public interface AnnotationVisitor { 12 | 13 | /** 14 | * @param typeIndex Annotation class index. 15 | * @param count Element count. 16 | */ 17 | void visitAnnotation(int typeIndex, int count); 18 | 19 | /** 20 | * @param nameIndex Name index. 21 | * @param value Element constant. 22 | */ 23 | void visitConstant(int nameIndex, @NotNull ElementValueConstant value); 24 | 25 | /** 26 | * @param nameIndex Name index. 27 | * @param value Enum element. 28 | */ 29 | void visitEnum(int nameIndex, @NotNull ElementValueEnum value); 30 | 31 | /** 32 | * @param nameIndex Name index. 33 | * @return Nested annotation visitor or {@code null}, 34 | * if annotation can be skipped. 35 | */ 36 | @Nullable AnnotationVisitor visitNestedAnnotation(int nameIndex); 37 | 38 | /** 39 | * @param nameIndex Name index. 40 | * @return Array visitor or {@code null}, 41 | * if annotation can be skipped. 42 | */ 43 | @Nullable AnnotationArrayVisitor visitArray(int nameIndex); 44 | 45 | /** 46 | * Called after annotation has been visited. 47 | */ 48 | void visitEnd(); 49 | } 50 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValue.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Annotation element value. 7 | * 8 | * @author xDark 9 | */ 10 | public interface ElementValue> { 11 | 12 | /** 13 | * @return Element type. 14 | */ 15 | @NotNull ElementType type(); 16 | } 17 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueArray.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Element value that represents an array. 8 | * 9 | * @author xdark 10 | */ 11 | public final class ElementValueArray implements ElementValue { 12 | static final Codec CODEC = Codec.of(input -> { 13 | int count = input.readUnsignedShort(); 14 | if (input.remaining() < count * 3) { 15 | throw new InvalidAnnotationException("Annotation too small"); 16 | } 17 | ElementValue[] values = new ElementValue[count]; 18 | for (int i = 0; i < count; i++) { 19 | int tag = input.readUnsignedByte(); 20 | ElementType type = ElementType.of(tag); 21 | if (type == null) { 22 | throw new InvalidAnnotationException("Unknown tag " + (char) tag); 23 | } 24 | values[i] = type.codec().read(input); 25 | } 26 | return new ElementValueArray(values); 27 | }, (output, value) -> { 28 | ElementValue[] values = value.getValues(); 29 | output.writeShort(values.length); 30 | for (ElementValue v : values) { 31 | ElementType type = v.type(); 32 | output.writeByte(type.tag()); 33 | ((Codec) type.codec()).write(output, v); 34 | } 35 | }, input -> { 36 | int count = input.readUnsignedShort(); 37 | for (int i = 0; i < count; i++) { 38 | int tag = input.readUnsignedByte(); 39 | ElementType type = ElementType.of(tag); 40 | if (type == null) { 41 | throw new InvalidAnnotationException("Unknown tag " + (char) tag); 42 | } 43 | type.codec().skip(input); 44 | } 45 | }); 46 | private final ElementValue[] values; 47 | 48 | /** 49 | * @param values Array of values. 50 | */ 51 | public ElementValueArray(ElementValue[] values) { 52 | this.values = values; 53 | } 54 | 55 | /** 56 | * @return Array of values. 57 | */ 58 | public ElementValue[] getValues() { 59 | return values; 60 | } 61 | 62 | @Override 63 | public @NotNull ElementType type() { 64 | return ElementType.ARRAY; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueBoolean.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a boolean. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueBoolean extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueBoolean::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueBoolean(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.BOOLEAN; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueByte.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a byte. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueByte extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueByte::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueByte(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.BYTE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueChar.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a char. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueChar extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueChar::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueChar(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.CHAR; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueClass.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a class. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueClass extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueClass::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueClass(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.CLASS; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueConstant.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | import java.util.function.IntFunction; 7 | 8 | /** 9 | * Annotation element value that points to an 10 | * entry in the constant pool. 11 | * 12 | * @author xDark 13 | */ 14 | public abstract class ElementValueConstant> implements ElementValue { 15 | private final int index; 16 | 17 | /** 18 | * @param index Constant pool entry index. 19 | */ 20 | protected ElementValueConstant(int index) { 21 | this.index = index; 22 | } 23 | 24 | /** 25 | * @return Constant pool entry index. 26 | */ 27 | public int getIndex() { 28 | return index; 29 | } 30 | 31 | protected static > Codec codec(IntFunction fn) { 32 | return Codec.of(input -> { 33 | return fn.apply(input.readUnsignedShort()); 34 | }, (output, value) -> { 35 | output.writeShort(value.getIndex()); 36 | }, Skip.exact(2)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueDouble.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a double. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueDouble extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueDouble::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueDouble(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.DOUBLE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueEnum.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Annotation element value that represents enum constant. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ElementValueEnum implements ElementValue { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ElementValueEnum(input.readUnsignedShort(), input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.getClassIndex()); 17 | output.writeShort(value.getNameIndex()); 18 | }, Skip.exact(4)); 19 | private final int classIndex; 20 | private final int nameIndex; 21 | 22 | /** 23 | * @param classIndex Constant pool entry index to a enum class. 24 | * @param nameIndex Constant pool entry index to a enum name. 25 | */ 26 | public ElementValueEnum(int classIndex, int nameIndex) { 27 | this.classIndex = classIndex; 28 | this.nameIndex = nameIndex; 29 | } 30 | 31 | /** 32 | * @return Constant pool entry index to a enum class. 33 | */ 34 | public int getClassIndex() { 35 | return classIndex; 36 | } 37 | 38 | /** 39 | * @return Constant pool entry index to a enum name. 40 | */ 41 | public int getNameIndex() { 42 | return nameIndex; 43 | } 44 | 45 | @Override 46 | public @NotNull ElementType type() { 47 | return ElementType.ENUM; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueFloat.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a float. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueFloat extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueFloat::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueFloat(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.FLOAT; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueInt.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to an int. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueInt extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueInt::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueInt(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.INT; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueLong.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a long. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueLong extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueLong::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueLong(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.LONG; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueShort.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a short. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueShort extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueShort::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueShort(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.SHORT; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/ElementValueString.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Annotation element value that points to a string. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ElementValueString extends ElementValueConstant { 12 | static final Codec CODEC = codec(ElementValueString::new); 13 | 14 | /** 15 | * @param index Constant pool entry index. 16 | */ 17 | public ElementValueString(int index) { 18 | super(index); 19 | } 20 | 21 | @Override 22 | public @NotNull ElementType type() { 23 | return ElementType.STRING; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/FilterAnnotationArrayVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Annotation array visitor that forwards to another visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public class FilterAnnotationArrayVisitor implements AnnotationArrayVisitor { 12 | @Nullable 13 | protected AnnotationArrayVisitor av; 14 | 15 | public FilterAnnotationArrayVisitor(@Nullable AnnotationArrayVisitor av) { 16 | this.av = av; 17 | } 18 | 19 | @Override 20 | public void visitArray(int length) { 21 | AnnotationArrayVisitor av = this.av; 22 | if (av != null) { 23 | av.visitArray(length); 24 | } 25 | } 26 | 27 | @Override 28 | public void visitConstant(@NotNull ElementValueConstant value) { 29 | AnnotationArrayVisitor av = this.av; 30 | if (av != null) { 31 | av.visitConstant(value); 32 | } 33 | } 34 | 35 | @Override 36 | public void visitEnum(@NotNull ElementValueEnum value) { 37 | AnnotationArrayVisitor av = this.av; 38 | if (av != null) { 39 | av.visitEnum(value); 40 | } 41 | } 42 | 43 | @Override 44 | public @Nullable AnnotationVisitor visitAnnotation() { 45 | AnnotationArrayVisitor av = this.av; 46 | return av == null ? null : av.visitAnnotation(); 47 | } 48 | 49 | @Override 50 | public void visitEnd() { 51 | AnnotationArrayVisitor av = this.av; 52 | if (av != null) { 53 | av.visitEnd(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/FilterAnnotationVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Annotation visitor that forwards to another visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public class FilterAnnotationVisitor implements AnnotationVisitor { 12 | @Nullable 13 | protected AnnotationVisitor av; 14 | 15 | public FilterAnnotationVisitor(@Nullable AnnotationVisitor av) { 16 | this.av = av; 17 | } 18 | 19 | @Override 20 | public void visitAnnotation(int typeIndex, int count) { 21 | AnnotationVisitor av = this.av; 22 | if (av != null) { 23 | av.visitAnnotation(typeIndex, count); 24 | } 25 | } 26 | 27 | @Override 28 | public void visitConstant(int nameIndex, @NotNull ElementValueConstant value) { 29 | AnnotationVisitor av = this.av; 30 | if (av != null) { 31 | av.visitConstant(nameIndex, value); 32 | } 33 | } 34 | 35 | @Override 36 | public void visitEnum(int nameIndex, @NotNull ElementValueEnum value) { 37 | AnnotationVisitor av = this.av; 38 | if (av != null) { 39 | av.visitEnum(nameIndex, value); 40 | } 41 | } 42 | 43 | @Override 44 | public @Nullable AnnotationVisitor visitNestedAnnotation(int nameIndex) { 45 | AnnotationVisitor av = this.av; 46 | return av == null ? null : av.visitNestedAnnotation(nameIndex); 47 | } 48 | 49 | @Override 50 | public @Nullable AnnotationArrayVisitor visitArray(int nameIndex) { 51 | AnnotationVisitor av = this.av; 52 | return av == null ? null : av.visitArray(nameIndex); 53 | } 54 | 55 | @Override 56 | public void visitEnd() { 57 | AnnotationVisitor av = this.av; 58 | if (av != null) { 59 | av.visitEnd(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/annotation/InvalidAnnotationException.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.annotation; 2 | 3 | import dev.xdark.classfile.InvalidClassException; 4 | 5 | /** 6 | * Thrown when annotation contains invalid data. 7 | * 8 | * @author xDark 9 | */ 10 | public final class InvalidAnnotationException extends InvalidClassException { 11 | 12 | public InvalidAnnotationException() { 13 | } 14 | 15 | public InvalidAnnotationException(String message) { 16 | super(message); 17 | } 18 | 19 | public InvalidAnnotationException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/AnnotationDefaultAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.annotation.ElementType; 4 | import dev.xdark.classfile.annotation.ElementValue; 5 | import dev.xdark.classfile.io.Codec; 6 | import dev.xdark.classfile.io.Skip; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * AnnotationDefault. 11 | * 12 | * @author xDark 13 | */ 14 | public final class AnnotationDefaultAttribute implements Attribute { 15 | static final Codec CODEC = Codec.of(input -> { 16 | int length = input.readInt(); 17 | if (length < 3) { 18 | throw new InvalidAttributeException("Length is less than 3"); 19 | } 20 | int tag = input.readUnsignedByte(); 21 | ElementType type = ElementType.of(tag); 22 | if (type == null) { 23 | throw new InvalidAttributeException("Unknown element type " + (char) tag); 24 | } 25 | return new AnnotationDefaultAttribute(type.codec().read(input)); 26 | }, (output, value) -> { 27 | int position = output.position(); 28 | output.writeInt(0); 29 | ElementValue v = value.getValue(); 30 | ElementType type = v.type(); 31 | output.writeByte(type.tag()); 32 | ((Codec) type.codec()).write(output, v); 33 | int newPosition = output.position(); 34 | output.position(position).writeInt(newPosition - position - 4); 35 | output.position(newPosition); 36 | }, Skip.u32()); 37 | private final ElementValue value; 38 | 39 | /** 40 | * @param value Default value. 41 | */ 42 | public AnnotationDefaultAttribute(ElementValue value) { 43 | this.value = value; 44 | } 45 | 46 | /** 47 | * @return Default value. 48 | */ 49 | public ElementValue getValue() { 50 | return value; 51 | } 52 | 53 | @Override 54 | public @NotNull AttributeInfo info() { 55 | return AttributeInfo.AnnotationDefault; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/Attribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Attribute. 7 | * 8 | * @author xDark 9 | */ 10 | public interface Attribute> { 11 | 12 | /** 13 | * @return Attribute info. 14 | */ 15 | @NotNull AttributeInfo info(); 16 | } 17 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/AttributeAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.constantpool.ConstantPoolBuilder; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Attribute adapter. 8 | * 9 | * @author xDark 10 | */ 11 | public class AttributeAdapter extends FilterAttributeVisitor { 12 | protected final ConstantPoolBuilder builder; 13 | 14 | /** 15 | * @param av Backing attribute visitor. 16 | * @param builder Constant pool builder. 17 | */ 18 | public AttributeAdapter(@NotNull AttributeVisitor av, ConstantPoolBuilder builder) { 19 | super(av); 20 | this.builder = builder; 21 | } 22 | 23 | /** 24 | * @param name Attribute name. 25 | * @param attribute Attribute. 26 | */ 27 | public void visitAttribute(String name, Attribute attribute) { 28 | visitAttribute(builder.putUtf8(name), attribute); 29 | } 30 | 31 | /** 32 | * @param attribute Attribute. 33 | * @throws IllegalArgumentException If attribute is not known. 34 | */ 35 | public void visitAttribute(Attribute attribute) { 36 | KnownInfo known = attribute.info().known(); 37 | if (known == null) { 38 | throw new IllegalArgumentException("Unknown attribute " + attribute); 39 | } 40 | visitAttribute(known.name(), attribute); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/AttributeCollector.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * Collects attributes into collection. 9 | * 10 | * @author xDark 11 | */ 12 | public final class AttributeCollector implements AttributeVisitor { 13 | 14 | private final Collection> attributes; 15 | 16 | /** 17 | * @param attributes Output collection. 18 | */ 19 | public AttributeCollector(Collection> attributes) { 20 | this.attributes = attributes; 21 | } 22 | 23 | @Override 24 | public void visitAttributes() { 25 | } 26 | 27 | @Override 28 | public void visitAttribute(int nameIndex, @NotNull Attribute attribute) { 29 | attributes.add(new NamedAttributeInstance(nameIndex, attribute)); 30 | } 31 | 32 | @Override 33 | public void visitEnd() { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/AttributeLocation.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | /** 4 | * Attribute location. 5 | * 6 | * @author xDrak 7 | */ 8 | public enum AttributeLocation { 9 | CLASS, 10 | METHOD, 11 | FIELD, 12 | RECORD, 13 | CODE, 14 | } 15 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/AttributeVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Attribute visitor. 7 | * 8 | * @author xDark 9 | */ 10 | public interface AttributeVisitor { 11 | 12 | /** 13 | * Called before the attributes are visited. 14 | */ 15 | void visitAttributes(); 16 | 17 | /** 18 | * Visits new attribute. 19 | * 20 | * @param nameIndex Attribute name index. 21 | * @param attribute Attribute visited. 22 | */ 23 | void visitAttribute(int nameIndex, @NotNull Attribute attribute); 24 | 25 | /** 26 | * Called after all attributes have been visited. 27 | */ 28 | void visitEnd(); 29 | } 30 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/ConstantValueAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * ConstantValue. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantValueAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 2) { 15 | throw new InvalidAttributeException("Attribute length is not 2"); 16 | } 17 | return new ConstantValueAttribute(input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeShort(2); 20 | output.writeShort(value.getIndex()); 21 | }, Skip.u32()); 22 | private final int index; 23 | 24 | /** 25 | * @param index Constant index. 26 | */ 27 | public ConstantValueAttribute(int index) { 28 | this.index = index; 29 | } 30 | 31 | /** 32 | * @return Constant index. 33 | */ 34 | public int getIndex() { 35 | return index; 36 | } 37 | 38 | @Override 39 | public @NotNull AttributeInfo info() { 40 | return AttributeInfo.ConstantValue; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/DeprecatedAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Deprecated. 9 | * 10 | * @author xDark 11 | */ 12 | public final class DeprecatedAttribute implements Attribute { 13 | private static final DeprecatedAttribute INSTANCE = new DeprecatedAttribute(); 14 | static final Codec CODEC = Codec.of(input -> { 15 | if (input.readInt() != 0) { 16 | throw new InvalidAttributeException("Attribute not empty"); 17 | } 18 | return INSTANCE; 19 | }, (output, value) -> { 20 | output.writeInt(0); 21 | }, Skip.u32()); 22 | 23 | @Override 24 | public @NotNull AttributeInfo info() { 25 | return AttributeInfo.Deprecated; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/EnclosingMethodAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * EnclosingMethod. 9 | * 10 | * @author xDark 11 | */ 12 | public final class EnclosingMethodAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 4) { 15 | throw new InvalidAttributeException("Attribute length is not 4"); 16 | } 17 | return new EnclosingMethodAttribute(input.readUnsignedShort(), input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeInt(4); 20 | output.writeShort(value.getClassIndex()); 21 | output.writeShort(value.getMethodIndex()); 22 | }, Skip.u32()); 23 | private final int classIndex; 24 | private final int methodIndex; 25 | 26 | /** 27 | * @param classIndex Class index. 28 | * @param methodIndex Method index. 29 | */ 30 | public EnclosingMethodAttribute(int classIndex, int methodIndex) { 31 | this.classIndex = classIndex; 32 | this.methodIndex = methodIndex; 33 | } 34 | 35 | /** 36 | * @return Class index. 37 | */ 38 | public int getClassIndex() { 39 | return classIndex; 40 | } 41 | 42 | /** 43 | * @return Method index. 44 | */ 45 | public int getMethodIndex() { 46 | return methodIndex; 47 | } 48 | 49 | @Override 50 | public @NotNull AttributeInfo info() { 51 | return AttributeInfo.EnclosingMethod; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/ExceptionsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Exceptions. 9 | */ 10 | public final class ExceptionsAttribute implements Attribute { 11 | static final Codec CODEC = Codec.of(input -> { 12 | int length = input.readInt(); 13 | if (length < 2) { 14 | throw new InvalidAttributeException("Length is less than 2"); 15 | } 16 | int count = input.readUnsignedShort(); 17 | if (length != (count + 1) * 2) { 18 | throw new InvalidAttributeException("Invalid attribute content"); 19 | } 20 | return new ExceptionsAttribute(AttributeUtil.readUnsignedShorts(input, count)); 21 | }, (output, value) -> { 22 | int[] packages = value.getExceptions(); 23 | output.writeInt((packages.length + 1) * 2); 24 | AttributeUtil.writeUnsignedShorts(output, packages); 25 | }, Skip.u32()); 26 | private final int[] exceptions; 27 | 28 | /** 29 | * @param exceptions Exception indices. 30 | */ 31 | public ExceptionsAttribute(int[] exceptions) { 32 | this.exceptions = exceptions; 33 | } 34 | 35 | /** 36 | * @return Exception indices. 37 | */ 38 | public int[] getExceptions() { 39 | return exceptions; 40 | } 41 | 42 | @Override 43 | public @NotNull AttributeInfo info() { 44 | return AttributeInfo.Exceptions; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/FilterAttributeVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Attribute visitor that forwards to another visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public class FilterAttributeVisitor implements AttributeVisitor { 12 | @Nullable 13 | protected AttributeVisitor av; 14 | 15 | protected FilterAttributeVisitor(@Nullable AttributeVisitor av) { 16 | this.av = av; 17 | } 18 | 19 | protected FilterAttributeVisitor() { 20 | } 21 | 22 | @Override 23 | public void visitAttributes() { 24 | AttributeVisitor av = this.av; 25 | if (av != null) { 26 | av.visitAttributes(); 27 | } 28 | } 29 | 30 | @Override 31 | public void visitAttribute(int nameIndex, @NotNull Attribute attribute) { 32 | AttributeVisitor av = this.av; 33 | if (av != null) { 34 | av.visitAttribute(nameIndex, attribute); 35 | } 36 | } 37 | 38 | @Override 39 | public void visitEnd() { 40 | AttributeVisitor av = this.av; 41 | if (av != null) { 42 | av.visitEnd(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/InvalidAttributeException.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.InvalidClassException; 4 | 5 | /** 6 | * Thrown when known attribute contains invalid data. 7 | * 8 | * @author xDark 9 | */ 10 | public final class InvalidAttributeException extends InvalidClassException { 11 | 12 | public InvalidAttributeException() { 13 | } 14 | 15 | public InvalidAttributeException(String message) { 16 | super(message); 17 | } 18 | 19 | public InvalidAttributeException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/KnownInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import java.util.EnumSet; 4 | import java.util.Set; 5 | 6 | /** 7 | * Known attribute info. 8 | * 9 | * @author xDark 10 | */ 11 | public final class KnownInfo { 12 | private final String name; 13 | private final Set locations; 14 | 15 | private KnownInfo(String name, Set locations) { 16 | this.name = name; 17 | this.locations = locations; 18 | } 19 | 20 | /** 21 | * @return Attribute name, according to JVM spec. 22 | */ 23 | public String name() { 24 | return name; 25 | } 26 | 27 | /** 28 | * @return Set of locations where this attribute can appear. 29 | */ 30 | public Set locations() { 31 | return locations; 32 | } 33 | 34 | static KnownInfo kinfo(String name, AttributeLocation... locations) { 35 | return new KnownInfo(name, EnumSet.of(locations[0], locations)); 36 | } 37 | 38 | static KnownInfo kinfo(String name, AttributeLocation location) { 39 | return new KnownInfo(name, EnumSet.of(location)); 40 | } 41 | 42 | static KnownInfo kinfo(String name, AttributeLocation location1, AttributeLocation location2) { 43 | return new KnownInfo(name, EnumSet.of(location1, location2)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/ModuleMainClassAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * ModuleMainClass. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ModuleMainClassAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 2) { 15 | throw new InvalidAttributeException("Attribute length is not 2"); 16 | } 17 | return new ModuleMainClassAttribute(input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeShort(2); 20 | output.writeShort(value.getIndex()); 21 | }, Skip.u32()); 22 | private final int index; 23 | 24 | /** 25 | * @param index Main class index. 26 | */ 27 | public ModuleMainClassAttribute(int index) { 28 | this.index = index; 29 | } 30 | 31 | /** 32 | * @return Main class index. 33 | */ 34 | public int getIndex() { 35 | return index; 36 | } 37 | 38 | @Override 39 | public @NotNull AttributeInfo info() { 40 | return AttributeInfo.ModuleMainClass; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/ModulePackagesAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * ModulePackages. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ModulePackagesAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | int length = input.readUnsignedShort(); 15 | if (length < 2) { 16 | throw new InvalidAttributeException("Length is less than 2"); 17 | } 18 | int count = input.readUnsignedShort(); 19 | if (length != (count + 1) * 2) { 20 | throw new InvalidAttributeException("Invalid attribute content"); 21 | } 22 | return new ModulePackagesAttribute(AttributeUtil.readUnsignedShorts(input, count)); 23 | }, (output, value) -> { 24 | int[] packages = value.getPackages(); 25 | output.writeShort((packages.length + 1) * 2); 26 | AttributeUtil.writeUnsignedShorts(output, packages); 27 | }, Skip.u32()); 28 | private final int[] packages; 29 | 30 | /** 31 | * @param packages Package indices. 32 | */ 33 | public ModulePackagesAttribute(int[] packages) { 34 | this.packages = packages; 35 | } 36 | 37 | /** 38 | * @return Package indices. 39 | */ 40 | public int[] getPackages() { 41 | return packages; 42 | } 43 | 44 | @Override 45 | public @NotNull AttributeInfo info() { 46 | return AttributeInfo.ModulePackages; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/NamedAttributeInstance.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | /** 4 | * Named attribute. 5 | * 6 | * @author xDark 7 | */ 8 | public final class NamedAttributeInstance> { 9 | private final int nameIndex; 10 | private final T attribute; 11 | 12 | /** 13 | * @param nameIndex Name index. 14 | * @param attribute Attribute. 15 | */ 16 | public NamedAttributeInstance(int nameIndex, T attribute) { 17 | this.nameIndex = nameIndex; 18 | this.attribute = attribute; 19 | } 20 | 21 | /** 22 | * @return Name index. 23 | */ 24 | public int getNameIndex() { 25 | return nameIndex; 26 | } 27 | 28 | /** 29 | * @return Attribute. 30 | */ 31 | public T getAttribute() { 32 | return attribute; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/NestHostAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * NestHost. 9 | * 10 | * @author xDark 11 | */ 12 | public final class NestHostAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 2) { 15 | throw new InvalidAttributeException("Attribute length is not 2"); 16 | } 17 | return new NestHostAttribute(input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeShort(2); 20 | output.writeShort(value.getIndex()); 21 | }, Skip.u32()); 22 | private final int index; 23 | 24 | /** 25 | * @param index Host class index. 26 | */ 27 | public NestHostAttribute(int index) { 28 | this.index = index; 29 | } 30 | 31 | /** 32 | * @return Host class index. 33 | */ 34 | public int getIndex() { 35 | return index; 36 | } 37 | 38 | @Override 39 | public @NotNull AttributeInfo info() { 40 | return AttributeInfo.NestHost; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/NestMembersAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * NestMembers. 9 | */ 10 | public final class NestMembersAttribute implements Attribute { 11 | static final Codec CODEC = Codec.of(input -> { 12 | int length = input.readInt(); 13 | if (length < 2) { 14 | throw new InvalidAttributeException("Length is less than 2"); 15 | } 16 | int count = input.readUnsignedShort(); 17 | if (length != (count + 1) * 2) { 18 | throw new InvalidAttributeException("Invalid attribute content"); 19 | } 20 | return new NestMembersAttribute(AttributeUtil.readUnsignedShorts(input, count)); 21 | }, (output, value) -> { 22 | int[] classes = value.getClasses(); 23 | output.writeInt((classes.length + 1) * 2); 24 | AttributeUtil.writeUnsignedShorts(output, classes); 25 | }, Skip.u32()); 26 | private final int[] classes; 27 | 28 | /** 29 | * @param classes Class indices. 30 | */ 31 | public NestMembersAttribute(int[] classes) { 32 | this.classes = classes; 33 | } 34 | 35 | /** 36 | * @return Class indices. 37 | */ 38 | public int[] getClasses() { 39 | return classes; 40 | } 41 | 42 | @Override 43 | public @NotNull AttributeInfo info() { 44 | return AttributeInfo.NestMembers; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/PermittedSubclassesAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * PermittedSubclasses. 9 | */ 10 | public final class PermittedSubclassesAttribute implements Attribute { 11 | static final Codec CODEC = Codec.of(input -> { 12 | int length = input.readInt(); 13 | if (length < 2) { 14 | throw new InvalidAttributeException("Length is less than 2"); 15 | } 16 | int count = input.readUnsignedShort(); 17 | if (length != (count + 1) * 2) { 18 | throw new InvalidAttributeException("Invalid attribute content"); 19 | } 20 | return new PermittedSubclassesAttribute(AttributeUtil.readUnsignedShorts(input, count)); 21 | }, (output, value) -> { 22 | int[] classes = value.getClasses(); 23 | output.writeInt((classes.length + 1) * 2); 24 | AttributeUtil.writeUnsignedShorts(output, classes); 25 | }, Skip.u32()); 26 | private final int[] classes; 27 | 28 | /** 29 | * @param classes Class indices. 30 | */ 31 | public PermittedSubclassesAttribute(int[] classes) { 32 | this.classes = classes; 33 | } 34 | 35 | /** 36 | * @return Class indices. 37 | */ 38 | public int[] getClasses() { 39 | return classes; 40 | } 41 | 42 | @Override 43 | public @NotNull AttributeInfo info() { 44 | return AttributeInfo.PermittedSubclasses; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/RuntimeAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.annotation.ElementType; 4 | import dev.xdark.classfile.annotation.ElementValueAnnotation; 5 | import dev.xdark.classfile.io.Codec; 6 | import dev.xdark.classfile.io.Skip; 7 | 8 | import java.util.List; 9 | import java.util.function.Function; 10 | 11 | /** 12 | * Shared code between Runtime[In]visibleAnnotationsAttribute. 13 | * 14 | * @author xDark 15 | */ 16 | public abstract class RuntimeAnnotationsAttribute> implements Attribute { 17 | private final List annotations; 18 | 19 | /** 20 | * @param annotations List of annotations. 21 | */ 22 | protected RuntimeAnnotationsAttribute(List annotations) { 23 | this.annotations = annotations; 24 | } 25 | 26 | /** 27 | * @return List of annotations. 28 | */ 29 | public final List getAnnotations() { 30 | return annotations; 31 | } 32 | 33 | protected static > Codec codec(Function, T> fn) { 34 | return Codec.of(input -> { 35 | int length = input.readInt(); 36 | if (length < 2 + 4 /* count + initial information for the annotation (typeIndex, pairCount) */) { 37 | throw new InvalidAttributeException("Length is less than 6"); 38 | } 39 | return fn.apply(AttributeUtil.readList(input, ElementType.ANNOTATION.codec())); 40 | }, (output, value) -> { 41 | int position = output.position(); 42 | output.writeInt(0); 43 | AttributeUtil.writeList(output, value.getAnnotations(), ElementType.ANNOTATION.codec()); 44 | int newPosition = output.position(); 45 | output.position(position).writeInt(newPosition - position - 4); 46 | output.position(newPosition); 47 | }, Skip.u32()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.annotation.ElementValueAnnotation; 4 | import dev.xdark.classfile.io.Codec; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * RuntimeInvisibleAnnotations. 11 | * 12 | * @author xDark 13 | */ 14 | public final class RuntimeInvisibleAnnotationsAttribute extends RuntimeAnnotationsAttribute { 15 | static final Codec CODEC = codec(RuntimeInvisibleAnnotationsAttribute::new); 16 | 17 | /** 18 | * @param annotations List of annotations. 19 | */ 20 | public RuntimeInvisibleAnnotationsAttribute(List annotations) { 21 | super(annotations); 22 | } 23 | 24 | @Override 25 | public @NotNull AttributeInfo info() { 26 | return AttributeInfo.RuntimeInvisibleAnnotations; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/RuntimeInvisibleRuntimeParameterAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * RuntimeInvisibleParameterAnnotations. 10 | * 11 | * @author xDark 12 | */ 13 | public final class RuntimeInvisibleRuntimeParameterAnnotationsAttribute extends RuntimeParameterAnnotationsAttribute { 14 | static final Codec CODEC = codec(RuntimeInvisibleRuntimeParameterAnnotationsAttribute::new); 15 | 16 | /** 17 | * @param parameterAnnotations List of parameter annotations. 18 | */ 19 | public RuntimeInvisibleRuntimeParameterAnnotationsAttribute(List parameterAnnotations) { 20 | super(parameterAnnotations); 21 | } 22 | 23 | @Override 24 | public @NotNull AttributeInfo info() { 25 | return AttributeInfo.RuntimeInvisibleParameterAnnotations; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.annotation.ElementValueAnnotation; 4 | import dev.xdark.classfile.io.Codec; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * RuntimeVisibleAnnotations. 11 | * 12 | * @author xDark 13 | */ 14 | public final class RuntimeVisibleAnnotationsAttribute extends RuntimeAnnotationsAttribute { 15 | static final Codec CODEC = codec(RuntimeVisibleAnnotationsAttribute::new); 16 | 17 | /** 18 | * @param annotations List of annotations. 19 | */ 20 | public RuntimeVisibleAnnotationsAttribute(List annotations) { 21 | super(annotations); 22 | } 23 | 24 | @Override 25 | public @NotNull AttributeInfo info() { 26 | return AttributeInfo.RuntimeVisibleAnnotations; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/RuntimeVisibleRuntimeParameterAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * RuntimeVisibleParameterAnnotations. 10 | * 11 | * @author xDark 12 | */ 13 | public final class RuntimeVisibleRuntimeParameterAnnotationsAttribute extends RuntimeParameterAnnotationsAttribute { 14 | static final Codec CODEC = codec(RuntimeVisibleRuntimeParameterAnnotationsAttribute::new); 15 | 16 | /** 17 | * @param parameterAnnotations List of parameter annotations. 18 | */ 19 | public RuntimeVisibleRuntimeParameterAnnotationsAttribute(List parameterAnnotations) { 20 | super(parameterAnnotations); 21 | } 22 | 23 | @Override 24 | public @NotNull AttributeInfo info() { 25 | return AttributeInfo.RuntimeVisibleParameterAnnotations; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/SignatureAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * ConstantValue. 9 | * 10 | * @author xDark 11 | */ 12 | public final class SignatureAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 2) { 15 | throw new InvalidAttributeException("Attribute length is not 2"); 16 | } 17 | return new SignatureAttribute(input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeInt(2); 20 | output.writeShort(value.getIndex()); 21 | }, Skip.u32()); 22 | private final int index; 23 | 24 | /** 25 | * @param index Signature index. 26 | */ 27 | public SignatureAttribute(int index) { 28 | this.index = index; 29 | } 30 | 31 | /** 32 | * @return Signature index. 33 | */ 34 | public int getIndex() { 35 | return index; 36 | } 37 | 38 | @Override 39 | public @NotNull AttributeInfo info() { 40 | return AttributeInfo.Signature; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/SourceDebugExtensionAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * SourceDebugExtension. 9 | * 10 | * @author xDark 11 | */ 12 | public final class SourceDebugExtensionAttribute implements Attribute { 13 | 14 | static final Codec CODEC = Codec.of(input -> { 15 | return new SourceDebugExtensionAttribute(input.read(input.readInt())); 16 | }, (output, value) -> { 17 | byte[] extension = value.getExtension(); 18 | output.writeInt(extension.length); 19 | output.write(extension); 20 | }, Skip.u32()); 21 | private final byte[] extension; 22 | 23 | /** 24 | * @param extension Extension. 25 | */ 26 | public SourceDebugExtensionAttribute(byte[] extension) { 27 | this.extension = extension; 28 | } 29 | 30 | @Override 31 | public @NotNull AttributeInfo info() { 32 | return AttributeInfo.SourceDebugExtension; 33 | } 34 | 35 | /** 36 | * @return Source debug extension. 37 | */ 38 | public byte[] getExtension() { 39 | return extension; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/SourceFileAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * SourceFile. 9 | * 10 | * @author xDark 11 | */ 12 | public final class SourceFileAttribute implements Attribute { 13 | static final Codec CODEC = Codec.of(input -> { 14 | if (input.readInt() != 2) { 15 | throw new InvalidAttributeException("Attribute length is not 2"); 16 | } 17 | return new SourceFileAttribute(input.readUnsignedShort()); 18 | }, (output, value) -> { 19 | output.writeInt(2); 20 | output.writeShort(value.sourceFileIndex()); 21 | }, Skip.u32()); 22 | 23 | private final int sourceFileIndex; 24 | 25 | /** 26 | * @param sourceFileIndex Source file index. 27 | */ 28 | public SourceFileAttribute(int sourceFileIndex) { 29 | this.sourceFileIndex = sourceFileIndex; 30 | } 31 | 32 | /** 33 | * @return SourceFile content index. 34 | */ 35 | public int sourceFileIndex() { 36 | return sourceFileIndex; 37 | } 38 | 39 | @Override 40 | public @NotNull AttributeInfo info() { 41 | return AttributeInfo.SourceFile; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/SyntheticAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Synthetic. 9 | * 10 | * @author xDark 11 | */ 12 | public final class SyntheticAttribute implements Attribute { 13 | private static final SyntheticAttribute INSTANCE = new SyntheticAttribute(); 14 | static final Codec CODEC = Codec.of(input -> { 15 | if (input.readInt() != 0) { 16 | throw new InvalidAttributeException("Attribute not empty"); 17 | } 18 | return INSTANCE; 19 | }, (output, value) -> { 20 | output.writeInt(0); 21 | }, Skip.u32()); 22 | 23 | @Override 24 | public @NotNull AttributeInfo info() { 25 | return AttributeInfo.Synthetic; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/UnknownAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Unknown attribute. 9 | * 10 | * @author xDark 11 | */ 12 | public final class UnknownAttribute implements Attribute { 13 | public static final Codec CODEC = Codec.of(input -> { 14 | return new UnknownAttribute(input.read(input.readInt())); 15 | }, (output, value) -> { 16 | byte[] content = value.getData(); 17 | output.writeInt(content.length); 18 | output.write(content); 19 | }, Skip.u32()); 20 | 21 | private final byte[] data; 22 | 23 | /** 24 | * @param content Data. 25 | */ 26 | public UnknownAttribute(byte[] content) { 27 | this.data = content; 28 | } 29 | 30 | /** 31 | * @return Attribute data. 32 | */ 33 | public byte[] getData() { 34 | return data; 35 | } 36 | 37 | @Override 38 | public @NotNull AttributeInfo info() { 39 | return AttributeInfo.UNKNOWN; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/CodeIO.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.attribute.CodeAttribute; 4 | import dev.xdark.classfile.io.Input; 5 | import dev.xdark.classfile.opcode.Instruction; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Code IO. 12 | * 13 | * @author xDark 14 | */ 15 | public final class CodeIO { 16 | private CodeIO() { 17 | } 18 | 19 | /** 20 | * Visits Code attribute. 21 | * 22 | * @param code Attribute to visit. 23 | * @param visitor Attribute visitor. 24 | */ 25 | public static void read(CodeAttribute code, CodeVisitor visitor) throws IOException { 26 | visitor.visitCode(); 27 | InstructionIO.read(Input.wrap(code.getCode()), new FilterInstructionVisitor() { 28 | @Override 29 | public void visitInstruction(@NotNull Instruction instruction) { 30 | visitor.visitInstruction(instruction); 31 | } 32 | }); 33 | code.getTryCatchBlocks().forEach(visitor::visitTryCatchBlock); 34 | visitor.visitMaxs(code.getMaxStack(), code.getMaxLocals()); 35 | visitor.visitEnd(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/CodeVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.attribute.AttributeVisitor; 4 | import dev.xdark.classfile.attribute.CodeAttribute; 5 | import dev.xdark.classfile.opcode.Instruction; 6 | import dev.xdark.classfile.opcode.Label; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * Code visitor. 12 | * 13 | * @author xDark 14 | */ 15 | public interface CodeVisitor { 16 | 17 | /** 18 | * Called before code is visited. 19 | */ 20 | void visitCode(); 21 | 22 | /** 23 | * @return Attribute visitor or {@code null}, 24 | * if attributes should be skipped. 25 | */ 26 | @Nullable AttributeVisitor visitAttributes(); 27 | 28 | /** 29 | * Visits an instruction. 30 | * 31 | * @param instruction Instruction to visit. 32 | */ 33 | void visitInstruction(@NotNull Instruction instruction); 34 | 35 | /** 36 | * Visits a label. 37 | * 38 | * @param label Label to visit. 39 | */ 40 | void visitLabel(@NotNull Label label); 41 | 42 | /** 43 | * Visits try/catch block. 44 | * 45 | * @param tryCatchBlock Try/catch block. 46 | */ 47 | void visitTryCatchBlock(@NotNull CodeAttribute.TryCatchBlock tryCatchBlock); 48 | 49 | /** 50 | * @param maxStack Max stack. 51 | * @param maxLocals Max locals. 52 | */ 53 | void visitMaxs(int maxStack, int maxLocals); 54 | 55 | /** 56 | * Called after code attribute has been visited. 57 | */ 58 | void visitEnd(); 59 | } 60 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/FilterCodeVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.attribute.AttributeVisitor; 4 | import dev.xdark.classfile.attribute.CodeAttribute; 5 | import dev.xdark.classfile.opcode.Instruction; 6 | import dev.xdark.classfile.opcode.Label; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * Code visitor that forwards to another visitor. 12 | * 13 | * @author xDark 14 | */ 15 | public class FilterCodeVisitor implements CodeVisitor { 16 | @Nullable 17 | protected CodeVisitor cv; 18 | 19 | public FilterCodeVisitor(@Nullable CodeVisitor cv) { 20 | this.cv = cv; 21 | } 22 | 23 | public FilterCodeVisitor() { 24 | } 25 | 26 | @Override 27 | public void visitCode() { 28 | CodeVisitor cv = this.cv; 29 | if (cv != null) { 30 | cv.visitCode(); 31 | } 32 | } 33 | 34 | @Override 35 | public @Nullable AttributeVisitor visitAttributes() { 36 | CodeVisitor cv = this.cv; 37 | return cv == null ? null : cv.visitAttributes(); 38 | } 39 | 40 | @Override 41 | public void visitInstruction(@NotNull Instruction instruction) { 42 | CodeVisitor cv = this.cv; 43 | if (cv != null) cv.visitInstruction(instruction); 44 | } 45 | 46 | @Override 47 | public void visitLabel(@NotNull Label label) { 48 | CodeVisitor cv = this.cv; 49 | if (cv != null) { 50 | cv.visitLabel(label); 51 | } 52 | } 53 | 54 | @Override 55 | public void visitTryCatchBlock(CodeAttribute.@NotNull TryCatchBlock tryCatchBlock) { 56 | CodeVisitor cv = this.cv; 57 | if (cv != null) { 58 | cv.visitTryCatchBlock(tryCatchBlock); 59 | } 60 | } 61 | 62 | @Override 63 | public void visitMaxs(int maxStack, int maxLocals) { 64 | CodeVisitor cv = this.cv; 65 | if (cv != null) { 66 | cv.visitMaxs(maxStack, maxLocals); 67 | } 68 | } 69 | 70 | @Override 71 | public void visitEnd() { 72 | CodeVisitor cv = this.cv; 73 | if (cv != null) { 74 | cv.visitEnd(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/FilterInstructionVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.opcode.Instruction; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | /** 8 | * Instruction visitor that forwards to another visitor. 9 | * 10 | * @author xDark 11 | */ 12 | public class FilterInstructionVisitor implements InstructionVisitor { 13 | @Nullable 14 | protected InstructionVisitor iv; 15 | 16 | public FilterInstructionVisitor(@Nullable InstructionVisitor iv) { 17 | this.iv = iv; 18 | } 19 | 20 | public FilterInstructionVisitor() { 21 | } 22 | 23 | @Override 24 | public void visitInstructions() { 25 | InstructionVisitor cv = this.iv; 26 | if (cv != null) { 27 | cv.visitInstructions(); 28 | } 29 | } 30 | 31 | @Override 32 | public void visitInstruction(@NotNull Instruction instruction) { 33 | InstructionVisitor cv = this.iv; 34 | if (cv != null) { 35 | cv.visitInstruction(instruction); 36 | } 37 | } 38 | 39 | @Override 40 | public void visitEnd() { 41 | InstructionVisitor cv = this.iv; 42 | if (cv != null) { 43 | cv.visitEnd(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/InstructionIO.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Input; 5 | import dev.xdark.classfile.io.Output; 6 | import dev.xdark.classfile.opcode.Instruction; 7 | import dev.xdark.classfile.opcode.Opcode; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.io.IOException; 11 | import java.util.List; 12 | 13 | /** 14 | * Instruction IO. 15 | * 16 | * @author xDark 17 | */ 18 | public final class InstructionIO { 19 | private InstructionIO() { 20 | } 21 | 22 | /** 23 | * Reads code instructions. 24 | * 25 | * @param input Input to read instructions from. 26 | * @param visitor Instructions visitor. 27 | * @throws IOException If any I/O error occurs. 28 | */ 29 | public static void read(@NotNull Input input, @NotNull InstructionVisitor visitor) throws IOException { 30 | visitor.visitInstructions(); 31 | while (input.hasRemaining()) { 32 | int position = input.position(); 33 | int n = input.readUnsignedByte(); 34 | Opcode opcode = Opcode.of(n); 35 | if (opcode == null) { 36 | throw new InvalidInstructionException("Unknown opcode " + n); 37 | } 38 | input.position(position); 39 | visitor.visitInstruction(opcode.codec().read(input)); 40 | } 41 | visitor.visitEnd(); 42 | } 43 | 44 | /** 45 | * Writes instructions. 46 | * 47 | * @param output Output to write instructions to. 48 | * @param instructions Instructions to write. 49 | * @throws IOException If any I/O error occurs. 50 | */ 51 | public static void write(@NotNull Output output, List> instructions) throws IOException { 52 | for (int i = 0, j = instructions.size(); i < j; i++) { 53 | Instruction insn = instructions.get(i); 54 | ((Codec) insn.getOpcode().codec()).write(output, insn); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/InstructionVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.opcode.Instruction; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Code visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public interface InstructionVisitor { 12 | 13 | /** 14 | * Called before instructions are visited. 15 | */ 16 | void visitInstructions(); 17 | 18 | /** 19 | * @param instruction Instruction to visit. 20 | */ 21 | void visitInstruction(@NotNull Instruction instruction); 22 | 23 | /** 24 | * Called after all instructions have been visited. 25 | */ 26 | void visitEnd(); 27 | } 28 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/code/InvalidInstructionException.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.code; 2 | 3 | import dev.xdark.classfile.InvalidClassException; 4 | 5 | /** 6 | * Thrown when instruction contains invalid data. 7 | * 8 | * @author xDark 9 | */ 10 | public final class InvalidInstructionException extends InvalidClassException { 11 | 12 | public InvalidInstructionException() { 13 | } 14 | 15 | public InvalidInstructionException(String message) { 16 | super(message); 17 | } 18 | 19 | public InvalidInstructionException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/frame/ChopFrame.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.frame; 2 | 3 | import dev.xdark.classfile.attribute.InvalidAttributeException; 4 | import dev.xdark.classfile.io.Codec; 5 | import dev.xdark.classfile.io.Skip; 6 | 7 | /** 8 | * Same locals as the previous frame except K locals are absent, the stack is empty. 9 | * Offset delta is equal to the tag. 10 | * K is calculated by {@code 251 - frameType}. 11 | * 12 | * @author xDark 13 | */ 14 | public final class ChopFrame extends StackMapFrame { 15 | static final Codec CODEC = Codec.of(input -> { 16 | int tag = input.readUnsignedByte(); 17 | if (!FrameTypeRange.CHOP.includes(tag)) { 18 | throw new InvalidAttributeException("Tag mismatch"); 19 | } 20 | return new ChopFrame(tag, input.readUnsignedShort()); 21 | }, (output, value) -> { 22 | output.writeByte(value.getType()); 23 | output.writeShort(value.getOffsetDelta()); 24 | }, Skip.exact(3)); 25 | 26 | private final int type; 27 | 28 | /** 29 | * @param type Frame tag. 30 | * @param offsetDelta Offset delta. 31 | */ 32 | public ChopFrame(int type, int offsetDelta) { 33 | super(offsetDelta); 34 | this.type = type; 35 | } 36 | 37 | @Override 38 | public int getType() { 39 | return type; 40 | } 41 | 42 | @Override 43 | public StackMapFrameType type() { 44 | return StackMapFrameType.CHOP; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/frame/FrameTypeRange.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.frame; 2 | 3 | /** 4 | * Stack frame tag ranges. 5 | * 6 | * @author xDark 7 | */ 8 | public final class FrameTypeRange { 9 | public static final FrameTypeRange 10 | SAME = range(0, 63), 11 | SAME_LOCALS_1_STACK_ITEM = range(64, 127), 12 | SAME_LOCALS_1_STACK_ITEM_EXTENDED = exact(247), 13 | CHOP = range(248, 250), 14 | SAME_FRAME_EXTENDED = exact(251), 15 | APPEND = range(252, 254), 16 | FULL_FRAME = exact(255); 17 | 18 | private final int from, to; 19 | 20 | private FrameTypeRange(int from, int to) { 21 | this.from = from; 22 | this.to = to; 23 | } 24 | 25 | /** 26 | * @return Minimum accepted tag. 27 | */ 28 | public int getFrom() { 29 | return from; 30 | } 31 | 32 | /** 33 | * @return Maximum accepted tag. 34 | */ 35 | public int getTo() { 36 | return to; 37 | } 38 | 39 | /** 40 | * @return Exact value. 41 | * @throws IllegalStateException if range contains more than 1 value. 42 | */ 43 | public int exact() { 44 | int from = this.from; 45 | if (from != to) { 46 | throw new IllegalStateException(); 47 | } 48 | return from; 49 | } 50 | 51 | /** 52 | * @param tag Tag to check. 53 | * @return Whether this tag is in range. 54 | */ 55 | public boolean includes(int tag) { 56 | return tag >= from && tag <= to; 57 | } 58 | 59 | private static FrameTypeRange range(int from, int to) { 60 | return new FrameTypeRange(from, to); 61 | } 62 | 63 | private static FrameTypeRange exact(int tag) { 64 | return new FrameTypeRange(tag, tag); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/frame/SameExtendedFrame.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.frame; 2 | 3 | import dev.xdark.classfile.attribute.InvalidAttributeException; 4 | import dev.xdark.classfile.io.Codec; 5 | import dev.xdark.classfile.io.Skip; 6 | 7 | /** 8 | * Same locals as the previous frame, the stack is empty. 9 | * Offset delta is read from the attribute info. 10 | * 11 | * @author xDark 12 | */ 13 | public final class SameExtendedFrame extends StackMapFrame { 14 | static final Codec CODEC = Codec.of(input -> { 15 | int tag = input.readUnsignedByte(); 16 | if (!FrameTypeRange.SAME_FRAME_EXTENDED.includes(tag)) { 17 | throw new InvalidAttributeException("Tag mismatch"); 18 | } 19 | return new SameExtendedFrame(input.readUnsignedShort()); 20 | }, (output, value) -> { 21 | output.writeByte(value.getType()); 22 | output.writeShort(value.getOffsetDelta()); 23 | }, Skip.exact(3)); 24 | 25 | /** 26 | * @param offsetDelta Offset delta. 27 | */ 28 | public SameExtendedFrame(int offsetDelta) { 29 | super(offsetDelta); 30 | } 31 | 32 | @Override 33 | public int getType() { 34 | return FrameTypeRange.SAME_FRAME_EXTENDED.exact(); 35 | } 36 | 37 | @Override 38 | public StackMapFrameType type() { 39 | return StackMapFrameType.SAME_FRAME_EXTENDED; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/frame/SameFrame.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.frame; 2 | 3 | import dev.xdark.classfile.attribute.InvalidAttributeException; 4 | import dev.xdark.classfile.io.Codec; 5 | import dev.xdark.classfile.io.Skip; 6 | 7 | /** 8 | * Same locals as the previous frame, the stack is empty. 9 | * Offset delta is equal to the tag. 10 | * 11 | * @author xDark 12 | */ 13 | public final class SameFrame extends StackMapFrame { 14 | static final Codec CODEC = Codec.of(input -> { 15 | int tag = input.readUnsignedByte(); 16 | if (!FrameTypeRange.SAME.includes(tag)) { 17 | throw new InvalidAttributeException("Tag mismatch"); 18 | } 19 | return new SameFrame(tag); 20 | }, (output, value) -> { 21 | output.writeByte(value.getType()); 22 | }, Skip.exact(1)); 23 | 24 | /** 25 | * @param offsetDelta Offset delta. 26 | */ 27 | public SameFrame(int offsetDelta) { 28 | super(offsetDelta); 29 | } 30 | 31 | @Override 32 | public int getType() { 33 | return offsetDelta; 34 | } 35 | 36 | @Override 37 | public StackMapFrameType type() { 38 | return StackMapFrameType.SAME; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/frame/StackMapFrame.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.frame; 2 | 3 | public abstract class StackMapFrame> { 4 | protected final int offsetDelta; 5 | 6 | /** 7 | * @param offsetDelta Offset delta. 8 | */ 9 | protected StackMapFrame(int offsetDelta) { 10 | this.offsetDelta = offsetDelta; 11 | } 12 | 13 | /** 14 | * @return Offset delta. 15 | */ 16 | public int getOffsetDelta() { 17 | return offsetDelta; 18 | } 19 | 20 | /** 21 | * @return Actual frame type. 22 | * May differ from {@link StackMapFrameType} if the type varies. 23 | */ 24 | public abstract int getType(); 25 | 26 | /** 27 | * @return Frame type. 28 | */ 29 | public abstract StackMapFrameType type(); 30 | } 31 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/DoubleVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Double_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class DoubleVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new DoubleVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Double; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/FloatVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Float_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class FloatVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new FloatVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Float; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/IntegerVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Integer_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class IntegerVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new IntegerVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Integer; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/LongVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Long_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class LongVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new LongVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Long; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/NullVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Null_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class NullVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new NullVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/ObjectVariableVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | /** 7 | * Object_variable_info. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ObjectVariableVerificationTypeInfo implements VerificationTypeInfo { 12 | public static final Codec CODEC = Codec.of(input -> { 13 | return new ObjectVariableVerificationTypeInfo(input.readUnsignedShort()); 14 | }, (output, value) -> { 15 | output.writeShort(value.getClassIndex()); 16 | }, Skip.exact(2)); 17 | private final int classIndex; 18 | 19 | /** 20 | * @param classIndex Type index. 21 | */ 22 | public ObjectVariableVerificationTypeInfo(int classIndex) { 23 | this.classIndex = classIndex; 24 | } 25 | 26 | /** 27 | * @return Class index. 28 | */ 29 | public int getClassIndex() { 30 | return classIndex; 31 | } 32 | 33 | @Override 34 | public VerificationType type() { 35 | return VerificationType.ITEM_Object; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/TopVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * Top_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class TopVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new TopVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_Top; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/UninitializedThisVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | 5 | /** 6 | * UninitializedThis_variable_info. 7 | * 8 | * @author xDark 9 | */ 10 | public final class UninitializedThisVerificationTypeInfo implements VerificationTypeInfo { 11 | public static final Codec CODEC = Codec.singleton(new UninitializedThisVerificationTypeInfo()); 12 | 13 | @Override 14 | public VerificationType type() { 15 | return VerificationType.ITEM_UninitializedThis; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/UninitializedVariableVerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | /** 7 | * Uninitialized_variable_info. 8 | * 9 | * @author xDark 10 | */ 11 | public final class UninitializedVariableVerificationTypeInfo implements VerificationTypeInfo { 12 | public static final Codec CODEC = Codec.of(input -> { 13 | return new UninitializedVariableVerificationTypeInfo(input.readUnsignedShort()); 14 | }, (output, value) -> { 15 | output.writeShort(value.getInstructionOffset()); 16 | }, Skip.exact(2)); 17 | private final int instructionOffset; 18 | 19 | /** 20 | * @param instructionOffset Instruction offset. 21 | */ 22 | public UninitializedVariableVerificationTypeInfo(int instructionOffset) { 23 | this.instructionOffset = instructionOffset; 24 | } 25 | 26 | /** 27 | * @return Instruction offset. 28 | */ 29 | public int getInstructionOffset() { 30 | return instructionOffset; 31 | } 32 | 33 | @Override 34 | public VerificationType type() { 35 | return VerificationType.ITEM_Uninitialized; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/stackmap/type/VerificationTypeInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.stackmap.type; 2 | 3 | /** 4 | * Verification type info. 5 | * 6 | * @author xDark 7 | */ 8 | public interface VerificationTypeInfo> { 9 | 10 | /** 11 | * @return Verification type. 12 | */ 13 | VerificationType type(); 14 | } 15 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/CatchTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * catch_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class CatchTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | input.skipBytes(1); 15 | return new CatchTargetInfo(input.readUnsignedByte()); 16 | }, (output, value) -> { 17 | output.writeByte(TargetType.CATCH.kind()); 18 | output.writeByte(value.getIndex()); 19 | }, Skip.exact(2)); 20 | private final int index; 21 | 22 | /** 23 | * @param index Exception table index. 24 | */ 25 | public CatchTargetInfo(int index) { 26 | this.index = index; 27 | } 28 | 29 | /** 30 | * @return Exception table index. 31 | */ 32 | public int getIndex() { 33 | return index; 34 | } 35 | 36 | @Override 37 | public @NotNull TargetType type() { 38 | return TargetType.CATCH; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/EmptyTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * empty_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class EmptyTargetInfo implements TargetInfo { 13 | private final TargetType type; 14 | static final Codec CODEC = Codec.of(input -> { 15 | return new EmptyTargetInfo(TargetType.require(input)); 16 | }, (output, value) -> { 17 | output.writeByte(value.type().kind()); 18 | }, Skip.exact(1)); 19 | 20 | /** 21 | * @param type Target type. 22 | */ 23 | public EmptyTargetInfo(TargetType type) { 24 | this.type = type; 25 | } 26 | 27 | @Override 28 | public @NotNull TargetType type() { 29 | return type; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/FormalParameterTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * formal_parameter_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class FormalParameterTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | input.skipBytes(1); 15 | return new FormalParameterTargetInfo(input.readUnsignedByte()); 16 | }, (output, value) -> { 17 | output.writeByte(TargetType.FORMAL_PARAMETER.kind()); 18 | output.writeByte(value.getIndex()); 19 | }, Skip.exact(2)); 20 | private final int index; 21 | 22 | /** 23 | * @param index Formal parameter index. 24 | */ 25 | public FormalParameterTargetInfo(int index) { 26 | this.index = index; 27 | } 28 | 29 | /** 30 | * @return Formal parameter index. 31 | */ 32 | public int getIndex() { 33 | return index; 34 | } 35 | 36 | @Override 37 | public @NotNull TargetType type() { 38 | return TargetType.FORMAL_PARAMETER; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/OffsetTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * offset_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class OffsetTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new OffsetTargetInfo(TargetType.require(input), input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeByte(value.type().kind()); 17 | output.writeShort(value.getOffset()); 18 | }, Skip.exact(3)); 19 | private final TargetType type; 20 | private final int offset; 21 | 22 | /** 23 | * @param type Target type. 24 | * @param offset Instruction offset. 25 | */ 26 | public OffsetTargetInfo(TargetType type, int offset) { 27 | this.type = type; 28 | this.offset = offset; 29 | } 30 | 31 | /** 32 | * @return Instruction offset. 33 | */ 34 | public int getOffset() { 35 | return offset; 36 | } 37 | 38 | @Override 39 | public @NotNull TargetType type() { 40 | return type; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/ParameterBoundTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * type_parameter_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ParameterBoundTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ParameterBoundTargetInfo(TargetType.require(input), input.readUnsignedByte(), input.readUnsignedByte()); 15 | }, (output, value) -> { 16 | output.writeByte(value.type().kind()); 17 | output.writeByte(value.getParameterIndex()); 18 | output.writeByte(value.getBoundIndex()); 19 | }, Skip.exact(3)); 20 | private final TargetType type; 21 | private final int parameterIndex; 22 | private final int boundIndex; 23 | 24 | /** 25 | * @param type Target type. 26 | * @param index Parameter index. 27 | * @param boundIndex Bound index. 28 | */ 29 | public ParameterBoundTargetInfo(TargetType type, int index, int boundIndex) { 30 | this.type = type; 31 | this.parameterIndex = index; 32 | this.boundIndex = boundIndex; 33 | } 34 | 35 | /** 36 | * @return Parameter index. 37 | */ 38 | public int getParameterIndex() { 39 | return parameterIndex; 40 | } 41 | 42 | /** 43 | * @return Bound index. 44 | */ 45 | public int getBoundIndex() { 46 | return boundIndex; 47 | } 48 | 49 | @Override 50 | public @NotNull TargetType type() { 51 | return type; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/ParameterTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * type_parameter_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ParameterTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ParameterTargetInfo(TargetType.require(input), input.readUnsignedByte()); 15 | }, (output, value) -> { 16 | output.writeByte(value.type().kind()); 17 | output.writeByte(value.getIndex()); 18 | }, Skip.exact(2)); 19 | private final TargetType type; 20 | private final int index; 21 | 22 | /** 23 | * @param type Target type. 24 | * @param index Parameter index. 25 | */ 26 | public ParameterTargetInfo(TargetType type, int index) { 27 | this.type = type; 28 | this.index = index; 29 | } 30 | 31 | /** 32 | * @return Parameter index. 33 | */ 34 | public int getIndex() { 35 | return index; 36 | } 37 | 38 | @Override 39 | public @NotNull TargetType type() { 40 | return type; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/RuntimeInvisibleTypeAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.attribute.AttributeInfo; 4 | import dev.xdark.classfile.io.Codec; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * RuntimeInvisibleTypeAnnotations. 11 | * 12 | * @author xDark 13 | */ 14 | public final class RuntimeInvisibleTypeAnnotationsAttribute extends RuntimeTypeAnnotationsAttribute { 15 | public static final Codec CODEC = codec(RuntimeInvisibleTypeAnnotationsAttribute::new); 16 | 17 | /** 18 | * @param annotations List of annotations. 19 | */ 20 | public RuntimeInvisibleTypeAnnotationsAttribute(List annotations) { 21 | super(annotations); 22 | } 23 | 24 | @Override 25 | public @NotNull AttributeInfo info() { 26 | return AttributeInfo.RuntimeInvisibleTypeAnnotations; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/RuntimeTypeAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.attribute.Attribute; 4 | import dev.xdark.classfile.attribute.InvalidAttributeException; 5 | import dev.xdark.classfile.io.Codec; 6 | import dev.xdark.classfile.io.Skip; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * Shared code between Runtime[In]visibleTypeAnnotations. 14 | * 15 | * @author xDark 16 | */ 17 | public abstract class RuntimeTypeAnnotationsAttribute> implements Attribute { 18 | private final List annotations; 19 | 20 | /** 21 | * @param annotations List of annotations. 22 | */ 23 | protected RuntimeTypeAnnotationsAttribute(List annotations) { 24 | this.annotations = annotations; 25 | } 26 | 27 | /** 28 | * @return List of annotations. 29 | */ 30 | public final List getAnnotations() { 31 | return annotations; 32 | } 33 | 34 | protected static > Codec codec(Function, T> fn) { 35 | return Codec.of(input -> { 36 | int length = input.readInt(); 37 | if (length < 2) { 38 | throw new InvalidAttributeException("Length is less than 2"); 39 | } 40 | int count = input.readUnsignedShort(); 41 | List annotations = new ArrayList<>(Math.min(32, count)); 42 | while (count-- != 0) { 43 | annotations.add(TypeAnnotation.CODEC.read(input)); 44 | } 45 | return fn.apply(annotations); 46 | }, (output, value) -> { 47 | int position = output.position(); 48 | output.writeInt(0); 49 | List annotations = value.getAnnotations(); 50 | int count = annotations.size(); 51 | output.writeShort(count); 52 | for (int i = 0; i < count; i++) { 53 | TypeAnnotation.CODEC.write(output, annotations.get(i)); 54 | } 55 | int newPosition = output.position(); 56 | output.position(position).writeInt(newPosition - position - 4); 57 | output.position(newPosition); 58 | }, Skip.u32()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/RuntimeVisibleTypeAnnotationsAttribute.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.attribute.AttributeInfo; 4 | import dev.xdark.classfile.io.Codec; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * RuntimeVisibleTypeAnnotations. 11 | * 12 | * @author xDark 13 | */ 14 | public final class RuntimeVisibleTypeAnnotationsAttribute extends RuntimeTypeAnnotationsAttribute { 15 | public static final Codec CODEC = codec(RuntimeVisibleTypeAnnotationsAttribute::new); 16 | 17 | /** 18 | * @param annotations List of annotations. 19 | */ 20 | public RuntimeVisibleTypeAnnotationsAttribute(List annotations) { 21 | super(annotations); 22 | } 23 | 24 | @Override 25 | public @NotNull AttributeInfo info() { 26 | return AttributeInfo.RuntimeVisibleTypeAnnotations; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/SuperTypeTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * supertype_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class SuperTypeTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | input.skipBytes(1); 15 | return new SuperTypeTargetInfo(input.readUnsignedShort()); 16 | }, (output, value) -> { 17 | output.writeByte(TargetType.SUPER_TYPE.kind()); 18 | output.writeShort(value.getIndex()); 19 | }, Skip.exact(3)); 20 | private final int index; 21 | 22 | /** 23 | * @param index Super class index. 24 | */ 25 | public SuperTypeTargetInfo(int index) { 26 | this.index = index; 27 | } 28 | 29 | /** 30 | * @return Super class index. 31 | */ 32 | public int getIndex() { 33 | return index; 34 | } 35 | 36 | @Override 37 | public @NotNull TargetType type() { 38 | return TargetType.SUPER_TYPE; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/TargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * target_info union. 7 | * 8 | * @author xDark 9 | */ 10 | public interface TargetInfo> { 11 | 12 | /** 13 | * @return Target type. 14 | */ 15 | @NotNull TargetType type(); 16 | } 17 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/ThrowsTargetInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * throws_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ThrowsTargetInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | input.skipBytes(1); 15 | return new ThrowsTargetInfo(input.readUnsignedShort()); 16 | }, (output, value) -> { 17 | output.writeByte(TargetType.THROWS.kind()); 18 | output.writeByte(value.getIndex()); 19 | }, Skip.exact(2)); 20 | private final int index; 21 | 22 | /** 23 | * @param index Type index. 24 | */ 25 | public ThrowsTargetInfo(int index) { 26 | this.index = index; 27 | } 28 | 29 | /** 30 | * @return Type index. 31 | */ 32 | public int getIndex() { 33 | return index; 34 | } 35 | 36 | @Override 37 | public @NotNull TargetType type() { 38 | return TargetType.THROWS; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/TypeArgumentInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * type_argument_target. 9 | * 10 | * @author xDark 11 | */ 12 | public final class TypeArgumentInfo implements TargetInfo { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new TypeArgumentInfo(TargetType.require(input), input.readUnsignedShort(), input.readUnsignedByte()); 15 | }, (output, value) -> { 16 | output.writeShort(value.getOffset()); 17 | output.writeByte(value.getIndex()); 18 | }, Skip.exact(3)); 19 | private final TargetType type; 20 | private final int offset; 21 | private final int index; 22 | 23 | /** 24 | * @param type Target type. 25 | * @param offset Instruction offset. 26 | * @param index Argument index. 27 | */ 28 | public TypeArgumentInfo(TargetType type, int offset, int index) { 29 | this.type = type; 30 | this.offset = offset; 31 | this.index = index; 32 | } 33 | 34 | /** 35 | * @return Instruction offset. 36 | */ 37 | public int getOffset() { 38 | return offset; 39 | } 40 | 41 | /** 42 | * @return Argument index. 43 | */ 44 | public int getIndex() { 45 | return index; 46 | } 47 | 48 | @Override 49 | public @NotNull TargetType type() { 50 | return type; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/attribute/type/TypePath.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.attribute.type; 2 | 3 | import dev.xdark.classfile.attribute.InvalidAttributeException; 4 | import dev.xdark.classfile.io.Codec; 5 | import dev.xdark.classfile.io.Skip; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * type_path. 12 | * 13 | * @author xDark 14 | */ 15 | public final class TypePath { 16 | public static final Codec CODEC = Codec.of(input -> { 17 | int length = input.readUnsignedByte(); 18 | if (input.remaining() < 2 * length) { 19 | throw new InvalidAttributeException("Invalid type path"); 20 | } 21 | List paths = new ArrayList<>(length); 22 | while (length-- != 0) { 23 | paths.add(Path.CODEC.read(input)); 24 | } 25 | return new TypePath(paths); 26 | }, (output, value) -> { 27 | List paths = value.getPaths(); 28 | int count = paths.size(); 29 | output.writeByte(count); 30 | for (int i = 0; i < count; i++) { 31 | Path.CODEC.write(output, paths.get(i)); 32 | } 33 | }, input -> { 34 | for (int i = 0, j = input.readUnsignedByte(); i < j; i++) { 35 | Path.CODEC.skip(input); 36 | } 37 | }); 38 | private final List paths; 39 | 40 | /** 41 | * @param paths List of paths. 42 | */ 43 | public TypePath(List paths) { 44 | this.paths = paths; 45 | } 46 | 47 | /** 48 | * @return List of paths. 49 | */ 50 | public List getPaths() { 51 | return paths; 52 | } 53 | 54 | public static final class Path { 55 | public static final Codec CODEC = Codec.of(input -> { 56 | return new Path(input.readUnsignedByte(), input.readUnsignedByte()); 57 | }, (output, value) -> { 58 | output.writeByte(value.getKind()); 59 | output.writeByte(value.getIndex()); 60 | }, Skip.exact(2)); 61 | private final int kind; 62 | private final int index; 63 | 64 | /** 65 | * @param kind Path kind. 66 | * @param index Argument index. 67 | */ 68 | public Path(int kind, int index) { 69 | this.kind = kind; 70 | this.index = index; 71 | } 72 | 73 | /** 74 | * @return Path kind. 75 | */ 76 | public int getKind() { 77 | return kind; 78 | } 79 | 80 | /** 81 | * @return Argument index. 82 | */ 83 | public int getIndex() { 84 | return index; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/BuiltConstantPool.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Objects; 8 | 9 | /** 10 | * Constant pool. 11 | * 12 | * @author xDark 13 | */ 14 | public final class BuiltConstantPool implements ConstantPool { 15 | 16 | private final List> entries; 17 | private final int size; 18 | 19 | /** 20 | * @param entries List of constant pool entries. 21 | */ 22 | public BuiltConstantPool(@NotNull List> entries) { 23 | this.entries = entries; 24 | size = entries.stream().filter(Objects::nonNull).mapToInt(x -> x.tag().size()).sum(); 25 | } 26 | 27 | @Override 28 | public @NotNull ConstantEntry get(int index) { 29 | List> entries; 30 | ConstantEntry entry; 31 | if (index < 1 || index >= (entries = this.entries).size() || (entry = entries.get(index)) == null) { 32 | throw new IllegalArgumentException(Integer.toString(index)); 33 | } 34 | return entry; 35 | } 36 | 37 | @Override 38 | public > @NotNull T get(int index, Tag tag) { 39 | ConstantEntry entry = get(index); 40 | if (entry.tag() != tag) { 41 | throw new IllegalArgumentException("Wrong tag type " + entry.tag()); 42 | } 43 | return (T) entry; 44 | } 45 | 46 | @Override 47 | public int size() { 48 | return size; 49 | } 50 | 51 | @NotNull 52 | @Override 53 | public Iterator<@NotNull ConstantEntry> iterator() { 54 | Iterator> iterator = entries.iterator(); 55 | return new Iterator>() { 56 | @Override 57 | public boolean hasNext() { 58 | return iterator.hasNext(); 59 | } 60 | 61 | @Override 62 | public ConstantEntry next() { 63 | ConstantEntry entry = iterator.next(); 64 | if (entry == null) { 65 | entry = iterator.next(); 66 | } 67 | return entry; 68 | } 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantClass.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Utf8. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantClass implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantClass(input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.index()); 17 | }, Skip.exact(2)); 18 | 19 | private final int value; 20 | 21 | /** 22 | * @param value UTF-8 index. 23 | */ 24 | public ConstantClass(int value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return UTF-8 index. 30 | */ 31 | public int index() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public @NotNull Tag tag() { 37 | return Tag.CONSTANT_Class; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (o == null || getClass() != o.getClass()) return false; 44 | 45 | ConstantClass that = (ConstantClass) o; 46 | 47 | return value == that.value; 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return value; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantDouble.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Integer. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantDouble implements ConstantEntry, ValueEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantDouble(input.readDouble()); 15 | }, (output, value) -> { 16 | output.writeDouble(value.value()); 17 | }, Skip.exact(8)); 18 | 19 | private final double value; 20 | 21 | /** 22 | * @param value Integer value. 23 | */ 24 | public ConstantDouble(double value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return Double value. 30 | */ 31 | public double value() { 32 | return value; 33 | } 34 | 35 | @NotNull 36 | @Override 37 | public Double getValue() { 38 | return value; 39 | } 40 | 41 | @Override 42 | public @NotNull Tag tag() { 43 | return Tag.CONSTANT_Double; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) return true; 49 | if (o == null || getClass() != o.getClass()) return false; 50 | 51 | ConstantDouble that = (ConstantDouble) o; 52 | 53 | return Double.compare(that.value, value) == 0; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return Double.hashCode(value); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantEntry.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Constant pool entry. 7 | * 8 | * @author xDark 9 | */ 10 | public interface ConstantEntry> { 11 | 12 | /** 13 | * @return Entry tag. 14 | */ 15 | @NotNull 16 | Tag tag(); 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantFieldReference.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * CONSTANT_Fieldref. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ConstantFieldReference extends ConstantReference { 12 | static final Codec CODEC = codec(ConstantFieldReference::new); 13 | 14 | /** 15 | * @param classIndex Class index. 16 | * @param nameAndTypeIndex NameAndType index. 17 | */ 18 | public ConstantFieldReference(int classIndex, int nameAndTypeIndex) { 19 | super(classIndex, nameAndTypeIndex); 20 | } 21 | 22 | @Override 23 | public @NotNull Tag tag() { 24 | return Tag.CONSTANT_Fieldref; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantFloat.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Integer. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantFloat implements ConstantEntry, ValueEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantFloat(input.readFloat()); 15 | }, (output, value) -> { 16 | output.writeFloat(value.value()); 17 | }, Skip.exact(4)); 18 | 19 | private final float value; 20 | 21 | /** 22 | * @param value Float value. 23 | */ 24 | public ConstantFloat(float value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return Float value. 30 | */ 31 | public float value() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public @NotNull Float getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public @NotNull Tag tag() { 42 | return Tag.CONSTANT_Float; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | 50 | ConstantFloat that = (ConstantFloat) o; 51 | 52 | return Float.compare(that.value, value) == 0; 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return Float.hashCode(value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantInteger.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Integer. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantInteger implements ConstantEntry, ValueEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantInteger(input.readInt()); 15 | }, (output, value) -> { 16 | output.writeInt(value.value()); 17 | }, Skip.exact(4)); 18 | 19 | private final int value; 20 | 21 | /** 22 | * @param value Integer value. 23 | */ 24 | public ConstantInteger(int value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return Integer value. 30 | */ 31 | public int value() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public @NotNull Integer getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public @NotNull Tag tag() { 42 | return Tag.CONSTANT_Integer; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | 50 | ConstantInteger that = (ConstantInteger) o; 51 | 52 | return value == that.value; 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return value; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantInterfaceMethodReference.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * CONSTANT_InterfaceMethodref. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ConstantInterfaceMethodReference extends ConstantReference { 12 | static final Codec CODEC = codec(ConstantInterfaceMethodReference::new); 13 | 14 | /** 15 | * @param classIndex Class index. 16 | * @param nameAndTypeIndex NameAndType index. 17 | */ 18 | public ConstantInterfaceMethodReference(int classIndex, int nameAndTypeIndex) { 19 | super(classIndex, nameAndTypeIndex); 20 | } 21 | 22 | @Override 23 | public @NotNull Tag tag() { 24 | return Tag.CONSTANT_InterfaceMethodref; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantInvokeDynamic.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_InvokeDynamic. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantInvokeDynamic implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantInvokeDynamic(input.readUnsignedShort(), input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.bootstrapMethodIndex()); 17 | output.writeShort(value.nameAndTypeIndex()); 18 | }, Skip.exact(4)); 19 | 20 | private final int bootstrapMethodIndex; 21 | private final int nameAndTypeIndex; 22 | 23 | /** 24 | * @param bootstrapMethodIndex Bootstrap method index. 25 | * @param nameAndTypeIndex Name and type index. 26 | */ 27 | public ConstantInvokeDynamic(int bootstrapMethodIndex, int nameAndTypeIndex) { 28 | this.bootstrapMethodIndex = bootstrapMethodIndex; 29 | this.nameAndTypeIndex = nameAndTypeIndex; 30 | } 31 | 32 | /** 33 | * @return Bootstrap method index. 34 | */ 35 | public int bootstrapMethodIndex() { 36 | return bootstrapMethodIndex; 37 | } 38 | 39 | /** 40 | * @return Name and type index. 41 | */ 42 | public int nameAndTypeIndex() { 43 | return nameAndTypeIndex; 44 | } 45 | 46 | @Override 47 | public @NotNull Tag tag() { 48 | return Tag.CONSTANT_InvokeDynamic; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | 56 | ConstantInvokeDynamic that = (ConstantInvokeDynamic) o; 57 | 58 | if (bootstrapMethodIndex != that.bootstrapMethodIndex) return false; 59 | return nameAndTypeIndex == that.nameAndTypeIndex; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | int result = bootstrapMethodIndex; 65 | result = 31 * result + nameAndTypeIndex; 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantLong.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Integer. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantLong implements ConstantEntry, ValueEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantLong(input.readLong()); 15 | }, (output, value) -> { 16 | output.writeLong(value.value()); 17 | }, Skip.exact(8)); 18 | 19 | private final long value; 20 | 21 | /** 22 | * @param value Integer value. 23 | */ 24 | public ConstantLong(long value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return Long value. 30 | */ 31 | public long value() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public @NotNull Long getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public @NotNull Tag tag() { 42 | return Tag.CONSTANT_Long; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | 50 | ConstantLong that = (ConstantLong) o; 51 | 52 | return value == that.value; 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return Long.hashCode(value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantMethodReference.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * CONSTANT_Methodref. 8 | * 9 | * @author xDark 10 | */ 11 | public final class ConstantMethodReference extends ConstantReference { 12 | static final Codec CODEC = codec(ConstantMethodReference::new); 13 | 14 | /** 15 | * @param classIndex Class index. 16 | * @param nameAndTypeIndex NameAndType index. 17 | */ 18 | public ConstantMethodReference(int classIndex, int nameAndTypeIndex) { 19 | super(classIndex, nameAndTypeIndex); 20 | } 21 | 22 | @Override 23 | public @NotNull Tag tag() { 24 | return Tag.CONSTANT_Methodref; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantMethodType.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_MethodType. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantMethodType implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantMethodType(input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.descriptorIndex()); 17 | }, Skip.exact(2)); 18 | private final int descriptorIndex; 19 | 20 | /** 21 | * @param descriptorIndex Descriptor index. 22 | */ 23 | public ConstantMethodType(int descriptorIndex) { 24 | this.descriptorIndex = descriptorIndex; 25 | } 26 | 27 | /** 28 | * @return Descriptor index. 29 | */ 30 | public int descriptorIndex() { 31 | return descriptorIndex; 32 | } 33 | 34 | @Override 35 | public @NotNull Tag tag() { 36 | return Tag.CONSTANT_MethodType; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | if (this == o) return true; 42 | if (o == null || getClass() != o.getClass()) return false; 43 | 44 | ConstantMethodType that = (ConstantMethodType) o; 45 | 46 | return descriptorIndex == that.descriptorIndex; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return descriptorIndex; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantModule.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Package. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantModule implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantModule(input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.index()); 17 | }, Skip.exact(2)); 18 | 19 | private final int nameIndex; 20 | 21 | /** 22 | * @param nameIndex Module name index. 23 | */ 24 | public ConstantModule(int nameIndex) { 25 | this.nameIndex = nameIndex; 26 | } 27 | 28 | /** 29 | * @return Module name index. 30 | */ 31 | public int index() { 32 | return nameIndex; 33 | } 34 | 35 | @Override 36 | public @NotNull Tag tag() { 37 | return Tag.CONSTANT_Module; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (o == null || getClass() != o.getClass()) return false; 44 | 45 | ConstantModule that = (ConstantModule) o; 46 | 47 | return nameIndex == that.nameIndex; 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return nameIndex; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantNameAndType.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_InterfaceMethodref. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantNameAndType implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantNameAndType(input.readUnsignedShort(), input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.nameIndex()); 17 | output.writeShort(value.typeIndex()); 18 | }, Skip.exact(4)); 19 | 20 | private final int nameIndex; 21 | private final int typeIndex; 22 | 23 | /** 24 | * @param nameIndex Name index. 25 | * @param typeIndex Type index. 26 | */ 27 | public ConstantNameAndType(int nameIndex, int typeIndex) { 28 | this.nameIndex = nameIndex; 29 | this.typeIndex = typeIndex; 30 | } 31 | 32 | /** 33 | * @return Name index. 34 | */ 35 | public int nameIndex() { 36 | return nameIndex; 37 | } 38 | 39 | /** 40 | * @return Type index. 41 | */ 42 | public int typeIndex() { 43 | return typeIndex; 44 | } 45 | 46 | @Override 47 | public @NotNull Tag tag() { 48 | return Tag.CONSTANT_NameAndType; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | 56 | ConstantNameAndType that = (ConstantNameAndType) o; 57 | 58 | if (nameIndex != that.nameIndex) return false; 59 | return typeIndex == that.typeIndex; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | int result = nameIndex; 65 | result = 31 * result + typeIndex; 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantPackage.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Module. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantPackage implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantPackage(input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.index()); 17 | }, Skip.exact(2)); 18 | 19 | private final int nameIndex; 20 | 21 | /** 22 | * @param nameIndex Package name index. 23 | */ 24 | public ConstantPackage(int nameIndex) { 25 | this.nameIndex = nameIndex; 26 | } 27 | 28 | /** 29 | * @return Package name index. 30 | */ 31 | public int index() { 32 | return nameIndex; 33 | } 34 | 35 | @Override 36 | public @NotNull Tag tag() { 37 | return Tag.CONSTANT_Package; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (o == null || getClass() != o.getClass()) return false; 44 | 45 | ConstantPackage that = (ConstantPackage) o; 46 | 47 | return nameIndex == that.nameIndex; 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return nameIndex; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantPool.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Iterator; 6 | 7 | /** 8 | * Constant pool. 9 | * 10 | * @author xDark 11 | */ 12 | public interface ConstantPool extends Iterable> { 13 | 14 | /** 15 | * @param index Entry index. 16 | * @return Entry. 17 | * @throws IllegalArgumentException If index is out of bounds, 18 | * or if the index points to the reserved slot. 19 | */ 20 | @NotNull ConstantEntry get(int index); 21 | 22 | /** 23 | * @param index Entry index. 24 | * @param tag Entry tag. 25 | * @return Entry. 26 | * @throws IllegalArgumentException If tag does not match. 27 | */ 28 | @NotNull > T get(int index, Tag tag); 29 | 30 | /** 31 | * @return Constant pool size. 32 | */ 33 | int size(); 34 | 35 | @NotNull 36 | @Override 37 | Iterator<@NotNull ConstantEntry> iterator(); 38 | } 39 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantPoolCollector.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * Collects constants into collection. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantPoolCollector implements ConstantPoolVisitor { 13 | private final Collection> entries; 14 | 15 | /** 16 | * @param entries Output collection. 17 | */ 18 | public ConstantPoolCollector(Collection> entries) { 19 | this.entries = entries; 20 | } 21 | 22 | @Override 23 | public void visitConstants() { 24 | } 25 | 26 | @Override 27 | public void visitConstant(@NotNull ConstantEntry entry) { 28 | entries.add(entry); 29 | } 30 | 31 | @Override 32 | public void visitEnd() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantPoolIO.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.InvalidClassException; 4 | import dev.xdark.classfile.io.Codec; 5 | import dev.xdark.classfile.io.Input; 6 | import dev.xdark.classfile.io.Output; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * Constant pool I/O. 13 | * 14 | * @author xDark 15 | */ 16 | public final class ConstantPoolIO { 17 | private ConstantPoolIO() { 18 | } 19 | 20 | /** 21 | * Reads constant pool. 22 | * 23 | * @param input Input to read constant pool from. 24 | * @param visitor Constant pool visitor. 25 | * @throws IOException If any I/O error occurs. 26 | */ 27 | public static void read(@NotNull Input input, @NotNull ConstantPoolVisitor visitor) throws IOException { 28 | int constantPoolCount = input.readUnsignedShort(); 29 | visitor.visitConstants(); 30 | for (int i = 1; i < constantPoolCount; i++) { 31 | int tagId = input.readUnsignedByte(); 32 | Tag tag = Tag.of(tagId); 33 | if (tag == null) { 34 | throw new InvalidClassException("Unknown tag " + tagId); 35 | } 36 | ConstantEntry entry = tag.codec().read(input); 37 | visitor.visitConstant(entry); 38 | if (tag.size() == 2) { 39 | i++; 40 | } 41 | } 42 | visitor.visitEnd(); 43 | } 44 | 45 | /** 46 | * Writes constant pool. 47 | * 48 | * @param output Output to write constant pool to. 49 | * @param constantPool Constant pool. 50 | * @throws IOException If any I/O error occurs. 51 | */ 52 | public static void write(@NotNull Output output, @NotNull ConstantPool constantPool) throws IOException { 53 | output.writeShort(constantPool.size() + 1); 54 | for (ConstantEntry entry : constantPool) { 55 | Tag tag = entry.tag(); 56 | output.writeByte(tag.id()); 57 | ((Codec) tag.codec()).write(output, entry); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantPoolVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Constant pool visitor. 7 | * 8 | * @author xDark 9 | */ 10 | public interface ConstantPoolVisitor { 11 | 12 | /** 13 | * Called before constants are visited. 14 | */ 15 | void visitConstants(); 16 | 17 | /** 18 | * @param entry Constant entry. 19 | */ 20 | void visitConstant(@NotNull ConstantEntry entry); 21 | 22 | /** 23 | * Called after all constants have been visited. 24 | */ 25 | void visitEnd(); 26 | } 27 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantReference.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | /** 7 | * Constant reference. 8 | * 9 | * @author xDark 10 | * @see ConstantMethodReference 11 | * @see ConstantInterfaceMethodReference 12 | * @see ConstantFieldReference 13 | */ 14 | public abstract class ConstantReference> implements ConstantEntry { 15 | private final int classIndex; 16 | private final int nameAndTypeIndex; 17 | 18 | /** 19 | * @param classIndex Class index. 20 | * @param nameAndTypeIndex NameAndType index. 21 | */ 22 | protected ConstantReference(int classIndex, int nameAndTypeIndex) { 23 | this.classIndex = classIndex; 24 | this.nameAndTypeIndex = nameAndTypeIndex; 25 | } 26 | 27 | /** 28 | * @return Class index. 29 | */ 30 | public final int classIndex() { 31 | return classIndex; 32 | } 33 | 34 | /** 35 | * @return Descriptor index. 36 | */ 37 | public final int nameAndTypeIndex() { 38 | return nameAndTypeIndex; 39 | } 40 | 41 | @Override 42 | public final boolean equals(Object o) { 43 | if (this == o) return true; 44 | if (o == null || getClass() != o.getClass()) return false; 45 | 46 | ConstantReference that = (ConstantReference) o; 47 | 48 | if (classIndex != that.classIndex) return false; 49 | return nameAndTypeIndex == that.nameAndTypeIndex; 50 | } 51 | 52 | @Override 53 | public final int hashCode() { 54 | int result = classIndex; 55 | result = 31 * result + nameAndTypeIndex; 56 | return result; 57 | } 58 | 59 | static > Codec codec(ConstantReferenceFunction fn) { 60 | return Codec.of(input -> { 61 | return fn.create(input.readUnsignedShort(), input.readUnsignedShort()); 62 | }, (output, value) -> { 63 | output.writeShort(value.classIndex()); 64 | output.writeShort(value.nameAndTypeIndex()); 65 | }, Skip.exact(4)); 66 | } 67 | 68 | interface ConstantReferenceFunction> { 69 | T create(int classNameIndex, int nameAndTypeIndex); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantString.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Utf8. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantString implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantString(input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeShort(value.index()); 17 | }, Skip.exact(2)); 18 | 19 | private final int index; 20 | 21 | /** 22 | * @param index UTF-8 index. 23 | */ 24 | public ConstantString(int index) { 25 | this.index = index; 26 | } 27 | 28 | /** 29 | * @return UTF-8 index. 30 | */ 31 | public int index() { 32 | return index; 33 | } 34 | 35 | @Override 36 | public @NotNull Tag tag() { 37 | return Tag.CONSTANT_String; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (o == null || getClass() != o.getClass()) return false; 44 | 45 | ConstantString that = (ConstantString) o; 46 | 47 | return index == that.index; 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return index; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantUtf8.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_Utf8. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantUtf8 implements ConstantEntry, ValueEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantUtf8(input.readUTF()); 15 | }, (output, value) -> { 16 | output.writeUTF(value.value()); 17 | }, Skip.exact(2)); 18 | 19 | private final String value; 20 | 21 | /** 22 | * @param value UTF-8 value. 23 | */ 24 | public ConstantUtf8(@NotNull String value) { 25 | this.value = value; 26 | } 27 | 28 | /** 29 | * @return UTF-8 value. 30 | */ 31 | public String value() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public @NotNull String getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public @NotNull Tag tag() { 42 | return Tag.CONSTANT_Utf8; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | 50 | ConstantUtf8 that = (ConstantUtf8) o; 51 | 52 | return value.equals(that.value); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return value.hashCode(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ConstantethodHandle.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * CONSTANT_InterfaceMethodref. 9 | * 10 | * @author xDark 11 | */ 12 | public final class ConstantethodHandle implements ConstantEntry { 13 | static final Codec CODEC = Codec.of(input -> { 14 | return new ConstantethodHandle(input.readUnsignedByte(), input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeByte(value.referenceKind()); 17 | output.writeShort(value.referenceIndex()); 18 | }, Skip.exact(3)); 19 | 20 | private final int referenceKind; 21 | private final int referenceIndex; 22 | 23 | /** 24 | * @param referenceKind Reference kind. 25 | * @param referenceIndex Reference index. 26 | */ 27 | public ConstantethodHandle(int referenceKind, int referenceIndex) { 28 | this.referenceKind = referenceKind; 29 | this.referenceIndex = referenceIndex; 30 | } 31 | 32 | /** 33 | * @return Reference kind. 34 | */ 35 | public int referenceKind() { 36 | return referenceKind; 37 | } 38 | 39 | /** 40 | * @return Reference index. 41 | */ 42 | public int referenceIndex() { 43 | return referenceIndex; 44 | } 45 | 46 | @Override 47 | public @NotNull Tag tag() { 48 | return Tag.CONSTANT_MethodHandle; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | 56 | ConstantethodHandle that = (ConstantethodHandle) o; 57 | 58 | if (referenceKind != that.referenceKind) return false; 59 | return referenceIndex == that.referenceIndex; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | int result = referenceKind; 65 | result = 31 * result + referenceIndex; 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/FilterConstantPoolVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Constant visitor that forwards to another visitor. 8 | * 9 | * @author xDark 10 | */ 11 | public class FilterConstantPoolVisitor implements ConstantPoolVisitor { 12 | @Nullable 13 | protected ConstantPoolVisitor cv; 14 | 15 | public FilterConstantPoolVisitor(@Nullable ConstantPoolVisitor cv) { 16 | this.cv = cv; 17 | } 18 | 19 | public FilterConstantPoolVisitor() { 20 | } 21 | 22 | @Override 23 | public void visitConstants() { 24 | ConstantPoolVisitor cv = this.cv; 25 | if (cv != null) { 26 | cv.visitConstants(); 27 | } 28 | } 29 | 30 | @Override 31 | public void visitConstant(@NotNull ConstantEntry entry) { 32 | ConstantPoolVisitor cv = this.cv; 33 | if (cv != null) { 34 | cv.visitConstant(entry); 35 | } 36 | } 37 | 38 | @Override 39 | public void visitEnd() { 40 | ConstantPoolVisitor cv = this.cv; 41 | if (cv != null) { 42 | cv.visitEnd(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/constantpool/ValueEntry.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.constantpool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Constant entry that holds known value, 7 | * such as long, double, int float, string, etc. 8 | * 9 | * @author xDark 10 | */ 11 | public interface ValueEntry { 12 | 13 | /** 14 | * @return Known value. 15 | */ 16 | @NotNull V getValue(); 17 | } 18 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/dynamic/MethodHandle.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.dynamic; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Method handle. 7 | * 8 | * @author xDark 9 | */ 10 | public final class MethodHandle { 11 | private final int referenceKind; 12 | private final String owner; 13 | private final String name; 14 | private final String descriptor; 15 | private final boolean itf; 16 | 17 | /** 18 | * @param referenceKind Reference kind. 19 | * @param owner Owner class name. 20 | * @param name Name. 21 | * @param descriptor Descriptor. 22 | * @param itf Whether the owner is an interface. 23 | */ 24 | public MethodHandle(int referenceKind, @NotNull String owner, @NotNull String name, @NotNull String descriptor, boolean itf) { 25 | this.referenceKind = referenceKind; 26 | this.owner = owner; 27 | this.name = name; 28 | this.descriptor = descriptor; 29 | this.itf = itf; 30 | } 31 | 32 | /** 33 | * @return Reference kind. 34 | */ 35 | public int getReferenceKind() { 36 | return referenceKind; 37 | } 38 | 39 | /** 40 | * @return Owner class name. 41 | */ 42 | @NotNull 43 | public String getOwner() { 44 | return owner; 45 | } 46 | 47 | /** 48 | * @return Name. 49 | */ 50 | @NotNull 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | /** 56 | * @return Descriptor. 57 | */ 58 | @NotNull 59 | public String getDescriptor() { 60 | return descriptor; 61 | } 62 | 63 | /** 64 | * @return Whether the owner is an interface. 65 | */ 66 | public boolean isInterface() { 67 | return itf; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) return true; 73 | if (o == null || getClass() != o.getClass()) return false; 74 | 75 | MethodHandle that = (MethodHandle) o; 76 | 77 | if (referenceKind != that.referenceKind) return false; 78 | if (itf != that.itf) return false; 79 | if (!owner.equals(that.owner)) return false; 80 | if (!name.equals(that.name)) return false; 81 | return descriptor.equals(that.descriptor); 82 | } 83 | 84 | @Override 85 | public int hashCode() { 86 | int result = referenceKind; 87 | result = 31 * result + owner.hashCode(); 88 | result = 31 * result + name.hashCode(); 89 | result = 31 * result + descriptor.hashCode(); 90 | result = 31 * result + (itf ? 1 : 0); 91 | return result; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/dynamic/ReferenceKind.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.dynamic; 2 | 3 | /** 4 | * MethodHandle reference kinds. 5 | * 6 | * @author xDark 7 | */ 8 | public interface ReferenceKind { 9 | int REF_GETFIELD = 1; 10 | int REF_GETSTATIC = 2; 11 | int REF_PUTFIELD = 3; 12 | int REF_PUTSTATIC = 4; 13 | int REF_INVOKEVIRTUAL = 5; 14 | int REF_INVOKESTATIC = 6; 15 | int REF_INVOKESPECIAL = 7; 16 | int REF_NEWINVOKESPECIAL = 8; 17 | int REF_INVOKEINTERFACE = 9; 18 | } 19 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/field/FieldAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.field; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeAdapter; 5 | import dev.xdark.classfile.attribute.AttributeVisitor; 6 | import dev.xdark.classfile.constantpool.ConstantPoolBuilder; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Field adapter. 11 | */ 12 | public class FieldAdapter extends FilterFieldVisitor { 13 | private final ConstantPoolBuilder builder; 14 | 15 | /** 16 | * @param fv Backing fild visitor. 17 | * @param builder Constant pool builder. 18 | */ 19 | public FieldAdapter(@NotNull FieldVisitor fv, @NotNull ConstantPoolBuilder builder) { 20 | super(fv); 21 | this.builder = builder; 22 | } 23 | 24 | /** 25 | * @param access Access flag. 26 | * @param name Name. 27 | * @param desc Descriptor. 28 | */ 29 | public void visit(AccessFlag access, String name, String desc) { 30 | visit(access, builder.putUtf8(name), builder.putUtf8(desc)); 31 | } 32 | 33 | @Override 34 | public AttributeAdapter visitAttributes() { 35 | AttributeVisitor av = super.visitAttributes(); 36 | return av == null ? null : new AttributeAdapter(av, builder); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/field/FieldVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.field; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeVisitor; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Field visitor. 10 | * 11 | * @author xDark 12 | * for example, some class may call {@link FieldVisitor#visitAttributes()} or any other method 13 | * before calling {@link FieldVisitor#visit(AccessFlag, int, int)}. 14 | */ 15 | public interface FieldVisitor { 16 | 17 | /** 18 | * @param access Access flag. 19 | * @param nameIndex Name index. 20 | * @param descriptorIndex Descriptor index. 21 | */ 22 | void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex); 23 | 24 | /** 25 | * @return New attribute visitor or {@code null}, 26 | * if attributes should not be visited. 27 | */ 28 | @Nullable AttributeVisitor visitAttributes(); 29 | 30 | /** 31 | * Called after method has been visited. 32 | */ 33 | void visitEnd(); 34 | } 35 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/field/FilterFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.field; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeVisitor; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Field visitor that forwards to another visitor. 10 | * 11 | * @author xDark 12 | */ 13 | public class FilterFieldVisitor implements FieldVisitor { 14 | @Nullable 15 | protected FieldVisitor fv; 16 | 17 | public FilterFieldVisitor(@Nullable FieldVisitor fv) { 18 | this.fv = fv; 19 | } 20 | 21 | public FilterFieldVisitor() { 22 | } 23 | 24 | @Override 25 | public void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 26 | FieldVisitor mv = this.fv; 27 | if (mv != null) { 28 | mv.visit(access, nameIndex, descriptorIndex); 29 | } 30 | } 31 | 32 | @Override 33 | public AttributeVisitor visitAttributes() { 34 | FieldVisitor mv = this.fv; 35 | return mv == null ? null : mv.visitAttributes(); 36 | } 37 | 38 | @Override 39 | public void visitEnd() { 40 | FieldVisitor mv = this.fv; 41 | if (mv != null) { 42 | mv.visitEnd(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/ContextCodec.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Context-aware codec. 9 | * 10 | * @author xDark 11 | */ 12 | public interface ContextCodec 13 | extends ContextDecoder, 14 | ContextEncoder, 15 | ContextSkip { 16 | 17 | /** 18 | * @param decoder Decoder. 19 | * @param encoder Encoder. 20 | * @return Composed codec. 21 | */ 22 | static ContextCodec of(@NotNull ContextDecoder decoder, @NotNull ContextEncoder encoder, ContextSkip skip) { 23 | return new ContextCodec() { 24 | @Override 25 | public @NotNull T read(@NotNull Input input, @NotNull D_CTX d_ctx) throws IOException { 26 | return decoder.read(input, d_ctx); 27 | } 28 | 29 | @Override 30 | public void write(@NotNull Output output, @NotNull T value, @NotNull E_CTX e_ctx) throws IOException { 31 | encoder.write(output, value, e_ctx); 32 | } 33 | 34 | @Override 35 | public void skip(@NotNull Input input, D_CTX d_ctx) throws IOException { 36 | skip.skip(input, d_ctx); 37 | } 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/ContextDecoder.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Context-aware decoder. 9 | * 10 | * @author xDark 11 | */ 12 | @FunctionalInterface 13 | public interface ContextDecoder { 14 | 15 | /** 16 | * @param input Input to read instance from. 17 | * @param ctx Context. 18 | * @return Read instance. 19 | * @throws IOException If any I/O error occurs. 20 | */ 21 | @NotNull T read(@NotNull Input input, @NotNull CTX ctx) throws IOException; 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/ContextEncoder.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Context-aware encoder. 9 | * 10 | * @author xDark 11 | */ 12 | @FunctionalInterface 13 | public interface ContextEncoder { 14 | 15 | /** 16 | * @param output Output to write instance to. 17 | * @param value Value to write. 18 | * @param ctx Context. 19 | * @throws IOException If any I/O error occurs. 20 | */ 21 | void write(@NotNull Output output, @NotNull T value, @NotNull CTX ctx) throws IOException; 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/ContextSkip.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Context-aware skip. 9 | * 10 | * @author xDark 11 | */ 12 | @FunctionalInterface 13 | public interface ContextSkip { 14 | 15 | /** 16 | * @param input Input to skip bytes in. 17 | * @param ctx Context. 18 | * @throws IOException If any I/O error occurs. 19 | */ 20 | void skip(@NotNull Input input, CTX ctx) throws IOException; 21 | 22 | /** 23 | * @param next Next skip. 24 | * @return Skip chain. 25 | */ 26 | default ContextSkip then(ContextSkip next) { 27 | return (input, ctx) -> { 28 | skip(input, ctx); 29 | next.skip(input, ctx); 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/Decoder.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Instance decoder. 9 | * 10 | * @author xDark 11 | */ 12 | @FunctionalInterface 13 | public interface Decoder { 14 | 15 | /** 16 | * @param input Input to read instance from. 17 | * @return Read instance. 18 | * @throws IOException If any I/O error occurs. 19 | */ 20 | @NotNull T read(@NotNull Input input) throws IOException; 21 | } 22 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/Encoder.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Instance encoder. 9 | * 10 | * @author xDark 11 | */ 12 | @FunctionalInterface 13 | public interface Encoder { 14 | 15 | /** 16 | * @param output Output to write instance to. 17 | * @param value Value to write. 18 | * @throws IOException If any I/O error occurs. 19 | */ 20 | void write(@NotNull Output output, @NotNull T value) throws IOException; 21 | } 22 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/Input.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import dev.xdark.classfile.io.buffer.ByteBufferInput; 4 | 5 | import java.io.DataInput; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | 9 | /** 10 | * Input interface. 11 | * 12 | * @author xDark 13 | */ 14 | public interface Input extends Seekable, DataInput { 15 | 16 | /** 17 | * @param length Byte array length. 18 | * @return Read array. 19 | */ 20 | byte[] read(int length) throws IOException; 21 | 22 | /** 23 | * @return How many bytes do we have left? 24 | */ 25 | int remaining(); 26 | 27 | /** 28 | * @return Whether the EOF was reached. 29 | */ 30 | boolean hasRemaining(); 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | @Override 36 | int position(); 37 | 38 | /** 39 | * @param position New position. 40 | * @return This input. 41 | */ 42 | @Override 43 | Input position(int position) throws IOException; 44 | 45 | static Input wrap(byte[] array, int off, int len) { 46 | return new ByteBufferInput(ByteBuffer.wrap(array, off, len)); 47 | } 48 | 49 | static Input wrap(byte[] array) { 50 | return new ByteBufferInput(ByteBuffer.wrap(array)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/Output.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import java.io.DataOutput; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Output interface. 8 | * 9 | * @author xDark 10 | */ 11 | public interface Output extends DataOutput, Seekable { 12 | 13 | /** 14 | * {@inheritDoc} 15 | */ 16 | @Override 17 | int position(); 18 | 19 | /** 20 | * @param position New position. 21 | * @return This output. 22 | */ 23 | @Override 24 | Output position(int position) throws IOException; 25 | } 26 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/Seekable.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Seekable I/O. 7 | * 8 | * @author xDark 9 | */ 10 | public interface Seekable { 11 | 12 | /** 13 | * @return Current position. 14 | */ 15 | int position(); 16 | 17 | /** 18 | * @param position New position. 19 | * @return This instance. 20 | */ 21 | Seekable position(int position) throws IOException; 22 | } 23 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/buffer/ByteBufferAllocator.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io.buffer; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** 6 | * {@link ByteBuffer} allocator. 7 | * 8 | * @author xDark 9 | */ 10 | public interface ByteBufferAllocator { 11 | ByteBufferAllocator HEAP = (ImmediateAllocator) ByteBuffer::allocate; 12 | ByteBufferAllocator DIRECT = (ImmediateAllocator) ByteBuffer::allocateDirect; 13 | 14 | /** 15 | * @param size Buffer size. 16 | * @return Allocated buffer. 17 | */ 18 | ByteBuffer allocate(int size); 19 | 20 | ByteBuffer reallocate(ByteBuffer buffer, int size); 21 | } 22 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/io/buffer/ImmediateAllocator.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.io.buffer; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | interface ImmediateAllocator extends ByteBufferAllocator { 6 | 7 | @Override 8 | default ByteBuffer reallocate(ByteBuffer buffer, int size) { 9 | return allocate(size); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/method/FilterMethodVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.method; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeVisitor; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Method visitor that forwards to another visitor. 10 | * 11 | * @author xDark 12 | */ 13 | public class FilterMethodVisitor implements MethodVisitor { 14 | @Nullable 15 | protected MethodVisitor mv; 16 | 17 | public FilterMethodVisitor(@Nullable MethodVisitor mv) { 18 | this.mv = mv; 19 | } 20 | 21 | public FilterMethodVisitor() { 22 | } 23 | 24 | @Override 25 | public void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex) { 26 | MethodVisitor mv = this.mv; 27 | if (mv != null) { 28 | mv.visit(access, nameIndex, descriptorIndex); 29 | } 30 | } 31 | 32 | @Override 33 | public AttributeVisitor visitAttributes() { 34 | MethodVisitor mv = this.mv; 35 | return mv == null ? null : mv.visitAttributes(); 36 | } 37 | 38 | @Override 39 | public void visitEnd() { 40 | MethodVisitor mv = this.mv; 41 | if (mv != null) { 42 | mv.visitEnd(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/method/MethodAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.method; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeAdapter; 5 | import dev.xdark.classfile.attribute.AttributeVisitor; 6 | import dev.xdark.classfile.constantpool.ConstantPoolBuilder; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Method adapter. 11 | */ 12 | public class MethodAdapter extends FilterMethodVisitor { 13 | private final ConstantPoolBuilder builder; 14 | 15 | /** 16 | * @param mv Backing method visitor. 17 | * @param builder Constant pool builder. 18 | */ 19 | public MethodAdapter(@NotNull MethodVisitor mv, @NotNull ConstantPoolBuilder builder) { 20 | super(mv); 21 | this.builder = builder; 22 | } 23 | 24 | /** 25 | * @param access Access flag. 26 | * @param name Name. 27 | * @param desc Descriptor. 28 | */ 29 | public void visit(AccessFlag access, String name, String desc) { 30 | visit(access, builder.putUtf8(name), builder.putUtf8(desc)); 31 | } 32 | 33 | @Override 34 | public AttributeAdapter visitAttributes() { 35 | AttributeVisitor av = super.visitAttributes(); 36 | return av == null ? null : new AttributeAdapter(av, builder); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/method/MethodVisitor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.method; 2 | 3 | import dev.xdark.classfile.AccessFlag; 4 | import dev.xdark.classfile.attribute.AttributeVisitor; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Method visitor. 10 | * 11 | * @author xDark 12 | * for example, some class may call {@link MethodVisitor#visitAttributes()} or any other method 13 | * before calling {@link MethodVisitor#visit(AccessFlag, int, int)}. 14 | */ 15 | public interface MethodVisitor { 16 | 17 | /** 18 | * @param access Access flag. 19 | * @param nameIndex Name index. 20 | * @param descriptorIndex Descriptor index. 21 | */ 22 | void visit(@NotNull AccessFlag access, int nameIndex, int descriptorIndex); 23 | 24 | /** 25 | * @return New attribute visitor or {@code null}, 26 | * if attributes should not be visited. 27 | */ 28 | @Nullable AttributeVisitor visitAttributes(); 29 | 30 | /** 31 | * Called after method has been visited. 32 | */ 33 | void visitEnd(); 34 | } 35 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/opcode/AbstractInstruction.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.opcode; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Basic instruction. 7 | * 8 | * @author xDark 9 | */ 10 | public abstract class AbstractInstruction> implements Instruction { 11 | private final Opcode opcode; 12 | 13 | /** 14 | * @param opcode Opcode. 15 | */ 16 | protected AbstractInstruction(Opcode opcode) { 17 | this.opcode = opcode; 18 | } 19 | 20 | @Override 21 | public final @NotNull Opcode getOpcode() { 22 | return opcode; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/opcode/EmptyInstruction.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.opcode; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | /** 7 | * Empty instruction with no operands. 8 | * 9 | * @author xDark 10 | */ 11 | public final class EmptyInstruction extends AbstractInstruction { 12 | static final Codec CODEC = Codec.of(input -> { 13 | return new EmptyInstruction(Opcode.require(input)); 14 | }, (output, value) -> { 15 | output.writeByte(value.getOpcode().opcode()); 16 | }, Skip.exact(1)); 17 | 18 | /** 19 | * @param opcode Opcode. 20 | */ 21 | public EmptyInstruction(Opcode opcode) { 22 | super(opcode); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/opcode/FieldInstruction.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.opcode; 2 | 3 | import dev.xdark.classfile.io.Codec; 4 | import dev.xdark.classfile.io.Skip; 5 | 6 | /** 7 | * Field operation instruction. 8 | * 9 | * @author xDark 10 | */ 11 | public final class FieldInstruction extends AbstractInstruction { 12 | static final Codec CODEC = Codec.of(input -> { 13 | Opcode opcode = Opcode.require(input); 14 | return new FieldInstruction(opcode, input.readUnsignedShort()); 15 | }, (output, value) -> { 16 | output.writeByte(value.getOpcode().opcode()); 17 | output.writeShort(value.getFieldIndex()); 18 | }, Skip.exact(3)); 19 | private final int fieldIndex; 20 | 21 | /** 22 | * @param opcode Opcode. 23 | * @param fieldIndex Constant pool entry index. 24 | */ 25 | public FieldInstruction(Opcode opcode, int fieldIndex) { 26 | super(opcode); 27 | this.fieldIndex = fieldIndex; 28 | } 29 | 30 | /** 31 | * @return Constant pool entry index. 32 | */ 33 | public int getFieldIndex() { 34 | return fieldIndex; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /classfile-core/src/main/java/dev/xdark/classfile/opcode/FlowInstruction.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.classfile.opcode; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Flow control instruction. 9 | * 10 | * @author xDark 11 | */ 12 | public interface FlowInstruction { 13 | 14 | /** 15 | * @return A list of targets. 16 | */ 17 | @NotNull List