Skip to content

Commit

Permalink
Also fix index handling in JSON.parse
Browse files Browse the repository at this point in the history
  • Loading branch information
gbrail committed Oct 31, 2023
1 parent d735f33 commit 354f477
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/org/mozilla/javascript/ScriptRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,10 @@ static Function getExistingCtor(Context cx, Scriptable scope, String constructor
* Return -1L if str is not an index, or the index value as lower 32 bits of the result. Note
* that the result needs to be cast to an int in order to produce the actual index, which may be
* negative.
*
* <p>Note that this method on its own does not actually produce an index that is useful for an
* actual Object or Array, because it may be larger than Integer.MAX_VALUE. Most callers should
* instead call toStringOrIndex, which calls this under the covers.
*/
public static long indexFromString(String str) {
// The length of the decimal string representation of
Expand Down
10 changes: 5 additions & 5 deletions src/org/mozilla/javascript/json/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.List;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.ScriptRuntime.StringIdOrIndex;
import org.mozilla.javascript.Scriptable;

/**
Expand Down Expand Up @@ -118,13 +119,12 @@ private Object readObject() throws ParseException {
consume(':');
value = readValue();

long index = ScriptRuntime.indexFromString(id);
if (index < 0) {
object.put(id, object, value);
StringIdOrIndex indexObj = ScriptRuntime.toStringIdOrIndex(id);
if (indexObj.getStringId() == null) {
object.put(indexObj.getIndex(), object, value);
} else {
object.put((int) index, object, value);
object.put(indexObj.getStringId(), object, value);
}

needsComma = true;
break;
default:
Expand Down
23 changes: 21 additions & 2 deletions testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.mozilla.javascript.tests.json;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import org.junit.After;
Expand Down Expand Up @@ -119,7 +120,6 @@ public void shouldParseEmptyJsonArray() throws Exception {
}

@Test
@SuppressWarnings("unchecked")
public void shouldParseHeterogeneousJsonArray() throws Exception {
NativeArray actual = (NativeArray) parser.parseValue("[ \"hello\" , 3, null, [false] ]");
assertEquals("hello", actual.get(0, actual));
Expand All @@ -138,18 +138,37 @@ public void shouldFailToParseArrayWithInvalidElements() throws Exception {
}

@Test
@SuppressWarnings({"serial", "unchecked"})
public void shouldParseJsonObject() throws Exception {
String json =
"{" + "\"bool\" : false, " + "\"str\" : \"xyz\", " + "\"obj\" : {\"a\":1} " + "}";
NativeObject actual = (NativeObject) parser.parseValue(json);
assertEquals(false, actual.get("bool", actual));
assertEquals("xyz", actual.get("str", actual));
assertArrayEquals(
"Property ordering should match",
new Object[] {"bool", "str", "obj"},
actual.getIds());

NativeObject innerObj = (NativeObject) actual.get("obj", actual);
assertEquals(1, innerObj.get("a", innerObj));
}

@Test
public void testECMAKeyOrdering() throws Exception {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
String json =
"{\"foo\": \"a\", \"bar\": \"b\", \"1\": \"c\", \"-1\": \"d\", \"x\": \"e\"}";
NativeObject actual = (NativeObject) parser.parseValue(json);
// Ensure that modern ECMAScript property ordering works, which depends on
// valid index values being treated as numbers and not as strings.
assertArrayEquals(
"Property ordering should match",
new Object[] {1, "foo", "bar", "-1", "x"},
actual.getIds());
}
}

@Test(expected = ParseException.class)
public void shouldFailToParseJsonObjectsWithInvalidFormat() throws Exception {
parser.parseValue("{\"only\", \"keys\"}");
Expand Down

0 comments on commit 354f477

Please sign in to comment.