andreax79/python-cstruct

Feature request: Make cstruct iterable

Opened this issue · 1 comments

Hi,

Just a thing for the wishlist: I would like to be able to parse binary data into a cstruct, and then convert it to e.g. a json element.
Currently though, the cstruct class isn't iterable.

If that would be added, it would be possible to convert generic objects to e.g. json and back, which is a pretty interesting feature.

Kind regards,
Arnout

Well, I ended up implementing a new function in mem_cstruct.py:

    def get_dict(self, convert_bytes_to_string = False) -> dict:
        # Returns a dict and recursively parses more children
        retdict = {}
        for field, field_type in self.__fields_types__.items():
            child = getattr(self, field)
            if field_type.is_struct or field_type.is_union:
                child = getattr(self, field)
                if isinstance(child, list):
                    retdict[field] = []
                    for listelm in child:
                        # TODO: Can this be a list again, or will it always be a cstruct?
                        subchild = listelm.get_dict(convert_bytes_to_string)
                        retdict[field].append(subchild)
                else:
                    retdict[field] = getattr(self, field).get_dict(convert_bytes_to_string)
            else:
                if type(child) == bytes and convert_bytes_to_string:
                    child = child.decode('utf-8', errors='ignore').rstrip('\0')

                retdict[field] = child
        return retdict

    def update_from_dict(self, dict_in, convert_strings_to_bytes = False):
        # Iterate through the dict levels, and attempt to update the matching nodes.
        # Do this recursively
        for key in dict_in:
            value = dict_in[key]
            if isinstance(value, dict):
                # Recurse into child
                getattr(self, key).update_from_dict(value, convert_strings_to_bytes)
            elif isinstance(value, list):
                cstructlist = getattr(self, key)
                if isinstance(cstructlist, List):
                    for idx in range(0, len(value)):
                        # TODO: Assume never list in list
                        if isinstance(value[idx], dict):
                            cstructlist[idx].update_from_dict(value[idx], convert_strings_to_bytes)
                        else:
                            cstructlist[idx] = value[idx]
                else:
                    raise Exception("Wrong type mapping for list object")
            else:
                # Attempt to update the current node
                if convert_strings_to_bytes and isinstance(value, str):
                    value = value.encode('utf-8')
                setattr(self, key, value)

This returns a dictionary, which can then easily be converted into json later