Skip to content

Commit 4645abb

Browse files
committed
Sync with underscore-java
1 parent d9a5427 commit 4645abb

File tree

5 files changed

+57
-28
lines changed

5 files changed

+57
-28
lines changed

src/main/java/com/github/underscore/Json.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
@SuppressWarnings({"java:S3740", "java:S3776"})
3434
public final class Json {
35+
36+
private static final int PARSE_MAX_DEPTH = 10_000;
37+
3538
private Json() {}
3639

3740
private static final String NULL = "null";
@@ -404,18 +407,16 @@ private static void escape(String s, StringBuilder sb) {
404407
case '\t':
405408
sb.append("\\t");
406409
break;
407-
case '\u20AC':
408-
sb.append('\u20AC');
410+
case '':
411+
sb.append('');
409412
break;
410413
default:
411414
if (ch <= '\u001F'
412415
|| ch >= '\u007F' && ch <= '\u009F'
413416
|| ch >= '\u2000' && ch <= '\u20FF') {
414417
String ss = Integer.toHexString(ch);
415418
sb.append("\\u");
416-
for (int k = 0; k < 4 - ss.length(); k++) {
417-
sb.append("0");
418-
}
419+
sb.append("0".repeat(4 - ss.length()));
419420
sb.append(ss.toUpperCase());
420421
} else {
421422
sb.append(ch);
@@ -459,25 +460,30 @@ public static class JsonParser {
459460
private int current;
460461
private StringBuilder captureBuffer;
461462
private int captureStart;
463+
private final int maxDepth;
462464

463-
public JsonParser(String string) {
465+
public JsonParser(String string, int maxDepth) {
464466
this.json = string;
467+
this.maxDepth = maxDepth;
465468
line = 1;
466469
captureStart = -1;
467470
}
468471

469472
public Object parse() {
470473
read();
471474
skipWhiteSpace();
472-
final Object result = readValue();
475+
final Object result = readValue(0);
473476
skipWhiteSpace();
474477
if (!isEndOfText()) {
475478
throw error("Unexpected character");
476479
}
477480
return result;
478481
}
479482

480-
private Object readValue() {
483+
private Object readValue(int depth) {
484+
if (depth > maxDepth) {
485+
throw error("Maximum depth exceeded");
486+
}
481487
switch (current) {
482488
case 'n':
483489
return readNull();
@@ -488,9 +494,9 @@ private Object readValue() {
488494
case '"':
489495
return readString();
490496
case '[':
491-
return readArray();
497+
return readArray(depth + 1);
492498
case '{':
493-
return readObject();
499+
return readObject(depth + 1);
494500
case '-':
495501
case '0':
496502
case '1':
@@ -508,7 +514,7 @@ private Object readValue() {
508514
}
509515
}
510516

511-
private List<Object> readArray() {
517+
private List<Object> readArray(int depth) {
512518
read();
513519
List<Object> array = new ArrayList<>();
514520
skipWhiteSpace();
@@ -517,7 +523,7 @@ private List<Object> readArray() {
517523
}
518524
do {
519525
skipWhiteSpace();
520-
array.add(readValue());
526+
array.add(readValue(depth));
521527
skipWhiteSpace();
522528
} while (readChar(','));
523529
if (!readChar(']')) {
@@ -526,7 +532,7 @@ private List<Object> readArray() {
526532
return array;
527533
}
528534

529-
private Map<String, Object> readObject() {
535+
private Map<String, Object> readObject(int depth) {
530536
read();
531537
Map<String, Object> object = new LinkedHashMap<>();
532538
skipWhiteSpace();
@@ -541,7 +547,7 @@ private Map<String, Object> readObject() {
541547
throw expected("':'");
542548
}
543549
skipWhiteSpace();
544-
object.put(name, readValue());
550+
object.put(name, readValue(depth));
545551
skipWhiteSpace();
546552
} while (readChar(','));
547553
if (!readChar('}')) {
@@ -834,7 +840,11 @@ public static String toJson(Map map) {
834840
}
835841

836842
public static Object fromJson(String string) {
837-
return new JsonParser(string).parse();
843+
return fromJson(string, PARSE_MAX_DEPTH);
844+
}
845+
846+
public static Object fromJson(String string, int maxDepth) {
847+
return new JsonParser(string, maxDepth).parse();
838848
}
839849

840850
public static String formatJson(String json, JsonStringBuilder.Step identStep) {

src/main/java/com/github/underscore/U.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,11 @@ public static Map<String, Object> fromJsonMap(final String string) {
26012601
return getStringObjectMap(object);
26022602
}
26032603

2604+
public static Map<String, Object> fromJsonMap(final String string, final int maxDepth) {
2605+
final Object object = Json.fromJson(string, maxDepth);
2606+
return getStringObjectMap(object);
2607+
}
2608+
26042609
@SuppressWarnings("unchecked")
26052610
private static Map<String, Object> getStringObjectMap(Object object) {
26062611
final Map<String, Object> result;

src/main/java/com/github/underscore/Xml.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
import java.util.function.BiFunction;
3939
import java.util.function.Function;
4040

41-
@SuppressWarnings({"java:S107", "java:S1119", "java:S3740", "java:S3776", "java:S4276"})
41+
@SuppressWarnings({"java:S107", "java:S1119", "java:S2583", "java:S3740", "java:S3776", "java:S4276"})
4242
public final class Xml {
4343
private Xml() {}
4444

@@ -96,7 +96,7 @@ public enum Step {
9696
FOUR_SPACES(4),
9797
COMPACT(0),
9898
TABS(1);
99-
private int ident;
99+
private final int ident;
100100

101101
Step(int ident) {
102102
this.ident = ident;
@@ -1030,7 +1030,7 @@ private static void escape(String s, StringBuilder sb) {
10301030
case '\t':
10311031
sb.append("\t");
10321032
break;
1033-
case '\u20AC':
1033+
case '':
10341034
sb.append("€");
10351035
break;
10361036
default:
@@ -1316,8 +1316,7 @@ private static Object createMap(
13161316
final int[] sourceIndex,
13171317
final Set<String> namespaces,
13181318
final FromType fromType) {
1319-
final Map<String, Object> map = new LinkedHashMap<>();
1320-
map.putAll(attrMap);
1319+
final Map<String, Object> map = new LinkedHashMap<>(attrMap);
13211320
final org.w3c.dom.NodeList nodeList = node.getChildNodes();
13221321
for (int index = 0; index < nodeList.getLength(); index++) {
13231322
final org.w3c.dom.Node currentNode = nodeList.item(index);
@@ -1760,14 +1759,12 @@ private static Map<String, String> getHeaderAttributes(final String xml) {
17601759
XML_HEADER.length(),
17611760
Math.max(XML_HEADER.length(), xml.indexOf("?>", XML_HEADER.length())));
17621761
final Map<String, String> attributes = parseAttributes(xmlLocal);
1763-
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
1764-
result.put(attribute.getKey(), attribute.getValue());
1765-
}
1762+
result.putAll(attributes);
17661763
}
17671764
return result;
17681765
}
17691766

1770-
protected static String getDoctypeValue(final String xml) {
1767+
static String getDoctypeValue(final String xml) {
17711768
int startIndex = xml.indexOf(DOCTYPE_HEADER) + DOCTYPE_HEADER.length();
17721769
char charToFind = '>';
17731770
int endIndexPlus = 0;
@@ -1819,7 +1816,7 @@ private static org.w3c.dom.Document createDocument() {
18191816
final javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder();
18201817
return builder.newDocument();
18211818
} catch (javax.xml.parsers.ParserConfigurationException ex) {
1822-
return null;
1819+
throw new IllegalArgumentException(ex);
18231820
}
18241821
}
18251822

@@ -1888,17 +1885,18 @@ public static Object fromXmlWithoutNamespaces(final String xml) {
18881885
(object, namespaces) -> {
18891886
final String localString = String.valueOf(object);
18901887
final String result;
1888+
String substring = localString.substring(
1889+
Math.max(0, localString.indexOf(':') + 1));
18911890
if (localString.startsWith("-")
18921891
&& namespaces.contains(
18931892
localString.substring(
18941893
1, Math.max(1, localString.indexOf(':'))))) {
18951894
result =
18961895
"-"
1897-
+ localString.substring(
1898-
Math.max(0, localString.indexOf(':') + 1));
1896+
+ substring;
18991897
} else if (namespaces.contains(
19001898
localString.substring(0, Math.max(0, localString.indexOf(':'))))) {
1901-
result = localString.substring(Math.max(0, localString.indexOf(':') + 1));
1899+
result = substring;
19021900
} else {
19031901
result = String.valueOf(object);
19041902
}

src/test/java/com/github/underscore/LodashTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,9 @@ void formatJson() {
15631563
assertEquals(
15641564
"{\n \"a\": {\n }\n}",
15651565
U.formatJson("{\n \"a\": {\n }\n}", Json.JsonStringBuilder.Step.FOUR_SPACES));
1566+
assertEquals(
1567+
"{\n \"a\": {\n }\n}",
1568+
U.formatJson("{\n \"a\": {\n }\n}", Json.JsonStringBuilder.Step.THREE_SPACES));
15661569
assertEquals(
15671570
"{\"a\":{}}",
15681571
U.formatJson("{\n \"a\": {\n }\n}", Json.JsonStringBuilder.Step.COMPACT));

src/test/java/com/github/underscore/StringTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,6 +3503,7 @@ void fromJsonMap() {
35033503
assertEquals("{value=[]}", U.fromJsonMap(stringJson).toString());
35043504
String stringJson2 = "{}";
35053505
assertEquals("{}", U.fromJsonMap(stringJson2).toString());
3506+
assertEquals("{}", U.fromJsonMap(stringJson2, 100).toString());
35063507
}
35073508

35083509
@Test
@@ -3517,6 +3518,18 @@ void fromJsonStackoverflowObject() throws IOException {
35173518
}
35183519
}
35193520

3521+
@Test
3522+
void fromJsonParseException() throws IOException {
3523+
String stringJson =
3524+
new String(
3525+
Files.readAllBytes(Paths.get("src/test/resources/wellFormedObject.json")));
3526+
try {
3527+
U.fromJsonMap(stringJson, 1000);
3528+
} catch (Throwable throwable) {
3529+
assertTrue(throwable instanceof Json.ParseException);
3530+
}
3531+
}
3532+
35203533
@Test
35213534
void fromJsonStackoverflowArray() throws IOException {
35223535
String stringJson =

0 commit comments

Comments
 (0)