private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress)
			throws DuplicateNameException, InvalidInputException {

		// TODO: 1. see if there is a mangled name that didn't get demangled at
		// TODO: 2 - refactor the three places that call this to just call getSymbolAt
		// and
		// in that method check for regular symbol and return or check for mangled
		// symbol that didn't get demangled then return or
		// check for this scenario where you need to get the string out

		Address typeinfoNameAddress = getTypeinfoNameAddress(typeinfoAddress);

		if (typeinfoNameAddress == null) {
			return null;
		}

		boolean existingString = false;

		// get defined string if defined already
		String mangledTypeinfoString = getDefinedStringAt(typeinfoNameAddress);
		if (mangledTypeinfoString != null) {
			existingString = true;
		}

		if (!existingString) {
			mangledTypeinfoString = getStringFromMemory(typeinfoNameAddress);
		}

		if (mangledTypeinfoString == null) {
			Msg.debug(this, "Could not get typeinfo string from " + typeinfoAddress.toString());
			return null;
		}

		String mangledLabel = mangledTypeinfoString;

		if (mangledLabel.startsWith("*")) {
			mangledLabel = mangledTypeinfoString.substring(1);
		}

		if (mangledLabel.startsWith(".rdata$")) {
			mangledLabel = mangledTypeinfoString.substring(7);
		}
		mangledLabel = "_ZTS" + mangledLabel;

		if (!isTypeinfoNameString(mangledLabel)) {
			return null;
		}

		if (!existingString) {
			boolean created = createString(typeinfoNameAddress, mangledTypeinfoString.length());
			if (!created) {
				Msg.debug(this, "Could not create string at " + typeinfoNameAddress);
			}
		}

		// create mangled label
		symbolTable.createLabel(typeinfoNameAddress, mangledLabel, globalNamespace,
			SourceType.ANALYSIS);

		// demangle the symbol to create demangled symbol
		DemanglerCmd cmd = new DemanglerCmd(typeinfoNameAddress, mangledLabel);
		cmd.applyTo(program, monitor);

		// get the newly created symbol to get the namespace
		Symbol typeinfoNameSymbol = symbolTable.getPrimarySymbol(typeinfoNameAddress);

		Namespace typeinfoNamespace = typeinfoNameSymbol.getParentNamespace();

		// need to account for rare case where there are more than one typeinfos with
		// exact same class and name so make two classes in this case - name second one
		// dupe#
		List<Symbol> symbols = symbolTable.getSymbols(typeinfoNameSymbol.getName(),
			typeinfoNamespace);
		if (symbols.size() > 1) {

			Namespace parentNamespace = typeinfoNamespace.getParentNamespace();
			Msg.debug(this, "Duplicate typeinfo namespace: " +
				typeinfoNamespace.toString());
			for (Symbol symbol : symbols) {
				Msg.debug(this, symbol.getAddress());
			}

			Namespace newNamespace = symbolTable.getOrCreateNameSpace(parentNamespace,
				typeinfoNamespace.getName() + "DUPE",
				SourceType.ANALYSIS);
			try {
				typeinfoNameSymbol.setNamespace(newNamespace);
			}
			catch (DuplicateNameException e) {
				return null;
			}
			catch (InvalidInputException e) {
				return null;
			}
			catch (CircularDependencyException e) {
				return null;
			}

		}

		Namespace classNamespace = typeinfoNameSymbol.getParentNamespace();

		if (classNamespace.isGlobal()) {
			Msg.debug(this, typeinfoAddress.toString() +
				"Could not create a class namespace for demangled namespace string ");
			return null;
		}

		// create the new typeinfo symbol in the demangled namespace
		Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
			SourceType.ANALYSIS);
		newSymbol.setPrimary();

		api.setPlateComment(typeinfoAddress, "typeinfo for " + classNamespace.getName(true));

		return newSymbol;
	}
Method to determine if the given address has one of the ClassTypeinfoDataType
types applied

@param address the given address
@return true if already has a class data type applied or false if not
Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java