diff --git a/supyr_struct/blocks/array_block.py b/supyr_struct/blocks/array_block.py index ba774a3..094a4de 100644 --- a/supyr_struct/blocks/array_block.py +++ b/supyr_struct/blocks/array_block.py @@ -2,7 +2,7 @@ from sys import getsizeof from supyr_struct.blocks.block import Block -from supyr_struct.blocks.list_block import ListBlock +from supyr_struct.blocks.list_block import ListBlock, repeat from supyr_struct.defs.constants import NAME, UNNAMED, NAME_MAP from supyr_struct.exceptions import DescEditError, DescKeyError from supyr_struct.buffer import get_rawdata_context @@ -37,7 +37,7 @@ def __init__(self, desc, parent=None, init_attrs=None, **kwargs): self.parse(init_attrs=init_attrs, **kwargs) else: # populate the listblock with the right number of fields - list.__init__(self, [None]*self.get_size()) + list.__init__(self, repeat(None, self.get_size())) def __sizeof__(self, seenset=None): ''' @@ -150,10 +150,9 @@ def __delitem__(self, index): # the descriptor since its list indexes # aren't attributes, but instanced objects start, stop, step = index.indices(len(self)) + step = -step if step < 0 else step if start < stop: start, stop = stop, start - if step > 0: - step = -step list.__delitem__(self, index) self.set_size() @@ -239,7 +238,7 @@ def extend(self, new_attrs, **kwargs): index = len(self) # create new, empty indices - list.extend(self, [None]*new_attrs) + list.extend(self, repeat(None, new_attrs)) # read new sub_structs into the empty indices for i in range(index, index + new_attrs): attr_f_type.parser(attr_desc, parent=self, @@ -705,10 +704,10 @@ def parse(self, **kwargs): # parsing/initializing all array elements, so clear and resize list.__delitem__(self, slice(None, None, None)) if initdata is not None: - list.extend(self, [None]*len(initdata)) + list.extend(self, repeat(None, len(initdata))) self.set_size() # update the size to the initdata length else: - list.extend(self, [None]*self.get_size()) + list.extend(self, repeat(None, self.get_size())) if rawdata is not None: # parse the ArrayBlock from raw data @@ -798,7 +797,7 @@ def __init__(self, desc, parent=None, steptree=None, self.parse(init_attrs=init_attrs, **kwargs) else: # populate the listblock with the right number of fields - list.__init__(self, [None]*self.get_size()) + list.__init__(self, repeat(None, self.get_size())) def __sizeof__(self, seenset=None): ''' diff --git a/supyr_struct/blocks/list_block.py b/supyr_struct/blocks/list_block.py index e643d09..9fd97fa 100644 --- a/supyr_struct/blocks/list_block.py +++ b/supyr_struct/blocks/list_block.py @@ -1,7 +1,7 @@ ''' ''' from copy import deepcopy -from itertools import takewhile +from itertools import repeat, takewhile from sys import getsizeof from supyr_struct.blocks.block import Block @@ -47,7 +47,7 @@ def __init__(self, desc, parent=None, init_attrs=None, **kwargs): self.parse(init_attrs=init_attrs, **kwargs) else: # populate the listblock with the right number of fields - list.__init__(self, [None]*desc['ENTRIES']) + list.__init__(self, repeat(None, desc['ENTRIES'])) def __str__(self, **kwargs): ''' @@ -215,7 +215,7 @@ def __deepcopy__(self, memo): # clear the Block so it can be populated list.__delitem__(dup_block, slice(None, None, None)) - list.extend(dup_block, [None]*len(self)) + list.extend(dup_block, repeat(None, len(self))) # populate the duplicate for i in range(len(self)): @@ -269,9 +269,9 @@ def __getitem__(self, index): If index is a string, returns self.__getattr__(index) ''' - if isinstance(index, str): - return self.__getattr__(index) - return list.__getitem__(self, index) + return (self.__getattr__(index) if isinstance(index, str) else + list.__getitem__(self, index) + ) def __setitem__(self, index, new_value): ''' @@ -300,8 +300,7 @@ def __setitem__(self, index, new_value): ''' if isinstance(index, int): # handle accessing negative indexes - if index < 0: - index += len(self) + index = index + len(self) if index < 0 else index assert not self.assert_is_valid_field_value(index, new_value) list.__setitem__(self, index, new_value) @@ -332,10 +331,9 @@ def __setitem__(self, index, new_value): elif isinstance(index, slice): start, stop, step = index.indices(len(self)) + step = -step if step < 0 else step if start > stop: start, stop = stop, start - if step < 0: - step = -step assert hasattr(new_value, '__iter__'), ( "must assign iterable to extended slice") @@ -810,7 +808,7 @@ def parse(self, **kwargs): if kwargs.get("clear", True): # parsing/initializing all attributes, so clear the block # and create as many elements as it needs to hold - list.__init__(self, [None]*desc['ENTRIES']) + list.__init__(self, repeat(None, desc['ENTRIES'])) if rawdata is not None: # parse the ListBlock from raw data @@ -899,7 +897,7 @@ def __init__(self, desc, parent=None, steptree=None, self.parse(init_attrs=init_attrs, **kwargs) else: # populate the listblock with the right number of fields - list.__init__(self, [None]*desc['ENTRIES']) + list.__init__(self, repeat(None, desc['ENTRIES'])) def __sizeof__(self, seenset=None): ''' diff --git a/supyr_struct/blocks/while_block.py b/supyr_struct/blocks/while_block.py index acdbd46..0efaf6d 100644 --- a/supyr_struct/blocks/while_block.py +++ b/supyr_struct/blocks/while_block.py @@ -4,7 +4,7 @@ stored anywhere and must be parsed until some function says to stop. ''' from supyr_struct.blocks.block import Block -from supyr_struct.blocks.list_block import ListBlock +from supyr_struct.blocks.list_block import ListBlock, repeat from supyr_struct.blocks.array_block import ArrayBlock, PArrayBlock from supyr_struct.defs.constants import SUB_STRUCT, NAME, UNNAMED from supyr_struct.exceptions import DescEditError, DescKeyError @@ -36,8 +36,7 @@ def __setitem__(self, index, new_value): ''' if isinstance(index, int): # handle accessing negative indexes - if index < 0: - index += len(self) + index = index + len(self) if index < 0 else index assert not self.assert_is_valid_field_value(index, new_value) list.__setitem__(self, index, new_value) @@ -48,10 +47,9 @@ def __setitem__(self, index, new_value): elif isinstance(index, slice): start, stop, step = index.indices(len(self)) + step = -step if step < 0 else step if start > stop: start, stop = stop, start - if step < 0: - step = -step assert hasattr(new_value, '__iter__'), ( "must assign iterable to extended slice") @@ -428,7 +426,7 @@ def parse(self, **kwargs): raise TypeError("Could not locate the sub-struct descriptor." + "\nCould not initialize array") - list.extend(self, [None]*init_len) + list.extend(self, repeat(None, init_len)) if kwargs.get('init_attrs', True) or issubclass(attr_f_type.node_cls, Block): # loop through each element in the array and initialize it diff --git a/supyr_struct/field_type_methods/decoders.py b/supyr_struct/field_type_methods/decoders.py index 4c1c520..8e6913b 100644 --- a/supyr_struct/field_type_methods/decoders.py +++ b/supyr_struct/field_type_methods/decoders.py @@ -67,12 +67,9 @@ def decode_decimal(self, rawdata, desc=None, parent=None, attr_index=None): Returns a Decimal represention of the "rawdata" argument. ''' - if self.endian == '<': - endian = 'little' - else: - endian = 'big' - d_exp = parent.get_meta('DECIMAL_EXP', attr_index) - bigint = str(int.from_bytes( + endian = 'little' if self.endian == '<' else 'big' + d_exp = parent.get_meta('DECIMAL_EXP', attr_index) + bigint = str(int.from_bytes( rawdata, endian, signed=self.enc.endswith('S'))) return Decimal(bigint[:len(bigint)-d_exp] + '.' + @@ -87,11 +84,10 @@ def decode_24bit_numeric(self, rawdata, desc=None, Returns an int decoded represention of the "rawdata" argument. ''' - if self.endian == '<': - rawint = unpack('I', b'\x00' + rawdata)[0] - + rawint = ( + unpack('I', b'\x00' + rawdata) + )[0] # if the int can be signed and IS signed then take care of that if rawint & 0x800000 and self.enc[1] == 't': return rawint - 0x1000000 # 0x1000000 == 0x800000 * 2 @@ -148,20 +144,14 @@ def decode_big_int(self, rawdata, desc=None, parent=None, attr_index=None): if not len(rawdata): return 0 - if self.endian == '<': - endian = 'little' - else: - endian = 'big' - - if self.enc[-1] == 's': - # ones compliment - bigint = int.from_bytes(rawdata, endian, signed=True) - if bigint < 0: - return bigint + 1 - return bigint - elif self.enc[-1] == 'S': + endian = 'little' if self.endian == '<' else 'big' + if self.enc[-1] == 'S': # twos compliment return int.from_bytes(rawdata, endian, signed=True) + elif self.enc[-1] == 's': + # ones compliment + bigint = int.from_bytes(rawdata, endian, signed=True) + return bigint + (bigint < 0) return int.from_bytes(rawdata, endian) diff --git a/supyr_struct/field_type_methods/encoders.py b/supyr_struct/field_type_methods/encoders.py index f7081d5..ea56de8 100644 --- a/supyr_struct/field_type_methods/encoders.py +++ b/supyr_struct/field_type_methods/encoders.py @@ -78,17 +78,17 @@ def encode_24bit_numeric(self, node, parent=None, attr_index=None): # int can be signed assert node >= -0x800000 and node <= 0x7fffff, ( '%s is too large to pack as a 24bit signed int.' % node) - if node < 0: - # int IS signed - node += 0x1000000 + # int IS signed + node += 0x1000000 if node < 0 else 0 else: assert node >= 0 and node <= 0xffffff, ( '%s is too large to pack as a 24bit unsigned int.' % node) # pack and return the int - if self.endian == '<': - return pack('I', node)[1:4] + return ( + pack('I', node)[1:4] + ) def encode_int_timestamp(self, node, parent=None, attr_index=None): @@ -148,19 +148,13 @@ def encode_big_int(self, node, parent=None, attr_index=None): if not bytecount: return b'' - if self.endian == '<': - endian = 'little' - else: - endian = 'big' - + endian = 'little' if self.endian == '<' else 'big' if self.enc[-1] == 'S': # twos compliment return node.to_bytes(bytecount, endian, signed=True) elif self.enc[-1] == 's': # ones compliment - if node < 0: - return (node-1).to_bytes(bytecount, endian, signed=True) - return node.to_bytes(bytecount, endian, signed=False) + return (node - (node < 0)).to_bytes(bytecount, endian, signed=True) return node.to_bytes(bytecount, endian) diff --git a/supyr_struct/field_type_methods/parsers.py b/supyr_struct/field_type_methods/parsers.py index e0b7ad0..cba8b9c 100644 --- a/supyr_struct/field_type_methods/parsers.py +++ b/supyr_struct/field_type_methods/parsers.py @@ -124,17 +124,17 @@ def container_parser(self, desc, node=None, parent=None, attr_index=None, if 'STEPTREE' in desc: kwargs['steptree_parents'].append(node) - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # loop once for each field in the node for i in range(len(node)): @@ -193,17 +193,17 @@ def array_parser(self, desc, node=None, parent=None, attr_index=None, a_desc = desc['SUB_STRUCT'] a_parser = a_desc['TYPE'].parser - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # loop once for each field in the node for i in range(node.get_size(**kwargs)): @@ -262,17 +262,17 @@ def while_array_parser(self, desc, node=None, parent=None, attr_index=None, a_desc = desc['SUB_STRUCT'] a_parser = a_desc['TYPE'].parser - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) i = 0 decider = desc.get('CASE') @@ -360,6 +360,7 @@ def switch_parser(self, desc, node=None, parent=None, attr_index=None, align = desc.get('ALIGN') if align: offset += (align - (offset % align)) % align + try: # try to reposition the rawdata if it needs to be peeked rawdata.seek(root_offset + offset) @@ -415,11 +416,12 @@ def struct_parser(self, desc, node=None, parent=None, attr_index=None, # a previously parsed field, but this node is being built # without a parent(such as from an exported block) then # the path wont be valid. The current offset will be used instead. - if attr_index is not None and 'POINTER' in desc: - offset = node.get_meta('POINTER', **kwargs) - elif 'ALIGN' in desc: - align = desc['ALIGN'] - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # loop once for each field in the node for i, off in enumerate(desc['ATTR_OFFS']): @@ -483,39 +485,39 @@ def quickstruct_parser(self, desc, node=None, parent=None, attr_index=None, # a previously parsed field, but this node is being built # without a parent(such as from an exported block) then # the path wont be valid. The current offset will be used instead. - if attr_index is not None and 'POINTER' in desc: - offset = node.get_meta('POINTER', **kwargs) - elif 'ALIGN' in desc: - align = desc['ALIGN'] - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) struct_off = root_offset + offset f_endian = self.f_endian # loop once for each field in the node for i, off in enumerate(desc['ATTR_OFFS']): - off += struct_off typ = desc[i]['TYPE'] # check the forced endianness of the typ being parsed # before trying to use the endianness of the struct - if f_endian == "=" and typ.f_endian == "=": - pass - elif typ.f_endian == ">": - typ = typ.big - elif typ.f_endian == "<" or f_endian == "<": - typ = typ.little - else: - typ = typ.big + endian = f_endian if typ.f_endian == "=" else typ.f_endian + typ = ( + typ if endian == "=" else + typ.little if endian == "<" else + typ.big + ) __lsi__(node, i, typ.struct_unpacker( - rawdata[off:off + typ.size])[0]) + rawdata[off + struct_off: off + struct_off + typ.size] + )[0]) # increment offset by the size of the struct offset += desc['SIZE'] else: for i in range(len(node)): - __lsi__(node, i, - desc[i].get(DEFAULT, desc[i]['TYPE'].default())) + sub_desc = desc[i] + sub_type = sub_desc['TYPE'] + __lsi__(node, i, sub_desc.get(DEFAULT, sub_type.default())) if 'STEPTREE' in desc: s_desc = desc['STEPTREE'] @@ -564,18 +566,18 @@ def stream_adapter_parser(self, desc, node=None, parent=None, attr_index=None, # If there is rawdata to build from if rawdata is not None: - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from # then go to it. Only do this, however, if the POINTER can # be expected to be accurate. If the pointer is a path to # a previously parsed field, but this node is being built # without a parent(such as from an exported block) then # the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # use the decoder method to get a decoded stream and # the length of the stream before it was decoded @@ -618,14 +620,14 @@ def union_parser(self, desc, node=None, parent=None, attr_index=None, # A case may be provided through kwargs. # This is to allow overriding behavior of the union and # to allow creating a node specified by the user - case_i = case = desc.get('CASE') case_map = desc['CASE_MAP'] - align = desc.get('ALIGN') - - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + case_i = case = desc.get('CASE') + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # read and store the rawdata to the new node rawdata.seek(root_offset + offset) @@ -744,14 +746,15 @@ def cstring_parser(self, desc, node=None, parent=None, attr_index=None, if rawdata is not None: orig_offset = offset - align = desc.get('ALIGN') - if attr_index is not None and desc.get('POINTER') is not None: - offset = parent.get_meta('POINTER', attr_index, **kwargs) - elif align: - offset += (align - (offset % align)) % align - - start = root_offset + offset - charsize = self.size + align = desc.get('ALIGN') + offset = ( + parent.get_meta('POINTER', attr_index, **kwargs) + if desc.get('POINTER') is not None else + offset + ((align - (offset%align))%align if align else 0) + ) + + start = root_offset + offset + charsize = self.size delimiter = self.delimiter # if the character size is greater than 1 we need to do special @@ -795,11 +798,12 @@ def py_array_parser(self, desc, node=None, parent=None, attr_index=None, if rawdata is not None: orig_offset = offset - align = desc.get('ALIGN') - if attr_index is not None and desc.get('POINTER') is not None: - offset = parent.get_meta('POINTER', attr_index, **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + parent.get_meta('POINTER', attr_index, **kwargs) + if desc.get('POINTER') is not None else + offset + ((align - (offset%align))%align if align else 0) + ) bytecount = parent.get_size(attr_index, offset=offset, rawdata=rawdata, **kwargs) @@ -845,7 +849,7 @@ def bytes_parser(self, desc, node=None, parent=None, attr_index=None, "and not None when reading a data field.") if rawdata is not None: orig_offset = offset - if attr_index is not None and desc.get('POINTER') is not None: + if desc.get('POINTER') is not None: offset = parent.get_meta('POINTER', attr_index, **kwargs) bytecount = parent.get_size(attr_index, offset=offset, @@ -885,11 +889,10 @@ def bit_struct_parser(self, desc, node=None, parent=None, attr_index=None, """If there is file data to build the structure from""" if rawdata is not None: rawdata.seek(root_offset + offset) - structsize = desc['SIZE'] - if self.endian == '<': - rawint = int.from_bytes(rawdata.read(structsize), 'little') - else: - rawint = int.from_bytes(rawdata.read(structsize), 'big') + size = desc['SIZE'] + rawint = int.from_bytes( + rawdata.read(size), 'little' if self.endian == '<' else 'big' + ) # loop once for each field in the node for i in range(len(node)): @@ -897,7 +900,7 @@ def bit_struct_parser(self, desc, node=None, parent=None, attr_index=None, rawint, desc=desc[i], parent=node, attr_index=i) # increment offset by the size of the struct - offset += structsize + offset += size return offset except (Exception, KeyboardInterrupt) as e: diff --git a/supyr_struct/field_type_methods/serializers.py b/supyr_struct/field_type_methods/serializers.py index 75abfbb..7fdaad8 100644 --- a/supyr_struct/field_type_methods/serializers.py +++ b/supyr_struct/field_type_methods/serializers.py @@ -99,17 +99,17 @@ def container_serializer(self, node, parent=None, attr_index=None, if hasattr(node, 'STEPTREE'): kwargs['steptree_parents'].append(node) - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # loop once for each node in the node for i in range(len(node)): @@ -178,16 +178,17 @@ def array_serializer(self, node, parent=None, attr_index=None, if hasattr(node, 'STEPTREE'): kwargs['steptree_parents'].append(node) - align = desc.get('ALIGN') # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # loop once for each node in the node for i in range(len(node)): @@ -258,17 +259,17 @@ def struct_serializer(self, node, parent=None, attr_index=None, if hasattr(node, 'STEPTREE'): kwargs['steptree_parents'].append(node) - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # write the whole size of the node so # any padding is filled in properly @@ -340,17 +341,17 @@ def quickstruct_serializer(self, node, parent=None, attr_index=None, offsets = desc['ATTR_OFFS'] structsize = desc['SIZE'] - align = desc.get('ALIGN') - # If there is a specific pointer to read the node from then go to it. # Only do this, however, if the POINTER can be expected to be accurate. # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # write the whole size of the node so # any padding is filled in properly @@ -363,16 +364,14 @@ def quickstruct_serializer(self, node, parent=None, attr_index=None, # loop once for each field in the node for i, off in enumerate(desc['ATTR_OFFS']): typ = desc[i]['TYPE'] - # check the forced endianness of the typ being serialized + # check the forced endianness of the typ being parsed # before trying to use the endianness of the struct - if f_endian == "=" and typ.f_endian == "=": - pass - elif typ.f_endian == ">": - typ = typ.big - elif typ.f_endian == "<" or f_endian == "<": - typ = typ.little - else: - typ = typ.big + endian = f_endian if typ.f_endian == "=" else typ.f_endian + typ = ( + typ if endian == "=" else + typ.little if endian == "<" else + typ.big + ) writebuffer.seek(struct_off + off) writebuffer.write(typ.struct_packer(__lgi__(node, i))) @@ -428,7 +427,6 @@ def stream_adapter_serializer(self, node, parent=None, attr_index=None, temp_buffer = BytearrayBuffer() orig_offset = offset desc = node.desc - align = desc.get('ALIGN') try: sub_desc = node.data.desc @@ -440,10 +438,12 @@ def stream_adapter_serializer(self, node, parent=None, attr_index=None, # If the pointer is a path to a previously parsed field, but this node # is being built without a parent(such as from an exported block) # then the path wont be valid. The current offset will be used instead. - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # write the sub_struct to the temp buffer sub_desc['TYPE'].serializer(node.data, node, 'SUB_STRUCT', @@ -477,18 +477,17 @@ def union_serializer(self, node, parent=None, attr_index=None, try: orig_offset = offset - desc = node.desc - align = desc.get('ALIGN') - - if attr_index is not None and desc.get('POINTER') is not None: - offset = node.get_meta('POINTER', **kwargs) - elif align: - offset += (align - (offset % align)) % align + desc = node.desc + align = desc.get('ALIGN') + offset = ( + offset + ((align - (offset%align))%align if align else 0) + if None in (attr_index, desc.get('POINTER')) else + node.get_meta('POINTER', **kwargs) + ) # if the u_node is not flushed to the UnionBlock, do it # before writing the UnionBlock to the writebuffer - if node.u_index is not None: - node.flush() + node.u_index is None or node.flush() # write the UnionBlock to the writebuffer writebuffer.seek(root_offset + offset) @@ -528,12 +527,13 @@ def data_serializer(self, node, parent=None, attr_index=None, """ """ node_bytes = self.encoder(node, parent, attr_index) - writebuffer.seek(root_offset + offset) - writebuffer.write(node_bytes) size = parent.get_size(attr_index, root_offset=root_offset, offset=offset, **kwargs) if size - len(node_bytes): - writebuffer.write(b'\x00'*(size - len(node_bytes))) + node_bytes += b'\x00'*(size - len(node_bytes)) + + writebuffer.seek(root_offset + offset) + writebuffer.write(node_bytes) return offset + size @@ -541,24 +541,18 @@ def cstring_serializer(self, node, parent=None, attr_index=None, writebuffer=None, root_offset=0, offset=0, **kwargs): """ """ - orig_offset = offset - p_desc = parent.desc - if p_desc['TYPE'].is_array: - desc = p_desc['SUB_STRUCT'] - else: - desc = p_desc[attr_index] - - if attr_index is not None: - if parent is not None: - # if the parent and attr_index arent - # None, pointers may need to be used - align = desc.get('ALIGN') - if desc.get('POINTER') is not None: - offset = parent.get_meta('POINTER', attr_index, **kwargs) - elif align: - offset += (align - (offset % align)) % align - elif align: - offset += (align - (offset % align)) % align + p_desc = parent.desc + desc = p_desc[ + 'SUB_STRUCT' if p_desc['TYPE'].is_array else attr_index + ] + # if the parent and attr_index arent + # None, pointers may need to be used + align = desc.get('ALIGN') + offset = ( + parent.get_meta('POINTER', attr_index, **kwargs) + if desc.get('POINTER') is not None else + offset + ((align - (offset%align))%align if align else 0) + ) node = self.encoder(node, parent, attr_index) writebuffer.seek(root_offset + offset) @@ -572,24 +566,17 @@ def py_array_serializer(self, node, parent=None, attr_index=None, writebuffer=None, root_offset=0, offset=0, **kwargs): """ """ - orig_offset = offset - p_desc = parent.desc - if p_desc['TYPE'].is_array: - desc = p_desc['SUB_STRUCT'] - else: - desc = p_desc[attr_index] - - if attr_index is not None: - if parent is not None: - # if the parent and attr_index arent - # None, pointers may need to be used - align = desc.get('ALIGN') - if desc.get('POINTER') is not None: - offset = parent.get_meta('POINTER', attr_index, **kwargs) - elif align: - offset += (align - (offset % align)) % align - elif align: - offset += (align - (offset % align)) % align + p_desc = parent.desc + desc = p_desc[ + 'SUB_STRUCT' if p_desc['TYPE'].is_array else attr_index + ] + # if the parent and attr_index arent None, pointers may need to be used + align = desc.get('ALIGN') + offset = ( + parent.get_meta('POINTER', attr_index, **kwargs) + if desc.get('POINTER') is not None else + offset + ((align - (offset%align))%align if align else 0) + ) writebuffer.seek(root_offset + offset) @@ -618,17 +605,12 @@ def bytes_serializer(self, node, parent=None, attr_index=None, writebuffer=None, root_offset=0, offset=0, **kwargs): """ """ - orig_offset = offset - - if parent and attr_index is not None: - p_desc = parent.desc - if p_desc['TYPE'].is_array: - desc = p_desc['SUB_STRUCT'] - else: - desc = p_desc[attr_index] - - if desc.get('POINTER') is not None: - offset = parent.get_meta('POINTER', attr_index, **kwargs) + p_desc = parent.desc + desc = p_desc[ + 'SUB_STRUCT' if p_desc['TYPE'].is_array else attr_index + ] + if desc.get('POINTER') is not None: + offset = parent.get_meta('POINTER', attr_index, **kwargs) writebuffer.seek(root_offset + offset) writebuffer.write(node) @@ -647,28 +629,26 @@ def bit_struct_serializer(self, node, parent=None, attr_index=None, try: data = 0 desc = node.desc - structsize = desc['SIZE'] + size = desc['SIZE'] # get a list of everything as unsigned # ints with their masks and offsets - for i in range(len(node)): + for i, subnode in enumerate(node): try: - bitint = node[i].desc[TYPE].encoder(node[i], node, i) + bitint = subnode.desc[TYPE].encoder(subnode, node, i) except AttributeError: - bitint = desc[i][TYPE].encoder(node[i], node, i) + bitint = desc[i][TYPE].encoder(subnode, node, i) # combine with the other data # 0=U_Int being written, 1=bit offset of U_Int, 2=U_Int mask - data += (bitint[0] & bitint[2]) << bitint[1] + data |= (bitint[0] & bitint[2]) << bitint[1] writebuffer.seek(root_offset + offset) + writebuffer.write(data.to_bytes( + size, ('little' if self.endian == '<' else 'big') + )) - if self.endian == '<': - writebuffer.write(data.to_bytes(structsize, 'little')) - else: - writebuffer.write(data.to_bytes(structsize, 'big')) - - return offset + structsize + return offset + size except (Exception, KeyboardInterrupt) as e: # if the error occurred while parsing something that doesnt have an # error report routine built into the function, do it for it. diff --git a/supyr_struct/util.py b/supyr_struct/util.py index 6a4016f..a1f703a 100644 --- a/supyr_struct/util.py +++ b/supyr_struct/util.py @@ -142,7 +142,8 @@ def desc_variant(desc, *replacements, verify=False, **kwargs): name = sub_desc.get('NAME', None) ftyp = sub_desc.get('TYPE') - # padding uses _ as its name, so if it's + # padding uses an underscore as its name, so + # we only match by name if it's not padding if name != "_": name_map[str_to_identifier(name)] = i elif not ftyp or ftyp.name != "Pad":