def _pfp__pack_data(self): """Pack the nested field """ if self._pfp__pack_type is None: return tmp_stream = six.BytesIO() self._._pfp__build(bitwrap.BitwrappedStream(tmp_stream)) raw_data = tmp_stream.getvalue() unpack_func = self._pfp__packer unpack_args = [] if self._pfp__packer is not None: unpack_func = self._pfp__packer unpack_args = [true(), raw_data] elif self._pfp__pack is not None: unpack_func = self._pfp__pack unpack_args = [raw_data] # does not need to be converted to a char array if not isinstance(unpack_func, functions.NativeFunction): io_stream = bitwrap.BitwrappedStream(six.BytesIO(raw_data)) unpack_args[-1] = Array(len(raw_data), Char, io_stream) res = unpack_func.call(unpack_args, *self._pfp__pack_func_call_info, no_cast=True) if isinstance(res, Array): res = res._pfp__build() io_stream = six.BytesIO(res) tmp_stream = bitwrap.BitwrappedStream(io_stream) self._pfp__no_unpack = True self._pfp__parse(tmp_stream) self._pfp__no_unpack = False
def _pfp__build(self, stream=None, save_offset=False): if stream is None: io_stream = six.BytesIO() tmp_stream = bitwrap.BitwrappedStream(io_stream) tmp_stream.padded = self._pfp__interp.get_bitfield_padded() super(Dom, self)._pfp__build(tmp_stream, save_offset=save_offset) # flush out any unaligned bitfields, etc tmp_stream.flush() res = io_stream.getvalue() return res else: if not isinstance(stream, bitwrap.BitwrappedStream): stream = bitwrap.BitwrappedStream(stream) return super(Dom, self)._pfp__build(stream, save_offset=save_offset)
def _pfp__build(self, stream=None, save_offset=False): """Build the union and write the result into the stream. :stream: None :returns: None """ max_size = -1 if stream is None: core_stream = six.BytesIO() new_stream = bitwrap.BitwrappedStream(core_stream) else: new_stream = stream for child in self._pfp__children: curr_pos = new_stream.tell() child._pfp__build(new_stream, save_offset) size = new_stream.tell() - curr_pos new_stream.seek(-size, 1) if size > max_size: max_size = size new_stream.seek(max_size, 1) if stream is None: return core_stream.getvalue() else: return max_size
def _pfp__width(self): """Return the width of the field (sizeof) """ raw_output = six.BytesIO() output = bitwrap.BitwrappedStream(raw_output) self._pfp__build(output) output.flush() return len(raw_output.getvalue())
def _pfp__unpack_data(self, raw_data): """Means that the field has already been parsed normally, and that it now needs to be unpacked. :raw_data: A string of the data that the field consumed while parsing """ if self._pfp__pack_type is None: return if self._pfp__no_unpack: return unpack_func = self._pfp__packer unpack_args = [] if self._pfp__packer is not None: unpack_func = self._pfp__packer unpack_args = [false(), raw_data] elif self._pfp__unpack is not None: unpack_func = self._pfp__unpack unpack_args = [raw_data] # does not need to be converted to a char array if not isinstance(unpack_func, functions.NativeFunction): io_stream = bitwrap.BitwrappedStream(six.BytesIO(raw_data)) unpack_args[-1] = Array(len(raw_data), Char, io_stream) res = unpack_func.call(unpack_args, *self._pfp__pack_func_call_info, no_cast=True) if isinstance(res, Array): res = res._pfp__build() io_stream = six.BytesIO(res) tmp_stream = bitwrap.BitwrappedStream(io_stream) tmp_stream.padded = self._pfp__interp.get_bitfield_padded() self._ = self._pfp__parsed_packed = self._pfp__pack_type(tmp_stream) self._._pfp__watch(self)
def FSeek(params, ctxt, scope, stream, coord): """Returns 0 if successful or -1 if the address is out of range """ if len(params) != 1: raise errors.InvalidArguments( coord, "{} args".format(len(params)), "FSeek accepts only one argument", ) if params[0] is None: return 0 pos = PYVAL(params[0]) curr_pos = stream.tell() fsize = stream.size() if pos > fsize: stream.seek(fsize) return -1 elif pos < 0: stream.seek(0) return -1 diff = pos - curr_pos if diff < 0: stream.seek(pos) return 0 data = stream.read(diff) # let the ctxt automatically append numbers, as needed, unless the previous # child was also a skipped field skipped_name = "_skipped" if len(ctxt._pfp__children ) > 0 and ctxt._pfp__children[-1]._pfp__name.startswith("_skipped"): old_name = ctxt._pfp__children[-1]._pfp__name data = ctxt._pfp__children[-1].raw_data + data skipped_name = old_name ctxt._pfp__children = ctxt._pfp__children[:-1] del ctxt._pfp__children_map[old_name] tmp_stream = bitwrap.BitwrappedStream(six.BytesIO(data)) new_field = pfp.fields.Array(len(data), pfp.fields.Char, tmp_stream) ctxt._pfp__add_child(skipped_name, new_field, stream) scope.add_var(skipped_name, new_field) return 0
def call(self, args, ctxt, scope, stream, interp, coord, no_cast=False): if self.send_interp: res = self.func(args, ctxt, scope, stream, coord, interp) else: res = self.func(args, ctxt, scope, stream, coord) if no_cast: res_field = res elif utils.is_str(res) and self.ret == pfp.fields.Array: tmp_stream = bitwrap.BitwrappedStream(six.BytesIO(res)) res_field = pfp.fields.Array(len(res), pfp.fields.Char, tmp_stream) else: res_field = self.ret() res_field._pfp__set_value(res) return res_field
def __getitem__(self, idx): if self.raw_data is None: return self.items[idx] else: if self.width < 0 or idx+1 > self.width: raise IndexError(idx) width = self.field_cls.width offset = width * idx data = self.raw_data[offset:offset+width] stream = bitwrap.BitwrappedStream(six.BytesIO(data)) res = self.field_cls(stream) res._pfp__watch(self) res._pfp__parent = self res._pfp__array_idx = idx res._pfp__name = "{}[{}]".format( self._pfp__name, idx ) return res
def call(self, args, ctxt, scope, stream, interp, coord, no_cast=False): if self.send_interp: res = self.func(args, ctxt, scope, stream, coord, interp) else: res = self.func(args, ctxt, scope, stream, coord) if no_cast: res_field = res elif utils.is_str(res) and self.ret == pfp.fields.Array: tmp_stream = bitwrap.BitwrappedStream(six.BytesIO(res)) res_field = pfp.fields.Array(len(res), pfp.fields.Char, tmp_stream) elif utils.is_str(self.ret) and scope.get_type(self.ret) is not None: # TODO should we do any type-checking here to make sure that the # return value matches what is declared as the return type? res_field = res else: res_field = self.ret() res_field._pfp__set_value(res) return res_field
def _pfp__notify_update(self, child=None): """Handle a child with an updated value """ if getattr(self, "_pfp__union_update_other_children", True): self._pfp__union_update_other_children = False new_data = child._pfp__build() new_stream = bitwrap.BitwrappedStream(six.BytesIO(new_data)) for other_child in self._pfp__children: if other_child is child: continue if isinstance(other_child, Array) and other_child.is_stringable(): other_child._pfp__set_value(new_data) else: other_child._pfp__parse(new_stream) new_stream.seek(0) self._pfp__no_update_other_children = True super(Union, self)._pfp__notify_update(child=child)