protected Structure addClassVftables(Structure classStructureDataType,
			RecoveredClass recoveredClass, Map<Address, DataType> vfPointerDataTypes)
			throws CancelledException, IllegalArgumentException {

		Map<Integer, Address> classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap();
		Set<Integer> classVftableOffsets = classOffsetToVftableMap.keySet();

		if (vfPointerDataTypes == null || classVftableOffsets.isEmpty()) {
			return classStructureDataType;
		}

		// If the map is not complete, the class structure will contain incomplete information so
		// put out a debug message to indicate this issue
		if (!isClassOffsetToVftableMapComplete(recoveredClass)) {
			Msg.debug(this,
				"class vftable offset map for " + recoveredClass.getName() + " is not complete");
		}

		// iterate over the set of offsets to vftables and either add to undefined area or overwrite
		// the parent class structures with the class vftable pointer then replace the rest of the
		// parent structure with its internal components
		for (Integer offset : classVftableOffsets) {
			monitor.checkCancelled();

			Address vftableAddress = classOffsetToVftableMap.get(offset);

			int vftableOffset = offset.intValue();

			DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);

			if (classVftablePointer == null) {
				continue;
			}

			// loop until the vftable pointer is added
			// if there is room and the component offset is not a structure, replace with vftablePtr
			// otherwise, within the range from top of containing component to the end of where the
			// vftable it to replace, clear component(s) or replace structure(s) with internal
			// components and loop until can replace with the vftable pointer
			while (true) {

				monitor.checkCancelled();

				// if enough empty bytes or can grow the structure - add class vftable pointer
				boolean addedToStructure =
					EditStructureUtils.addDataTypeToStructure(classStructureDataType, vftableOffset,
						classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
				if (addedToStructure) {
					break;
				}

				// if the component at the offset is the start of the component, and the component
				// isn't a structure and if the component is big enough to be replaced, or there
				// are enough undefined that can be replaced then replace
				DataTypeComponent componentAt =
					classStructureDataType.getComponentAt(vftableOffset);

				if (componentAt != null && !(componentAt.getDataType() instanceof Structure) &&
					(componentAt.getLength() >= classVftablePointer.getLength() ||
						EditStructureUtils.hasEnoughUndefinedsOfAnyLengthAtOffset(
							classStructureDataType, vftableOffset, classVftablePointer.getLength(),
							monitor))) {

					EditStructureUtils.clearLengthAtOffset(classStructureDataType, vftableOffset,
						classVftablePointer.getLength(), monitor);
					classStructureDataType.replaceAtOffset(vftableOffset, classVftablePointer,
						classVftablePointer.getLength(), CLASS_VTABLE_PTR_FIELD_EXT, "");
					break;
				}

				// otherwise if in middle of a containing dt then loop until all structs in
				// range are expanded and other items are cleared
				DataTypeComponent currentComponent =
					classStructureDataType.getComponentContaining(vftableOffset);

				int currentOffset = currentComponent.getOffset();
				int endOffset = vftableOffset + classVftablePointer.getLength();
				while (currentComponent != null && currentOffset < endOffset) {

					int nextOffset = currentComponent.getEndOffset() + 1;
					// if there is a structure at the offset, replace it with its pieces
					if (currentComponent.getDataType() instanceof Structure) {
						DataType currentDT = currentComponent.getDataType();
						Structure internalStruct = (Structure) currentDT;
						expandInternalStructure(classStructureDataType, internalStruct,
							currentOffset);
					}
					// if not a structure then clear it
					else {
						classStructureDataType.clearAtOffset(currentOffset);
					}
					currentOffset = nextOffset;
					currentComponent = classStructureDataType.getComponentAt(currentOffset);
				}
			}
		}
		return classStructureDataType;
	}
Method to add/overwrite class vftable pointers to the given class structure
@param classStructureDataType the class structure data type
@param recoveredClass the given recovered class
@param vfPointerDataTypes the map of addresses/vftables, a null should be passed to indicate
no known vftables for the given class.
@return the modified structure with the vftable pointers added or an unchanged structure if
the vftable map is null or if the given class's offset to vftable map is empty
@throws CancelledException if cancelled
@throws IllegalArgumentException if there are issues modifying the structure
Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java