diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index b5d7443639..c2c40ea97c 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -11,9 +11,6 @@ import mindustry.logic.LExecutor.*; public class LAssembler{ public static ObjectMap> customParsers = new ObjectMap<>(); - private static final long invalidNumNegative = Long.MIN_VALUE; - private static final long invalidNumPositive = Long.MAX_VALUE; - public boolean privileged; /** Maps names to variable. */ public OrderedMap vars = new OrderedMap<>(); @@ -110,23 +107,48 @@ public class LAssembler{ } double parseDouble(String symbol){ + //fail fast for obvious non-numbers + if(symbol.isEmpty() || !isNumStart(symbol.charAt(0))) return Double.NaN; + //parse hex/binary syntax - if(symbol.startsWith("0b")) return parseLong(false, symbol, 2, 2, symbol.length()); - if(symbol.startsWith("+0b")) return parseLong(false, symbol, 2, 3, symbol.length()); - if(symbol.startsWith("-0b")) return parseLong(true,symbol, 2, 3, symbol.length()); - if(symbol.startsWith("0x")) return parseLong(false,symbol, 16, 2, symbol.length()); - if(symbol.startsWith("+0x")) return parseLong(false,symbol, 16, 3, symbol.length()); - if(symbol.startsWith("-0x")) return parseLong(true,symbol, 16, 3, symbol.length()); + if(symbol.startsWith("0b")) return parseHexOrBin(false, symbol, true, 2); + if(symbol.startsWith("+0b")) return parseHexOrBin(false, symbol, true, 3); + if(symbol.startsWith("-0b")) return parseHexOrBin(true, symbol, true, 3); + if(symbol.startsWith("0x")) return parseHexOrBin(false, symbol, false, 2); + if(symbol.startsWith("+0x")) return parseHexOrBin(false, symbol, false, 3); + if(symbol.startsWith("-0x")) return parseHexOrBin(true, symbol, false, 3); if(symbol.startsWith("%[") && symbol.endsWith("]") && symbol.length() > 3) return parseNamedColor(symbol); if(symbol.startsWith("%") && (symbol.length() == 7 || symbol.length() == 9)) return parseColor(symbol); return Strings.parseDouble(symbol, Double.NaN); } - double parseLong(boolean negative, String s, int radix, int start, int end) { - long usedInvalidNum = negative ? invalidNumPositive : invalidNumNegative; - long l = Strings.parseLong(s, radix, start, end, usedInvalidNum); - return l == usedInvalidNum ? Double.NaN : negative ? -l : l; + boolean isNumStart(char c){ + //note that 'e10' isn't a valid number; '%ffffff' is. Hex numbers start with '0x'. + return c >= '0' && c <= '9' || c == '.' || c == '-' || c == '+' || c == '%'; + } + + //parses *unsigned* hex or bin number, including negative ones (0xffffffffffffffff as -1) + //detects overflow by input length and uses bit manipulation to avoid signed arithmetics + double parseHexOrBin(boolean negative, String s, boolean binary, int offset){ + int end = s.length(); + if(offset >= end) return Double.NaN; + + int pos = offset; + while(pos < end && s.charAt(pos) == '0') pos ++; //skip leading zeros to avoid incorrect overflow detection + + int shift = binary ? 1 : 4; + if(end - pos > 64 / shift) return Double.NaN; + + long acc = 0; + int radix = 1 << shift; + while(pos < end){ + int digit = Character.digit(s.charAt(pos), radix); + if(digit < 0) return Double.NaN; + acc = acc << shift | digit; + pos ++; + } + return negative ? -acc : acc; } double parseColor(String symbol){ @@ -178,4 +200,4 @@ public class LAssembler{ return vars.get(name); } -} \ No newline at end of file +}