public static MDTypeInfo parse(MDMang dmang, int rttiNum) throws MDException {
		MDTypeInfo typeInfo;
		boolean isBased = false;
		if (dmang.peek() == '_') {
			isBased = true;
			dmang.increment();
		}
		char code = dmang.peek();
		switch (code) {
			case '$': // Special Handling Function:
				dmang.increment();
				typeInfo = parseSpecialHandlingFunction(dmang, rttiNum);
				break;
			case '0':
				dmang.increment();
				typeInfo = new MDVariableInfo(dmang);
				typeInfo.setPrivate();
				typeInfo.setStatic();
				break;
			case '1':
				dmang.increment();
				typeInfo = new MDVariableInfo(dmang);
				typeInfo.setProtected();
				typeInfo.setStatic();
				break;
			case '2':
				dmang.increment();
				typeInfo = new MDVariableInfo(dmang);
				typeInfo.setPublic();
				typeInfo.setStatic();
				break;
			case '3': // Believe this to be "global" data
				dmang.increment();
				typeInfo = new MDVariableInfo(dmang);
				break;
			case '4': // Believe this to be "static local" data
				dmang.increment();
				typeInfo = new MDVariableInfo(dmang);
				break;
			case '5': // Believe this to be "guard" data.
				dmang.increment();
				typeInfo = new MDGuard(dmang);
				break;
			case '6':
				// 20180403: Figured out that this could be a VFTable or an RTTI4; the other
				//  RTTI will show up as case'8'.
				dmang.increment();
				if (rttiNum == 4) {
					typeInfo = new MDRTTI4(dmang);
				}
				else { //should be -1
					typeInfo = new MDVFTable(dmang);
				}
				break;
			case '7':
				// Found on 20140327:
				// "??_7testAccessLevel@@6B@" = "const testAccessLevel::`vftable'"
				// Found on 20140521 (Win7):
				// "??_7CAnalogAudioStream@@6BCUnknown@@CKsSupport@@@", discovered
				// nesting
				// isData = true; //TODO: this is actually data, but not sure of our
				// downstream processing based on this flag. Fix somehow.
				dmang.increment();
				typeInfo = new MDVBTable(dmang);
				break;
			case '8':
				// All but the RTTI except RTT4 seem to show up here
				//  under case '8'; RTTI4 is co-mingled under case '6' with VFTable.
				// TODO: UINFO: metatype (we had isVBTable = true, but I now believe
				// that
				// is wrong).
				// isData = true; //TODO: this is actually data, but not sure of our
				// downstream processing based on this flag. Fix somehow.
				dmang.increment();
				switch (rttiNum) {
					case 0:
						typeInfo = new MDRTTI0(dmang);
						break;
					case 1:
						typeInfo = new MDRTTI1(dmang);
						break;
					case 2:
						typeInfo = new MDRTTI2(dmang);
						break;
					case 3:
						typeInfo = new MDRTTI3(dmang);
						break;
					default: //4 (shouldn't happen) and -1
						typeInfo = new MDTypeInfo(dmang);
						break;
				}
				break;
			case '9': // Believe this to be vcall.
				// dmang.parseInfoPush(1, "VCall access???");
				dmang.increment();
				typeInfo = new MDTypeInfo(dmang);
				// TODO: Not sure if the following are used or not
				// isMember = false; //no reason to have set true
				// hasReturn = false; //no reason to have set true
				// hasArgs = false; //no reason to have set true
				// dmang.parseInfoPop();
				break;
			case 'A': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment
			case 'B':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPrivate();
				// When considering code 'A' to be at index 0, then for this and other processing
				// below, those that have an *even* index are *near* pointers and those with
				// an *odd* index are *far* pointers
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'C':
			case 'D':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPrivate();
				typeInfo.setStatic();
				break;
			case 'E':
			case 'F':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPrivate();
				typeInfo.setVirtual();
				break;
			case 'G':
			case 'H':
				dmang.increment();
				typeInfo = new MDVFAdjustor(dmang);
				typeInfo.setPrivate();
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'I': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment
			case 'J':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setProtected();
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'K':
			case 'L':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setProtected();
				typeInfo.setStatic();
				break;
			case 'M':
			case 'N':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setProtected();
				typeInfo.setVirtual();
				break;
			case 'O':
			case 'P':
				dmang.increment();
				typeInfo = new MDVFAdjustor(dmang);
				typeInfo.setProtected();
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'Q': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment
			case 'R':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPublic();
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'S':
			case 'T':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPublic();
				typeInfo.setStatic();
				break;
			case 'U':
			case 'V':
				dmang.increment();
				typeInfo = new MDMemberFunctionInfo(dmang);
				typeInfo.setPublic();
				typeInfo.setVirtual();
				break;
			case 'W':
			case 'X':
				dmang.increment();
				typeInfo = new MDVFAdjustor(dmang);
				typeInfo.setPublic();
				typeInfo.setPointerFormat(
					((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
				break;
			case 'Y':
			case 'Z':
				// These are non-member functions
				dmang.increment();
				typeInfo = new MDFunctionInfo(dmang);
				typeInfo.setNonMember();
				break;
			default: // TODO: Any missing cases?
				// MDMANG SPECIALIZATION USED.
				if (dmang.allowMDTypeInfoParserDefault()) {
					// Partial hack: location of these push/pop method calls.
					// dmang.parseInfoPush(0, "(no access)");
					// No getAndIncrement() here
					// TODO: See if I can eliminate this temporary initialization.
					typeInfo = new MDTypeInfo(dmang);
					// dmang.parseInfoPop();
					break;
				}
				throw new MDException("Invalid MDTypeInfo, unknown case: " + code);
		}
		if (isBased && (typeInfo instanceof MDFunctionInfo)) {
			MDBasedAttribute based = new MDBasedAttribute(dmang);
			based.parse();
			((MDFunctionInfo) typeInfo).setBased(based);
		}
		return typeInfo;
	}
This method parses the data sequence to determine the appropriate MDTypeInfo
 to continue parsing.  The method can be recursive, so rttiNum is passed into
 the recursion.
@param dmang The MDMang demangler control.
@param rttiNum The RTTI number currently seen in the processing (-1 if none)
@return The MDTypeInfo created for the data sequence being parsed.
@throws MDException For a host of data-driven parsing reasons.
Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfoParser.java