def createEnumeration(self, element):
        """
        Convert CastXML XML element into a Ghidra EnumDataType.
        
        Args:
            element (ElementTree): XML element
            
        Returns (EnumDataType): Ghidra EnumDataType
        """
        enumName = element.attrib['name']
        if enumName == "":
            enumName = "anon_enum" + element.attrib['id']

        print("Enum: {0}".format(enumName))

        enumBitSize = int(element.attrib['size'])
        enumByteSize = enumBitSize / 8

        filePath = self.getFileFromId(element.attrib['file'])
        categoryPath = self.getCategoryPathFromFile(filePath)

        enumDataType = EnumDataType(categoryPath, enumName, enumByteSize)
        for enumValue in element:
            name = enumValue.attrib['name']
            bitSize = int(element.attrib['size'])
            init = int(enumValue.attrib['init'])

            #print("{0} = {1}".format(name, init))

            # Convert to signed integer as Java cannot coerce large unsigned numbers
            init = init & ((1 << bitSize) - 1)
            init = init | (-(init & (1 << (bitSize - 1))))

            enumDataType.add(name, init)

        self.recordTypeForId(element.attrib['id'], enumDataType)

        return enumDataType
    0x21: "Global Common symbol",
    0x40: "Local Symbols",
    0x41: "Global Symbols"
}

# Init data type
ptr_data_type = PointerDataType()
byte_data_type = ByteDataType()
char_data_type = CharDataType()
void_data_type = VoidDataType()
unsigned_int_type = UnsignedIntegerDataType()
short_data_type = ShortDataType()
char_ptr_type = ptr_data_type.getPointer(char_data_type, 4)
void_ptr_type = ptr_data_type.getPointer(void_data_type, 4)
# Prepare VxWorks symbol types
vx_5_sym_enum = EnumDataType("Vx5symType", 1)
for flag in vx_5_symbol_type_enum:
    vx_5_sym_enum.add(vx_5_symbol_type_enum[flag], flag)
vx_6_sym_enum = EnumDataType("Vx6symType", 1)
for flag in vx_6_symbol_type_enum:
    vx_6_sym_enum.add(vx_6_symbol_type_enum[flag], flag)

# Init VxWorks symbol table structs
vx_5_symtbl_dt = StructureDataType("VX_5_SYMBOL_IN_TBL", 0x10)
vx_5_symtbl_dt.replaceAtOffset(0, unsigned_int_type, 4, "symHashNode", "")
vx_5_symtbl_dt.replaceAtOffset(4, char_ptr_type, 4, "symNamePtr", "")
vx_5_symtbl_dt.replaceAtOffset(8, void_ptr_type, 4, "symPrt", "")
vx_5_symtbl_dt.replaceAtOffset(0x0c, short_data_type, 4, "symGroup", "")
vx_5_symtbl_dt.replaceAtOffset(0x0e, vx_5_sym_enum, 1, "symType", "")
vx_5_symtbl_dt.replaceAtOffset(0x0f, byte_data_type, 1, "End", "")
            accu = (tmp + accu * 0x1003f) % 2**32
        hash = accu ^ xor_value
        libs.update({hash: dll_name})


def get_lib(hash):
    dll_name = libs.get(hash)
    if dll_name is None:
        print "ERROR: Could not find dll name for hash " + str(hash)
        return "Unknown"
    return dll_name


init_libs(currentAddress)

enum = EnumDataType('emotet_lib_hash', 4)
for lib in libs:
    enum.add(libs[lib], lib)
dtm = currentProgram.getDataTypeManager()
dtm.addDataType(enum, None)

refs = getReferencesTo(currentAddress)

for r in refs:
    callee = r.getFromAddress()
    inst = inst_ = getInstructionAt(callee)
    i = 0
    # TODO: use pcode and reaching definition
    while not inst.toString().startswith('MOV ECX,0x'):
        inst = getInstructionBefore(inst)
        i += 1
def syncEnums():
    if not enumNames:
        scanEnums()

    # sync all the stuff up
    n = 0
    for key, enum in enumInfo.iteritems():
        if key not in enumTypeMap:
            if isEnumSafe(enum['choices']):
                # gotta throw this one in!
                name = 'Enum' + key
                dt = EnumDataType(enumCatPath, name, 4, dtManager)
                dt.description = 'hash ' + key
                for i, choice in enumerate(enum['choices']):
                    try:
                        dt.add(choice, i)
                    except:
                        dt.add(choice + ('__%d'%i), i)
                dtManager.addDataType(dt, handler)
                enumTypeMap[key] = dt
                enumNames[key] = name
            else:
                print('{} is not safe'.format(enum))

        if key in enumTypeMap and 'needsU16Variant' in enum:
            name = enumNames[key] + '_u16'
            if key not in enumTypeMapU16:
                dt = EnumDataType(enumCatPath, name, 2, dtManager)
                dt.description = 'hashU16 ' + key
                for i, choice in enumerate(enum['choices']):
                    try:
                        dt.add(choice, i)
                    except:
                        dt.add(choice + ('__%d'%i), i)
                dtManager.addDataType(dt, handler)
                enumTypeMapU16[key] = dt
            else:
                if enumTypeMapU16[key].name != name:
                    enumTypeMapU16[key].name = name


        # poke the enum's text array
        for i, addrValue in enumerate(enum['locations']):
            addr = toAddr(addrValue)
            sym = getSymbolAt(addr)

            # is there a name we can pull, for data-type-less enums?
            if key not in enumNames and not sym.dynamic and sym.parentNamespace == enumNS:
                enumNames[key] = sym.name
            # if not, make sure we have one
            if key not in enumNames:
                enumNames[key] = 'Enum' + key

            # either way, give this enum the name it needs
            nameToUse = enumNames[key]
            if i > 0:
                nameToUse += '_%d' % i
            if sym.parentNamespace != enumNS or sym.name != nameToUse:
                sym.setNameAndNamespace(nameToUse, enumNS, SourceType.DEFAULT)

        # poke the enum's getters
        for i, addrValue in enumerate(enum['getters']):
            addr = toAddr(addrValue)
            sym = getSymbolAt(addr)
            fn = getFunctionAt(addr)

            # it's easier here, as we've already picked a canonical name
            nameToUse = enumNames[key]
            if nameToUse.startswith('e'):
                nameToUse = nameToUse[1:]
            nameToUse = 'get' + nameToUse
            if sym.name != nameToUse:
                sym.setNameAndNamespace(nameToUse, enumNS, SourceType.DEFAULT)

            # give the function the correct signature too
            if fn.returnType.name == 'undefined':
                fn.setReturnType(charPtrPtrDT, SourceType.DEFAULT)
                fn.setCallingConvention('__cdecl')

        n += 1
			tmp = ord(c)
			accu = (tmp + accu * 0x1003f)%2**32;
		hash = accu ^ xor_value
		funcs.update({hash:func_name})


def get_func(hash):
	func_name = funcs.get(hash)
	if func_name is None:
		print "ERROR: Could not find function name for hash " + hex(hash)
		return "Unknown"
	return func_name

init_funcs(currentAddress)

enum = EnumDataType('emotet_func_hash',4)
for func in funcs:
	enum.add(funcs[func], func)
dtm = currentProgram.getDataTypeManager()
dtm.addDataType(enum,None)

refs = getReferencesTo(currentAddress)

for r in refs:
	callee = r.getFromAddress()
	inst = inst_ = getInstructionAt(callee)
	i = 0
	# TODO: use pcode and reaching definition
	while not inst.toString().startswith('MOV EDX,0x'):
		inst = getInstructionBefore(inst)
		i += 1