Skip to content

Commit

Permalink
parse Java classfile
Browse files Browse the repository at this point in the history
  • Loading branch information
phith0n committed Aug 16, 2021
1 parent 5479d7b commit d984b85
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 0 deletions.
5 changes: 5 additions & 0 deletions class/attribute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package class

type Attribute interface {

}
77 changes: 77 additions & 0 deletions class/classfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package class

import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"github.com/phith0n/zkar/commons"
)

type ClassFile struct {
MagicNumber []byte
MinorVersion uint16
MajorVersion uint16
ConstantPool []*Constant
AccessFlag uint16
ThisClassOffset uint16
SuperClassOffset uint16
InterfaceOffsetArray []uint16
Fields []*Field
Methods []*Method
Attributes []*Attribute
}

func (cf *ClassFile) readHeader(stream *commons.Stream) error {
bs, err := stream.ReadN(4)
if err != nil {
return fmt.Errorf("read magic number failed, no enough data in the stream")
}

if !bytes.Equal(bs, []byte("\xCA\xFE\xBA\xBE")) {
return fmt.Errorf("magic number %v is not equal to CAFEBABE", hex.EncodeToString(bs))
}

cf.MagicNumber = bs
bs, err = stream.ReadN(4)
if err != nil {
return fmt.Errorf("read minor and major version failed, no enough data in the stream")
}

cf.MinorVersion = binary.BigEndian.Uint16(bs[:2])
cf.MajorVersion = binary.BigEndian.Uint16(bs[2:])
return nil
}

func (cf *ClassFile) readConstantPool(stream *commons.Stream) error {
bs, err := stream.ReadN(2)
if err != nil {
return fmt.Errorf("read constant pool size failed, no enough data in the stream")
}

var size = binary.BigEndian.Uint16(bs)

// Note: Constant Pool index is start from 1, not 0
for i := uint16(1); i < size; i++ {
err = cf.readConstantPool(stream)
if err != nil {
return err
}
}

return nil
}

func (cf *ClassFile) readConstant(stream *commons.Stream) error {
bs, err := stream.ReadN(1)
if err != nil {
return fmt.Errorf("read constant type failed, no enough data in the stream")
}

switch bs[0] {
case CONSTANT_UTF8_INFO:

}

return nil
}
25 changes: 25 additions & 0 deletions class/constant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package class

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
)

type Constant interface {
Type() string
}
5 changes: 5 additions & 0 deletions class/field.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package class

type Field struct {

}
5 changes: 5 additions & 0 deletions class/method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package class

type Method struct {

}
14 changes: 14 additions & 0 deletions class/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package class

import "github.com/phith0n/zkar/commons"

func ParseClass(data []byte) (*ClassFile, error) {
stream := commons.NewStream(data)
classFile := new(ClassFile)
err := classFile.readHeader(stream)
if err != nil {
return nil, err
}

return classFile, nil
}
18 changes: 18 additions & 0 deletions class/parser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package class

import (
"github.com/phith0n/litter"
"github.com/stretchr/testify/require"
"io/ioutil"
"testing"
)

func TestParseClass(t *testing.T) {
data, err := ioutil.ReadFile("../testcases/classfile/TrainPrint.class")
require.Nil(t, err)

classFile, err := ParseClass(data)
require.Nil(t, err)

litter.Dump(classFile)
}
Binary file added testcases/classfile/TrainPrint.class
Binary file not shown.

0 comments on commit d984b85

Please sign in to comment.