Blame SOURCES/rhino-backout-686806.patch

f649cc
diff --git a/src/org/mozilla/javascript/json/JsonParser.java b/src/org/mozilla/javascript/json/JsonParser.java
f649cc
index 5079502..0c06d26 100644
f649cc
--- a/src/org/mozilla/javascript/json/JsonParser.java
f649cc
+++ b/src/org/mozilla/javascript/json/JsonParser.java
f649cc
@@ -86,23 +86,15 @@ public class JsonParser {
f649cc
     }
f649cc
 
f649cc
     private Object readObject() throws ParseException {
f649cc
-        consumeWhitespace();
f649cc
         Scriptable object = cx.newObject(scope);
f649cc
-        // handle empty object literal case early
f649cc
-        if (pos < length && src.charAt(pos) == '}') {
f649cc
-            pos += 1;
f649cc
-            return object;
f649cc
-        }
f649cc
         String id;
f649cc
         Object value;
f649cc
         boolean needsComma = false;
f649cc
+        consumeWhitespace();
f649cc
         while (pos < length) {
f649cc
             char c = src.charAt(pos++);
f649cc
             switch(c) {
f649cc
                 case '}':
f649cc
-                    if (!needsComma) {
f649cc
-                        throw new ParseException("Unexpected comma in object literal");
f649cc
-                    }
f649cc
                     return object;
f649cc
                 case ',':
f649cc
                     if (!needsComma) {
f649cc
@@ -136,21 +128,13 @@ public class JsonParser {
f649cc
     }
f649cc
 
f649cc
     private Object readArray() throws ParseException {
f649cc
-        consumeWhitespace();
f649cc
-        // handle empty array literal case early
f649cc
-        if (pos < length && src.charAt(pos) == ']') {
f649cc
-            pos += 1;
f649cc
-            return cx.newArray(scope, 0);
f649cc
-        }
f649cc
         List<Object> list = new ArrayList<Object>();
f649cc
         boolean needsComma = false;
f649cc
+        consumeWhitespace();
f649cc
         while (pos < length) {
f649cc
             char c = src.charAt(pos);
f649cc
             switch(c) {
f649cc
                 case ']':
f649cc
-                    if (!needsComma) {
f649cc
-                        throw new ParseException("Unexpected comma in array literal");
f649cc
-                    }
f649cc
                     pos += 1;
f649cc
                     return cx.newArray(scope, list.toArray());
f649cc
                 case ',':
f649cc
@@ -173,166 +157,108 @@ public class JsonParser {
f649cc
     }
f649cc
 
f649cc
     private String readString() throws ParseException {
f649cc
-        /*
f649cc
-         * Optimization: if the source contains no escaped characters, create the
f649cc
-         * string directly from the source text.
f649cc
-         */
f649cc
-        int stringStart = pos;
f649cc
+        StringBuilder b = new StringBuilder();
f649cc
         while (pos < length) {
f649cc
             char c = src.charAt(pos++);
f649cc
             if (c <= '\u001F') {
f649cc
                 throw new ParseException("String contains control character");
f649cc
-            } else if (c == '\\') {
f649cc
-                break;
f649cc
-            } else if (c == '"') {
f649cc
-                return src.substring(stringStart, pos - 1);
f649cc
             }
f649cc
-        }
f649cc
-
f649cc
-        /*
f649cc
-         * Slow case: string contains escaped characters.  Copy a maximal sequence
f649cc
-         * of unescaped characters into a temporary buffer, then an escaped
f649cc
-         * character, and repeat until the entire string is consumed.
f649cc
-         */
f649cc
-        StringBuilder b = new StringBuilder();
f649cc
-        while (pos < length) {
f649cc
-            assert src.charAt(pos - 1) == '\\';
f649cc
-            b.append(src, stringStart, pos - 1);
f649cc
-            if (pos >= length) {
f649cc
-                throw new ParseException("Unterminated string");
f649cc
-            }
f649cc
-            char c = src.charAt(pos++);
f649cc
-            switch (c) {
f649cc
-                case '"':
f649cc
-                    b.append('"');
f649cc
-                    break;
f649cc
+            switch(c) {
f649cc
                 case '\\':
f649cc
-                    b.append('\\');
f649cc
-                    break;
f649cc
-                case '/':
f649cc
-                    b.append('/');
f649cc
-                    break;
f649cc
-                case 'b':
f649cc
-                    b.append('\b');
f649cc
-                    break;
f649cc
-                case 'f':
f649cc
-                    b.append('\f');
f649cc
-                    break;
f649cc
-                case 'n':
f649cc
-                    b.append('\n');
f649cc
-                    break;
f649cc
-                case 'r':
f649cc
-                    b.append('\r');
f649cc
-                    break;
f649cc
-                case 't':
f649cc
-                    b.append('\t');
f649cc
-                    break;
f649cc
-                case 'u':
f649cc
-                    if (length - pos < 5) {
f649cc
-                        throw new ParseException("Invalid character code: \\u" + src.substring(pos));
f649cc
+                    if (pos >= length) {
f649cc
+                        throw new ParseException("Unterminated string");
f649cc
                     }
f649cc
-                    int code = fromHex(src.charAt(pos + 0)) << 12
f649cc
-                             | fromHex(src.charAt(pos + 1)) << 8
f649cc
-                             | fromHex(src.charAt(pos + 2)) << 4
f649cc
-                             | fromHex(src.charAt(pos + 3));
f649cc
-                    if (code < 0) {
f649cc
-                        throw new ParseException("Invalid character code: " + src.substring(pos, pos + 4));
f649cc
+                    c = src.charAt(pos++);
f649cc
+                    switch (c) {
f649cc
+                        case '"':
f649cc
+                            b.append('"');
f649cc
+                            break;
f649cc
+                        case '\\':
f649cc
+                            b.append('\\');
f649cc
+                            break;
f649cc
+                        case '/':
f649cc
+                            b.append('/');
f649cc
+                            break;
f649cc
+                        case 'b':
f649cc
+                            b.append('\b');
f649cc
+                            break;
f649cc
+                        case 'f':
f649cc
+                            b.append('\f');
f649cc
+                            break;
f649cc
+                        case 'n':
f649cc
+                            b.append('\n');
f649cc
+                            break;
f649cc
+                        case 'r':
f649cc
+                            b.append('\r');
f649cc
+                            break;
f649cc
+                        case 't':
f649cc
+                            b.append('\t');
f649cc
+                            break;
f649cc
+                        case 'u':
f649cc
+                            if (length - pos < 5) {
f649cc
+                                throw new ParseException("Invalid character code: \\u" + src.substring(pos));
f649cc
+                            }
f649cc
+                            try {
f649cc
+                                b.append((char) Integer.parseInt(src.substring(pos, pos + 4), 16));
f649cc
+                                pos += 4;
f649cc
+                            } catch (NumberFormatException nfx) {
f649cc
+                                throw new ParseException("Invalid character code: " + src.substring(pos, pos + 4));
f649cc
+                            }
f649cc
+                            break;
f649cc
+                        default:
f649cc
+                            throw new ParseException("Unexcpected character in string: '\\" + c + "'");
f649cc
                     }
f649cc
-                    pos += 4;
f649cc
-                    b.append((char) code);
f649cc
                     break;
f649cc
+                case '"':
f649cc
+                    return b.toString();
f649cc
                 default:
f649cc
-                    throw new ParseException("Unexpected character in string: '\\" + c + "'");
f649cc
-            }
f649cc
-            stringStart = pos;
f649cc
-            while (pos < length) {
f649cc
-                c = src.charAt(pos++);
f649cc
-                if (c <= '\u001F') {
f649cc
-                    throw new ParseException("String contains control character");
f649cc
-                } else if (c == '\\') {
f649cc
+                    b.append(c);
f649cc
                     break;
f649cc
-                } else if (c == '"') {
f649cc
-                    b.append(src, stringStart, pos - 1);
f649cc
-                    return b.toString();
f649cc
-                }
f649cc
             }
f649cc
         }
f649cc
         throw new ParseException("Unterminated string literal");
f649cc
     }
f649cc
 
f649cc
-    private int fromHex(char c) {
f649cc
-        return c >= '0' && c <= '9' ? c - '0'
f649cc
-                : c >= 'A' && c <= 'F' ? c - 'A' + 10
f649cc
-                : c >= 'a' && c <= 'f' ? c - 'a' + 10
f649cc
-                : -1;
f649cc
-    }
f649cc
-
f649cc
-    private Number readNumber(char c) throws ParseException {
f649cc
-        assert c == '-' || (c >= '0' && c <= '9');
f649cc
-        final int numberStart = pos - 1;
f649cc
-        if (c == '-') {
f649cc
-            c = nextOrNumberError(numberStart);
f649cc
-            if (!(c >= '0' && c <= '9')) {
f649cc
-                throw numberError(numberStart, pos);
f649cc
-            }
f649cc
-        }
f649cc
-        if (c != '0') {
f649cc
-            readDigits();
f649cc
-        }
f649cc
-        // read optional fraction part
f649cc
-        if (pos < length) {
f649cc
-            c = src.charAt(pos);
f649cc
-            if (c == '.') {
f649cc
-                pos += 1;
f649cc
-                c = nextOrNumberError(numberStart);
f649cc
-                if (!(c >= '0' && c <= '9')) {
f649cc
-                    throw numberError(numberStart, pos);
f649cc
-                }
f649cc
-                readDigits();
f649cc
+    private Number readNumber(char first) throws ParseException {
f649cc
+        StringBuilder b = new StringBuilder();
f649cc
+        b.append(first);
f649cc
+        while (pos < length) {
f649cc
+            char c = src.charAt(pos);
f649cc
+            if (!Character.isDigit(c)
f649cc
+                    && c != '-'
f649cc
+                    && c != '+'
f649cc
+                    && c != '.'
f649cc
+                    && c != 'e'
f649cc
+                    && c != 'E') {
f649cc
+                break;
f649cc
             }
f649cc
+            pos += 1;
f649cc
+            b.append(c);
f649cc
         }
f649cc
-        // read optional exponent part
f649cc
-        if (pos < length) {
f649cc
-            c = src.charAt(pos);
f649cc
-            if (c == 'e' || c == 'E') {
f649cc
-                pos += 1;
f649cc
-                c = nextOrNumberError(numberStart);
f649cc
-                if (c == '-' || c == '+') {
f649cc
-                    c = nextOrNumberError(numberStart);
f649cc
-                }
f649cc
-                if (!(c >= '0' && c <= '9')) {
f649cc
-                    throw numberError(numberStart, pos);
f649cc
+        String num = b.toString();
f649cc
+        int numLength = num.length();
f649cc
+        try {
f649cc
+            // check for leading zeroes
f649cc
+            for (int i = 0; i < numLength; i++) {
f649cc
+                char c = num.charAt(i);
f649cc
+                if (Character.isDigit(c)) {
f649cc
+                    if (c == '0'
f649cc
+                            && numLength > i + 1
f649cc
+                            && Character.isDigit(num.charAt(i + 1))) {
f649cc
+                        throw new ParseException("Unsupported number format: " + num);
f649cc
+                    }
f649cc
+                    break;
f649cc
                 }
f649cc
-                readDigits();
f649cc
             }
f649cc
-        }
f649cc
-        String num = src.substring(numberStart, pos);
f649cc
-        final double dval = Double.parseDouble(num);
f649cc
-        final int ival = (int)dval;
f649cc
-        if (ival == dval) {
f649cc
-            return Integer.valueOf(ival);
f649cc
-        } else {
f649cc
-            return Double.valueOf(dval);
f649cc
-        }
f649cc
-    }
f649cc
-
f649cc
-    private ParseException numberError(int start, int end) {
f649cc
-        return new ParseException("Unsupported number format: " + src.substring(start, end));
f649cc
-    }
f649cc
-
f649cc
-    private char nextOrNumberError(int numberStart) throws ParseException {
f649cc
-        if (pos >= length) {
f649cc
-            throw numberError(numberStart, length);
f649cc
-        }
f649cc
-        return src.charAt(pos++);
f649cc
-    }
f649cc
-
f649cc
-    private void readDigits() {
f649cc
-        for (; pos < length; ++pos) {
f649cc
-            char c = src.charAt(pos);
f649cc
-            if (!(c >= '0' && c <= '9')) {
f649cc
-                break;
f649cc
+            final double dval = Double.parseDouble(num);
f649cc
+            final int ival = (int)dval;
f649cc
+            if (ival == dval) {
f649cc
+                return Integer.valueOf(ival);
f649cc
+            } else {
f649cc
+                return Double.valueOf(dval);
f649cc
             }
f649cc
+        } catch (NumberFormatException nfe) {
f649cc
+            throw new ParseException("Unsupported number format: " + num);
f649cc
         }
f649cc
     }
f649cc
 
f649cc
diff --git a/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java b/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java
f649cc
index ee885ae..2783b50 100644
f649cc
--- a/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java
f649cc
+++ b/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java
f649cc
@@ -196,66 +196,6 @@ public class JsonParserTest {
f649cc
         parser.parseValue("[1 ");
f649cc
     }
f649cc
 
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseIllegalUnicodeEscapeSeq() throws Exception {
f649cc
-        parser.parseValue("\"\\u-123\"");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseIllegalUnicodeEscapeSeq2() throws Exception {
f649cc
-        parser.parseValue("\"\\u006\u0661\"");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseIllegalUnicodeEscapeSeq3() throws Exception {
f649cc
-        parser.parseValue("\"\\u006ูก\"");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInObject1() throws Exception {
f649cc
-        parser.parseValue("{\"a\": 1,}");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInObject2() throws Exception {
f649cc
-        parser.parseValue("{,\"a\": 1}");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInObject3() throws Exception {
f649cc
-        parser.parseValue("{,}");
f649cc
-    }
f649cc
-
f649cc
-    @Test
f649cc
-    public void shouldParseEmptyObject() throws Exception {
f649cc
-        parser.parseValue("{}");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInArray1() throws Exception {
f649cc
-        parser.parseValue("[1,]");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInArray2() throws Exception {
f649cc
-        parser.parseValue("[,1]");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseTrailingCommaInArray3() throws Exception {
f649cc
-        parser.parseValue("[,]");
f649cc
-    }
f649cc
-
f649cc
-    @Test
f649cc
-    public void shouldParseEmptyArray() throws Exception {
f649cc
-        parser.parseValue("[]");
f649cc
-    }
f649cc
-
f649cc
-    @Test(expected = ParseException.class)
f649cc
-    public void shouldFailToParseIllegalNumber() throws Exception {
f649cc
-        parser.parseValue("1.");
f649cc
-    }
f649cc
-
f649cc
     private String str(char... chars) {
f649cc
         return new String(chars);
f649cc
     }