def _create_entry(self, field): """ Look at self.parse for full documentation. This looks at <subfield> fields of the <field> to create the union entries. """ xml_subfields = field.findall('subfield') xml_subfields.append( field) #Weird, but true. <value> can be in <field> too. name = get_name(field) field_name = trim_name(name) field_bits = field.get('num_bits', -1) try: int(field_bits) except Exception: logging.error('%s failed to parse bits to int: %s' % (name, field_bits)) return None enum_instance = None result = [] for xml_subfield in xml_subfields: xml_values = xml_subfield.findall('value') if xml_values is None or len( xml_values) == 0: # No value - not an enum continue if xml_subfield != field: subfield_name: str = get_name(xml_subfield) subfield_name = trim_name(subfield_name) else: subfield_name = '' inst_name = 'genz_%s_%s' % (field_name, subfield_name) #empty subfield_name produces trailing '_'. Thus - clean it up. inst_name = inst_name.strip('_') enum_instance = fields.CEnumEntry(inst_name, origin=xml_subfield, parent=field) for xml_value in xml_values: entry_name = get_name(xml_value) entry_name = trim_name(entry_name) if entry_name == 'reserved': continue entry_name = '%s_%s_%s' % (field_name, subfield_name, entry_name) entry_name = trim_name(entry_name) entry_name = entry_name.upper() val = xml_value.get('val', -1) entry = fields.EStateEntry(entry_name, val) entry.origin = field enum_instance.append(entry) self._instance.append(enum_instance) result.append(enum_instance) return result
def parse(self, root): """ In the Root - find <array> element and parse it by the rules of a regular <struct> entry. """ arrays = root.findall('array') if len(arrays) == 0: return if self._instance is None: self._instance = [] for array in arrays: if self.elements_type is None: self.elements_type = array.get('elements') elements = array.findall('element') if elements is None or len(elements) == 0: logging.warning('Empty array in the table "%s"' % root.get('name', 'unknown')) continue for element in elements: name_to_set = get_name(root) # if not name_to_set.lower().endswith('array'): name_to_set = '%s Array' % name_to_set element.set('name', name_to_set) cgen = CGenerator.CGenerator(root, parse_on_init=False, name='table: %s' % name_to_set) cgen.struct_tag_name = 'element' cgen.parse_xml(array) self._instance.append(cgen)
def _get_longest_name_length(self, root): """ Used for plain silly prettification for the array entries. Helps to align the condensed names in a one column for better readability. """ value = -1 for class_elem in root: raw_name = get_name(class_elem) if len(raw_name) > value: value = len(raw_name) return value
def _create_entry(self, field): """ Look at self.parse for full documentation. This looks at <subfield> fields of the <field> to create the union entries. @param field: xml field to extract <subfield> from. @return: CSubunion instance with all the added entries. Or None if failed. """ xml_subfields = field.findall('subfield') name = get_name(field) field_name = trim_name(name) field_bits = field.get('num_bits', -1) try: int(field_bits) except Exception: logging.error('%s failed to parse bits to int: %s' % (name, field_bits)) return union_instance = None for xml_subfield in xml_subfields: subfield_name: str = get_name(xml_subfield) subfield_name = trim_name(subfield_name) if xml_subfield.find('value') is not None: continue if union_instance is None: union_instance = fields.CSubunion('genz_%s' % field_name, field_bits) sub_bits = xml_subfield.get('num_bits', -1) union_instance.add(subfield_name, sub_bits, field_bits) return union_instance
def parse(self, root): """ Generate a struct array of "meta" structs describing a Class. Refere to "struct_meta" property for documentation on the meta values. @param root: xml root tree to start parsing from. """ if root is None: return if self._instance is None: self._instance = fields.CArrayEntry(self.name, 'struct %s' % self.struct_name) list_of_names = [] longest_name_length = self._get_longest_name_length(root) for class_elem in root: raw_name = get_name(class_elem) trimmed_name = raw_name.lower().split('(')[0].strip() name = trim_name(trimmed_name, replaceable=' —[:](),=.\n', removable='\'|!<>@#$%^&*+–’-/') if 'switch' in name: name = 'switch' if 'bridge' in trimmed_name: name = 'bridge' if name not in list_of_names: list_of_names.append(name) enum_index = len(self.enum.entries) estate = fields.EStateEntry('GENZ_%s' % name.upper(), enum_index) spaces = ' ' * (longest_name_length - len(raw_name)) # { raw_name, condenced_name, condenced_enum_value } name = '"%s", %s"%s", %s' % (raw_name, spaces, name, estate.name) struct_entry = fields.CStructEntry(name, ignore_long_name_warning=True) struct_entry.l_space = '%s { ' % struct_entry.l_space struct_entry.str_close_symbol = ' },' self._instance.append(struct_entry) self.enum.append(estate) last_state = fields.EStateEntry('GENZ_NUM_HARDWARE_TYPES', None) self.enum.append(last_state) return self.instance
def parse(self, root=None): """ @param root: xml root tree to start parsing from. """ root_name = get_name(root) arrays = root.findall('array') if len(arrays) > 1: logging.warn('More than one <array> in "%s"... not bad, but not good either.' % root_name) #use indexed loop to asign index to the name when(if) more than one array for index in range(len(arrays)): array_xml = arrays[index] elements = array_xml.findall('element') array_offset = array_xml.get('offset', -1) if len(elements) > 1: logging.warn('More than one <element> in "%s" with "%s" array offset... only first will get parsed.' % (root_name, array_offset)) if len(elements) == 0: logging.warn('No <element> in array of "%s"! Skipping...' % root_name) continue
def _create_entry(self, field, p_value): """ TODO @param field @param entry_name <str>: name of the pointer (not the Type name). @param type_name <str>: entry type name. @return: created/parsed entry on success. None - nothing happened. """ field_name = get_name(field) field_name = trim_name(field_name) field_num_bits = field.get('num_bits') ptr_to = field.get('ptr_to', None) if ptr_to is None: return None try: field_min_bits = int(field.get('min_bit')) except ValueError: # in a perfect world - this should never happened. logging.warning('Field %s min_bits is not int?' % field_name) field_min_bits = -1 p_size = '4' if field_num_bits == '32' else '6' if field_min_bits > 0: try: p_value = int((field_min_bits / 8) + int(p_value, 0)) p_value = hex(p_value) except ValueError: p_value = '-1' pointer_entry = fields.CPointerEntry(field_name, p_size, p_value, ptr_to=ptr_to) pointer_entry.origin = field pointer_entry.parent = self.root return pointer_entry
def build_struct_instance(self, field): """ TODO """ if not isinstance(field, str): name = get_name(field) else: name = field name = trim_name(name) struct = fields.CStruct('genz_%s' % name, origin=field) struct.vers = field.get('vers', None) struct.index = field.get('type', -1) # struct.tag = self.root.tag length_comment = is_name_too_long(struct.name) if length_comment: struct.open_bracket = '%s %s' % (struct.open_bracket, length_comment) return struct
def parse(self, root): struct_name = get_name(root) struct_name = trim_name(struct_name) entry_name = '%s_ptrs' % struct_name if self._instance is None: self._instance = fields.CArrayEntry(entry_name, self.type_name) self._instance.parent = self.root offsets = root.findall('offset') for offset in offsets: p_value = offset.get('value', -1) for field in offset.findall('field'): if field.get('ptr_to', None) is None: continue entry = self._create_entry(field=field, p_value=p_value) if entry is not None: self._instance.append(entry) if len(self._instance.entries) == 0: self._instance = None
def create_entry(self, field, bits): """ @param field: the xml field to create a struct entry from. @param bits: the 'num_bits' attr of the <offset> field (e.g. parent of field). """ if field is None: logging.error('Failed parsing field (is None)! Root: %s' % self.root) return s_entry = None name = get_name(field) field_name = trim_name(name) # If a field has <value> entries - it is an Enum, not a struct entry. if (len(field.findall('value')) > 0): logging.info('A "%s" field is an Enum...' % field_name) if (len(field.findall('subfield')) > 0): msg = 'Both <value> and <subfield> in the "%s" field!' msg += ' What is it? Struct entry or Enum?' logging.error(msg % (field_name)) return props = field.attrib is_no_name = False if name is None: name = str(field.attrib) is_no_name = True if props.get('offset_bits', None) is None: props['offset_bits'] = bits var_type = None bitfield = props['num_bits'] if 'uuid' in field_name and not field_name.endswith('ptr'): base_bit = props.get('base_bit', None) if base_bit is not None: # ignore second half of split uuid return field_name = uuid_re.sub('', field_name) var_type = 'uuid_t' bitfield = -1 s_entry = fields.CStructEntry(name=field_name, num_type=props['offset_bits'], bitfield=bitfield, var_type=var_type) s_entry.origin = field s_entry.parent = self.root if is_no_name: s_entry.str_start = '//' s_entry.str_end = ' //FIXME: entry had no name' #FIXME: we are ignoring ... entries for now, but will be fixed later if s_entry.name == '...': s_entry.str_start = '//' s_entry.str_end = ' //FIXME: name "..." entry' #FIXME: write this to a file, but comment it out to know which entries # we can't parse. if s_entry.bitfield == 0 or s_entry.num_type == 0: s_entry.str_start = '//' s_entry.str_end = ' //FIXME: 0 bits.' return s_entry if name.lower() == 'unknown': s_entry.str_start = '//' s_entry.str_end = ' //FIXME: UNKNOWN in name' if 'rsvd' in name.lower(): s_entry.str_start = '//' s_entry.str_end = ' //FIXME: skipping rsvd(X) fields for now' s_entry = self.split_entry(s_entry) return s_entry