aboutsummaryrefslogtreecommitdiffstats
path: root/src/read_turtle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/read_turtle.c')
-rw-r--r--src/read_turtle.c119
1 files changed, 106 insertions, 13 deletions
diff --git a/src/read_turtle.c b/src/read_turtle.c
index 8d9ec78a..fa7b9731 100644
--- a/src/read_turtle.c
+++ b/src/read_turtle.c
@@ -3,6 +3,7 @@
#include "read_turtle.h"
#include "byte_source.h"
+#include "env.h"
#include "namespaces.h"
#include "node.h"
#include "ntriples.h"
@@ -21,6 +22,8 @@
#include "serd/statement.h"
#include "serd/status.h"
#include "serd/string_view.h"
+#include "serd/uri.h"
+#include "zix/attributes.h"
#include <assert.h>
#include <stdbool.h>
@@ -292,6 +295,66 @@ read_PN_PREFIX(SerdReader* const reader, SerdNode* const dest)
return st ? st : read_PN_PREFIX_tail(reader, dest);
}
+typedef struct {
+ SerdReader* reader;
+ SerdNode* node;
+ SerdStatus status;
+} WriteNodeContext;
+
+static size_t
+write_to_stack(const void* const ZIX_NONNULL buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const ZIX_NONNULL stream)
+{
+ WriteNodeContext* const ctx = (WriteNodeContext*)stream;
+ const uint8_t* const utf8 = (const uint8_t*)buf;
+
+ ctx->status = push_bytes(ctx->reader, ctx->node, utf8, nmemb * size);
+
+ return nmemb;
+}
+
+static SerdStatus
+resolve_IRIREF(SerdReader* const reader,
+ SerdNode* const dest,
+ const size_t string_start_offset)
+{
+ // If the URI is already absolute, we don't need to do anything
+ if (serd_uri_string_has_scheme(serd_node_string(dest))) {
+ return SERD_SUCCESS;
+ }
+
+ // Parse the URI reference so we can resolve it
+ SerdURIView uri = serd_parse_uri(serd_node_string(dest));
+
+ // Resolve relative URI reference to a full URI
+ uri = serd_resolve_uri(uri, serd_env_base_uri_view(reader->env));
+ if (!uri.scheme.length) {
+ return r_err(reader,
+ SERD_BAD_SYNTAX,
+ "failed to resolve relative URI reference <%s>",
+ serd_node_string(dest));
+ }
+
+ // Push a new temporary node for constructing the resolved URI
+ SerdNode* const temp = push_node(reader, SERD_URI, "", 0);
+ if (!temp) {
+ return SERD_BAD_STACK;
+ }
+
+ // Write resolved URI to the temporary node
+ WriteNodeContext ctx = {reader, temp, SERD_SUCCESS};
+ temp->length = serd_write_uri(uri, write_to_stack, &ctx);
+ if (!ctx.status) {
+ // Replace the destination with the new expanded node
+ memmove(dest, temp, serd_node_total_size(temp));
+ serd_stack_pop_to(&reader->stack, string_start_offset + dest->length);
+ }
+
+ return ctx.status;
+}
+
static SerdStatus
read_IRIREF(SerdReader* const reader, SerdNode** const dest)
{
@@ -302,14 +365,24 @@ read_IRIREF(SerdReader* const reader, SerdNode** const dest)
return SERD_BAD_STACK;
}
- return read_IRIREF_suffix(reader, *dest);
+ const size_t string_start_offset = reader->stack.size;
+
+ st = read_IRIREF_suffix(reader, *dest);
+ if (!tolerate_status(reader, st)) {
+ return st;
+ }
+
+ return (reader->flags & SERD_READ_RELATIVE)
+ ? SERD_SUCCESS
+ : resolve_IRIREF(reader, *dest, string_start_offset);
}
static SerdStatus
read_PrefixedName(SerdReader* const reader,
SerdNode* const dest,
const bool read_prefix,
- bool* const ate_dot)
+ bool* const ate_dot,
+ const size_t string_start_offset)
{
SerdStatus st = SERD_SUCCESS;
if (read_prefix) {
@@ -320,8 +393,24 @@ read_PrefixedName(SerdReader* const reader,
return SERD_FAILURE;
}
- TRY(st, push_byte(reader, dest, eat_byte_safe(reader, ':')));
- TRY_FAILING(st, read_PN_LOCAL(reader, dest, ate_dot));
+ skip_byte(reader, ':');
+
+ // Search environment for the prefix URI
+ const SerdStringView prefix = serd_node_string_view(dest);
+ const SerdStringView prefix_uri = serd_env_find_prefix(reader->env, prefix);
+ if (!prefix_uri.length) {
+ return r_err(reader, st, "unknown prefix \"%s\"", prefix.data);
+ }
+
+ // Pop back to the start of the string
+ serd_stack_pop_to(&reader->stack, string_start_offset);
+ dest->length = 0U;
+ dest->type = SERD_URI;
+ push_bytes(reader, dest, (const uint8_t*)prefix_uri.data, prefix_uri.length);
+ if ((st = read_PN_LOCAL(reader, dest, ate_dot)) > SERD_FAILURE) {
+ return st;
+ }
+
return SERD_SUCCESS;
}
@@ -420,14 +509,15 @@ read_turtle_iri(SerdReader* const reader,
SerdNode** const dest,
bool* const ate_dot)
{
- switch (peek_byte(reader)) {
- case '<':
+ if (peek_byte(reader) == '<') {
return read_IRIREF(reader, dest);
- default:
- *dest = push_node(reader, SERD_CURIE, "", 0);
- return *dest ? read_PrefixedName(reader, *dest, true, ate_dot)
- : SERD_BAD_STACK;
}
+
+ if (!(*dest = push_node(reader, SERD_CURIE, "", 0))) {
+ return SERD_BAD_STACK;
+ }
+
+ return read_PrefixedName(reader, *dest, true, ate_dot, reader->stack.size);
}
static SerdStatus
@@ -481,7 +571,8 @@ read_verb(SerdReader* reader, SerdNode** const dest)
return SERD_BAD_STACK;
}
- SerdStatus st = SERD_SUCCESS;
+ const size_t string_start_offset = reader->stack.size;
+ SerdStatus st = SERD_SUCCESS;
TRY_LAX(st, read_PN_PREFIX(reader, *dest));
bool ate_dot = false;
@@ -495,7 +586,9 @@ read_verb(SerdReader* reader, SerdNode** const dest)
: SERD_BAD_STACK);
}
- if ((st = read_PrefixedName(reader, *dest, false, &ate_dot)) || ate_dot) {
+ if ((st = read_PrefixedName(
+ reader, *dest, false, &ate_dot, string_start_offset)) ||
+ ate_dot) {
*dest = NULL;
return r_err(
reader, st > SERD_FAILURE ? st : SERD_BAD_SYNTAX, "expected verb");
@@ -586,7 +679,7 @@ read_named_object(SerdReader* const reader,
SerdStatus st = SERD_SUCCESS;
// Attempt to read a prefixed name
- st = read_PrefixedName(reader, node, true, ate_dot);
+ st = read_PrefixedName(reader, node, true, ate_dot, reader->stack.size);
// Check if this is actually a special boolean node
if (st == SERD_FAILURE && (node_has_string(node, true_string) ||