Module refinery.lib.java

Parsing of the Java Class file format as per the official specification.

Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Parsing of the Java Class file format as per
 [the official specification](https://docs.oracle.com/javase/specs/jvms/se14/html/jvms-4.html).
"""
from typing import Union, Any, Dict, List, ByteString, Type, Optional, TypeVar, Generic
from enum import IntEnum

from refinery.lib.structures import (
    AttrType,
    PerInstanceAttribute,
    StreamDetour,
    Struct,
    StructReader,
)

__all__ = (
    'opc',
    'JvAccessFlags',
    'JvAttribute',
    'JvBaseType',
    'JvClassFile',
    'JvClassMember',
    'JvClassProperty',
    'JvCode',
    'JvConstType',
    'JvDynamic',
    'JvException',
    'JvMethodHandle',
    'JvMethodHandleRefKind',
    'JvNameAndType',
    'JvOpCode',
    'JvString',
)


class Index(PerInstanceAttribute):
    def __init__(self, jtype: Type[AttrType]):
        super().__init__()
        self.jtype = jtype

    def resolve(self, parent: Any, value: int) -> AttrType:
        if not value:
            return None
        try:
            cpool = parent.pool
        except AttributeError as AE:
            raise AttributeError from AE
        try:
            result = cpool[value - 1]
        except IndexError as IE:
            raise AttributeError from IE
        if not isinstance(result, self.jtype):
            raise TypeError
        return result


class JvConstType(IntEnum):
    Utf8             = 0x01 # noqa
    Int              = 0x03 # noqa
    Float            = 0x04 # noqa
    Long             = 0x05 # noqa
    Double           = 0x06 # noqa
    Class            = 0x07 # noqa
    String           = 0x08 # noqa
    Field            = 0x09 # noqa
    Method           = 0x0A # noqa
    InterfaceMethod  = 0x0B # noqa
    NameAndType      = 0x0C # noqa
    MethodHandle     = 0x0F # noqa
    MethodType       = 0x10 # noqa
    Dynamic          = 0x11 # noqa
    InvokeDynamic    = 0x12 # noqa
    Module           = 0x13 # noqa
    Package          = 0x14 # noqa


class JvMethodHandleRefKind(IntEnum):
    GetField          = 1 # noqa
    GetStatic         = 2 # noqa
    PutField          = 3 # noqa
    PutStatic         = 4 # noqa
    InvokeVirtual     = 5 # noqa
    InvokeStatic      = 6 # noqa
    InvokeSpecial     = 7 # noqa
    InvokeSpecialNew  = 8 # noqa
    InvokeInterface   = 9 # noqa


class _HasPoolAndTag(Struct):
    def __init__(self, _: StructReader, pool: list, tag: JvConstType):
        self.pool = pool
        self.tag = tag


class JvStructWithName(_HasPoolAndTag):
    name: str = Index(str)
    def __repr__(self): return self.name


class JvNameAndType(JvStructWithName):
    descriptor: str = Index(str)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.name = reader.u16()
        self.descriptor = reader.u16()


class JvString(_HasPoolAndTag):
    value: str = Index(str)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.value = reader.u16()

    def __repr__(self): return repr(self.value)

    def __str__(self): return self.value


class JvClassProperty(_HasPoolAndTag):
    name: JvString = Index(JvString)
    info: JvNameAndType = Index(JvNameAndType)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.name = reader.u16()
        self.info = reader.u16()

    def __repr__(self): return F'{self.name}::{self.info}'


class JvMethodHandle(_HasPoolAndTag):
    reference: JvClassProperty = Index(JvClassProperty)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.kind = JvMethodHandleRefKind(reader.read_byte())
        self.reference = reader.u16()


class JvDynamic(_HasPoolAndTag):
    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.bootstrap_method_attr_index = reader.u16()
        self.info = reader.u16()


class JvAccessFlags(Struct):
    def __init__(self, reader: StructReader):
        (
            self.MODULE,      # 0x8000
            self.ENUM,        # 0x4000
            self.ANNOTATION,  # 0x2000
            self.SYNTHETIC,   # 0x1000
            _,                # ...
            self.ABSTRACT,    # 0x0400
            self.INTERFACE,   # 0x0200
            _, _, _,          # ...
            self.SUPER,       # 0x0020
            self.FINAL,       # 0x0010
            _, _, _,          # ...
            self.PUBLIC,      # 0x0001
        ) = reader.read_flags(16)


ParserType = TypeVar('ParserType')


class JvAttribute(JvStructWithName, Generic[ParserType]):
    def __init__(self, reader: StructReader, pool: list):
        self.pool = pool
        self.name = reader.u16()
        self.data = reader.read(reader.u32())

    def parse(self, parser: Type[ParserType]) -> ParserType:
        return parser(self.data, pool=self.pool)


class JvClassMember(JvStructWithName):
    descriptor: str = Index(str)

    def __init__(self, reader: StructReader, pool: list):
        self.pool = pool
        self.access = JvAccessFlags(reader)
        self.name = reader.u16()
        self.descriptor = reader.u16()
        self.attributes = [JvAttribute(reader, pool=pool) for _ in range(reader.u16())]


class opc(IntEnum):
    nop             = 0x00  # noqa
    aconst_null     = 0x01  # noqa
    iconst_m1       = 0x02  # noqa
    iconst_0        = 0x03  # noqa
    iconst_1        = 0x04  # noqa
    iconst_2        = 0x05  # noqa
    iconst_3        = 0x06  # noqa
    iconst_4        = 0x07  # noqa
    iconst_5        = 0x08  # noqa
    lconst_0        = 0x09  # noqa
    lconst_1        = 0x0a  # noqa
    fconst_0        = 0x0b  # noqa
    fconst_1        = 0x0c  # noqa
    fconst_2        = 0x0d  # noqa
    dconst_0        = 0x0e  # noqa
    dconst_1        = 0x0f  # noqa
    bipush          = 0x10  # noqa
    sipush          = 0x11  # noqa
    ldc             = 0x12  # noqa
    ldc_w           = 0x13  # noqa
    ldc2_w          = 0x14  # noqa
    iload           = 0x15  # noqa
    lload           = 0x16  # noqa
    fload           = 0x17  # noqa
    dload           = 0x18  # noqa
    aload           = 0x19  # noqa
    iload_0         = 0x1a  # noqa
    iload_1         = 0x1b  # noqa
    iload_2         = 0x1c  # noqa
    iload_3         = 0x1d  # noqa
    lload_0         = 0x1e  # noqa
    lload_1         = 0x1f  # noqa
    lload_2         = 0x20  # noqa
    lload_3         = 0x21  # noqa
    fload_0         = 0x22  # noqa
    fload_1         = 0x23  # noqa
    fload_2         = 0x24  # noqa
    fload_3         = 0x25  # noqa
    dload_0         = 0x26  # noqa
    dload_1         = 0x27  # noqa
    dload_2         = 0x28  # noqa
    dload_3         = 0x29  # noqa
    aload_0         = 0x2a  # noqa
    aload_1         = 0x2b  # noqa
    aload_2         = 0x2c  # noqa
    aload_3         = 0x2d  # noqa
    iaload          = 0x2e  # noqa
    laload          = 0x2f  # noqa
    faload          = 0x30  # noqa
    daload          = 0x31  # noqa
    aaload          = 0x32  # noqa
    baload          = 0x33  # noqa
    caload          = 0x34  # noqa
    saload          = 0x35  # noqa
    istore          = 0x36  # noqa
    lstore          = 0x37  # noqa
    fstore          = 0x38  # noqa
    dstore          = 0x39  # noqa
    astore          = 0x3a  # noqa
    istore_0        = 0x3b  # noqa
    istore_1        = 0x3c  # noqa
    istore_2        = 0x3d  # noqa
    istore_3        = 0x3e  # noqa
    lstore_0        = 0x3f  # noqa
    lstore_1        = 0x40  # noqa
    lstore_2        = 0x41  # noqa
    lstore_3        = 0x42  # noqa
    fstore_0        = 0x43  # noqa
    fstore_1        = 0x44  # noqa
    fstore_2        = 0x45  # noqa
    fstore_3        = 0x46  # noqa
    dstore_0        = 0x47  # noqa
    dstore_1        = 0x48  # noqa
    dstore_2        = 0x49  # noqa
    dstore_3        = 0x4a  # noqa
    astore_0        = 0x4b  # noqa
    astore_1        = 0x4c  # noqa
    astore_2        = 0x4d  # noqa
    astore_3        = 0x4e  # noqa
    iastore         = 0x4f  # noqa
    lastore         = 0x50  # noqa
    fastore         = 0x51  # noqa
    dastore         = 0x52  # noqa
    aastore         = 0x53  # noqa
    bastore         = 0x54  # noqa
    castore         = 0x55  # noqa
    sastore         = 0x56  # noqa
    pop             = 0x57  # noqa
    pop2            = 0x58  # noqa
    dup             = 0x59  # noqa
    dup_x1          = 0x5a  # noqa
    dup_x2          = 0x5b  # noqa
    dup2            = 0x5c  # noqa
    dup2_x1         = 0x5d  # noqa
    dup2_x2         = 0x5e  # noqa
    swap            = 0x5f  # noqa
    iadd            = 0x60  # noqa
    ladd            = 0x61  # noqa
    fadd            = 0x62  # noqa
    dadd            = 0x63  # noqa
    isub            = 0x64  # noqa
    lsub            = 0x65  # noqa
    fsub            = 0x66  # noqa
    dsub            = 0x67  # noqa
    imul            = 0x68  # noqa
    lmul            = 0x69  # noqa
    fmul            = 0x6a  # noqa
    dmul            = 0x6b  # noqa
    idiv            = 0x6c  # noqa
    ldiv            = 0x6d  # noqa
    fdiv            = 0x6e  # noqa
    ddiv            = 0x6f  # noqa
    irem            = 0x70  # noqa
    lrem            = 0x71  # noqa
    frem            = 0x72  # noqa
    drem            = 0x73  # noqa
    ineg            = 0x74  # noqa
    lneg            = 0x75  # noqa
    fneg            = 0x76  # noqa
    dneg            = 0x77  # noqa
    ishl            = 0x78  # noqa
    lshl            = 0x79  # noqa
    ishr            = 0x7a  # noqa
    lshr            = 0x7b  # noqa
    iushr           = 0x7c  # noqa
    lushr           = 0x7d  # noqa
    iand            = 0x7e  # noqa
    land            = 0x7f  # noqa
    ior             = 0x80  # noqa
    lor             = 0x81  # noqa
    ixor            = 0x82  # noqa
    lxor            = 0x83  # noqa
    iinc            = 0x84  # noqa
    i2l             = 0x85  # noqa
    i2f             = 0x86  # noqa
    i2d             = 0x87  # noqa
    l2i             = 0x88  # noqa
    l2f             = 0x89  # noqa
    l2d             = 0x8a  # noqa
    f2i             = 0x8b  # noqa
    f2l             = 0x8c  # noqa
    f2d             = 0x8d  # noqa
    d2i             = 0x8e  # noqa
    d2l             = 0x8f  # noqa
    d2f             = 0x90  # noqa
    i2b             = 0x91  # noqa
    i2c             = 0x92  # noqa
    i2s             = 0x93  # noqa
    lcmp            = 0x94  # noqa
    fcmpl           = 0x95  # noqa
    fcmpg           = 0x96  # noqa
    dcmpl           = 0x97  # noqa
    dcmpg           = 0x98  # noqa
    ifeq            = 0x99  # noqa
    ifne            = 0x9a  # noqa
    iflt            = 0x9b  # noqa
    ifge            = 0x9c  # noqa
    ifgt            = 0x9d  # noqa
    ifle            = 0x9e  # noqa
    if_icmpeq       = 0x9f  # noqa
    if_icmpne       = 0xa0  # noqa
    if_icmplt       = 0xa1  # noqa
    if_icmpge       = 0xa2  # noqa
    if_icmpgt       = 0xa3  # noqa
    if_icmple       = 0xa4  # noqa
    if_acmpeq       = 0xa5  # noqa
    if_acmpne       = 0xa6  # noqa
    goto            = 0xa7  # noqa
    jsr             = 0xa8  # noqa
    ret             = 0xa9  # noqa
    tableswitch     = 0xaa  # noqa
    lookupswitch    = 0xab  # noqa
    ireturn         = 0xac  # noqa
    lreturn         = 0xad  # noqa
    freturn         = 0xae  # noqa
    dreturn         = 0xaf  # noqa
    areturn         = 0xb0  # noqa
    vreturn         = 0xb1  # noqa
    getstatic       = 0xb2  # noqa
    putstatic       = 0xb3  # noqa
    getfield        = 0xb4  # noqa
    putfield        = 0xb5  # noqa
    invokevirtual   = 0xb6  # noqa
    invokespecial   = 0xb7  # noqa
    invokestatic    = 0xb8  # noqa
    invokeinterface = 0xb9  # noqa
    invokedynamic   = 0xba  # noqa
    new             = 0xbb  # noqa
    newarray        = 0xbc  # noqa
    anewarray       = 0xbd  # noqa
    arraylength     = 0xbe  # noqa
    athrow          = 0xbf  # noqa
    checkcast       = 0xc0  # noqa
    instanceof      = 0xc1  # noqa
    monitorenter    = 0xc2  # noqa
    monitorexit     = 0xc3  # noqa
    wide            = 0xc4  # noqa
    multianewarray  = 0xc5  # noqa
    ifnull          = 0xc6  # noqa
    ifnonnull       = 0xc7  # noqa
    goto_w          = 0xc8  # noqa
    jsr_w           = 0xc9  # noqa
    dbgbreak        = 0xca  # noqa
    impdep1         = 0xfe  # noqa
    impdep2         = 0xff  # noqa

    def __repr__(self) -> str: return self.name


class JvBaseType(IntEnum):
    BOOLEAN = 0x4  # noqa
    CHAR    = 0x5  # noqa
    FLOAT   = 0x6  # noqa
    DOUBLE  = 0x7  # noqa
    BYTE    = 0x8  # noqa
    SHORT   = 0x9  # noqa
    INT     = 0xA  # noqa
    LONG    = 0xB  # noqa

    def __repr__(self) -> str: return self.name


class JvOpCode(Struct):

    OPC_ARGMAP = {
        opc.bipush          : 'b',
        opc.sipush          : 'h',
        opc.ldc             : 'B',
        opc.ldc_w           : 'H',
        opc.ldc2_w          : 'H',
        opc.iload           : 'B',
        opc.lload           : 'B',
        opc.fload           : 'B',
        opc.dload           : 'B',
        opc.aload           : 'B',
        opc.istore          : 'B',
        opc.lstore          : 'B',
        opc.fstore          : 'B',
        opc.dstore          : 'B',
        opc.astore          : 'B',
        opc.iinc            : 'Bb',
        opc.ifeq            : 'H',
        opc.ifne            : 'H',
        opc.iflt            : 'H',
        opc.ifge            : 'H',
        opc.ifgt            : 'H',
        opc.ifle            : 'H',
        opc.if_icmpeq       : 'H',
        opc.if_icmpne       : 'H',
        opc.if_icmplt       : 'H',
        opc.if_icmpge       : 'H',
        opc.if_icmpgt       : 'H',
        opc.if_icmple       : 'H',
        opc.if_acmpeq       : 'H',
        opc.if_acmpne       : 'H',
        opc.goto            : 'H',
        opc.jsr             : 'H',
        opc.ret             : 'B',
        opc.getstatic       : 'H',
        opc.putstatic       : 'H',
        opc.getfield        : 'H',
        opc.putfield        : 'H',
        opc.invokevirtual   : 'H',
        opc.invokespecial   : 'H',
        opc.invokestatic    : 'H',
        opc.invokeinterface : 'HBx',
        opc.invokedynamic   : 'Hxx',
        opc.new             : 'H',
        opc.anewarray       : 'H',
        opc.checkcast       : 'H',
        opc.instanceof      : 'H',
        opc.multianewarray  : 'HB',
        opc.ifnull          : 'H',
        opc.ifnonnull       : 'H',
        opc.goto_w          : 'L',
        opc.jsr_w           : 'L',
    }

    OPC_CONSTPOOL = {
        opc.ldc,
        opc.ldc_w,
        opc.ldc2_w,
        opc.getstatic,
        opc.putstatic,
        opc.getfield,
        opc.putfield,
        opc.invokevirtual,
        opc.invokespecial,
        opc.invokestatic,
        opc.new,
        opc.anewarray,
        opc.checkcast,
        opc.instanceof,
        opc.multianewarray,
    }

    def __getitem__(self, k):
        return self.arguments[k]

    def __init__(self, reader: StructReader, pool: list):
        with StreamDetour(reader):
            self.code = opc(reader.read_byte())
            self.table: Optional[Dict[int, int]] = None
            try:
                fmt = self.OPC_ARGMAP[self.code]
            except KeyError:
                self.arguments = []
            else:
                self.arguments = list(reader.read_struct(fmt))
            if self.code == opc.newarray:
                self.arguments = [JvBaseType(reader.read_byte())]
            elif self.code in self.OPC_CONSTPOOL:
                try:
                    self.arguments[0] = pool[self.arguments[0] - 1]
                except (AttributeError, IndexError):
                    pass
            elif self.code == opc.lookupswitch:
                reader.byte_align(blocksize=4)
                default, npairs = reader.read_struct('LL')
                pairs = reader.read_struct(F'{npairs * 2}L')
                self.table = dict(zip(*([iter(pairs)] * 2)))
                self.table[None] = default
            elif self.code == opc.tableswitch:
                reader.byte_align(blocksize=4)
                default, low, high = reader.read_struct('LLL')
                assert low <= high
                offsets = reader.read_struct(F'{high - low + 1}L')
                self.table = {k + low: offset for k, offset in enumerate(offsets)}
                self.table[None] = default
            elif self.code == opc.wide:
                argop = opc(reader.u8())
                self.arguments = (argop, reader.u16())
                if argop == opc.iinc:
                    self.arguments += reader.i16(),
                else:
                    assert argop in (
                        opc.iload, opc.istore,
                        opc.fload, opc.fstore,
                        opc.aload, opc.astore,
                        opc.lload, opc.lstore,
                        opc.dload, opc.dstore,
                        opc.ret)
            offset = reader.tell()
        self.raw = bytes(reader.read(offset - reader.tell()))

    def __bytes__(self):
        return self.raw


class JvException(Struct):
    def __init__(self, reader: StructReader):
        self.start = reader.u16()
        self.end = reader.u16()
        self.handler = reader.u16()
        self.catch = reader.u16()


class JvCode(Struct):
    def __init__(self, reader: StructReader, pool: list):
        reader.bigendian = True
        self.max_stack = reader.u16()
        self.max_locals = reader.u16()
        self.disassembly: List[JvOpCode] = []
        with StructReader(reader.read(reader.u32())) as code:
            code.bigendian = True
            while not code.eof:
                self.disassembly.append(JvOpCode(code, pool=pool))
        self.exceptions = [JvException(reader      ) for _ in range(reader.u16())] # noqa
        self.attributes = [JvAttribute(reader, pool) for _ in range(reader.u16())] # noqa


class JvClassFile(Struct):

    TYPEHANDLER: Dict[JvConstType, Struct] = {
        JvConstType.Class            : JvString,
        JvConstType.String           : JvString,
        JvConstType.Field            : JvClassProperty,
        JvConstType.Method           : JvClassProperty,
        JvConstType.InterfaceMethod  : JvClassProperty,
        JvConstType.NameAndType      : JvNameAndType,
        JvConstType.MethodHandle     : JvMethodHandle,
        JvConstType.MethodType       : JvString,
        JvConstType.Dynamic          : JvDynamic,
        JvConstType.InvokeDynamic    : JvDynamic,
        JvConstType.Module           : JvString,
        JvConstType.Package          : JvString,
    }

    this: JvString = Index(JvString)
    parent: JvString = Index(JvString)

    def __init__(self, reader: StructReader):
        reader.bigendian = True
        if reader.read(4).hex() != 'cafebabe':
            raise ValueError('class file magic missing.')
        minor = reader.u16()
        major = reader.u16()
        self.version = (major, minor)

        self.pool: List[Union[Struct, int, float, str]] = []
        self._read_pool(reader)

        self.strings: List[str] = {
            s.value for s in self.pool if isinstance(s, Struct) and s.tag == JvConstType.String}

        self.access = JvAccessFlags(reader)

        self.this = reader.u16()
        self.parent = reader.u16()

        try:
            self.interfaces = [self.pool[reader.u16()]
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Interfaces.')
        try:
            self.fields = [JvClassMember(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Fields.')
        try:
            self.methods = [JvClassMember(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Methods.')
        try:
            self.attributes = [JvAttribute(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Attributes.')

    @staticmethod
    def decode_utf8m(string: ByteString) -> str:
        """
        Based on the following code:
        https://gist.github.com/BarelyAliveMau5/000e7e453b6d4ebd0cb06f39bc2e7aec
        Given in answer to the following SO question:
        https://stackoverflow.com/a/48037020
        """
        new_string = bytearray()
        length = len(string)
        i = 0
        while i < length:
            byte1 = string[i]
            if (byte1 & 0x80) == 0:
                new_string.append(byte1)
            elif (byte1 & 0xE0) == 0xC0:
                i += 1
                byte2 = string[i]
                if byte1 != 0xC0 or byte2 != 0x80:
                    new_string.append(byte1)
                    new_string.append(byte2)
                else:
                    new_string.append(0)
            elif (byte1 & 0xF0) == 0xE0:
                i += 1
                byte2 = string[i]
                i += 1
                byte3 = string[i]
                if i + 3 < length and byte1 == 0xED and (byte2 & 0xF0) == 0xA0:
                    byte4 = string[i + 1]
                    byte5 = string[i + 2]
                    byte6 = string[i + 3]
                    if byte4 == 0xED and (byte5 & 0xF0) == 0xB0:
                        i += 3
                        u21 = ((byte2 & 0x0F) + 1) << 16
                        u21 += (byte3 & 0x3F) << 10
                        u21 += (byte5 & 0x0F) << 6
                        u21 += (byte6 & 0x3F)
                        new_string.append(0xF0 + ((u21 >> 18) & 0x07))
                        new_string.append(0x80 + ((u21 >> 12) & 0x3F))
                        new_string.append(0x80 + ((u21 >> 6) & 0x3F))
                        new_string.append(0x80 + (u21 & 0x3F))
                        continue
                new_string.append(byte1)
                new_string.append(byte2)
                new_string.append(byte3)
            i += 1
        return new_string.decode('utf8')

    def _read_pool(self, reader):
        assert not self.pool, 'pool can only be read once.'
        size = reader.u16() - 1
        reserved_slot = False
        for _ in range(size):
            if reserved_slot:
                self.pool.append(NotImplemented)
                reserved_slot = False
                continue
            tid = reader.read_byte()
            try:
                tag = JvConstType(tid)
            except KeyError:
                raise ValueError(F'Encountered invalid type specifier {tid:02X}.')
            if tag == JvConstType.Utf8:
                size = reader.u16()
                data = reader.read(size)
                data = self.decode_utf8m(data)
                self.pool.append(data)
                continue
            try:
                tf, reserved_slot = {
                    JvConstType.Long   : ('Q', True),
                    JvConstType.Double : ('d', True),
                    JvConstType.Int    : ('I', False),
                    JvConstType.Float  : ('f', False),
                }[tag]
            except KeyError:
                JvType = self.TYPEHANDLER[tag]
                self.pool.append(JvType(reader, pool=self.pool, tag=tag))
            else:
                self.pool.append(reader.read_struct(tf))
                continue

Classes

class opc (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

Expand source code Browse git
class opc(IntEnum):
    nop             = 0x00  # noqa
    aconst_null     = 0x01  # noqa
    iconst_m1       = 0x02  # noqa
    iconst_0        = 0x03  # noqa
    iconst_1        = 0x04  # noqa
    iconst_2        = 0x05  # noqa
    iconst_3        = 0x06  # noqa
    iconst_4        = 0x07  # noqa
    iconst_5        = 0x08  # noqa
    lconst_0        = 0x09  # noqa
    lconst_1        = 0x0a  # noqa
    fconst_0        = 0x0b  # noqa
    fconst_1        = 0x0c  # noqa
    fconst_2        = 0x0d  # noqa
    dconst_0        = 0x0e  # noqa
    dconst_1        = 0x0f  # noqa
    bipush          = 0x10  # noqa
    sipush          = 0x11  # noqa
    ldc             = 0x12  # noqa
    ldc_w           = 0x13  # noqa
    ldc2_w          = 0x14  # noqa
    iload           = 0x15  # noqa
    lload           = 0x16  # noqa
    fload           = 0x17  # noqa
    dload           = 0x18  # noqa
    aload           = 0x19  # noqa
    iload_0         = 0x1a  # noqa
    iload_1         = 0x1b  # noqa
    iload_2         = 0x1c  # noqa
    iload_3         = 0x1d  # noqa
    lload_0         = 0x1e  # noqa
    lload_1         = 0x1f  # noqa
    lload_2         = 0x20  # noqa
    lload_3         = 0x21  # noqa
    fload_0         = 0x22  # noqa
    fload_1         = 0x23  # noqa
    fload_2         = 0x24  # noqa
    fload_3         = 0x25  # noqa
    dload_0         = 0x26  # noqa
    dload_1         = 0x27  # noqa
    dload_2         = 0x28  # noqa
    dload_3         = 0x29  # noqa
    aload_0         = 0x2a  # noqa
    aload_1         = 0x2b  # noqa
    aload_2         = 0x2c  # noqa
    aload_3         = 0x2d  # noqa
    iaload          = 0x2e  # noqa
    laload          = 0x2f  # noqa
    faload          = 0x30  # noqa
    daload          = 0x31  # noqa
    aaload          = 0x32  # noqa
    baload          = 0x33  # noqa
    caload          = 0x34  # noqa
    saload          = 0x35  # noqa
    istore          = 0x36  # noqa
    lstore          = 0x37  # noqa
    fstore          = 0x38  # noqa
    dstore          = 0x39  # noqa
    astore          = 0x3a  # noqa
    istore_0        = 0x3b  # noqa
    istore_1        = 0x3c  # noqa
    istore_2        = 0x3d  # noqa
    istore_3        = 0x3e  # noqa
    lstore_0        = 0x3f  # noqa
    lstore_1        = 0x40  # noqa
    lstore_2        = 0x41  # noqa
    lstore_3        = 0x42  # noqa
    fstore_0        = 0x43  # noqa
    fstore_1        = 0x44  # noqa
    fstore_2        = 0x45  # noqa
    fstore_3        = 0x46  # noqa
    dstore_0        = 0x47  # noqa
    dstore_1        = 0x48  # noqa
    dstore_2        = 0x49  # noqa
    dstore_3        = 0x4a  # noqa
    astore_0        = 0x4b  # noqa
    astore_1        = 0x4c  # noqa
    astore_2        = 0x4d  # noqa
    astore_3        = 0x4e  # noqa
    iastore         = 0x4f  # noqa
    lastore         = 0x50  # noqa
    fastore         = 0x51  # noqa
    dastore         = 0x52  # noqa
    aastore         = 0x53  # noqa
    bastore         = 0x54  # noqa
    castore         = 0x55  # noqa
    sastore         = 0x56  # noqa
    pop             = 0x57  # noqa
    pop2            = 0x58  # noqa
    dup             = 0x59  # noqa
    dup_x1          = 0x5a  # noqa
    dup_x2          = 0x5b  # noqa
    dup2            = 0x5c  # noqa
    dup2_x1         = 0x5d  # noqa
    dup2_x2         = 0x5e  # noqa
    swap            = 0x5f  # noqa
    iadd            = 0x60  # noqa
    ladd            = 0x61  # noqa
    fadd            = 0x62  # noqa
    dadd            = 0x63  # noqa
    isub            = 0x64  # noqa
    lsub            = 0x65  # noqa
    fsub            = 0x66  # noqa
    dsub            = 0x67  # noqa
    imul            = 0x68  # noqa
    lmul            = 0x69  # noqa
    fmul            = 0x6a  # noqa
    dmul            = 0x6b  # noqa
    idiv            = 0x6c  # noqa
    ldiv            = 0x6d  # noqa
    fdiv            = 0x6e  # noqa
    ddiv            = 0x6f  # noqa
    irem            = 0x70  # noqa
    lrem            = 0x71  # noqa
    frem            = 0x72  # noqa
    drem            = 0x73  # noqa
    ineg            = 0x74  # noqa
    lneg            = 0x75  # noqa
    fneg            = 0x76  # noqa
    dneg            = 0x77  # noqa
    ishl            = 0x78  # noqa
    lshl            = 0x79  # noqa
    ishr            = 0x7a  # noqa
    lshr            = 0x7b  # noqa
    iushr           = 0x7c  # noqa
    lushr           = 0x7d  # noqa
    iand            = 0x7e  # noqa
    land            = 0x7f  # noqa
    ior             = 0x80  # noqa
    lor             = 0x81  # noqa
    ixor            = 0x82  # noqa
    lxor            = 0x83  # noqa
    iinc            = 0x84  # noqa
    i2l             = 0x85  # noqa
    i2f             = 0x86  # noqa
    i2d             = 0x87  # noqa
    l2i             = 0x88  # noqa
    l2f             = 0x89  # noqa
    l2d             = 0x8a  # noqa
    f2i             = 0x8b  # noqa
    f2l             = 0x8c  # noqa
    f2d             = 0x8d  # noqa
    d2i             = 0x8e  # noqa
    d2l             = 0x8f  # noqa
    d2f             = 0x90  # noqa
    i2b             = 0x91  # noqa
    i2c             = 0x92  # noqa
    i2s             = 0x93  # noqa
    lcmp            = 0x94  # noqa
    fcmpl           = 0x95  # noqa
    fcmpg           = 0x96  # noqa
    dcmpl           = 0x97  # noqa
    dcmpg           = 0x98  # noqa
    ifeq            = 0x99  # noqa
    ifne            = 0x9a  # noqa
    iflt            = 0x9b  # noqa
    ifge            = 0x9c  # noqa
    ifgt            = 0x9d  # noqa
    ifle            = 0x9e  # noqa
    if_icmpeq       = 0x9f  # noqa
    if_icmpne       = 0xa0  # noqa
    if_icmplt       = 0xa1  # noqa
    if_icmpge       = 0xa2  # noqa
    if_icmpgt       = 0xa3  # noqa
    if_icmple       = 0xa4  # noqa
    if_acmpeq       = 0xa5  # noqa
    if_acmpne       = 0xa6  # noqa
    goto            = 0xa7  # noqa
    jsr             = 0xa8  # noqa
    ret             = 0xa9  # noqa
    tableswitch     = 0xaa  # noqa
    lookupswitch    = 0xab  # noqa
    ireturn         = 0xac  # noqa
    lreturn         = 0xad  # noqa
    freturn         = 0xae  # noqa
    dreturn         = 0xaf  # noqa
    areturn         = 0xb0  # noqa
    vreturn         = 0xb1  # noqa
    getstatic       = 0xb2  # noqa
    putstatic       = 0xb3  # noqa
    getfield        = 0xb4  # noqa
    putfield        = 0xb5  # noqa
    invokevirtual   = 0xb6  # noqa
    invokespecial   = 0xb7  # noqa
    invokestatic    = 0xb8  # noqa
    invokeinterface = 0xb9  # noqa
    invokedynamic   = 0xba  # noqa
    new             = 0xbb  # noqa
    newarray        = 0xbc  # noqa
    anewarray       = 0xbd  # noqa
    arraylength     = 0xbe  # noqa
    athrow          = 0xbf  # noqa
    checkcast       = 0xc0  # noqa
    instanceof      = 0xc1  # noqa
    monitorenter    = 0xc2  # noqa
    monitorexit     = 0xc3  # noqa
    wide            = 0xc4  # noqa
    multianewarray  = 0xc5  # noqa
    ifnull          = 0xc6  # noqa
    ifnonnull       = 0xc7  # noqa
    goto_w          = 0xc8  # noqa
    jsr_w           = 0xc9  # noqa
    dbgbreak        = 0xca  # noqa
    impdep1         = 0xfe  # noqa
    impdep2         = 0xff  # noqa

    def __repr__(self) -> str: return self.name

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var nop
var aconst_null
var iconst_m1
var iconst_0
var iconst_1
var iconst_2
var iconst_3
var iconst_4
var iconst_5
var lconst_0
var lconst_1
var fconst_0
var fconst_1
var fconst_2
var dconst_0
var dconst_1
var bipush
var sipush
var ldc
var ldc_w
var ldc2_w
var iload
var lload
var fload
var dload
var aload
var iload_0
var iload_1
var iload_2
var iload_3
var lload_0
var lload_1
var lload_2
var lload_3
var fload_0
var fload_1
var fload_2
var fload_3
var dload_0
var dload_1
var dload_2
var dload_3
var aload_0
var aload_1
var aload_2
var aload_3
var iaload
var laload
var faload
var daload
var aaload
var baload
var caload
var saload
var istore
var lstore
var fstore
var dstore
var astore
var istore_0
var istore_1
var istore_2
var istore_3
var lstore_0
var lstore_1
var lstore_2
var lstore_3
var fstore_0
var fstore_1
var fstore_2
var fstore_3
var dstore_0
var dstore_1
var dstore_2
var dstore_3
var astore_0
var astore_1
var astore_2
var astore_3
var iastore
var lastore
var fastore
var dastore
var aastore
var bastore
var castore
var sastore
var pop
var pop2
var dup
var dup_x1
var dup_x2
var dup2
var dup2_x1
var dup2_x2
var swap
var iadd
var ladd
var fadd
var dadd
var isub
var lsub
var fsub
var dsub
var imul
var lmul
var fmul
var dmul
var idiv
var ldiv
var fdiv
var ddiv
var irem
var lrem
var frem
var drem
var ineg
var lneg
var fneg
var dneg
var ishl
var lshl
var ishr
var lshr
var iushr
var lushr
var iand
var land
var ior
var lor
var ixor
var lxor
var iinc
var i2l
var i2f
var i2d
var l2i
var l2f
var l2d
var f2i
var f2l
var f2d
var d2i
var d2l
var d2f
var i2b
var i2c
var i2s
var lcmp
var fcmpl
var fcmpg
var dcmpl
var dcmpg
var ifeq
var ifne
var iflt
var ifge
var ifgt
var ifle
var if_icmpeq
var if_icmpne
var if_icmplt
var if_icmpge
var if_icmpgt
var if_icmple
var if_acmpeq
var if_acmpne
var goto
var jsr
var ret
var tableswitch
var lookupswitch
var ireturn
var lreturn
var freturn
var dreturn
var areturn
var vreturn
var getstatic
var putstatic
var getfield
var putfield
var invokevirtual
var invokespecial
var invokestatic
var invokeinterface
var invokedynamic
var new
var newarray
var anewarray
var arraylength
var athrow
var checkcast
var instanceof
var monitorenter
var monitorexit
var wide
var multianewarray
var ifnull
var ifnonnull
var goto_w
var jsr_w
var dbgbreak
var impdep1
var impdep2
class JvAccessFlags (reader)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvAccessFlags(Struct):
    def __init__(self, reader: StructReader):
        (
            self.MODULE,      # 0x8000
            self.ENUM,        # 0x4000
            self.ANNOTATION,  # 0x2000
            self.SYNTHETIC,   # 0x1000
            _,                # ...
            self.ABSTRACT,    # 0x0400
            self.INTERFACE,   # 0x0200
            _, _, _,          # ...
            self.SUPER,       # 0x0020
            self.FINAL,       # 0x0010
            _, _, _,          # ...
            self.PUBLIC,      # 0x0001
        ) = reader.read_flags(16)

Ancestors

class JvAttribute (reader, pool)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvAttribute(JvStructWithName, Generic[ParserType]):
    def __init__(self, reader: StructReader, pool: list):
        self.pool = pool
        self.name = reader.u16()
        self.data = reader.read(reader.u32())

    def parse(self, parser: Type[ParserType]) -> ParserType:
        return parser(self.data, pool=self.pool)

Ancestors

  • refinery.lib.java.JvStructWithName
  • refinery.lib.java._HasPoolAndTag
  • Struct
  • typing.Generic

Instance variables

var name
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]

Methods

def parse(self, parser)
Expand source code Browse git
def parse(self, parser: Type[ParserType]) -> ParserType:
    return parser(self.data, pool=self.pool)
class JvBaseType (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

Expand source code Browse git
class JvBaseType(IntEnum):
    BOOLEAN = 0x4  # noqa
    CHAR    = 0x5  # noqa
    FLOAT   = 0x6  # noqa
    DOUBLE  = 0x7  # noqa
    BYTE    = 0x8  # noqa
    SHORT   = 0x9  # noqa
    INT     = 0xA  # noqa
    LONG    = 0xB  # noqa

    def __repr__(self) -> str: return self.name

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var BOOLEAN
var CHAR
var FLOAT
var DOUBLE
var BYTE
var SHORT
var INT
var LONG
class JvClassFile (reader)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvClassFile(Struct):

    TYPEHANDLER: Dict[JvConstType, Struct] = {
        JvConstType.Class            : JvString,
        JvConstType.String           : JvString,
        JvConstType.Field            : JvClassProperty,
        JvConstType.Method           : JvClassProperty,
        JvConstType.InterfaceMethod  : JvClassProperty,
        JvConstType.NameAndType      : JvNameAndType,
        JvConstType.MethodHandle     : JvMethodHandle,
        JvConstType.MethodType       : JvString,
        JvConstType.Dynamic          : JvDynamic,
        JvConstType.InvokeDynamic    : JvDynamic,
        JvConstType.Module           : JvString,
        JvConstType.Package          : JvString,
    }

    this: JvString = Index(JvString)
    parent: JvString = Index(JvString)

    def __init__(self, reader: StructReader):
        reader.bigendian = True
        if reader.read(4).hex() != 'cafebabe':
            raise ValueError('class file magic missing.')
        minor = reader.u16()
        major = reader.u16()
        self.version = (major, minor)

        self.pool: List[Union[Struct, int, float, str]] = []
        self._read_pool(reader)

        self.strings: List[str] = {
            s.value for s in self.pool if isinstance(s, Struct) and s.tag == JvConstType.String}

        self.access = JvAccessFlags(reader)

        self.this = reader.u16()
        self.parent = reader.u16()

        try:
            self.interfaces = [self.pool[reader.u16()]
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Interfaces.')
        try:
            self.fields = [JvClassMember(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Fields.')
        try:
            self.methods = [JvClassMember(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Methods.')
        try:
            self.attributes = [JvAttribute(reader, pool=self.pool)
                for _ in range(reader.u16())]
        except IndexError:
            raise ValueError('Failed parsing Attributes.')

    @staticmethod
    def decode_utf8m(string: ByteString) -> str:
        """
        Based on the following code:
        https://gist.github.com/BarelyAliveMau5/000e7e453b6d4ebd0cb06f39bc2e7aec
        Given in answer to the following SO question:
        https://stackoverflow.com/a/48037020
        """
        new_string = bytearray()
        length = len(string)
        i = 0
        while i < length:
            byte1 = string[i]
            if (byte1 & 0x80) == 0:
                new_string.append(byte1)
            elif (byte1 & 0xE0) == 0xC0:
                i += 1
                byte2 = string[i]
                if byte1 != 0xC0 or byte2 != 0x80:
                    new_string.append(byte1)
                    new_string.append(byte2)
                else:
                    new_string.append(0)
            elif (byte1 & 0xF0) == 0xE0:
                i += 1
                byte2 = string[i]
                i += 1
                byte3 = string[i]
                if i + 3 < length and byte1 == 0xED and (byte2 & 0xF0) == 0xA0:
                    byte4 = string[i + 1]
                    byte5 = string[i + 2]
                    byte6 = string[i + 3]
                    if byte4 == 0xED and (byte5 & 0xF0) == 0xB0:
                        i += 3
                        u21 = ((byte2 & 0x0F) + 1) << 16
                        u21 += (byte3 & 0x3F) << 10
                        u21 += (byte5 & 0x0F) << 6
                        u21 += (byte6 & 0x3F)
                        new_string.append(0xF0 + ((u21 >> 18) & 0x07))
                        new_string.append(0x80 + ((u21 >> 12) & 0x3F))
                        new_string.append(0x80 + ((u21 >> 6) & 0x3F))
                        new_string.append(0x80 + (u21 & 0x3F))
                        continue
                new_string.append(byte1)
                new_string.append(byte2)
                new_string.append(byte3)
            i += 1
        return new_string.decode('utf8')

    def _read_pool(self, reader):
        assert not self.pool, 'pool can only be read once.'
        size = reader.u16() - 1
        reserved_slot = False
        for _ in range(size):
            if reserved_slot:
                self.pool.append(NotImplemented)
                reserved_slot = False
                continue
            tid = reader.read_byte()
            try:
                tag = JvConstType(tid)
            except KeyError:
                raise ValueError(F'Encountered invalid type specifier {tid:02X}.')
            if tag == JvConstType.Utf8:
                size = reader.u16()
                data = reader.read(size)
                data = self.decode_utf8m(data)
                self.pool.append(data)
                continue
            try:
                tf, reserved_slot = {
                    JvConstType.Long   : ('Q', True),
                    JvConstType.Double : ('d', True),
                    JvConstType.Int    : ('I', False),
                    JvConstType.Float  : ('f', False),
                }[tag]
            except KeyError:
                JvType = self.TYPEHANDLER[tag]
                self.pool.append(JvType(reader, pool=self.pool, tag=tag))
            else:
                self.pool.append(reader.read_struct(tf))
                continue

Ancestors

Class variables

var TYPEHANDLER

Static methods

def decode_utf8m(string)

Based on the following code: https://gist.github.com/BarelyAliveMau5/000e7e453b6d4ebd0cb06f39bc2e7aec Given in answer to the following SO question: https://stackoverflow.com/a/48037020

Expand source code Browse git
@staticmethod
def decode_utf8m(string: ByteString) -> str:
    """
    Based on the following code:
    https://gist.github.com/BarelyAliveMau5/000e7e453b6d4ebd0cb06f39bc2e7aec
    Given in answer to the following SO question:
    https://stackoverflow.com/a/48037020
    """
    new_string = bytearray()
    length = len(string)
    i = 0
    while i < length:
        byte1 = string[i]
        if (byte1 & 0x80) == 0:
            new_string.append(byte1)
        elif (byte1 & 0xE0) == 0xC0:
            i += 1
            byte2 = string[i]
            if byte1 != 0xC0 or byte2 != 0x80:
                new_string.append(byte1)
                new_string.append(byte2)
            else:
                new_string.append(0)
        elif (byte1 & 0xF0) == 0xE0:
            i += 1
            byte2 = string[i]
            i += 1
            byte3 = string[i]
            if i + 3 < length and byte1 == 0xED and (byte2 & 0xF0) == 0xA0:
                byte4 = string[i + 1]
                byte5 = string[i + 2]
                byte6 = string[i + 3]
                if byte4 == 0xED and (byte5 & 0xF0) == 0xB0:
                    i += 3
                    u21 = ((byte2 & 0x0F) + 1) << 16
                    u21 += (byte3 & 0x3F) << 10
                    u21 += (byte5 & 0x0F) << 6
                    u21 += (byte6 & 0x3F)
                    new_string.append(0xF0 + ((u21 >> 18) & 0x07))
                    new_string.append(0x80 + ((u21 >> 12) & 0x3F))
                    new_string.append(0x80 + ((u21 >> 6) & 0x3F))
                    new_string.append(0x80 + (u21 & 0x3F))
                    continue
            new_string.append(byte1)
            new_string.append(byte2)
            new_string.append(byte3)
        i += 1
    return new_string.decode('utf8')

Instance variables

var this
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
var parent
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
class JvClassMember (reader, pool)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvClassMember(JvStructWithName):
    descriptor: str = Index(str)

    def __init__(self, reader: StructReader, pool: list):
        self.pool = pool
        self.access = JvAccessFlags(reader)
        self.name = reader.u16()
        self.descriptor = reader.u16()
        self.attributes = [JvAttribute(reader, pool=pool) for _ in range(reader.u16())]

Ancestors

  • refinery.lib.java.JvStructWithName
  • refinery.lib.java._HasPoolAndTag
  • Struct

Instance variables

var descriptor
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
class JvClassProperty (reader, **kwargs)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvClassProperty(_HasPoolAndTag):
    name: JvString = Index(JvString)
    info: JvNameAndType = Index(JvNameAndType)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.name = reader.u16()
        self.info = reader.u16()

    def __repr__(self): return F'{self.name}::{self.info}'

Ancestors

  • refinery.lib.java._HasPoolAndTag
  • Struct

Instance variables

var name
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
var info
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
class JvCode (reader, pool)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvCode(Struct):
    def __init__(self, reader: StructReader, pool: list):
        reader.bigendian = True
        self.max_stack = reader.u16()
        self.max_locals = reader.u16()
        self.disassembly: List[JvOpCode] = []
        with StructReader(reader.read(reader.u32())) as code:
            code.bigendian = True
            while not code.eof:
                self.disassembly.append(JvOpCode(code, pool=pool))
        self.exceptions = [JvException(reader      ) for _ in range(reader.u16())] # noqa
        self.attributes = [JvAttribute(reader, pool) for _ in range(reader.u16())] # noqa

Ancestors

class JvConstType (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

Expand source code Browse git
class JvConstType(IntEnum):
    Utf8             = 0x01 # noqa
    Int              = 0x03 # noqa
    Float            = 0x04 # noqa
    Long             = 0x05 # noqa
    Double           = 0x06 # noqa
    Class            = 0x07 # noqa
    String           = 0x08 # noqa
    Field            = 0x09 # noqa
    Method           = 0x0A # noqa
    InterfaceMethod  = 0x0B # noqa
    NameAndType      = 0x0C # noqa
    MethodHandle     = 0x0F # noqa
    MethodType       = 0x10 # noqa
    Dynamic          = 0x11 # noqa
    InvokeDynamic    = 0x12 # noqa
    Module           = 0x13 # noqa
    Package          = 0x14 # noqa

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var Utf8
var Int
var Float
var Long
var Double
var Class
var String
var Field
var Method
var InterfaceMethod
var NameAndType
var MethodHandle
var MethodType
var Dynamic
var InvokeDynamic
var Module
var Package
class JvDynamic (reader, **kwargs)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvDynamic(_HasPoolAndTag):
    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.bootstrap_method_attr_index = reader.u16()
        self.info = reader.u16()

Ancestors

  • refinery.lib.java._HasPoolAndTag
  • Struct
class JvException (reader)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvException(Struct):
    def __init__(self, reader: StructReader):
        self.start = reader.u16()
        self.end = reader.u16()
        self.handler = reader.u16()
        self.catch = reader.u16()

Ancestors

class JvMethodHandle (reader, **kwargs)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvMethodHandle(_HasPoolAndTag):
    reference: JvClassProperty = Index(JvClassProperty)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.kind = JvMethodHandleRefKind(reader.read_byte())
        self.reference = reader.u16()

Ancestors

  • refinery.lib.java._HasPoolAndTag
  • Struct

Instance variables

var reference
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
class JvMethodHandleRefKind (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

Expand source code Browse git
class JvMethodHandleRefKind(IntEnum):
    GetField          = 1 # noqa
    GetStatic         = 2 # noqa
    PutField          = 3 # noqa
    PutStatic         = 4 # noqa
    InvokeVirtual     = 5 # noqa
    InvokeStatic      = 6 # noqa
    InvokeSpecial     = 7 # noqa
    InvokeSpecialNew  = 8 # noqa
    InvokeInterface   = 9 # noqa

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var GetField
var GetStatic
var PutField
var PutStatic
var InvokeVirtual
var InvokeStatic
var InvokeSpecial
var InvokeSpecialNew
var InvokeInterface
class JvNameAndType (reader, **kwargs)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvNameAndType(JvStructWithName):
    descriptor: str = Index(str)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.name = reader.u16()
        self.descriptor = reader.u16()

Ancestors

  • refinery.lib.java.JvStructWithName
  • refinery.lib.java._HasPoolAndTag
  • Struct

Instance variables

var descriptor
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]
class JvOpCode (reader, pool)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvOpCode(Struct):

    OPC_ARGMAP = {
        opc.bipush          : 'b',
        opc.sipush          : 'h',
        opc.ldc             : 'B',
        opc.ldc_w           : 'H',
        opc.ldc2_w          : 'H',
        opc.iload           : 'B',
        opc.lload           : 'B',
        opc.fload           : 'B',
        opc.dload           : 'B',
        opc.aload           : 'B',
        opc.istore          : 'B',
        opc.lstore          : 'B',
        opc.fstore          : 'B',
        opc.dstore          : 'B',
        opc.astore          : 'B',
        opc.iinc            : 'Bb',
        opc.ifeq            : 'H',
        opc.ifne            : 'H',
        opc.iflt            : 'H',
        opc.ifge            : 'H',
        opc.ifgt            : 'H',
        opc.ifle            : 'H',
        opc.if_icmpeq       : 'H',
        opc.if_icmpne       : 'H',
        opc.if_icmplt       : 'H',
        opc.if_icmpge       : 'H',
        opc.if_icmpgt       : 'H',
        opc.if_icmple       : 'H',
        opc.if_acmpeq       : 'H',
        opc.if_acmpne       : 'H',
        opc.goto            : 'H',
        opc.jsr             : 'H',
        opc.ret             : 'B',
        opc.getstatic       : 'H',
        opc.putstatic       : 'H',
        opc.getfield        : 'H',
        opc.putfield        : 'H',
        opc.invokevirtual   : 'H',
        opc.invokespecial   : 'H',
        opc.invokestatic    : 'H',
        opc.invokeinterface : 'HBx',
        opc.invokedynamic   : 'Hxx',
        opc.new             : 'H',
        opc.anewarray       : 'H',
        opc.checkcast       : 'H',
        opc.instanceof      : 'H',
        opc.multianewarray  : 'HB',
        opc.ifnull          : 'H',
        opc.ifnonnull       : 'H',
        opc.goto_w          : 'L',
        opc.jsr_w           : 'L',
    }

    OPC_CONSTPOOL = {
        opc.ldc,
        opc.ldc_w,
        opc.ldc2_w,
        opc.getstatic,
        opc.putstatic,
        opc.getfield,
        opc.putfield,
        opc.invokevirtual,
        opc.invokespecial,
        opc.invokestatic,
        opc.new,
        opc.anewarray,
        opc.checkcast,
        opc.instanceof,
        opc.multianewarray,
    }

    def __getitem__(self, k):
        return self.arguments[k]

    def __init__(self, reader: StructReader, pool: list):
        with StreamDetour(reader):
            self.code = opc(reader.read_byte())
            self.table: Optional[Dict[int, int]] = None
            try:
                fmt = self.OPC_ARGMAP[self.code]
            except KeyError:
                self.arguments = []
            else:
                self.arguments = list(reader.read_struct(fmt))
            if self.code == opc.newarray:
                self.arguments = [JvBaseType(reader.read_byte())]
            elif self.code in self.OPC_CONSTPOOL:
                try:
                    self.arguments[0] = pool[self.arguments[0] - 1]
                except (AttributeError, IndexError):
                    pass
            elif self.code == opc.lookupswitch:
                reader.byte_align(blocksize=4)
                default, npairs = reader.read_struct('LL')
                pairs = reader.read_struct(F'{npairs * 2}L')
                self.table = dict(zip(*([iter(pairs)] * 2)))
                self.table[None] = default
            elif self.code == opc.tableswitch:
                reader.byte_align(blocksize=4)
                default, low, high = reader.read_struct('LLL')
                assert low <= high
                offsets = reader.read_struct(F'{high - low + 1}L')
                self.table = {k + low: offset for k, offset in enumerate(offsets)}
                self.table[None] = default
            elif self.code == opc.wide:
                argop = opc(reader.u8())
                self.arguments = (argop, reader.u16())
                if argop == opc.iinc:
                    self.arguments += reader.i16(),
                else:
                    assert argop in (
                        opc.iload, opc.istore,
                        opc.fload, opc.fstore,
                        opc.aload, opc.astore,
                        opc.lload, opc.lstore,
                        opc.dload, opc.dstore,
                        opc.ret)
            offset = reader.tell()
        self.raw = bytes(reader.read(offset - reader.tell()))

    def __bytes__(self):
        return self.raw

Ancestors

Class variables

var OPC_ARGMAP
var OPC_CONSTPOOL
class JvString (reader, **kwargs)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class JvString(_HasPoolAndTag):
    value: str = Index(str)

    def __init__(self, reader: StructReader, **kwargs):
        super().__init__(reader, **kwargs)
        self.value = reader.u16()

    def __repr__(self): return repr(self.value)

    def __str__(self): return self.value

Ancestors

  • refinery.lib.java._HasPoolAndTag
  • Struct

Instance variables

var value
Expand source code Browse git
def __get__(self, parent, tp=None) -> AttrType:
    pid = id(parent)
    if pid not in self.__get:
        try:
            seed = self.__set[pid]
        except KeyError as K:
            raise AttributeError from K
        self.__get[pid] = self.resolve(parent, seed)
    return self.__get[pid]