Wed, 22 Jan 2025 21:02:46 +0100
remove token_escape bool from CxJson struct
src/cx/json.h | file | annotate | diff | comparison | revisions | |
src/json.c | file | annotate | diff | comparison | revisions | |
tests/test_json.c | file | annotate | diff | comparison | revisions |
--- a/src/cx/json.h Wed Jan 22 20:36:10 2025 +0100 +++ b/src/cx/json.h Wed Jan 22 21:02:46 2025 +0100 @@ -374,11 +374,6 @@ * Internally reserved memory for the value buffer stack. */ CxJsonValue* vbuf_internal[8]; - - /** - * Used internally. - */ - bool tokenizer_escape; // TODO: check if it can be replaced with look-behind }; /**
--- a/src/json.c Wed Jan 22 20:36:10 2025 +0100 +++ b/src/json.c Wed Jan 22 21:02:46 2025 +0100 @@ -263,6 +263,9 @@ CxJsonTokenType ttype = json->uncompleted.tokentype; size_t token_part_start = json->buffer.pos; + bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING + && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\'; + for (size_t i = json->buffer.pos; i < json->buffer.size; i++) { char c = json->buffer.space[i]; if (ttype != CX_JSON_TOKEN_STRING) { @@ -301,8 +304,8 @@ } } else { // currently inside a string - if (json->tokenizer_escape) { - json->tokenizer_escape = false; + if (escape_end_of_string) { + escape_end_of_string = false; } else { if (c == '"') { *result = token_create(json, true, token_part_start, i + 1); @@ -312,7 +315,7 @@ json->buffer.pos = i + 1; return CX_JSON_NO_ERROR; } else if (c == '\\') { - json->tokenizer_escape = true; + escape_end_of_string = true; } } }
--- a/tests/test_json.c Wed Jan 22 20:36:10 2025 +0100 +++ b/tests/test_json.c Wed Jan 22 21:02:46 2025 +0100 @@ -143,6 +143,39 @@ cxJsonDestroy(&json); } +CX_TEST(test_json_escaped_end_of_string) { + CxJson json; + cxJsonInit(&json, NULL); + CX_TEST_DO { + // first test, normal scenario + cxJsonFill(&json, "\"a \\\"test\\\" string\""); + CxJsonValue *val; + CxJsonStatus result = cxJsonNext(&json, &val); + CX_TEST_ASSERT(result == CX_JSON_NO_ERROR); + CX_TEST_ASSERT(cxJsonIsString(val)); + CX_TEST_ASSERT(0 == cx_strcmp( + cxJsonAsCxString(val), + cx_str("a \"test\" string")) + ); + cxJsonValueFree(val); + + // second test - uncompleted token with hanging escape char + cxJsonFill(&json, "\"a \\\"test\\"); + result = cxJsonNext(&json, &val); + CX_TEST_ASSERT(result == CX_JSON_INCOMPLETE_DATA); + cxJsonFill(&json, "\" string\""); + result = cxJsonNext(&json, &val); + CX_TEST_ASSERT(result == CX_JSON_NO_ERROR); + CX_TEST_ASSERT(cxJsonIsString(val)); + CX_TEST_ASSERT(0 == cx_strcmp( + cxJsonAsCxString(val), + cx_str("a \"test\" string")) + ); + cxJsonValueFree(val); + } + cxJsonDestroy(&json); +} + CX_TEST(test_json_object_incomplete_token) { cxstring text = cx_str( "{\"message\":\"success\" , \"__timestamp\":1729348561}"); @@ -1009,6 +1042,7 @@ cx_test_register(suite, test_json_init_default); cx_test_register(suite, test_json_simple_object); cx_test_register(suite, test_json_escaped_strings); + cx_test_register(suite, test_json_escaped_end_of_string); cx_test_register(suite, test_json_object_incomplete_token); cx_test_register(suite, test_json_token_wrongly_completed); cx_test_register(suite, test_json_object_error);