From 1c1645ed45f40a2d73101c6237b19b28aad2b598 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 15 Feb 2021 11:43:55 -0500 Subject: Fix writing long literals with triple quotes --- NEWS | 6 +++++ src/serd_config.h | 2 +- src/writer.c | 12 ++++++++-- test/test_writer.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wscript | 2 +- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 test/test_writer.c diff --git a/NEWS b/NEWS index 7e40cd29..03636d41 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +serd (0.30.11) unstable; + + * Fix writing long literals with triple quotes + + -- David Robillard Mon, 15 Feb 2021 16:34:35 +0000 + serd (0.30.10) stable; * Add fallback configuration if documentation theme is unavailable diff --git a/src/serd_config.h b/src/serd_config.h index 349d7124..15508c81 100644 --- a/src/serd_config.h +++ b/src/serd_config.h @@ -29,7 +29,7 @@ #define SERD_CONFIG_H // Define version unconditionally so a warning will catch a mismatch -#define SERD_VERSION "0.30.10" +#define SERD_VERSION "0.30.11" #if !defined(SERD_NO_DEFAULT_CONFIG) diff --git a/src/writer.c b/src/writer.c index 82ac5eeb..af2980c5 100644 --- a/src/writer.c +++ b/src/writer.c @@ -332,8 +332,13 @@ write_text(SerdWriter* writer, const uint8_t* utf8, size_t n_bytes) { - size_t len = 0; + size_t len = 0; + size_t n_consecutive_quotes = 0; for (size_t i = 0; i < n_bytes;) { + if (utf8[i] != '"') { + n_consecutive_quotes = 0; + } + // Fast bulk write for long strings of printable ASCII size_t j = i; for (; j < n_bytes; ++j) { @@ -350,6 +355,8 @@ write_text(SerdWriter* writer, const uint8_t in = utf8[i++]; if (ctx == WRITE_LONG_STRING) { + n_consecutive_quotes = (in == '\"') ? (n_consecutive_quotes + 1) : 0; + switch (in) { case '\\': len += sink("\\\\", 2, writer); @@ -364,7 +371,8 @@ write_text(SerdWriter* writer, len += sink(&in, 1, writer); // Write character as-is continue; case '\"': - if (i == n_bytes) { // '"' at string end + if (n_consecutive_quotes >= 3 || i == n_bytes) { + // Two quotes in a row, or quote at string end, escape len += sink("\\\"", 2, writer); } else { len += sink(&in, 1, writer); diff --git a/test/test_writer.c b/test/test_writer.c new file mode 100644 index 00000000..baaff736 --- /dev/null +++ b/test/test_writer.c @@ -0,0 +1,65 @@ +/* + Copyright 2011-2021 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#undef NDEBUG + +#include "serd/serd.h" + +#include +#include + +#define USTR(s) ((const uint8_t*)(s)) + +static void +test_write_long_literal(void) +{ + SerdEnv* env = serd_env_new(NULL); + SerdChunk chunk = {NULL, 0}; + SerdWriter* writer = serd_writer_new( + SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); + + assert(writer); + + SerdNode s = serd_node_from_string(SERD_URI, USTR("http://example.org/s")); + SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p")); + SerdNode o = + serd_node_from_string(SERD_LITERAL, USTR("hello \"\"\"world\"\"\"!")); + + assert(!serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL)); + + serd_writer_free(writer); + + uint8_t* out = serd_chunk_sink_finish(&chunk); + + static const char* const expected = + "\n" + "\t \"\"\"hello \"\"\\\"world\"\"\\\"!\"\"\" .\n\n"; + + assert(!strcmp((char*)out, expected)); + serd_free(out); +} + +int +main(void) +{ + const char* const path = "serd_test.ttl"; + + test_writer(path); + test_write_long_literal(); + + printf("Success\n"); + return 0; +} diff --git a/wscript b/wscript index 034bd85e..2a4085b4 100644 --- a/wscript +++ b/wscript @@ -11,7 +11,7 @@ from waflib.extras import autowaf # major increment <=> incompatible changes # minor increment <=> compatible changes (additions) # micro increment <=> no interface changes -SERD_VERSION = '0.30.10' +SERD_VERSION = '0.30.11' SERD_MAJOR_VERSION = '0' # Mandatory waf variables -- cgit v1.2.1