From d9b3e4d5f8f741abdec9ff2bc029671e1964a0ce Mon Sep 17 00:00:00 2001 From: phith0n Date: Fri, 22 Mar 2024 18:32:31 +0800 Subject: [PATCH] improvement for class parser --- .golangci.yml | 22 +++++++++-- class/access.go | 49 ----------------------- class/attribute_access.go | 22 +++++++++++ class/class_access.go | 50 +++++++++++++++++++++++ class/classfile.go | 4 +- class/constant.go | 68 ++++++++++++++++---------------- class/constant_class.go | 2 +- class/constant_double.go | 2 +- class/constant_dynamic.go | 2 +- class/constant_fieldref.go | 2 +- class/constant_float.go | 2 +- class/constant_integer.go | 2 +- class/constant_invoke_dynamic.go | 2 +- class/constant_long.go | 2 +- class/constant_method_handle.go | 2 +- class/constant_method_type.go | 2 +- class/constant_methodref.go | 2 +- class/constant_module.go | 2 +- class/constant_nametype.go | 2 +- class/constant_package.go | 2 +- class/constant_utf8.go | 2 +- class/field.go | 4 +- 22 files changed, 144 insertions(+), 105 deletions(-) delete mode 100644 class/access.go create mode 100644 class/attribute_access.go create mode 100644 class/class_access.go diff --git a/.golangci.yml b/.golangci.yml index d8d001d..aa7082a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,14 +1,30 @@ linters: disable-all: true enable: - - deadcode + - unused - errcheck - gosimple - govet - ineffassign - staticcheck - - structcheck - unused - - varcheck - gofmt - goconst + - misspell + - nolintlint + - tagliatelle +linters-settings: + misspell: + locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + tagliatelle: + case: + rules: + json: snake + yaml: snake + xml: snake + form: snake + msgpack: snake diff --git a/class/access.go b/class/access.go deleted file mode 100644 index d627abf..0000000 --- a/class/access.go +++ /dev/null @@ -1,49 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -const ( - ACC_PUBLIC uint16 = 0x0001 // Declared public; may be accessed from outside its package. - ACC_PRIVATE uint16 = 0x0002 // Marked private in source. - ACC_PROTECTED uint16 = 0x0004 // Marked protected in source. - ACC_STATIC uint16 = 0x0008 // Marked or implicitly static in source. - ACC_FINAL uint16 = 0x0010 // Declared final; no subclasses allowed. - ACC_SUPER uint16 = 0x0020 // Treat superclass methods specially when invoked by the invokespecial instruction. - ACC_INTERFACE uint16 = 0x0200 // Is an interface, not a class. - ACC_ABSTRACT uint16 = 0x0400 // Declared abstract; must not be instantiated. - ACC_SYNTHETIC uint16 = 0x1000 // Declared synthetic; not present in the source code. - ACC_ANNOTATION uint16 = 0x2000 // Declared as an annotation type. - ACC_ENUM uint16 = 0x4000 // Declared as an enum type. - ACC_MODULE uint16 = 0x8000 // Is a module, not a class or interface. -) - -func (cf *ClassFile) HasAccessFlag(flag uint16) bool { - return (flag & cf.AccessFlag) == flag -} - -func (cf *ClassFile) readAccessFlag(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read access flag failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint16(bs) - cf.AccessFlag = i - - // check access flag valid - if cf.HasAccessFlag(ACC_FINAL) && cf.HasAccessFlag(ACC_ABSTRACT) { - return fmt.Errorf("ACC_FINAL and ACC_ABSTRACT are not able to set at the same time") - } - - if cf.HasAccessFlag(ACC_ANNOTATION) && !cf.HasAccessFlag(ACC_ANNOTATION) { - return fmt.Errorf("if ACC_ANNOTATION is set, ACC_ANNOTATION must also be set") - } - - // TODO: more check - - return nil -} diff --git a/class/attribute_access.go b/class/attribute_access.go new file mode 100644 index 0000000..6977c4e --- /dev/null +++ b/class/attribute_access.go @@ -0,0 +1,22 @@ +package class + +type AttrAccessFlag uint16 + +const ( + AttrAccPublic AttrAccessFlag = 0x0001 // Declared public; may be accessed from outside its package. + AttrAccPrivate AttrAccessFlag = 0x0002 // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + AttrAccProtected AttrAccessFlag = 0x0004 // Declared protected; may be accessed within subclasses. + AttrAccStatic AttrAccessFlag = 0x0008 // Declared static. + AttrAccFinal AttrAccessFlag = 0x0010 // Declared final; must not be overridden (§5.4.5). + AttrAccSynchronized AttrAccessFlag = 0x0020 // Declared synchronized; invocation is wrapped by a monitor use. + AttrAccBridge AttrAccessFlag = 0x0040 // A bridge method, generated by the compiler. + AttrAccVarargs AttrAccessFlag = 0x0080 // Declared with variable number of arguments. + AttrAccNative AttrAccessFlag = 0x0100 // Declared native; implemented in a language other than the Java programming language. + AttrAccAbstract AttrAccessFlag = 0x0400 // Declared abstract; no implementation is provided. + AttrAccStrict AttrAccessFlag = 0x0800 // In a class file whose major version number is at least 46 and at most 60: Declared strictfp. + AttrAccSynthetic AttrAccessFlag = 0x1000 // Declared synthetic; not present in the source code. +) + +func (aaf AttrAccessFlag) HasAccessFlag(flag AttrAccessFlag) bool { + return (flag & aaf) == flag +} diff --git a/class/class_access.go b/class/class_access.go new file mode 100644 index 0000000..d727163 --- /dev/null +++ b/class/class_access.go @@ -0,0 +1,50 @@ +package class + +import ( + "encoding/binary" + "fmt" + "github.com/phith0n/zkar/commons" +) + +type ClassAccessFlag uint16 + +const ( + ClassAccPublic ClassAccessFlag = 0x0001 // Declared public; may be accessed from outside its package. + ClassAccPrivate ClassAccessFlag = 0x0002 // Marked private in source. + ClassAccProtected ClassAccessFlag = 0x0004 // Marked protected in source. + ClassAccStatic ClassAccessFlag = 0x0008 // Marked or implicitly static in source. + ClassAccFinal ClassAccessFlag = 0x0010 // Declared final; no subclasses allowed. + ClassAccSuper ClassAccessFlag = 0x0020 // Treat superclass methods specially when invoked by the invokespecial instruction. + ClassAccInterface ClassAccessFlag = 0x0200 // Is an interface, not a class. + ClassAccAbstract ClassAccessFlag = 0x0400 // Declared abstract; must not be instantiated. + ClassAccSynthetic ClassAccessFlag = 0x1000 // Declared synthetic; not present in the source code. + ClassAccAnnotation ClassAccessFlag = 0x2000 // Declared as an annotation type. + ClassAccEnum ClassAccessFlag = 0x4000 // Declared as an enum type. + ClassAccModule ClassAccessFlag = 0x8000 // Is a module, not a class or interface. +) + +func (caf ClassAccessFlag) HasAccessFlag(flag ClassAccessFlag) bool { + return (flag & caf) == flag +} + +func (cf *ClassFile) readAccessFlag(stream *commons.Stream) error { + bs, err := stream.ReadN(2) + if err != nil { + return fmt.Errorf("read access flag failed, no enough data in the stream") + } + + var i = binary.BigEndian.Uint16(bs) + cf.AccessFlag = ClassAccessFlag(i) + + // check access flag valid + if cf.AccessFlag.HasAccessFlag(ClassAccFinal) && cf.AccessFlag.HasAccessFlag(ClassAccAbstract) { + return fmt.Errorf("ACC_FINAL and ACC_ABSTRACT are not able to set at the same time") + } + + if cf.AccessFlag.HasAccessFlag(ClassAccAnnotation) && !cf.AccessFlag.HasAccessFlag(ClassAccInterface) { + return fmt.Errorf("if ACC_ANNOTATION is set, ACC_ANNOTATION must also be set") + } + + // TODO: maybe need more check + return nil +} diff --git a/class/classfile.go b/class/classfile.go index bcdbe3b..e8563b3 100644 --- a/class/classfile.go +++ b/class/classfile.go @@ -13,7 +13,7 @@ type ClassFile struct { MinorVersion uint16 MajorVersion uint16 ConstantPool []Constant - AccessFlag uint16 + AccessFlag ClassAccessFlag ThisClassIndex uint16 SuperClassIndex uint16 InterfaceIndexArray []uint16 @@ -29,7 +29,7 @@ func (cf *ClassFile) readHeader(stream *commons.Stream) error { } if !bytes.Equal(bs, []byte("\xCA\xFE\xBA\xBE")) { - return fmt.Errorf("magic number %v is not equal to CAFEBABE", hex.EncodeToString(bs)) + return fmt.Errorf("magic number %v is not equal to 0xCAFEBABE", hex.EncodeToString(bs)) } cf.MagicNumber = bs diff --git a/class/constant.go b/class/constant.go index 4d3f775..d45b4d6 100644 --- a/class/constant.go +++ b/class/constant.go @@ -7,23 +7,23 @@ import ( ) const ( - CONSTANT_UTF8_INFO = 1 - CONSTANT_INTEGER_INFO = 3 - CONSTANT_FLOAT_INFO = 4 - CONSTANT_LONG_INFO = 5 - CONSTANT_DOUBLE_INFO = 6 - CONSTANT_CLASS_INFO = 7 - CONSTANT_STRING_INGFO = 8 - CONSTANT_FIELD_REF_INFO = 9 - CONSTANT_METHOD_REF_INFO = 10 - CONSTANT_INTERFACE_METHOD_REF = 11 - CONSTANT_NAME_AND_TYPE_INFO = 12 - CONSTANT_METHOD_HANDLE_INFO = 15 - CONSTANT_METHOD_TYPE_INFO = 16 - CONSTANT_DYNAMIC_INFO = 17 - CONSTANT_INVOKE_DYNAMIC_INFO = 18 - CONSTANT_MODULE_INFO = 19 - CONSTANT_PACKAGE_INFO = 20 + ConstantUtf8Info = 1 + ConstantIntegerInfo = 3 + ConstantFloatInfo = 4 + ConstantLongInfo = 5 + ConstantDoubleInfo = 6 + ConstantClassInfo = 7 + ConstantStringInfo = 8 + ConstantFieldRefInfo = 9 + ConstantMethodRefInfo = 10 + ConstantInterfaceMethodRefInfo = 11 + ConstantNameAndTypeInfo = 12 + ConstantMethodHandleInfo = 15 + ConstantMethodTypeInfo = 16 + ConstantDynamicInfo = 17 + ConstantInvokeDynamicInfo = 18 + ConstantModuleInfo = 19 + ConstantPackageInfo = 20 ) type Constant interface { @@ -57,39 +57,39 @@ func (cf *ClassFile) readConstant(stream *commons.Stream) error { var obj Constant switch bs[0] { - case CONSTANT_UTF8_INFO: + case ConstantUtf8Info: obj, err = cf.readConstantUTF8(stream) - case CONSTANT_INTEGER_INFO: + case ConstantIntegerInfo: obj, err = cf.readConstantInteger(stream) - case CONSTANT_FLOAT_INFO: + case ConstantFloatInfo: obj, err = cf.readConstantFloat(stream) - case CONSTANT_LONG_INFO: + case ConstantLongInfo: obj, err = cf.readConstantLong(stream) - case CONSTANT_DOUBLE_INFO: + case ConstantDoubleInfo: obj, err = cf.readConstantDouble(stream) - case CONSTANT_CLASS_INFO: + case ConstantClassInfo: obj, err = cf.readConstantClass(stream) - case CONSTANT_STRING_INGFO: + case ConstantStringInfo: obj, err = cf.readConstantString(stream) - case CONSTANT_FIELD_REF_INFO: + case ConstantFieldRefInfo: obj, err = cf.readConstantFieldRef(stream) - case CONSTANT_METHOD_REF_INFO: + case ConstantMethodRefInfo: obj, err = cf.readConstantMethodRef(stream) - case CONSTANT_INTERFACE_METHOD_REF: + case ConstantInterfaceMethodRefInfo: obj, err = cf.readConstantInterfaceMethodRef(stream) - case CONSTANT_NAME_AND_TYPE_INFO: + case ConstantNameAndTypeInfo: obj, err = cf.readConstantNameAndType(stream) - case CONSTANT_METHOD_HANDLE_INFO: + case ConstantMethodHandleInfo: obj, err = cf.readConstantMethodHandle(stream) - case CONSTANT_METHOD_TYPE_INFO: + case ConstantMethodTypeInfo: obj, err = cf.readConstantMethodType(stream) - case CONSTANT_DYNAMIC_INFO: + case ConstantDynamicInfo: obj, err = cf.readConstantDynamic(stream) - case CONSTANT_INVOKE_DYNAMIC_INFO: + case ConstantInvokeDynamicInfo: obj, err = cf.readConstantInvokeDynamic(stream) - case CONSTANT_MODULE_INFO: + case ConstantModuleInfo: obj, err = cf.readConstantModule(stream) - case CONSTANT_PACKAGE_INFO: + case ConstantPackageInfo: obj, err = cf.readConstantPackage(stream) default: err = fmt.Errorf("constant type %v doesn't exists", bs) diff --git a/class/constant_class.go b/class/constant_class.go index 4fd78c8..120cf1a 100644 --- a/class/constant_class.go +++ b/class/constant_class.go @@ -11,7 +11,7 @@ type ConstantClass struct { } func (c *ConstantClass) ToBytes() []byte { - var bs = []byte{CONSTANT_CLASS_INFO} + var bs = []byte{ConstantClassInfo} bs = append(bs, commons.NumberToBytes(c.NameIndex)...) return bs } diff --git a/class/constant_double.go b/class/constant_double.go index 6e8cbbe..3e1f4ed 100644 --- a/class/constant_double.go +++ b/class/constant_double.go @@ -12,7 +12,7 @@ type ConstantDouble struct { } func (c *ConstantDouble) ToBytes() []byte { - var bs = []byte{CONSTANT_DOUBLE_INFO} + var bs = []byte{ConstantDoubleInfo} bs = append(bs, commons.NumberToBytes(c.Double)...) return bs } diff --git a/class/constant_dynamic.go b/class/constant_dynamic.go index 756eb91..4253d31 100644 --- a/class/constant_dynamic.go +++ b/class/constant_dynamic.go @@ -12,7 +12,7 @@ type ConstantDynamic struct { } func (c *ConstantDynamic) ToBytes() []byte { - var bs = []byte{CONSTANT_DYNAMIC_INFO} + var bs = []byte{ConstantDynamicInfo} bs = append(bs, commons.NumberToBytes(c.BootstrapMethodIndex)...) bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) return bs diff --git a/class/constant_fieldref.go b/class/constant_fieldref.go index a6f7592..119cc15 100644 --- a/class/constant_fieldref.go +++ b/class/constant_fieldref.go @@ -12,7 +12,7 @@ type ConstantFieldRef struct { } func (c *ConstantFieldRef) ToBytes() []byte { - var bs = []byte{CONSTANT_FIELD_REF_INFO} + var bs = []byte{ConstantFieldRefInfo} bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) return bs diff --git a/class/constant_float.go b/class/constant_float.go index f83a304..b552465 100644 --- a/class/constant_float.go +++ b/class/constant_float.go @@ -12,7 +12,7 @@ type ConstantFloat struct { } func (c *ConstantFloat) ToBytes() []byte { - var bs = []byte{CONSTANT_FLOAT_INFO} + var bs = []byte{ConstantFloatInfo} bs = append(bs, commons.NumberToBytes(c.Float)...) return bs } diff --git a/class/constant_integer.go b/class/constant_integer.go index c2de5ec..16aa533 100644 --- a/class/constant_integer.go +++ b/class/constant_integer.go @@ -11,7 +11,7 @@ type ConstantInteger struct { } func (c *ConstantInteger) ToBytes() []byte { - var bs = []byte{CONSTANT_INTEGER_INFO} + var bs = []byte{ConstantIntegerInfo} bs = append(bs, commons.NumberToBytes(c.Integer)...) return bs } diff --git a/class/constant_invoke_dynamic.go b/class/constant_invoke_dynamic.go index 8f35c32..27b8861 100644 --- a/class/constant_invoke_dynamic.go +++ b/class/constant_invoke_dynamic.go @@ -12,7 +12,7 @@ type ConstantInvokeDynamic struct { } func (c *ConstantInvokeDynamic) ToBytes() []byte { - var bs = []byte{CONSTANT_INVOKE_DYNAMIC_INFO} + var bs = []byte{ConstantInvokeDynamicInfo} bs = append(bs, commons.NumberToBytes(c.BootstrapMethodIndex)...) bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) return bs diff --git a/class/constant_long.go b/class/constant_long.go index 0bb6f47..503cd2a 100644 --- a/class/constant_long.go +++ b/class/constant_long.go @@ -11,7 +11,7 @@ type ConstantLong struct { } func (c *ConstantLong) ToBytes() []byte { - var bs = []byte{CONSTANT_LONG_INFO} + var bs = []byte{ConstantLongInfo} bs = append(bs, commons.NumberToBytes(c.Long)...) return bs } diff --git a/class/constant_method_handle.go b/class/constant_method_handle.go index 934b608..01cdf7c 100644 --- a/class/constant_method_handle.go +++ b/class/constant_method_handle.go @@ -12,7 +12,7 @@ type ConstantMethodHandle struct { } func (c *ConstantMethodHandle) ToBytes() []byte { - var bs = []byte{CONSTANT_METHOD_HANDLE_INFO} + var bs = []byte{ConstantMethodHandleInfo} bs = append(bs, c.ReferenceKind) bs = append(bs, commons.NumberToBytes(c.ReferenceIndex)...) return bs diff --git a/class/constant_method_type.go b/class/constant_method_type.go index 6f51a28..a4c5825 100644 --- a/class/constant_method_type.go +++ b/class/constant_method_type.go @@ -11,7 +11,7 @@ type ConstantMethodType struct { } func (c *ConstantMethodType) ToBytes() []byte { - var bs = []byte{CONSTANT_METHOD_TYPE_INFO} + var bs = []byte{ConstantMethodTypeInfo} bs = append(bs, commons.NumberToBytes(c.DescriptorIndex)...) return bs } diff --git a/class/constant_methodref.go b/class/constant_methodref.go index 9d43b5a..f5c7e74 100644 --- a/class/constant_methodref.go +++ b/class/constant_methodref.go @@ -12,7 +12,7 @@ type ConstantMethodRef struct { } func (c *ConstantMethodRef) ToBytes() []byte { - var bs = []byte{CONSTANT_METHOD_REF_INFO} + var bs = []byte{ConstantMethodRefInfo} bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) return bs diff --git a/class/constant_module.go b/class/constant_module.go index 7e87514..af19436 100644 --- a/class/constant_module.go +++ b/class/constant_module.go @@ -11,7 +11,7 @@ type ConstantModule struct { } func (c *ConstantModule) ToBytes() []byte { - var bs = []byte{CONSTANT_MODULE_INFO} + var bs = []byte{ConstantModuleInfo} bs = append(bs, commons.NumberToBytes(c.NameIndex)...) return bs } diff --git a/class/constant_nametype.go b/class/constant_nametype.go index cb829c8..a5d90cc 100644 --- a/class/constant_nametype.go +++ b/class/constant_nametype.go @@ -12,7 +12,7 @@ type ConstantNameAndType struct { } func (c *ConstantNameAndType) ToBytes() []byte { - var bs = []byte{CONSTANT_NAME_AND_TYPE_INFO} + var bs = []byte{ConstantNameAndTypeInfo} bs = append(bs, commons.NumberToBytes(c.NameIndex)...) bs = append(bs, commons.NumberToBytes(c.DescriptorIndex)...) return bs diff --git a/class/constant_package.go b/class/constant_package.go index 3dbc6b7..ecdf900 100644 --- a/class/constant_package.go +++ b/class/constant_package.go @@ -11,7 +11,7 @@ type ConstantPackage struct { } func (c *ConstantPackage) ToBytes() []byte { - var bs = []byte{CONSTANT_PACKAGE_INFO} + var bs = []byte{ConstantPackageInfo} bs = append(bs, commons.NumberToBytes(c.NameIndex)...) return bs } diff --git a/class/constant_utf8.go b/class/constant_utf8.go index 7493814..6bd4db9 100644 --- a/class/constant_utf8.go +++ b/class/constant_utf8.go @@ -11,7 +11,7 @@ type ConstantUTF8 struct { } func (c *ConstantUTF8) ToBytes() []byte { - var bs = []byte{CONSTANT_UTF8_INFO} + var bs = []byte{ConstantUtf8Info} // integer overflow bs = append(bs, commons.NumberToBytes(uint16(len(c.Data)))...) diff --git a/class/field.go b/class/field.go index ead1a54..2185b87 100644 --- a/class/field.go +++ b/class/field.go @@ -7,7 +7,7 @@ import ( ) type Field struct { - AccessFlag uint16 + AccessFlag AttrAccessFlag NameIndex uint16 DescriptorIndex uint16 Attributes []Attribute @@ -38,7 +38,7 @@ func (cf *ClassFile) readField(stream *commons.Stream) (*Field, error) { if err != nil { return nil, fmt.Errorf("read field access flag failed, no enough data in the stream") } - field.AccessFlag = binary.BigEndian.Uint16(bs[:2]) + field.AccessFlag = AttrAccessFlag(binary.BigEndian.Uint16(bs[:2])) field.NameIndex = binary.BigEndian.Uint16(bs[2:4]) field.DescriptorIndex = binary.BigEndian.Uint16(bs[4:6]) var size = binary.BigEndian.Uint16(bs[6:])