aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-07-09 14:59:05 +0200
committerDavid Robillard <d@drobilla.net>2017-07-09 14:59:05 +0200
commit4d535bbe0390ed4f03c611e433145c9e49cbf3ad (patch)
tree3ec86327944909c214dabe419ef67c3400fb1aec
parent4270fbbc761e4d36e9fc28a361b7e8d7c21166d2 (diff)
downloadserd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.tar.gz
serd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.tar.bz2
serd-4d535bbe0390ed4f03c611e433145c9e49cbf3ad.zip
Add serd_node_from_substring()
This allows creating nodes in-place from substrings of other strings to allow zero-copy serialization from existing delimited buffers.
-rw-r--r--NEWS6
-rw-r--r--serd/serd.h10
-rw-r--r--src/node.c18
-rw-r--r--src/serd_internal.h6
-rw-r--r--src/string.c47
-rw-r--r--tests/serd_test.c21
-rw-r--r--wscript2
7 files changed, 97 insertions, 13 deletions
diff --git a/NEWS b/NEWS
index 5839d2a3..0798b1a1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,11 @@
-serd (0.27.1) unstable;
+serd (0.27.2) unstable;
* Add support for reading from a user provided callback
+ * Add serd_node_from_substring()
* Fix strict parsing of abolute URI schemes
+ * Fix parsing of hex escapes in file URIs (thanks Johannes Mueller)
- -- David Robillard <d@drobilla.net> Thu, 29 Jun 2017 12:20:40 -0400
+ -- David Robillard <d@drobilla.net> Sun, 09 Jul 2017 14:58:47 +0200
serd (0.26.0) stable;
diff --git a/serd/serd.h b/serd/serd.h
index ca72a232..027c4e20 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -449,6 +449,16 @@ SerdNode
serd_node_from_string(SerdType type, const uint8_t* str);
/**
+ Make a (shallow) node from a prefix of `str`.
+
+ This measures, but does not copy, `str`. No memory is allocated.
+ Note that the returned node may not be null terminated.
+*/
+SERD_API
+SerdNode
+serd_node_from_substring(SerdType type, const uint8_t* str, size_t len);
+
+/**
Make a deep copy of `node`.
@return a node that the caller must free with serd_node_free().
diff --git a/src/node.c b/src/node.c
index 42992917..10df10d9 100644
--- a/src/node.c
+++ b/src/node.c
@@ -48,6 +48,22 @@ serd_node_from_string(SerdType type, const uint8_t* str)
SERD_API
SerdNode
+serd_node_from_substring(SerdType type, const uint8_t* str, const size_t len)
+{
+ if (!str) {
+ return SERD_NODE_NULL;
+ }
+
+ uint32_t flags = 0;
+ size_t buf_n_bytes = 0;
+ const size_t buf_n_chars = serd_substrlen(str, len, &buf_n_bytes, &flags);
+ assert(buf_n_bytes <= len);
+ SerdNode ret = { str, buf_n_bytes, buf_n_chars, flags, type };
+ return ret;
+}
+
+SERD_API
+SerdNode
serd_node_copy(const SerdNode* node)
{
if (!node || !node->buf) {
@@ -187,7 +203,7 @@ serd_node_new_file_uri(const uint8_t* path,
serd_uri_parse(chunk.buf, out);
}
- return serd_node_from_string(SERD_URI, chunk.buf);
+ return serd_node_from_substring(SERD_URI, chunk.buf, chunk.len);
}
SERD_API
diff --git a/src/serd_internal.h b/src/serd_internal.h
index afbea5fb..55f6a6b6 100644
--- a/src/serd_internal.h
+++ b/src/serd_internal.h
@@ -325,6 +325,12 @@ is_windows_path(const uint8_t* path)
&& (path[2] == '/' || path[2] == '\\');
}
+size_t
+serd_substrlen(const uint8_t* str,
+ const size_t len,
+ size_t* n_bytes,
+ SerdNodeFlags* flags);
+
/* URI utilities */
static inline bool
diff --git a/src/string.c b/src/string.c
index 9381015d..dedd0713 100644
--- a/src/string.c
+++ b/src/string.c
@@ -36,6 +36,42 @@ serd_strerror(SerdStatus status)
return (const uint8_t*)"Unknown error"; // never reached
}
+static inline void
+serd_update_flags(const uint8_t c, SerdNodeFlags* const flags)
+{
+ switch (c) {
+ case '\r': case '\n':
+ *flags |= SERD_HAS_NEWLINE;
+ break;
+ case '"':
+ *flags |= SERD_HAS_QUOTE;
+ }
+}
+
+size_t
+serd_substrlen(const uint8_t* const str,
+ const size_t len,
+ size_t* const n_bytes,
+ SerdNodeFlags* const flags)
+{
+ size_t n_chars = 0;
+ size_t i = 0;
+ SerdNodeFlags f = 0;
+ for (; i < len && str[i]; ++i) {
+ if ((str[i] & 0xC0) != 0x80) { // Start of new character
+ ++n_chars;
+ serd_update_flags(str[i], &f);
+ }
+ }
+ if (n_bytes) {
+ *n_bytes = i;
+ }
+ if (flags) {
+ *flags = f;
+ }
+ return n_chars;
+}
+
SERD_API
size_t
serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags)
@@ -44,16 +80,9 @@ serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags)
size_t i = 0;
SerdNodeFlags f = 0;
for (; str[i]; ++i) {
- if ((str[i] & 0xC0) != 0x80) {
- // Does not start with `10', start of a new character
+ if ((str[i] & 0xC0) != 0x80) { // Start of new character
++n_chars;
- switch (str[i]) {
- case '\r': case '\n':
- f |= SERD_HAS_NEWLINE;
- break;
- case '"':
- f |= SERD_HAS_QUOTE;
- }
+ serd_update_flags(str[i], &f);
}
}
if (n_bytes) {
diff --git a/tests/serd_test.c b/tests/serd_test.c
index 39ebc117..1eace3fd 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -366,6 +366,27 @@ main(void)
return failure("Creating node from NULL string failed\n");
}
+ // Test serd_node_from_substring
+
+ SerdNode empty = serd_node_from_substring(SERD_LITERAL, NULL, 32);
+ if (empty.buf || empty.n_bytes || empty.n_chars || empty.flags || empty.type) {
+ return failure("Successfully created node from NULL substring\n");
+ }
+
+ SerdNode a_b = serd_node_from_substring(SERD_LITERAL, USTR("a\"bc"), 3);
+ if (a_b.n_bytes != 3 || a_b.n_chars != 3 || a_b.flags != SERD_HAS_QUOTE
+ || strncmp((const char*)a_b.buf, "a\"b", 3)) {
+ return failure("Bad node %s %zu %zu %d %d\n",
+ a_b.buf, a_b.n_bytes, a_b.n_chars, a_b.flags, a_b.type);
+ }
+
+ a_b = serd_node_from_substring(SERD_LITERAL, USTR("a\"bc"), 10);
+ if (a_b.n_bytes != 4 || a_b.n_chars != 4 || a_b.flags != SERD_HAS_QUOTE
+ || strncmp((const char*)a_b.buf, "a\"bc", 4)) {
+ return failure("Bad node %s %zu %zu %d %d\n",
+ a_b.buf, a_b.n_bytes, a_b.n_chars, a_b.flags, a_b.type);
+ }
+
// Test serd_node_new_uri_from_string
SerdNode nonsense = serd_node_new_uri_from_string(NULL, NULL, NULL);
diff --git a/wscript b/wscript
index fdd6c81d..4a80da1d 100644
--- a/wscript
+++ b/wscript
@@ -11,7 +11,7 @@ import waflib.extras.autowaf as autowaf
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
-SERD_VERSION = '0.27.1'
+SERD_VERSION = '0.27.2'
SERD_MAJOR_VERSION = '0'
# Mandatory waf variables