diff options
Diffstat (limited to 'src/n3.c')
-rw-r--r-- | src/n3.c | 139 |
1 files changed, 119 insertions, 20 deletions
@@ -15,6 +15,7 @@ */ #include "byte_source.h" +#include "env.h" #include "namespaces.h" #include "node.h" #include "reader.h" @@ -707,6 +708,63 @@ read_IRIREF_scheme(SerdReader* reader, SerdNode* dest) return SERD_FAILURE; } +typedef struct { + SerdReader* reader; + SerdNode* node; + SerdStatus status; +} WriteNodeContext; + +static size_t +write_to_stack(const void* const SERD_NONNULL buf, + const size_t size, + const size_t nmemb, + void* const SERD_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 + SerdURIView uri = serd_parse_uri(serd_node_string(dest)); + if (uri.scheme.len) { + return SERD_SUCCESS; + } + + // Resolve relative URI reference to a full URI + uri = serd_resolve_uri(uri, serd_env_base_uri_view(reader->env)); + if (!uri.scheme.len) { + return SERD_ERR_BAD_URI; + } + + // Push a new temporary node for constructing the resolved URI + SerdNode* const temp = push_node(reader, SERD_URI, "", 0); + if (!temp) { + return SERD_ERR_OVERFLOW; + } + + // Write resolved URI to the temporary node + WriteNodeContext ctx = {reader, temp, SERD_SUCCESS}; + temp->n_bytes = serd_write_uri(uri, write_to_stack, &ctx); + if (ctx.status) { + return 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->n_bytes); + + return SERD_SUCCESS; +} + static SerdStatus read_IRIREF(SerdReader* reader, SerdNode** dest) { @@ -718,6 +776,8 @@ read_IRIREF(SerdReader* reader, SerdNode** dest) return SERD_ERR_OVERFLOW; } + const size_t string_start_offset = reader->stack.size; + if (!fancy_syntax(reader) && read_IRIREF_scheme(reader, *dest)) { return r_err(reader, SERD_ERR_BAD_SYNTAX, "expected IRI scheme\n"); } @@ -732,7 +792,9 @@ read_IRIREF(SerdReader* reader, SerdNode** dest) return r_err( reader, SERD_ERR_BAD_SYNTAX, "invalid IRI character `%c'\n", c); case '>': - return SERD_SUCCESS; + return (st || (reader->flags & SERD_READ_RELATIVE)) + ? st + : resolve_IRIREF(reader, *dest, string_start_offset); case '\\': if (read_UCHAR(reader, *dest, &code)) { return r_err(reader, SERD_ERR_BAD_SYNTAX, "invalid IRI escape\n"); @@ -780,10 +842,11 @@ read_IRIREF(SerdReader* reader, SerdNode** dest) } static SerdStatus -read_PrefixedName(SerdReader* reader, - SerdNode* dest, - bool read_prefix, - bool* ate_dot) +read_PrefixedName(SerdReader* reader, + SerdNode* dest, + bool read_prefix, + bool* ate_dot, + const size_t string_start_offset) { SerdStatus st = SERD_SUCCESS; if (read_prefix && ((st = read_PN_PREFIX(reader, dest)) > SERD_FAILURE)) { @@ -795,10 +858,32 @@ read_PrefixedName(SerdReader* reader, } if ((st = push_byte(reader, dest, eat_byte_safe(reader, ':'))) || - (st = read_PN_LOCAL(reader, dest, ate_dot)) > SERD_FAILURE) { + (st = read_PN_LOCAL(reader, dest, ate_dot)) > SERD_FAILURE || + (reader->flags & SERD_READ_PREFIXED)) { return st; } + // Expand to absolute URI + SerdStringView prefix; + SerdStringView suffix; + if ((st = serd_env_expand_in_place(reader->env, dest, &prefix, &suffix))) { + return r_err(reader, st, "failed to expand URI\n"); + } + + // Push a new temporary node for constructing the full URI + SerdNode* const temp = push_node(reader, SERD_URI, "", 0); + if ((st = push_bytes(reader, temp, (const uint8_t*)prefix.buf, prefix.len)) || + (st = push_bytes(reader, temp, (const uint8_t*)suffix.buf, suffix.len))) { + return st; + } + + // Replace the destination with the new expanded node + const size_t total_size = serd_node_total_size(temp); + memmove(dest, temp, total_size); + + serd_stack_pop_to(&reader->stack, + string_start_offset + serd_node_length(dest)); + return SERD_SUCCESS; } @@ -889,14 +974,15 @@ read_number(SerdReader* reader, SerdNode** dest, bool* ate_dot) static SerdStatus read_iri(SerdReader* reader, SerdNode** dest, bool* 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_ERR_OVERFLOW; } + + if (!(*dest = push_node(reader, SERD_CURIE, "", 0))) { + return SERD_ERR_OVERFLOW; + } + + return read_PrefixedName(reader, *dest, true, ate_dot, reader->stack.size); } static SerdStatus @@ -986,10 +1072,11 @@ read_verb(SerdReader* reader, SerdNode** dest) return SERD_ERR_OVERFLOW; } - SerdStatus st = read_PN_PREFIX(reader, *dest); - bool ate_dot = false; - SerdNode* node = *dest; - const int next = peek_byte(reader); + const size_t string_start_offset = reader->stack.size; + SerdStatus st = read_PN_PREFIX(reader, *dest); + bool ate_dot = false; + SerdNode* node = *dest; + const int next = peek_byte(reader); if (!st && node->n_bytes == 1 && serd_node_string(node)[0] == 'a' && next != ':' && !is_PN_CHARS_BASE((uint32_t)next)) { serd_stack_pop_to(&reader->stack, orig_stack_size); @@ -998,7 +1085,8 @@ read_verb(SerdReader* reader, SerdNode** dest) : SERD_ERR_OVERFLOW); } - if (st > SERD_FAILURE || read_PrefixedName(reader, *dest, false, &ate_dot) || + if (st > SERD_FAILURE || + read_PrefixedName(reader, *dest, false, &ate_dot, string_start_offset) || ate_dot) { *dest = NULL; return r_err(reader, SERD_ERR_BAD_SYNTAX, "bad verb\n"); @@ -1207,7 +1295,7 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) ++orig_cursor.col; ret = read_literal(reader, &o, ate_dot); break; - default: + default: { /* Either a boolean literal, or a qname. Read the prefix first, and if it is in fact a "true" or "false" literal, produce that instead. */ @@ -1215,8 +1303,10 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) return SERD_ERR_OVERFLOW; } + const size_t string_start_offset = reader->stack.size; while (!read_PN_CHARS_BASE(reader, o)) { } + if ((o->n_bytes == 4 && !memcmp(serd_node_string(o), "true", 4)) || (o->n_bytes == 5 && !memcmp(serd_node_string(o), "false", 5))) { o->flags |= SERD_HAS_DATATYPE; @@ -1229,12 +1319,14 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) } else if (read_PN_PREFIX_tail(reader, o) > SERD_FAILURE) { ret = SERD_ERR_BAD_SYNTAX; } else { - if ((ret = read_PrefixedName(reader, o, false, ate_dot))) { + if ((ret = read_PrefixedName( + reader, o, false, ate_dot, string_start_offset))) { ret = ret > SERD_FAILURE ? ret : SERD_ERR_BAD_SYNTAX; return r_err(reader, ret, "expected prefixed name\n"); } } } + } if (!ret && emit && simple && o) { serd_node_zero_pad(o); @@ -1475,6 +1567,7 @@ read_base(SerdReader* reader, bool sparql, bool token) SerdNode* uri = NULL; TRY(st, read_IRIREF(reader, &uri)); serd_node_zero_pad(uri); + TRY(st, serd_env_set_base_uri(reader->env, serd_node_string_view(uri))); TRY(st, serd_sink_write_base(reader->sink, uri)); read_ws_star(reader); @@ -1517,12 +1610,18 @@ read_prefixID(SerdReader* reader, bool sparql, bool token) serd_node_zero_pad(name); serd_node_zero_pad(uri); - st = serd_sink_write_prefix(reader->sink, name, uri); + + TRY(st, + serd_env_set_prefix( + reader->env, serd_node_string_view(name), serd_node_string_view(uri))); + + TRY(st, serd_sink_write_prefix(reader->sink, name, uri)); if (!sparql) { read_ws_star(reader); st = eat_byte_check(reader, '.') ? SERD_SUCCESS : SERD_ERR_BAD_SYNTAX; } + return st; } |