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): def readint(length: int): return int(bytes(reader.read(length * 2)), 16) self.signature = reader.read(6) if self.signature != b'070701': raise ValueError('invalid CPIO header signature') self.inode = readint(4) self.mode = readint(4) self.uid = readint(4) self.gid = readint(4) self.nlinks = readint(4) mtime = readint(4) self.mtime = datetime.utcfromtimestamp(mtime) self.size = readint(4) self.dev = readint(4), readint(4) self.rdev = readint(4), readint(4) namesize = readint(4) self.checksum = readint(4) self.name = bytes(reader.read(namesize)).decode('ascii').rstrip('\0') reader.byte_align(4) self.data = reader.read(self.size) reader.byte_align(4)
def process(self, data: bytearray): formatter = string.Formatter() until = self.args.until until = until and PythonExpression(until, all_variables_allowed=True) reader = StructReader(memoryview(data)) mainspec = self.args.spec byteorder = mainspec[:1] if byteorder in '<!=@>': mainspec = mainspec[1:] else: byteorder = '=' def fixorder(spec): if spec[0] not in '<!=@>': spec = byteorder + spec return spec it = itertools.count() if self.args.multi else (0, ) for index in it: if reader.eof: break if index >= self.args.count: break meta = metavars(data, ghost=True) meta['index'] = index args = [] last = None checkpoint = reader.tell() try: for prefix, name, spec, conversion in formatter.parse( mainspec): if prefix: args.extend(reader.read_struct(fixorder(prefix))) if name is None: continue if conversion: reader.byte_align( PythonExpression.evaluate(conversion, meta)) if spec: spec = meta.format_str(spec, self.codec, args) if spec != '': try: spec = PythonExpression.evaluate(spec, meta) except ParserError: pass if spec == '': last = value = reader.read() elif isinstance(spec, int): last = value = reader.read_bytes(spec) else: value = reader.read_struct(fixorder(spec)) if not value: self.log_warn(F'field {name} was empty, ignoring.') continue if len(value) > 1: self.log_info( F'parsing field {name} produced {len(value)} items reading a tuple' ) else: value = value[0] args.append(value) if name == _SHARP: raise ValueError( 'Extracting a field with name # is forbidden.') elif name.isdecimal(): index = int(name) limit = len(args) - 1 if index > limit: self.log_warn( F'cannot assign index field {name}, the highest index is {limit}' ) else: args[index] = value continue elif name: meta[name] = value if until and not until(meta): self.log_info( F'the expression ({until}) evaluated to zero; aborting.' ) break with StreamDetour(reader, checkpoint) as detour: full = reader.read(detour.cursor - checkpoint) if last is None: last = full outputs = [] for template in self.args.outputs: used = set() outputs.append( meta.format(template, self.codec, [full, *args], {_SHARP: last}, True, used=used)) for key in used: meta.pop(key, None) for output in outputs: chunk = self.labelled(output, **meta) chunk.set_next_batch(index) yield chunk except EOF: leftover = repr(SizeInt(len(reader) - checkpoint)).strip() self.log_info(F'discarding {leftover} left in buffer') break