private static <T> T parseHelper(String s, boolean forceHex, Function<BigInteger, T> func,
			BigInteger max) throws NumberFormatException {
		String origStr = s;

		// Trim the string, and throw exception if it's null/empty
		s = (s == null ? "" : s.trim());
		if (s.isEmpty()) {
			throw new NumberFormatException("String to parse is empty");
		}

		// Chop off the optional sign character of the string, we'll add it back later
		String sign = "";
		if (s.startsWith("-") || s.startsWith("+")) {
			sign = s.substring(0, 1);
			s = s.substring(1);
		}

		// Process the radix
		boolean hexPrefix = s.startsWith(HEX_PREFIX_x) || s.startsWith(HEX_PREFIX_X);
		int radix = forceHex || hexPrefix ? 16 : 10;
		if (hexPrefix) {
			s = s.substring(2);
		}

		// Make sure next character is not + or - (protects against things like "0x-ffff")
		if (!s.isEmpty() && (s.charAt(0) == '-' || s.charAt(0) == '+')) {
			throw new NumberFormatException("Cannot parse " + origStr);
		}

		// Try to convert the string to the desired type
		try {

			// Check size
			if (new BigInteger(s, radix).compareTo(max) > 0) {
				throw new NumberFormatException(s + " exceeds maximum data type size.");
			}

			return func.apply(new BigInteger(sign + s, radix));
		}
		catch (NumberFormatException e) {
			// A little hacky, but the message should be complete and report the original string
			NumberFormatException e2 = new NumberFormatException("Cannot parse " + origStr);
			e2.setStackTrace(e.getStackTrace());
			throw e2;
		}
		catch (ArithmeticException e) {
			throw new NumberFormatException(origStr + " is too big.");
		}
	}
Parses the given decimal/hex string as a custom type. This method allows values with the top 
bit set to be implicitly parsed as negative values.

@param s the string to parse
@param forceHex true if the string to parse should be treated as hex, even if it doesn't 
  start with {@code 0x}; otherwise, false;
@param func a {@link Function} used to convert the parsed {@link BigInteger} to a custom type
@param max the maximum value that can be used to represent the type of value being parsed if
  it were treated as unsigned
@param <T> The type of value being parsed
@return the parsed value
@throws NumberFormatException if the string does not represent a valid value
Ghidra/Framework/Generic/src/main/java/ghidra/util/NumericUtilities.java