def ConvTypeToStr(t): """Gets a string name and size information for a type. Args: t: The type object. Returns: (name, length, dimensions): name: String name of the type. length: Number of elements in the type (1 if not an array). dim: Number of dimensions of the type. Raises: ValueError: The provided type is not recognized. """ cc_str, ul_str = ConvTypeToStrHelper(t) if use_underlines: cc_str = ul_str if cc_str is not None: return cc_str, 1, 0 elif isinstance(t, type(ctypes.Structure)): if t._typedef_: return autogen_util.CStructName(t), 1, 0 else: return 'struct ' + autogen_util.CStructName(t), 1, 0 elif isinstance(t, type(ctypes.Array)): s, l, dim = ConvTypeToStr(t()._type_) return s, len(t()) * l, dim + 1 raise ValueError('Unknown type: %s' % t)
def Pack(message): """Return a packed representation of the message. Args: message: Message to unpack. Returns: Byte array (as c_ubyte_Array_N, where N is the packed size) containing the packed message. Returns None if packing was unsuccessful. """ # TODO: Make AioClient selective about sending raw bytes, and then # make Pack() raise an exception if the message doesn't live in a pack module. pack_module = _GetPackModule(type(message).__module__) if not pack_module: return class_name = autogen_util.CStructName(type(message)) try: pack_class = getattr(pack_module, class_name) pack_function = getattr(pack_module, 'Pack' + class_name) pack_size = getattr(pack_module, 'PACK_' + class_name.upper() + '_SIZE') except AttributeError: return # The pack function expects a reference to the message type defined in its own # module. This constructs an appropriate object using the same memory # underlying the original message. if not isinstance(message, pack_class): message = pack_class.from_buffer(message) packed = (ctypes.c_uint8 * pack_size)() assert pack_function(ctypes.byref(message), 1, packed) return packed
def _GetTypeInfo(t): """Return information about a type. Args: t: A type. Returns: A tuple of three elements. The first element is the type name, the second entry is a string for the type of pointer that represents this object (e.g. "double" for both Array1D_double and Array2D_double and "char" for String), and the third element is a list of dimensions indicating the length of strings and arrays. Raises: TypeError: A type was passed in which this function cannot handle. """ ctype_to_str_dict = { ctypes.c_bool: ('Boolean', 'bool'), ctypes.c_double: ('Double', 'double'), ctypes.c_float: ('Float', 'float'), ctypes.c_int8: ('Int8', 'int8_t'), ctypes.c_int16: ('Int16', 'int16_t'), ctypes.c_int32: ('Int32', 'int32_t'), ctypes.c_int64: ('Int64', 'int64_t'), ctypes.c_uint8: ('UInt8', 'uint8_t'), ctypes.c_uint16: ('UInt16', 'uint16_t'), ctypes.c_uint32: ('UInt32', 'uint32_t'), ctypes.c_uint64: ('UInt64', 'uint64_t'), } if _IsStringType(t): return ('String', 'char', [_ArrayCTypeLength(t)]) elif _IsArrayType(t): (scalar_type, dim) = _GetArrayTypeInfo(t) (scalar_type_name, scalar_ptr_name, scalar_dim) = _GetTypeInfo(scalar_type) return ('Array%dD_%s' % (len(dim), scalar_type_name), scalar_ptr_name, dim + scalar_dim) elif _IsStructType(t): return ('Struct_' + autogen_util.CStructName(t), autogen_util.CStructName(t), []) elif _IsFundamentalType(t) and t in ctype_to_str_dict: names = ctype_to_str_dict[t] return (names[0], names[1], []) else: raise TypeError('Unknown type: %s.' % str(t))
def PackSize(message_type): pack_module = _GetPackModule(message_type.__module__) if not pack_module: return class_name = autogen_util.CStructName(message_type) try: return getattr(pack_module, 'PACK_' + class_name.upper() + '_SIZE') except AttributeError: return
def Unpack(packed, message_type): """Unpack a packed message. Args: packed: Packed message data in a (ctypes.c_uint8 * N), where N is the pack size, or a string of the same length. message_type: Class of the unpacked message. Returns: An instance of type `message_type` populated with the packed data, or None if the unpacking was unsuccessful. Raises: UnpackError: `packed` is of the wrong type. """ pack_module = _GetPackModule(message_type.__module__) if not pack_module: return class_name = autogen_util.CStructName(message_type) try: pack_class = getattr(pack_module, class_name) unpack_function = getattr(pack_module, 'Unpack' + class_name) pack_size = getattr(pack_module, 'PACK_' + class_name.upper() + '_SIZE') except AttributeError: return buffer_type = ctypes.c_uint8 * pack_size if isinstance(packed, str) and len(packed) == pack_size: packed = buffer_type.from_buffer_copy(packed) if not isinstance(packed, buffer_type): raise UnpackError('Packed message must be of type %s or a string of the ' 'same length. Actual type is %s.' % (buffer_type.__name__, type(packed))) # The pack function expects a reference to the message type defined in its own # module. message = pack_class() assert unpack_function(packed, 1, ctypes.byref(message)) == pack_size if pack_class() != message_type: message = message_type.from_buffer(message) return message
def GatherStructs(header, xml_file, python_file): """Returns Python structures necessary to build structs in header file. Args: header: Path to header file. xml_file: Path to XML file. python_file: Path to Python file. Returns: 3-tuple consisting of: parent_structs: Top-level structs needing pack functions. child_structs: Structs on which parent_structs depend. child_ctypes: ctype classes for child_structs. """ def IsTypedefStruct(t): """Tells whether the struct is typedef'd. E.g. typedef struct {} a; versus struct a {}; Args: t: The struct translated from C. Returns: True if the struct is typedef'ed. """ return t.__name__.startswith('struct_') def RootTypeElmt(type_id, by_id): """Find the element that defines the base type. The root type is one that is not derived as a typedef or array. Args: type_id: ID of the XML Dom that defines a type. by_id: <key, value> dictionary of XML Dom ID and the Dom element. Returns: The XML Dom element that defines the root type. """ while True: if type_id is None or type_id not in by_id: return None elmt = by_id[type_id] if elmt.tag == 'Typedef': type_id = elmt.attrib.get('type', None) elif elmt.tag == 'ArrayType': type_id = elmt.attrib.get('type', None) else: return elmt global use_underlines # pylint: disable=W0603 xml_elmts = ElementTree.parse(xml_file).getroot() file_ids = [elmt.attrib['id'] for elmt in xml_elmts if (elmt.tag == 'File' and os.path.realpath(elmt.attrib['name']).endswith(header))] assert len(file_ids) == 1 local_structs = {elmt.attrib['id']: elmt for elmt in xml_elmts if (elmt.tag == 'Struct' and elmt.attrib['file'] == file_ids[0])} by_id = {elmt.attrib['id']: elmt for elmt in xml_elmts if elmt.attrib.get('id', None)} all_structs = {elmt.attrib['id']: elmt for elmt in xml_elmts if elmt.tag == 'Struct'} struct_names = collections.defaultdict(list) # The same struct can have multiple names. sid_by_name = {} for sid, elmt in all_structs.iteritems(): if elmt.attrib.get('name', None): struct_names[sid].append(elmt.attrib['name']) sid_by_name[elmt.attrib['name']] = sid typedef_structs = [] for root_id, elmt in by_id.iteritems(): if elmt.tag == 'Typedef': name = elmt.attrib['name'] child_id = root_id while child_id in by_id and by_id[child_id].tag == 'Typedef': child_id = by_id[child_id].attrib['type'] if child_id in by_id and by_id[child_id].tag == 'Struct': typedef_structs.append(name) struct_names[child_id].append(name) sid_by_name[name] = child_id if all([not IsCamelCase(s) for s in typedef_structs] + [not IsCamelCase(s.attrib['name']) for s in local_structs.itervalues() if s.attrib.get('name', None)]): use_underlines = True mod = imp.load_source('tmp', python_file) child_strs = [] ctype_strs = [] for sid in local_structs.iterkeys(): s = struct_names[sid][0] slst, clst = FindChildTypes(getattr(mod, s)) child_strs += slst ctype_strs += clst parent_structs = set([ getattr(mod, struct_names[sid][0]) for sid in local_structs.iterkeys()]) child_structs = set([getattr(mod, s) for s in child_strs]) child_structs.difference_update(parent_structs) child_ctypes = set([getattr(ctypes, s) for s in ctype_strs]) # Sort lists to generate exactly the same code for each execution. child_ctypes = sorted(child_ctypes, key=str) # Adds a _typedef_ field that records whether the struct is a # typedef'd struct or not. (e.g. typedef struct {} a; versus # struct a {};) for s in parent_structs | child_structs: s._typedef_ = IsTypedefStruct(s) # Add struct typedefs as an _aliases_ field. for s in parent_structs | child_structs: for typedef in typedef_structs: if not getattr(mod, typedef, None): continue if s == getattr(mod, typedef) and typedef != s.__name__: if not hasattr(s, '_aliases_'): s._aliases_ = [] s._aliases_.append(typedef) for s in parent_structs | child_structs: if hasattr(s, '_aliases_'): s._aliases_.sort() # Add an _enums_ field to list fields in a struct which are enums. enum_types = set() for s in parent_structs | child_structs: s._enums_ = {} struct_name = autogen_util.CStructName(s) if struct_name not in sid_by_name: continue for field_id in all_structs[ sid_by_name[struct_name]].attrib['members'].split(): if field_id in by_id and by_id[field_id].tag == 'Field': name = by_id[field_id].attrib['name'] base_type = RootTypeElmt(by_id[field_id].attrib['type'], by_id) if base_type.tag == 'Enumeration': enum_type = base_type.attrib['name'] s._enums_[name] = enum_type enum_types.add(enum_type) # Sort the returned lists in a deterministic order for a definite CRC. enum_types = sorted(enum_types) return parent_structs, child_structs, child_ctypes, enum_types
def WriteDefinePackedSize(f, s, name=None): if not name: name = autogen_util.CStructName(s) size = GetTypePackedSize(s) f.write('\n#define PACK_%s_SIZE %d' % (str.upper(name), size))