diff --git a/src/main/java/ortus/boxlang/modules/compat/bifs/conversion/JSONDeserialize.java b/src/main/java/ortus/boxlang/modules/compat/bifs/conversion/JSONDeserialize.java index 2e12228..5c16d37 100644 --- a/src/main/java/ortus/boxlang/modules/compat/bifs/conversion/JSONDeserialize.java +++ b/src/main/java/ortus/boxlang/modules/compat/bifs/conversion/JSONDeserialize.java @@ -57,15 +57,28 @@ public Object _invoke( IBoxContext context, ArgumentsScope arguments ) { */ private String escapeControlCharacters( String json ) { StringBuilder escapedJson = new StringBuilder(); - boolean inQuotes = false; // Flag to track if we're inside quotes (single or double) + boolean inQuotes = false; // Flag to track if we're inside quotes + boolean isEscaped = false; for ( int i = 0; i < json.length(); i++ ) { char c = json.charAt( i ); - // Check for single or double quotes and toggle the inQuotes flag - if ( c == '\"' || c == '\'' ) { + if ( isEscaped ) { + // If we're in an escape sequence, append the character as-is escapedJson.append( c ); - inQuotes = !inQuotes; + isEscaped = false; + } else if ( !inQuotes && c == '"' ) { + // Check for quote and toggle the inQuotes flag + escapedJson.append( c ); + inQuotes = true; + } else if ( inQuotes && c == '\\' ) { + // If we hit an escape inside a string + escapedJson.append( c ); + isEscaped = true; + } else if ( inQuotes && c == '"' ) { + // We've reached the end of the quotes now + escapedJson.append( c ); + inQuotes = false; } else if ( inQuotes && c < 32 ) { // Only escape control characters if inside quotes switch ( c ) { diff --git a/src/test/java/ortus/boxlang/modules/compat/JSONTest.java b/src/test/java/ortus/boxlang/modules/compat/JSONTest.java index f2d7c41..3f859e1 100644 --- a/src/test/java/ortus/boxlang/modules/compat/JSONTest.java +++ b/src/test/java/ortus/boxlang/modules/compat/JSONTest.java @@ -3,6 +3,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import ortus.boxlang.compiler.parser.BoxSourceType; + /** * This loads the module and runs an integration test on the module. */ @@ -28,7 +30,50 @@ public void testJSONControlCharacters() { result = jsonDeserialize( seed, false ); """ , context ); + + runtime.executeSource( """ + seed = '{ + "test": "foo bar + baz bum + + " }'; + result = jsonDeserialize( seed, false ); + """ + , context ); // @formatter:on } + + @DisplayName( "Test control characters in JSON singular quote" ) + @Test + public void testJSONControlCharactersSingularQuote() { + // Given + loadModule(); + + // @formatter:off + runtime.executeSource( """ + test = "{ + ""text"": ""'"" + }"; + """ + , context, BoxSourceType.CFSCRIPT ); + // @formatter:on + } + + @DisplayName( "Test control characters in JSON escaped stuff" ) + @Test + // @Disabled + public void testJSONControlCharactersEscaped() { + // Given + loadModule(); + + // @formatter:off + runtime.executeSource( """ + test = '{ + "text": "foo\\"bar\\\\baz\\nbum" + }'; + """ + , context, BoxSourceType.CFSCRIPT ); + // @formatter:on + } }