From 9120100fab7e09ba01c54ff38169fa504ea10cf9 Mon Sep 17 00:00:00 2001 From: phith0n Date: Fri, 5 Apr 2024 21:37:20 +0800 Subject: [PATCH] continue to write attrs --- .golangci.yml | 2 + class/annotation.go | 10 +- class/attr_annotation_default.go | 22 ++++ class/attr_bootstrap_methods.go | 3 +- class/attr_innerclasses.go | 8 +- class/attr_linenumber_table.go | 3 +- class/attr_localvartable.go | 3 +- class/attr_localvartypetable.go | 3 +- class/attr_method_parameters.go | 40 +++++++ class/attr_module.go | 111 ++++++++++++++++++ class/attr_nest_members.go | 3 +- class/attr_permitted_subclasses.go | 3 +- .../attr_runtime_invisible_type_annotation.go | 33 ++++++ class/constant_interface_methodref.go | 2 +- class/constant_str.go | 2 +- class/parameter_access.go | 13 ++ class/type_annotation.go | 22 ++-- class/type_annotation_target.go | 16 +-- class/type_path.go | 7 +- 19 files changed, 267 insertions(+), 39 deletions(-) create mode 100644 class/attr_annotation_default.go create mode 100644 class/attr_method_parameters.go create mode 100644 class/attr_module.go create mode 100644 class/attr_runtime_invisible_type_annotation.go create mode 100644 class/parameter_access.go diff --git a/.golangci.yml b/.golangci.yml index aa7082a..811f726 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -28,3 +28,5 @@ linters-settings: xml: snake form: snake msgpack: snake + staticcheck: + checks: ["all"] diff --git a/class/annotation.go b/class/annotation.go index f80a1cd..e0232ed 100644 --- a/class/annotation.go +++ b/class/annotation.go @@ -7,13 +7,13 @@ import ( ) type Annotation struct { - TypeIndex uint16 + TypeIndex uint16 ElementValuePairs []*ElementValuePair } type ElementValuePair struct { ElementNameIndex uint16 - ElementValue *ElementValue + Value *ElementValue } func NewAnnotation(stream *commons.Stream) (*Annotation, error) { @@ -22,11 +22,11 @@ func NewAnnotation(stream *commons.Stream) (*Annotation, error) { return nil, fmt.Errorf("read Annotation failed, no enough data in the stream") } + length := binary.BigEndian.Uint16(bs[2:]) a := &Annotation{ TypeIndex: binary.BigEndian.Uint16(bs[:2]), } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs[2:]); i++ { + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(2) if err != nil { return nil, fmt.Errorf("read Annotation ElementValuePair[%d] failed, no enough data in the stream", i) @@ -35,7 +35,7 @@ func NewAnnotation(stream *commons.Stream) (*Annotation, error) { pair := &ElementValuePair{ ElementNameIndex: binary.BigEndian.Uint16(bs), } - pair.ElementValue, err = NewElementValue(stream) + pair.Value, err = NewElementValue(stream) if err != nil { return nil, fmt.Errorf("read Annotation ElementValuePair[%d] failed, caused by: %v", i, err) } diff --git a/class/attr_annotation_default.go b/class/attr_annotation_default.go new file mode 100644 index 0000000..9b9d3c8 --- /dev/null +++ b/class/attr_annotation_default.go @@ -0,0 +1,22 @@ +package class + +import ( + "fmt" + "github.com/phith0n/zkar/commons" +) + +type AttrAnnotationDefault struct { + *AttributeBase + + DefaultValue *ElementValue +} + +func (a *AttrAnnotationDefault) readInfo(stream *commons.Stream) error { + value, err := NewElementValue(stream) + if err != nil { + return fmt.Errorf("read AttrAnnotationDefault failed, caused by: %v", err) + } + + a.DefaultValue = value + return nil +} diff --git a/class/attr_bootstrap_methods.go b/class/attr_bootstrap_methods.go index 25d4efb..64c195e 100644 --- a/class/attr_bootstrap_methods.go +++ b/class/attr_bootstrap_methods.go @@ -47,10 +47,11 @@ func (a *AttrBootstrapMethods) readBootstrapMethod(stream *commons.Stream) (*Boo return nil, fmt.Errorf("read AttrBootstrapMethods BootstrapMethod failed, no enough data in the stream") } + length := binary.BigEndian.Uint16(bs[2:]) method := &BootstrapMethod{ BootstrapMethodRef: binary.BigEndian.Uint16(bs[:2]), } - for i := uint16(0); i < binary.BigEndian.Uint16(bs[2:]); i++ { + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(2) if err != nil { return nil, fmt.Errorf("read AttrBootstrapMethods BootstrapMethod argument[%d] failed, no enough data in the stream", i) diff --git a/class/attr_innerclasses.go b/class/attr_innerclasses.go index 72f3a36..c49f031 100644 --- a/class/attr_innerclasses.go +++ b/class/attr_innerclasses.go @@ -25,7 +25,7 @@ type InnerClass struct { // The value of the InnerClassAccessFlags item is a mask of flags used to denote access permissions to // and properties of class or interface C as declared in the source code from which this class file was compiled. - InnerClassAccessFlags uint16 + InnerClassAccessFlags ClassAccessFlag } func (a *AttrInnerClasses) readInfo(stream *commons.Stream) error { @@ -56,11 +56,11 @@ func (a *AttrInnerClasses) readInnerClass(stream *commons.Stream) (*InnerClass, InnerClassInfo: binary.BigEndian.Uint16(bs[:2]), OuterClassInfo: binary.BigEndian.Uint16(bs[2:4]), InnerClassIndex: binary.BigEndian.Uint16(bs[4:6]), - InnerClassAccessFlags: binary.BigEndian.Uint16(bs[6:]), + InnerClassAccessFlags: ClassAccessFlag(binary.BigEndian.Uint16(bs[6:])), } return c, nil } -func (ic *InnerClass) HasFlag(flag uint16) bool { - return (flag & ic.InnerClassAccessFlags) == flag +func (ic *InnerClass) HasFlag(flag ClassAccessFlag) bool { + return ic.InnerClassAccessFlags.HasAccessFlag(flag) } diff --git a/class/attr_linenumber_table.go b/class/attr_linenumber_table.go index ba5915a..0d31d15 100644 --- a/class/attr_linenumber_table.go +++ b/class/attr_linenumber_table.go @@ -27,7 +27,8 @@ func (a *AttrLineNumberTable) readInfo(stream *commons.Stream) error { return fmt.Errorf("read AttrLineNumberTable failed, no enough data in the stream") } - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(4) if err != nil { return fmt.Errorf("read AttrLineNumberTable line numbers failed, no enough data in the stream") diff --git a/class/attr_localvartable.go b/class/attr_localvartable.go index 9ec0d6d..ecbb237 100644 --- a/class/attr_localvartable.go +++ b/class/attr_localvartable.go @@ -26,7 +26,8 @@ func (a *AttrLocalVariableTable) readInfo(stream *commons.Stream) error { return fmt.Errorf("read AttrLocalVariableTable failed, no enough data in the stream") } - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(10) if err != nil { return fmt.Errorf("read AttrLocalVariableTable tables failed, no enough data in the stream") diff --git a/class/attr_localvartypetable.go b/class/attr_localvartypetable.go index 576263f..3df0623 100644 --- a/class/attr_localvartypetable.go +++ b/class/attr_localvartypetable.go @@ -27,7 +27,8 @@ func (a *AttrLocalVariableTypeTable) readInfo(stream *commons.Stream) error { return fmt.Errorf("read AttrLocalVariableTypeTable failed, no enough data in the stream") } - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(10) if err != nil { return fmt.Errorf("read AttrLocalVariableTypeTable tables failed, no enough data in the stream") diff --git a/class/attr_method_parameters.go b/class/attr_method_parameters.go new file mode 100644 index 0000000..2e4dd06 --- /dev/null +++ b/class/attr_method_parameters.go @@ -0,0 +1,40 @@ +package class + +import ( + "encoding/binary" + "fmt" + "github.com/phith0n/zkar/commons" +) + +// AttrMethodParameters https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.24 +type AttrMethodParameters struct { + *AttributeBase + + Parameters []*MethodParameter +} + +type MethodParameter struct { + NameIndex uint16 + AccessFlags ParameterAccessFlag +} + +func (a *AttrMethodParameters) readInfo(stream *commons.Stream) error { + bs, err := stream.ReadN(1) + if err != nil { + return fmt.Errorf("read AttrMethodParameters NameIndex failed, no enough data in the stream") + } + + length := bs[0] + for i := uint8(0); i < length; i++ { + bs, err = stream.ReadN(4) + if err != nil { + return fmt.Errorf("read AttrMethodParameters NameIndex and AccessFlag failed, no enough data in the stream") + } + + a.Parameters = append(a.Parameters, &MethodParameter{ + NameIndex: binary.BigEndian.Uint16(bs[:2]), + AccessFlags: ParameterAccessFlag(binary.BigEndian.Uint16(bs[2:])), + }) + } + return nil +} diff --git a/class/attr_module.go b/class/attr_module.go new file mode 100644 index 0000000..0529f14 --- /dev/null +++ b/class/attr_module.go @@ -0,0 +1,111 @@ +package class + +import ( + "encoding/binary" + "fmt" + "github.com/phith0n/zkar/commons" +) + +type AttrModule struct { + *AttributeBase + + ModuleName uint16 + ModuleFlags uint16 + ModuleVersionIndex uint16 + + Requires []*ModuleRequires + Exports []*ModuleExports + Opens []*ModuleOpens + UsesIndex []uint16 + Provides []*ModuleProvides +} + +func (a *AttrModule) readInfo(stream *commons.Stream) error { + bs, err := stream.ReadN(6) + if err != nil { + return fmt.Errorf("read AttrModule failed, no enough data in the stream") + } + + a.ModuleName = binary.BigEndian.Uint16(bs[:2]) + a.ModuleFlags = binary.BigEndian.Uint16(bs[2:4]) + a.ModuleVersionIndex = binary.BigEndian.Uint16(bs[4:]) + return nil +} + +type ModuleRequires struct { + RequiresIndex uint16 + RequiresFlags uint16 + RequiresVersionIndex uint16 +} + +func (a *AttrModule) readRequires(stream *commons.Stream) ([]*ModuleRequires, error) { + bs, err := stream.ReadN(2) + if err != nil { + return nil, fmt.Errorf("read AttrModule Requires failed, no enough data in the stream") + } + + var requires []*ModuleRequires + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { + bs, err = stream.ReadN(6) + if err != nil { + return nil, fmt.Errorf("read AttrModule Requires[%d] failed, no enough data in the stream", i) + } + + requires = append(requires, &ModuleRequires{ + RequiresIndex: binary.BigEndian.Uint16(bs[:2]), + RequiresFlags: binary.BigEndian.Uint16(bs[2:4]), + RequiresVersionIndex: binary.BigEndian.Uint16(bs[4:]), + }) + } + return requires, nil +} + +type ModuleExports struct { + ExportsIndex uint16 + ExportsFlags uint16 + ExportsToIndex []uint16 +} + +func (a *AttrModule) readExports(stream *commons.Stream) ([]*ModuleExports, error) { + bs, err := stream.ReadN(2) + if err != nil { + return nil, fmt.Errorf("read AttrModule Exports failed, no enough data in the stream") + } + + var exports []*ModuleExports + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { + bs, err = stream.ReadN(6) + if err != nil { + return nil, fmt.Errorf("read AttrModule Exports[%d] failed, no enough data in the stream", i) + } + + export := &ModuleExports{ + ExportsIndex: binary.BigEndian.Uint16(bs[:2]), + ExportsFlags: binary.BigEndian.Uint16(bs[2:4]), + } + + for j := uint16(0); j < binary.BigEndian.Uint16(bs[4:]); j++ { + data, err := stream.ReadN(2) + if err != nil { + return nil, fmt.Errorf("read AttrModule Exports[%d] ExportsToIndex[%d] failed, no enough data in the stream", i, j) + } + + export.ExportsToIndex = append(export.ExportsToIndex, binary.BigEndian.Uint16(data)) + } + exports = append(exports, export) + } + return exports, nil +} + +type ModuleOpens struct { + OpensIndex uint16 + OpensFlags uint16 + OpensToIndex []uint16 +} + +type ModuleProvides struct { + ProvidesIndex uint16 + ProvidesWithIndex []uint16 +} diff --git a/class/attr_nest_members.go b/class/attr_nest_members.go index b7629f3..85ffe7b 100644 --- a/class/attr_nest_members.go +++ b/class/attr_nest_members.go @@ -21,7 +21,8 @@ func (a *AttrNestMembers) readInfo(stream *commons.Stream) error { return fmt.Errorf("read AttrNestMembers failed, no enough data in the stream") } - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(2) if err != nil { return fmt.Errorf("read AttrNestMembers class[%d] failed, no enough data in the stream", i) diff --git a/class/attr_permitted_subclasses.go b/class/attr_permitted_subclasses.go index fcdec22..454899c 100644 --- a/class/attr_permitted_subclasses.go +++ b/class/attr_permitted_subclasses.go @@ -21,7 +21,8 @@ func (a *AttrPermittedSubclasses) readInfo(stream *commons.Stream) error { return fmt.Errorf("read AttrPermittedSubclasses failed, no enough data in the stream") } - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(2) if err != nil { return fmt.Errorf("read AttrPermittedSubclasses class[%d] failed, no enough data in the stream", i) diff --git a/class/attr_runtime_invisible_type_annotation.go b/class/attr_runtime_invisible_type_annotation.go new file mode 100644 index 0000000..c6b0424 --- /dev/null +++ b/class/attr_runtime_invisible_type_annotation.go @@ -0,0 +1,33 @@ +package class + +import ( + "encoding/binary" + "fmt" + "github.com/phith0n/zkar/commons" +) + +// AttrRuntimeInvisibleTypeAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.21 +type AttrRuntimeInvisibleTypeAnnotations struct { + *AttributeBase + + Annotations []*TypeAnnotation +} + +func (a *AttrRuntimeInvisibleTypeAnnotations) readInfo(stream *commons.Stream) error { + bs, err := stream.ReadN(2) + if err != nil { + return fmt.Errorf("read AttrRuntimeInvisibleTypeAnnotations failed, no enough data in the stream") + } + + for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + var annotation *TypeAnnotation + annotation, err = NewTypeAnnotation(stream) + if err != nil { + return fmt.Errorf("read AttrRuntimeInvisibleTypeAnnotations TypeAnnotation[%d] failed, caused by: %v", i, err) + } + + a.Annotations = append(a.Annotations, annotation) + } + + return nil +} diff --git a/class/constant_interface_methodref.go b/class/constant_interface_methodref.go index b97b68f..6b01ab4 100644 --- a/class/constant_interface_methodref.go +++ b/class/constant_interface_methodref.go @@ -12,7 +12,7 @@ type ConstantInterfaceMethodRef struct { } func (c *ConstantInterfaceMethodRef) ToBytes() []byte { - var bs = []byte{CONSTANT_INTERFACE_METHOD_REF} + var bs = []byte{ConstantInterfaceMethodRefInfo} bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) return bs diff --git a/class/constant_str.go b/class/constant_str.go index c3ba1fd..68cb7dd 100644 --- a/class/constant_str.go +++ b/class/constant_str.go @@ -11,7 +11,7 @@ type ConstantString struct { } func (c *ConstantString) ToBytes() []byte { - var bs = []byte{CONSTANT_STRING_INGFO} + var bs = []byte{ConstantStringInfo} bs = append(bs, commons.NumberToBytes(c.StringIndex)...) return bs } diff --git a/class/parameter_access.go b/class/parameter_access.go new file mode 100644 index 0000000..8b3e1ff --- /dev/null +++ b/class/parameter_access.go @@ -0,0 +1,13 @@ +package class + +type ParameterAccessFlag uint16 + +const ( + ParameterAccFinal ParameterAccessFlag = 0x0010 + ParameterAccSynthetic ParameterAccessFlag = 0x1000 + ParameterAccMandated ParameterAccessFlag = 0x8000 +) + +func (caf ParameterAccessFlag) HasAccessFlag(flag ParameterAccessFlag) bool { + return (flag & caf) == flag +} diff --git a/class/type_annotation.go b/class/type_annotation.go index a201ad5..30598df 100644 --- a/class/type_annotation.go +++ b/class/type_annotation.go @@ -7,22 +7,22 @@ import ( // TypeAnnotation https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.20 type TypeAnnotation struct { - TargetType uint8 - TypeParameterTarget *TypeParameterTarget - SuperTypeTarget *SuperTypeTarget + TargetType uint8 + TypeParameterTarget *TypeParameterTarget + SuperTypeTarget *SuperTypeTarget TypeParameterBoundTarget *TypeParameterBoundTarget - EmptyTarget *EmptyTarget - FormalParameterTarget *FormalParameterTarget - ThrowsTarget *ThrowsTarget - LocalVarTarget *LocalVarTarget - CatchTarget *CatchTarget - OffsetTarget *OffsetTarget - TypeArgumentTarget *TypeArgumentTarget + EmptyTarget *EmptyTarget + FormalParameterTarget *FormalParameterTarget + ThrowsTarget *ThrowsTarget + LocalVarTarget *LocalVarTarget + CatchTarget *CatchTarget + OffsetTarget *OffsetTarget + TypeArgumentTarget *TypeArgumentTarget TargetPath *TypePath // same as Annotation - TypeIndex uint16 + TypeIndex uint16 ElementValuePairs []*ElementValuePair } diff --git a/class/type_annotation_target.go b/class/type_annotation_target.go index 420f7c2..8213a0a 100644 --- a/class/type_annotation_target.go +++ b/class/type_annotation_target.go @@ -35,7 +35,7 @@ func NewSuperTypeTarget(stream *commons.Stream) (*SuperTypeTarget, error) { type TypeParameterBoundTarget struct { TypeParameterIndex uint8 - BoundIndex uint8 + BoundIndex uint8 } func NewTypeParameterBoundTarget(stream *commons.Stream) (*TypeParameterBoundTarget, error) { @@ -48,7 +48,6 @@ func NewTypeParameterBoundTarget(stream *commons.Stream) (*TypeParameterBoundTar } type EmptyTarget struct { - } type FormalParameterTarget struct { @@ -83,8 +82,8 @@ type LocalVarTarget struct { type LocalVarTargetTable struct { StartPC uint16 - Length uint16 - Index uint16 + Length uint16 + Index uint16 } func NewLocalVarTarget(stream *commons.Stream) (*LocalVarTarget, error) { @@ -94,7 +93,8 @@ func NewLocalVarTarget(stream *commons.Stream) (*LocalVarTarget, error) { } target := &LocalVarTarget{} - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { + length := binary.BigEndian.Uint16(bs) + for i := uint16(0); i < length; i++ { bs, err = stream.ReadN(6) if err != nil { return nil, fmt.Errorf("read LocalVarTarget Table[%d] failed, no enough data in the stream", i) @@ -137,7 +137,7 @@ func NewOffsetTarget(stream *commons.Stream) (*OffsetTarget, error) { } type TypeArgumentTarget struct { - Offset uint16 + Offset uint16 TypeArgumentIndex uint8 } @@ -148,7 +148,7 @@ func NewTypeArgumentTarget(stream *commons.Stream) (*TypeArgumentTarget, error) } return &TypeArgumentTarget{ - Offset: binary.BigEndian.Uint16(bs[:2]), + Offset: binary.BigEndian.Uint16(bs[:2]), TypeArgumentIndex: bs[2], }, nil -} \ No newline at end of file +} diff --git a/class/type_path.go b/class/type_path.go index 7d5d2cf..c559f1e 100644 --- a/class/type_path.go +++ b/class/type_path.go @@ -10,7 +10,7 @@ type TypePath struct { } type TypePathNode struct { - TypePathKind uint8 + TypePathKind uint8 TypeArgumentIndex uint8 } @@ -21,14 +21,15 @@ func NewTypePath(stream *commons.Stream) (*TypePath, error) { } tp := &TypePath{} - for i := uint8(0); i < bs[0]; i++ { + length := bs[0] + for i := uint8(0); i < length; i++ { bs, err = stream.ReadN(2) if err != nil { return nil, fmt.Errorf("read TypePath Node failed, no enough data in the stream") } tp.Path = append(tp.Path, &TypePathNode{ - TypePathKind: bs[0], + TypePathKind: bs[0], TypeArgumentIndex: bs[1], }) }