def __init__(self, reader: StructReader): 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=self.pool)) self.exceptions = [JvException(reader) for _ in range(reader.u16())] self.attributes = [JvAttribute(reader) for _ in range(reader.u16())]
def __init__(self, reader: StructReader): if reader.read(4) != self.SIGNATURE: raise ValueError self.disk_number = reader.u16() self.start_disk_number = reader.u16() self.entries_on_disk = reader.u16() self.entries_in_directory = reader.u16() self.directory_size = reader.u32() self.directory_offset = reader.u32() try: cl = reader.u32() self.comment = cl and reader.read(cl) or None except EOFError: self.comment = None
def _decompress_xpress(self, reader: StructReader, writer: MemoryFile, target: Optional[int] = None) -> bytearray: if target is not None: target += writer.tell() flags = BitBufferedReader(reader) nibble_cache = None while not reader.eof: if target is not None and writer.tell() >= target: return if not flags.next(): writer.write(reader.read(1)) continue offset, length = divmod(reader.u16(), 8) offset += 1 if length == 7: length = nibble_cache if length is None: length_pair = reader.u8() nibble_cache = length_pair >> 4 length = length_pair & 0xF else: nibble_cache = None if length == 15: length = reader.u8() if length == 0xFF: length = reader.u16() or reader.u32() length -= 22 if length < 0: raise RuntimeError( F'Invalid match length of {length} for long delta sequence' ) length += 15 length += 7 length += 3 writer.replay(offset, length)
def __init__(self, reader: StructReader): if reader.read(4) != self.SIGNATURE: raise ValueError self.version_made_by = reader.u16() self.version_to_extract = reader.u16() self.flags = reader.u16() self.compression = reader.u16() self.date = datefix.dostime(reader.u32()) self.crc32 = reader.u32() self.compressed_size = reader.u32() self.decompressed_size = reader.u32() len_filename = reader.u16() len_extra = reader.u16() len_comment = reader.u16() self.disk_nr_start = reader.u16() self.internal_attributes = reader.u16() self.external_attributes = reader.u32() self.header_offset = reader.u32() self.filename = len_filename and reader.read(len_filename) or None self.extra = len_extra and reader.read(len_extra) or None self.comment = len_comment and reader.read(len_comment) or None
def __init__(self, reader: StructReader): 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] = self.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.get_byte()) 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 __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.')
def _decompress_xpress_huffman(self, reader: StructReader, writer: MemoryFile, target: Optional[int] = None, max_chunk_size: int = 0x10000) -> None: limit = writer.tell() if target is not None: target += limit while not reader.eof: if reader.remaining_bytes < XPRESS_NUM_SYMBOLS // 2: raise IndexError( F'There are only {reader.remaining_bytes} bytes reamining in the input buffer,' F' but at least {XPRESS_NUM_SYMBOLS//2} are required to read a Huffman table.' ) table = bytearray( reader.read_integer(4) for _ in range(XPRESS_NUM_SYMBOLS)) table = make_huffman_decode_table(table, XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN) limit = limit + max_chunk_size flags = BitBufferedReader(reader, 16) while True: position = writer.tell() if position == target: if reader.remaining_bytes: self.log_info( F'chunk decompressed with {reader.remaining_bytes} bytes remaining in input buffer' ) return if position >= limit: if position > limit: limit = position self.log_info( F'decompression of one chunk generated more than the limit of {max_chunk_size} bytes' ) flags.collect() break try: sym = flags.huffman_symbol(table, XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN) except EOFError: self.log_debug('end of file while reading huffman symbol') break if sym < XPRESS_NUM_CHARS: writer.write_byte(sym) continue length = sym & 0xF offsetlog = (sym >> 4) & 0xF flags.collect() if reader.eof: break offset = (1 << offsetlog) | flags.read(offsetlog) if length == 0xF: nudge = reader.read_byte() if nudge < 0xFF: length += nudge else: length = reader.u16() or reader.u32() length += XPRESS_MIN_MATCH_LEN writer.replay(offset, length)
def decompress_stream(self, data: ByteString, LZOv1: bool = False) -> bytearray: """ An implementation of LZO decompression. We use the article "[LZO stream format as understood by Linux's LZO decompressor](https://www.kernel.org/doc/html/latest/staging/lzo.html)" as a reference since no proper specification is available. """ def integer() -> int: length = 0 while True: byte = src.read_byte() if byte: return length + byte length += 0xFF if length > 0x100000: raise LZOError('Too many zeros in integer encoding.') def literal(count): dst.write(src.read_bytes(count)) def copy(distance: int, length: int): if distance > len(dst): raise LZOError(F'Distance {distance} > bufsize {len(dst)}') buffer = dst.getbuffer() if distance > length: start = len(buffer) - distance end = start + length dst.write(buffer[start:end]) else: block = buffer[-distance:] while len(block) < length: block += block[:length - len(block)] if len(block) > length: block[length:] = () dst.write(block) src = StructReader(memoryview(data)) dst = MemoryFile() state = 0 first = src.read_byte() if first == 0x10: raise LZOError('Invalid first stream byte 0x10.') elif first <= 0x12: src.seekrel(-1) elif first <= 0x15: state = first - 0x11 literal(state) else: state = 4 literal(first - 0x11) while True: instruction = src.read_byte() if instruction < 0x10: if state == 0: length = instruction or integer() + 15 state = length + 3 if state < 4: raise LZOError('Literal encoding is too short.') else: state = instruction & 0b0011 D = (instruction & 0b1100) >> 2 H = src.read_byte() distance = (H << 2) + D + 1 if state >= 4: distance += 0x800 length = 3 else: length = 2 copy(distance, length) elif instruction < 0x20: L = instruction & 0b0111 H = instruction & 0b1000 length = L or integer() + 7 argument = src.u16() state = argument & 3 distance = (H << 11) + (argument >> 2) if not distance: return dst.getbuffer() if LZOv1 and distance & 0x803F == 0x803F and length in range(261, 265): raise LZOError('Compressed data contains sequence that is banned in LZOv1.') if LZOv1 and distance == 0xBFFF: X = src.read_byte() count = ((X << 3) | L) + 4 self.log_debug(F'Writing run of {X} zero bytes according to LZOv1.') dst.write(B'\0' * count) else: copy(distance + 0x4000, length + 2) elif instruction < 0x40: L = instruction & 0b11111 length = L or integer() + 31 argument = src.u16() state = argument & 3 distance = (argument >> 2) + 1 copy(distance, length + 2) else: if instruction < 0x80: length = 3 + ((instruction >> 5) & 1) else: length = 5 + ((instruction >> 5) & 3) H = src.read_byte() D = (instruction & 0b11100) >> 2 state = instruction & 3 distance = (H << 3) + D + 1 copy(distance, length) if state: literal(state)
def __init__(self, reader: StructReader): self.name = reader.u16() self.descriptor = reader.u16()
def __init__(self, reader: StructReader): self.start = reader.u16() self.end = reader.u16() self.handler = reader.u16() self.catch = reader.u16()
def __init__(self, reader: StructReader): self.access = JvAccessFlags(reader) self.name = reader.u16() self.descriptor = reader.u16() self.attributes = [JvAttribute(reader, pool=self.pool) for _ in range(reader.u16())]
def __init__(self, reader: StructReader): self.name = reader.u16() self.data = reader.read(reader.u32())
def __init__(self, reader: StructReader): self.bootstrap_method_attr_index = reader.u16() self.info = reader.u16()
def __init__(self, reader: StructReader): self.kind = JvMethodHandleRefKind(reader.read_byte()) self.reference = reader.u16()
def __init__(self, reader: StructReader): self.name = reader.u16() self.info = reader.u16()
def __init__(self, reader: StructReader): self.value = reader.u16() def __repr__(self): return repr(self.value)