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