From 89acb5bcb51b1e7718a16dd536419f870ee9d885 Mon Sep 17 00:00:00 2001 From: gamax92 Date: Sun, 11 Aug 2019 11:59:49 +0200 Subject: [PATCH] LuaString: port strx2number for accurate double scanning, handle plus signs when converting strings to numbers --- src/core/org/luaj/vm2/LuaString.java | 90 ++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaString.java b/src/core/org/luaj/vm2/LuaString.java index 2c3e8869..979a172a 100644 --- a/src/core/org/luaj/vm2/LuaString.java +++ b/src/core/org/luaj/vm2/LuaString.java @@ -749,22 +749,87 @@ public class LuaString extends LuaValue { double d = scannumber( base ); return Double.isNaN(d)? NIL: valueOf(d); } - + + private boolean isspace(byte c) { + return c == ' ' || (c >= '\t' && c <= '\r'); + } + + private boolean isdigit(byte c) { + return (c >= '0' && c <= '9'); + } + + private boolean isxdigit(byte c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + + private int hexvalue(byte c) { + return c <= '9' ? c - '0' : c <= 'F' ? c + 10 - 'A' : c + 10 - 'a'; + } + /** * Convert to a number in base 10, or base 16 if the string starts with '0x', * or return Double.NaN if it cannot be converted to a number. * @return double value if conversion is valid, or Double.NaN if not */ public double scannumber() { - int i=m_offset,j=m_offset+m_length; - while ( i=j ) + int i = m_offset, j = m_offset + m_length; + while (i < j && isspace(m_bytes[i])) + ++i; + while (i < j && isspace(m_bytes[j - 1])) + --j; + if (i >= j) return Double.NaN; - if ( m_bytes[i]=='0' && i+1= end) + return Double.NaN; + if (m_bytes[start++] != '0') + return Double.NaN; + if (m_bytes[start] != 'x' && m_bytes[start] != 'X') + return Double.NaN; + ++start; + double m = 0; + int e = 0; + boolean i = isxdigit(m_bytes[start]); + while (start < end && isxdigit(m_bytes[start])) + m = (m * 16) + hexvalue(m_bytes[start++]); + if (start < end && m_bytes[start] == '.') { + ++start; + while (start < end && isxdigit(m_bytes[start])) { + m = (m * 16) + hexvalue(m_bytes[start++]); + e -= 4; + } + } + if (!i && e == 0) + return Double.NaN; + if (start < end && (m_bytes[start] == 'p' || m_bytes[start] == 'P')) { + ++start; + int exp1 = 0; + boolean neg1 = false; + if (start < end) { + if (m_bytes[start] == '-') + neg1 = true; + if (neg1 || m_bytes[start] == '+') + ++start; + } + if (start >= end || !isdigit(m_bytes[start])) + return Double.NaN; + while (start < end && isdigit(m_bytes[start])) + exp1 = exp1 * 10 + m_bytes[start++] - '0'; + if (neg1) + exp1 = -exp1; + e += exp1; + } + if (start != end) + return Double.NaN; + return sgn * m * MathLib.dpow_d(2.0, e); } /** @@ -776,8 +841,8 @@ public class LuaString extends LuaValue { if ( base < 2 || base > 36 ) return Double.NaN; int i=m_offset,j=m_offset+m_length; - while ( i=j ) return Double.NaN; return scanlong( base, i, j ); @@ -794,7 +859,8 @@ public class LuaString extends LuaValue { private double scanlong( int base, int start, int end ) { long x = 0; boolean neg = (m_bytes[start] == '-'); - for ( int i=(neg?start+1:start); i='0'&&m_bytes[i]<='9')? '0': m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10)); if ( digit < 0 || digit >= base )