3232
3333@ SuppressWarnings ({"java:S3740" , "java:S3776" })
3434public 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 ) {
0 commit comments