public static Address getAddressValue(MemBuffer buf, int size, Settings settings,
			Consumer<String> errorHandler) {

		String spaceName = AddressSpaceSettingsDefinition.DEF.getValue(settings);
		AddressSpace targetSpace = null;

		Memory mem = buf.getMemory();

		boolean signedOffset = false;
		PointerType pointerType = PointerTypeSettingsDefinition.DEF.getType(settings);
		if (pointerType == PointerType.RELATIVE) {
			signedOffset = true;
		}

		Long offset = getStoredOffset(buf, size, signedOffset, errorHandler);
		if (offset == null) {
			return null;
		}

		long addrOffset = offset;

		long mask = OffsetMaskSettingsDefinition.DEF.getValue(settings);
		if (mask == 0) {
			errorHandler.accept("Invalid pointer mask: 0");
			return null;
		}
		if (mask != OffsetMaskSettingsDefinition.DEFAULT) {
			addrOffset &= mask;
		}

		int shift = (int) OffsetShiftSettingsDefinition.DEF.getValue(settings);
		if (shift < 0) {
			if (signedOffset) {
				addrOffset >>= -shift; // signed right-shift
			}
			else {
				addrOffset >>>= -shift; // unsigned right-shift
			}
		}
		else if (shift > 0) {
			addrOffset <<= shift; // left-shift
		}

		try {
			if (pointerType != PointerType.DEFAULT && spaceName != null) {
				errorHandler.accept("Address Space and Pointer Type settings conflict");
				return null;
			}
			// Address space setting ignored if Pointer Type has been specified
			if (pointerType == PointerType.IMAGE_BASE_RELATIVE) {
				if (addrOffset == 0) {
					// Done for consistency with old ImageBaseOffsetDataType.
					// A 0 relative offset is considered invalid (NaP)
					return null; // NaP without error
				}
				if (mem == null) {
					errorHandler.accept("Memory not specified");
				}
				// must ignore AddressSpaceSettingsDefinition
				Address imageBase = mem.getProgram().getImageBase();
				targetSpace = imageBase.getAddressSpace();
				return imageBase.addWrap(addrOffset * targetSpace.getAddressableUnitSize());
			}
			else if (pointerType == PointerType.RELATIVE) {
				if (addrOffset == 0) {
					// A 0 relative offset is considered invalid (NaP)
					return null; // NaP without error
				}
				// must ignore AddressSpaceSettingsDefinition
				Address base = buf.getAddress();
				targetSpace = base.getAddressSpace();
				return base.addWrap(addrOffset * targetSpace.getAddressableUnitSize());
			}
			else if (pointerType == PointerType.FILE_OFFSET) {
				if (mem == null) {
					errorHandler.accept("Memory not specified");
				}
				else if (mem.getAllFileBytes().size() == 0) {
					errorHandler.accept("No File bytes used");
				}
				else {
					List<Address> addressList = mem.locateAddressesForFileOffset(addrOffset);
					if (addressList.size() == 1) {
						return addressList.get(0);
					}
					if (addressList.size() > 1) {
						errorHandler.accept(
							"Non-unique File offset mapping: 0x" + Long.toHexString(addrOffset));
					}
					else {
						errorHandler.accept(
							"File offset mapping not found: 0x" + Long.toHexString(addrOffset));
					}
				}
				return null;
			}
			else if (pointerType != PointerType.DEFAULT) {
				errorHandler.accept("Unsupported pointer type: " + pointerType.toString());
				return null;
			}

			if (spaceName != null) {
				if (mem == null) {
					errorHandler.accept("Memory not specified");
					return null;
				}
				Program program = mem.getProgram();
				targetSpace = program.getAddressFactory().getAddressSpace(spaceName);
				if (targetSpace == null) {
					errorHandler.accept(
						"Address space not defined: " + spaceName + ":" + formatOffset(addrOffset));
					return null;
				}
			}
			if (targetSpace == null) {
				targetSpace = buf.getAddress().getAddressSpace();
			}

			if (targetSpace instanceof SegmentedAddressSpace) {
				if (size != 2 && size != 4) {
					errorHandler.accept("Unsupported segmented address size: " + size);
					return null;
				}
				if (mask != OffsetMaskSettingsDefinition.DEFAULT || shift != 0) {
					errorHandler.accept("Unsupported mask/shift setting for segmented address");
					return null;
				}
				return getSegmentedAddressValue(buf, size, addrOffset);
			}

			// addrOffset treated as word offset when targetSpace addressable unitsize > 1
			// TODO: May need setting to force treatment as byte-offset
			return targetSpace.getAddress(addrOffset, true);
		}
		catch (IllegalArgumentException | AddressOutOfBoundsException e) {
			errorHandler.accept(e.toString());
		}
		return null;
	}
Generate an address value based upon bytes stored at the specified buf
location.  Interpretation of settings may depend on access to a {@link Memory} 
object associated with the specified {@link MemBuffer} buf.
<BR>
The following pointer-typedef settings are supported:
<ul>
<li>{@link AddressSpaceSettingsDefinition}</li>
<li>{@link OffsetMaskSettingsDefinition}</li>
<li>{@link OffsetShiftSettingsDefinition}</li>
<li>{@link PointerTypeSettingsDefinition}</li>
</ul>

@param buf memory buffer positioned to stored pointer
@param size pointer size in bytes
@param settings settings which may influence address generation
@param errorHandler if null returned an error may be conveyed to this errorHandler
@return address value or null if unusable buf or data
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java