aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-02-15 11:43:55 -0500
committerDavid Robillard <d@drobilla.net>2021-02-15 13:13:41 -0500
commit1c1645ed45f40a2d73101c6237b19b28aad2b598 (patch)
treee2668c09d68544bab5130764b3154ea25cac58e2
parent4a731906879cd11f51c08764552c04375844f0ba (diff)
downloadserd-1c1645ed45f40a2d73101c6237b19b28aad2b598.tar.gz
serd-1c1645ed45f40a2d73101c6237b19b28aad2b598.tar.bz2
serd-1c1645ed45f40a2d73101c6237b19b28aad2b598.zip
Fix writing long literals with triple quotes
-rw-r--r--NEWS6
-rw-r--r--src/serd_config.h2
-rw-r--r--src/writer.c12
-rw-r--r--test/test_writer.c65
-rw-r--r--wscript2
5 files changed, 83 insertions, 4 deletions
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 <d@drobilla.net> 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 <d@drobilla.net>
+
+ 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 <assert.h>
+#include <string.h>
+
+#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 =
+ "<http://example.org/s>\n"
+ "\t<http://example.org/p> \"\"\"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