Mercurial > hg > sv-dependency-builds
changeset 115:1609fb751561
sord-0 -> sord and serd-0 -> serd
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Thu, 09 Jan 2014 21:21:48 +0000 |
parents | 241db1b1eff2 |
children | e448888319fc |
files | osx/include/serd-0/serd/serd.h osx/include/serd/serd.h osx/include/sord-0/sord/sord.h osx/include/sord-0/sord/sordmm.hpp osx/include/sord/sord.h osx/include/sord/sordmm.hpp |
diffstat | 6 files changed, 2243 insertions(+), 2243 deletions(-) [+] |
line wrap: on
line diff
--- a/osx/include/serd-0/serd/serd.h Thu Jan 09 13:23:08 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,963 +0,0 @@ -/* - Copyright 2011-2012 David Robillard <http://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. -*/ - -/** - @file serd.h API for Serd, a lightweight RDF syntax library. -*/ - -#ifndef SERD_SERD_H -#define SERD_SERD_H - -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> - -#ifdef SERD_SHARED -# ifdef _WIN32 -# define SERD_LIB_IMPORT __declspec(dllimport) -# define SERD_LIB_EXPORT __declspec(dllexport) -# else -# define SERD_LIB_IMPORT __attribute__((visibility("default"))) -# define SERD_LIB_EXPORT __attribute__((visibility("default"))) -# endif -# ifdef SERD_INTERNAL -# define SERD_API SERD_LIB_EXPORT -# else -# define SERD_API SERD_LIB_IMPORT -# endif -#else -# define SERD_API -#endif - -#ifdef __cplusplus -extern "C" { -#else -# include <stdbool.h> -#endif - -/** - @defgroup serd Serd - A lightweight RDF syntax library. - @{ -*/ - -/** - Environment. - - Represents the state required to resolve a CURIE or relative URI, e.g. the - base URI and set of namespace prefixes at a particular point. -*/ -typedef struct SerdEnvImpl SerdEnv; - -/** - RDF reader. - - Parses RDF by calling user-provided sink functions as input is consumed - (much like an XML SAX parser). -*/ -typedef struct SerdReaderImpl SerdReader; - -/** - RDF writer. - - Provides a number of functions to allow writing RDF syntax out to some - stream. These functions are deliberately compatible with the sink functions - used by SerdReader, so a reader can be directly connected to a writer to - re-serialise a document with minimal overhead. -*/ -typedef struct SerdWriterImpl SerdWriter; - -/** - Return status code. -*/ -typedef enum { - SERD_SUCCESS, /**< No error */ - SERD_FAILURE, /**< Non-fatal failure */ - SERD_ERR_UNKNOWN, /**< Unknown error */ - SERD_ERR_BAD_SYNTAX, /**< Invalid syntax */ - SERD_ERR_BAD_ARG, /**< Invalid argument */ - SERD_ERR_NOT_FOUND, /**< Not found */ - SERD_ERR_ID_CLASH, /**< Encountered clashing blank node IDs */ - SERD_ERR_BAD_CURIE, /**< Invalid CURIE (e.g. prefix does not exist) */ - SERD_ERR_INTERNAL /**< Unexpected internal error (should not happen) */ -} SerdStatus; - -/** - RDF syntax type. -*/ -typedef enum { - /** - Turtle - Terse RDF Triple Language (UTF-8). - @see <a href="http://www.w3.org/TeamSubmission/turtle/">Turtle</a> - */ - SERD_TURTLE = 1, - - /** - NTriples - Line-based RDF triples (ASCII). - @see <a href="http://www.w3.org/TR/rdf-testcases#ntriples">NTriples</a> - */ - SERD_NTRIPLES = 2 -} SerdSyntax; - -/** - Flags indication inline abbreviation information for a statement. -*/ -typedef enum { - SERD_EMPTY_S = 1 << 1, /**< Empty blank node subject */ - SERD_EMPTY_O = 1 << 2, /**< Empty blank node object */ - SERD_ANON_S_BEGIN = 1 << 3, /**< Start of anonymous subject */ - SERD_ANON_O_BEGIN = 1 << 4, /**< Start of anonymous object */ - SERD_ANON_CONT = 1 << 5, /**< Continuation of anonymous node */ - SERD_LIST_S_BEGIN = 1 << 6, /**< Start of list subject */ - SERD_LIST_O_BEGIN = 1 << 7, /**< Start of list object */ - SERD_LIST_CONT = 1 << 8 /**< Continuation of list */ -} SerdStatementFlag; - -/** - Bitwise OR of SerdNodeFlag values. -*/ -typedef uint32_t SerdStatementFlags; - -/** - Type of a syntactic RDF node. - - This is more precise than the type of an abstract RDF node. An abstract - node is either a resource, literal, or blank. In syntax there are two ways - to refer to a resource (by URI or CURIE) and two ways to refer to a blank - (by ID or anonymously). Anonymous (inline) blank nodes are expressed using - SerdStatementFlags rather than this type. -*/ -typedef enum { - /** - The type of a nonexistent node. - - This type is useful as a sentinel, but is never emitted by the reader. - */ - SERD_NOTHING = 0, - - /** - Literal value. - - A literal optionally has either a language, or a datatype (not both). - */ - SERD_LITERAL = 1, - - /** - URI (absolute or relative). - - Value is an unquoted URI string, which is either a relative reference - with respect to the current base URI (e.g. "foo/bar"), or an absolute - URI (e.g. "http://example.org/foo"). - @see <a href="http://tools.ietf.org/html/rfc3986">RFC3986</a>. - */ - SERD_URI = 2, - - /** - CURIE, a shortened URI. - - Value is an unquoted CURIE string relative to the current environment, - e.g. "rdf:type". - @see <a href="http://www.w3.org/TR/curie">CURIE Syntax 1.0</a> - */ - SERD_CURIE = 3, - - /** - A blank node. - - Value is a blank node ID, e.g. "id3", which is meaningful only within - this serialisation. - @see <a href="http://www.w3.org/TeamSubmission/turtle#nodeID">Turtle - <tt>nodeID</tt></a> - */ - SERD_BLANK = 4, - -} SerdType; - -/** - Flags indicating certain string properties relevant to serialisation. -*/ -typedef enum { - SERD_HAS_NEWLINE = 1, /**< Contains line breaks ('\\n' or '\\r') */ - SERD_HAS_QUOTE = 1 << 1 /**< Contains quotes ('"') */ -} SerdNodeFlag; - -/** - Bitwise OR of SerdNodeFlag values. -*/ -typedef uint32_t SerdNodeFlags; - -/** - A syntactic RDF node. -*/ -typedef struct { - const uint8_t* buf; /**< Value string */ - size_t n_bytes; /**< Size in bytes (not including null) */ - size_t n_chars; /**< Length in characters (not including null)*/ - SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ - SerdType type; /**< Node type */ -} SerdNode; - -/** - An unterminated string fragment. -*/ -typedef struct { - const uint8_t* buf; /**< Start of chunk */ - size_t len; /**< Length of chunk in bytes */ -} SerdChunk; - -/** - An error description. -*/ -typedef struct { - SerdStatus status; /**< Error code */ - const uint8_t* filename; /**< File where error was encountered, or NULL */ - unsigned line; /**< Line where error was encountered, or 0 */ - unsigned col; /**< Column where error was encountered */ - const char* fmt; /**< Message format string (printf style) */ - va_list* args; /**< Arguments for fmt */ -} SerdError; - -/** - A parsed URI. - - This struct directly refers to chunks in other strings, it does not own any - memory itself. Thus, URIs can be parsed and/or resolved against a base URI - in-place without allocating memory. -*/ -typedef struct { - SerdChunk scheme; /**< Scheme */ - SerdChunk authority; /**< Authority */ - SerdChunk path_base; /**< Path prefix if relative */ - SerdChunk path; /**< Path suffix */ - SerdChunk query; /**< Query */ - SerdChunk fragment; /**< Fragment */ -} SerdURI; - -/** - Syntax style options. - - The style of the writer output can be controlled by ORing together - values from this enumeration. Note that some options are only supported - for some syntaxes (e.g. NTriples does not support abbreviation and is - always ASCII). -*/ -typedef enum { - SERD_STYLE_ABBREVIATED = 1, /**< Abbreviate triples when possible. */ - SERD_STYLE_ASCII = 1 << 1, /**< Escape all non-ASCII characters. */ - SERD_STYLE_RESOLVED = 1 << 2, /**< Resolve URIs against base URI. */ - SERD_STYLE_CURIED = 1 << 3, /**< Shorten URIs into CURIEs. */ - SERD_STYLE_BULK = 1 << 4 /**< Write output in pages. */ -} SerdStyle; - -/** - @name String Utilities - @{ -*/ - -/** - Return a string describing a status code. -*/ -SERD_API -const uint8_t* -serd_strerror(SerdStatus status); - -/** - Measure a UTF-8 string. - @return Length of @c str in characters (except NULL). - @param str A null-terminated UTF-8 string. - @param n_bytes (Output) Set to the size of @c str in bytes (except NULL). - @param flags (Output) Set to the applicable flags. -*/ -SERD_API -size_t -serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags); - -/** - Parse a string to a double. - - The API of this function is identical to the standard C strtod function, - except this function is locale-independent and always matches the lexical - format used in the Turtle grammar (the decimal point is always "."). -*/ -SERD_API -double -serd_strtod(const char* str, char** endptr); - -/** - Decode a base64 string. - This function can be used to deserialise a blob node created with - serd_node_new_blob(). - - @param str Base64 string to decode. - @param len The length of @c str. - @param size Set to the size of the returned blob in bytes. - @return A newly allocated blob which must be freed with free(). -*/ -SERD_API -void* -serd_base64_decode(const uint8_t* str, size_t len, size_t* size); - -/** - @} - @name URI - @{ -*/ - -static const SerdURI SERD_URI_NULL = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; - -/** - Return the local path for @c uri, or NULL if @c uri is not a file URI. - Note this (inappropriately named) function only removes the file scheme if - necessary, and returns @c uri unmodified if it is an absolute path. Percent - encoding and other issues are not handled, to properly convert a file URI to - a path, use serd_file_uri_parse(). -*/ -SERD_API -const uint8_t* -serd_uri_to_path(const uint8_t* uri); - -/** - Get the unescaped path and hostname from a file URI. - @param uri A file URI. - @param hostname If non-NULL, set to the hostname, if present. - @return The path component of the URI. - - Both the returned path and @c hostname (if applicable) are owned by the - caller and must be freed with free(). -*/ -SERD_API -uint8_t* -serd_file_uri_parse(const uint8_t* uri, uint8_t** hostname); - -/** - Return true iff @c utf8 starts with a valid URI scheme. -*/ -SERD_API -bool -serd_uri_string_has_scheme(const uint8_t* utf8); - -/** - Parse @c utf8, writing result to @c out. -*/ -SERD_API -SerdStatus -serd_uri_parse(const uint8_t* utf8, SerdURI* out); - -/** - Set @c out to @c uri resolved against @c base. -*/ -SERD_API -void -serd_uri_resolve(const SerdURI* uri, const SerdURI* base, SerdURI* out); - -/** - Sink function for raw string output. -*/ -typedef size_t (*SerdSink)(const void* buf, size_t len, void* stream); - -/** - Serialise @c uri with a series of calls to @c sink. -*/ -SERD_API -size_t -serd_uri_serialise(const SerdURI* uri, SerdSink sink, void* stream); - -/** - Serialise @c uri relative to @c base with a series of calls to @c sink. - - The @c uri is written as a relative URI iff if it a child of @c base and @c - root. The optional @c root parameter must be a prefix of @c base and can be - used keep up-references ("../") within a certain namespace. -*/ -SERD_API -size_t -serd_uri_serialise_relative(const SerdURI* uri, - const SerdURI* base, - const SerdURI* root, - SerdSink sink, - void* stream); - -/** - @} - @name Node - @{ -*/ - -static const SerdNode SERD_NODE_NULL = { 0, 0, 0, 0, SERD_NOTHING }; - -/** - Make a (shallow) node from @c str. - - This measures, but does not copy, @c str. No memory is allocated. -*/ -SERD_API -SerdNode -serd_node_from_string(SerdType type, const uint8_t* str); - -/** - Make a deep copy of @c node. - - @return a node that the caller must free with @ref serd_node_free. -*/ -SERD_API -SerdNode -serd_node_copy(const SerdNode* node); - -/** - Return true iff @c a is equal to @c b. -*/ -SERD_API -bool -serd_node_equals(const SerdNode* a, const SerdNode* b); - -/** - Simple wrapper for serd_node_new_uri to resolve a URI node. -*/ -SERD_API -SerdNode -serd_node_new_uri_from_node(const SerdNode* uri_node, - const SerdURI* base, - SerdURI* out); - -/** - Simple wrapper for serd_node_new_uri to resolve a URI string. -*/ -SERD_API -SerdNode -serd_node_new_uri_from_string(const uint8_t* str, - const SerdURI* base, - SerdURI* out); - -/** - Create a new file URI node from a file system path and optional hostname. - - Backslashes in Windows paths will be converted and '%' will always be - percent encoded. If @c escape is true, all other invalid characters will be - percent encoded as well. - - If @c path is relative, @c hostname is ignored. - If @c out is not NULL, it will be set to the parsed URI. -*/ -SERD_API -SerdNode -serd_node_new_file_uri(const uint8_t* path, - const uint8_t* hostname, - SerdURI* out, - bool escape); - -/** - Create a new node by serialising @c uri into a new string. - - @param uri The URI to parse and serialise. - - @param base Base URI to resolve @c uri against (or NULL for no resolution). - - @param out Set to the parsing of the new URI (i.e. points only to - memory owned by the new returned node). -*/ -SERD_API -SerdNode -serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out); - -/** - Create a new node by serialising @c d into an xsd:decimal string. - - The resulting node will always contain a `.', start with a digit, and end - with a digit (i.e. will have a leading and/or trailing `0' if necessary). - It will never be in scientific notation. A maximum of @c frac_digits digits - will be written after the decimal point, but trailing zeros will - automatically be omitted (except one if @c d is a round integer). - - Note that about 16 and 8 fractional digits are required to precisely - represent a double and float, respectively. - - @param d The value for the new node. - @param frac_digits The maximum number of digits after the decimal place. -*/ -SERD_API -SerdNode -serd_node_new_decimal(double d, unsigned frac_digits); - -/** - Create a new node by serialising @c i into an xsd:integer string. -*/ -SERD_API -SerdNode -serd_node_new_integer(int64_t i); - -/** - Create a node by serialising @c buf into an xsd:base64Binary string. - This function can be used to make a serialisable node out of arbitrary - binary data, which can be decoded using serd_base64_decode(). - - @param buf Raw binary input data. - @param size Size of @c buf. - @param wrap_lines Wrap lines at 76 characters to conform to RFC 2045. -*/ -SERD_API -SerdNode -serd_node_new_blob(const void* buf, size_t size, bool wrap_lines); - -/** - Free any data owned by @c node. - - Note that if @c node is itself dynamically allocated (which is not the case - for nodes created internally by serd), it will not be freed. -*/ -SERD_API -void -serd_node_free(SerdNode* node); - -/** - @} - @name Event Handlers - @{ -*/ - -/** - Sink (callback) for errors. - - @param handle Handle for user data. - @param error Error description. -*/ -typedef SerdStatus (*SerdErrorSink)(void* handle, - const SerdError* error); - -/** - Sink (callback) for base URI changes. - - Called whenever the base URI of the serialisation changes. -*/ -typedef SerdStatus (*SerdBaseSink)(void* handle, - const SerdNode* uri); - -/** - Sink (callback) for namespace definitions. - - Called whenever a prefix is defined in the serialisation. -*/ -typedef SerdStatus (*SerdPrefixSink)(void* handle, - const SerdNode* name, - const SerdNode* uri); - -/** - Sink (callback) for statements. - - Called for every RDF statement in the serialisation. -*/ -typedef SerdStatus (*SerdStatementSink)(void* handle, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang); - -/** - Sink (callback) for anonymous node end markers. - - This is called to indicate that the anonymous node with the given - @c value will no longer be referred to by any future statements - (i.e. the anonymous serialisation of the node is finished). -*/ -typedef SerdStatus (*SerdEndSink)(void* handle, - const SerdNode* node); - -/** - @} - @name Environment - @{ -*/ - -/** - Create a new environment. -*/ -SERD_API -SerdEnv* -serd_env_new(const SerdNode* base_uri); - -/** - Free @c ns. -*/ -SERD_API -void -serd_env_free(SerdEnv* env); - -/** - Get the current base URI. -*/ -SERD_API -const SerdNode* -serd_env_get_base_uri(const SerdEnv* env, - SerdURI* out); - -/** - Set the current base URI. -*/ -SERD_API -SerdStatus -serd_env_set_base_uri(SerdEnv* env, - const SerdNode* uri); - -/** - Set a namespace prefix. -*/ -SERD_API -SerdStatus -serd_env_set_prefix(SerdEnv* env, - const SerdNode* name, - const SerdNode* uri); - -/** - Set a namespace prefix. -*/ -SERD_API -SerdStatus -serd_env_set_prefix_from_strings(SerdEnv* env, - const uint8_t* name, - const uint8_t* uri); - -/** - Qualify @c uri into a CURIE if possible. -*/ -SERD_API -bool -serd_env_qualify(const SerdEnv* env, - const SerdNode* uri, - SerdNode* prefix, - SerdChunk* suffix); - -/** - Expand @c curie. -*/ -SERD_API -SerdStatus -serd_env_expand(const SerdEnv* env, - const SerdNode* curie, - SerdChunk* uri_prefix, - SerdChunk* uri_suffix); - -/** - Expand @c node, which must be a CURIE or URI, to a full URI. -*/ -SERD_API -SerdNode -serd_env_expand_node(const SerdEnv* env, - const SerdNode* node); - -/** - Call @c func for each prefix defined in @c env. -*/ -SERD_API -void -serd_env_foreach(const SerdEnv* env, - SerdPrefixSink func, - void* handle); - -/** - @} - @name Reader - @{ -*/ - -/** - Create a new RDF reader. -*/ -SERD_API -SerdReader* -serd_reader_new(SerdSyntax syntax, - void* handle, - void (*free_handle)(void*), - SerdBaseSink base_sink, - SerdPrefixSink prefix_sink, - SerdStatementSink statement_sink, - SerdEndSink end_sink); - -/** - Set a function to be called when errors occur during reading. - - The @p error_sink will be called with @p handle as its first argument. If - no error function is set, errors are printed to stderr in GCC style. -*/ -SERD_API -void -serd_reader_set_error_sink(SerdReader* reader, - SerdErrorSink error_sink, - void* handle); - -/** - Return the @c handle passed to @ref serd_reader_new. -*/ -SERD_API -void* -serd_reader_get_handle(const SerdReader* reader); - -/** - Set a prefix to be added to all blank node identifiers. - - This is useful when multiple files are to be parsed into the same output - (e.g. a store, or other files). Since Serd preserves blank node IDs, this - could cause conflicts where two non-equivalent blank nodes are merged, - resulting in corrupt data. By setting a unique blank node prefix for each - parsed file, this can be avoided, while preserving blank node names. -*/ -SERD_API -void -serd_reader_add_blank_prefix(SerdReader* reader, - const uint8_t* prefix); - -/** - Set the URI of the default graph. - - If this is set, the reader will emit quads with the graph set to the given - node for any statements that are not in a named graph (which is currently - all of them since Serd currently does not support any graph syntaxes). -*/ -SERD_API -void -serd_reader_set_default_graph(SerdReader* reader, - const SerdNode* graph); - -/** - Read a file at a given @c uri. -*/ -SERD_API -SerdStatus -serd_reader_read_file(SerdReader* reader, - const uint8_t* uri); - -/** - Start an incremental read from a file handle. - - Iff @p bulk is true, @p file will be read a page at a time. This is more - efficient, but uses a page of memory and means that an entire page of input - must be ready before any callbacks will fire. To react as soon as input - arrives, set @p bulk to false. -*/ -SERD_API -SerdStatus -serd_reader_start_stream(SerdReader* me, - FILE* file, - const uint8_t* name, - bool bulk); - -/** - Read a single "chunk" of data during an incremental read. - - This function will read a single top level description, and return. This - may be a directive, statement, or several statements; essentially it reads - until a '.' is encountered. This is particularly useful for reading - directly from a pipe or socket. -*/ -SERD_API -SerdStatus -serd_reader_read_chunk(SerdReader* me); - -/** - Finish an incremental read from a file handle. -*/ -SERD_API -SerdStatus -serd_reader_end_stream(SerdReader* me); - -/** - Read @c file. -*/ -SERD_API -SerdStatus -serd_reader_read_file_handle(SerdReader* reader, - FILE* file, - const uint8_t* name); - -/** - Read @c utf8. -*/ -SERD_API -SerdStatus -serd_reader_read_string(SerdReader* me, const uint8_t* utf8); - -/** - Free @c reader. -*/ -SERD_API -void -serd_reader_free(SerdReader* reader); - -/** - @} - @name Writer - @{ -*/ - -/** - Create a new RDF writer. -*/ -SERD_API -SerdWriter* -serd_writer_new(SerdSyntax syntax, - SerdStyle style, - SerdEnv* env, - const SerdURI* base_uri, - SerdSink sink, - void* stream); - -/** - Free @c writer. -*/ -SERD_API -void -serd_writer_free(SerdWriter* writer); - -/** - Return the env used by @c writer. -*/ -SERD_API -SerdEnv* -serd_writer_get_env(SerdWriter* writer); - -/** - A convenience sink function for writing to a FILE*. - - This function can be used as a SerdSink when writing to a FILE*. The - @c stream parameter must be a FILE* opened for writing. -*/ -SERD_API -size_t -serd_file_sink(const void* buf, size_t len, void* stream); - -/** - A convenience sink function for writing to a string. - - This function can be used as a SerdSink to write to a SerdChunk which is - resized as necessary with realloc(). The @c stream parameter must point to - an initialized SerdChunk. When the write is finished, the string should be - retrieved with serd_chunk_sink_finish(). -*/ -SERD_API -size_t -serd_chunk_sink(const void* buf, size_t len, void* stream); - -/** - Finish a serialisation to a chunk with serd_chunk_sink(). - - The returned string is the result of the serialisation, which is NULL - terminated (by this function) and owned by the caller. -*/ -SERD_API -uint8_t* -serd_chunk_sink_finish(SerdChunk* stream); - -/** - Set a function to be called when errors occur during writing. - - The @p error_sink will be called with @p handle as its first argument. If - no error function is set, errors are printed to stderr. -*/ -SERD_API -void -serd_writer_set_error_sink(SerdWriter* writer, - SerdErrorSink error_sink, - void* handle); - -/** - Set a prefix to be removed from matching blank node identifiers. -*/ -SERD_API -void -serd_writer_chop_blank_prefix(SerdWriter* writer, - const uint8_t* prefix); - -/** - Set the current output base URI (and emit directive if applicable). - - Note this function can be safely casted to SerdBaseSink. -*/ -SERD_API -SerdStatus -serd_writer_set_base_uri(SerdWriter* writer, - const SerdNode* uri); - -/** - Set the current root URI. - - The root URI should be a prefix of the base URI. The path of the root URI - is the highest path any relative up-reference can refer to. For example, - with root <file:///foo/root> and base <file:///foo/root/base>, - <file:///foo/root> will be written as <../>, but <file:///foo> will be - written non-relatively as <file:///foo>. If the root is not explicitly set, - it defaults to the base URI, so no up-references will be created at all. -*/ -SERD_API -SerdStatus -serd_writer_set_root_uri(SerdWriter* writer, - const SerdNode* uri); - -/** - Set a namespace prefix (and emit directive if applicable). - - Note this function can be safely casted to SerdPrefixSink. -*/ -SERD_API -SerdStatus -serd_writer_set_prefix(SerdWriter* writer, - const SerdNode* name, - const SerdNode* uri); - -/** - Write a statement. - - Note this function can be safely casted to SerdStatementSink. -*/ -SERD_API -SerdStatus -serd_writer_write_statement(SerdWriter* writer, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang); - -/** - Mark the end of an anonymous node's description. - - Note this function can be safely casted to SerdEndSink. -*/ -SERD_API -SerdStatus -serd_writer_end_anon(SerdWriter* writer, - const SerdNode* node); - -/** - Finish a write. -*/ -SERD_API -SerdStatus -serd_writer_finish(SerdWriter* writer); - -/** - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SERD_SERD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/serd/serd.h Thu Jan 09 21:21:48 2014 +0000 @@ -0,0 +1,963 @@ +/* + Copyright 2011-2012 David Robillard <http://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. +*/ + +/** + @file serd.h API for Serd, a lightweight RDF syntax library. +*/ + +#ifndef SERD_SERD_H +#define SERD_SERD_H + +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#ifdef SERD_SHARED +# ifdef _WIN32 +# define SERD_LIB_IMPORT __declspec(dllimport) +# define SERD_LIB_EXPORT __declspec(dllexport) +# else +# define SERD_LIB_IMPORT __attribute__((visibility("default"))) +# define SERD_LIB_EXPORT __attribute__((visibility("default"))) +# endif +# ifdef SERD_INTERNAL +# define SERD_API SERD_LIB_EXPORT +# else +# define SERD_API SERD_LIB_IMPORT +# endif +#else +# define SERD_API +#endif + +#ifdef __cplusplus +extern "C" { +#else +# include <stdbool.h> +#endif + +/** + @defgroup serd Serd + A lightweight RDF syntax library. + @{ +*/ + +/** + Environment. + + Represents the state required to resolve a CURIE or relative URI, e.g. the + base URI and set of namespace prefixes at a particular point. +*/ +typedef struct SerdEnvImpl SerdEnv; + +/** + RDF reader. + + Parses RDF by calling user-provided sink functions as input is consumed + (much like an XML SAX parser). +*/ +typedef struct SerdReaderImpl SerdReader; + +/** + RDF writer. + + Provides a number of functions to allow writing RDF syntax out to some + stream. These functions are deliberately compatible with the sink functions + used by SerdReader, so a reader can be directly connected to a writer to + re-serialise a document with minimal overhead. +*/ +typedef struct SerdWriterImpl SerdWriter; + +/** + Return status code. +*/ +typedef enum { + SERD_SUCCESS, /**< No error */ + SERD_FAILURE, /**< Non-fatal failure */ + SERD_ERR_UNKNOWN, /**< Unknown error */ + SERD_ERR_BAD_SYNTAX, /**< Invalid syntax */ + SERD_ERR_BAD_ARG, /**< Invalid argument */ + SERD_ERR_NOT_FOUND, /**< Not found */ + SERD_ERR_ID_CLASH, /**< Encountered clashing blank node IDs */ + SERD_ERR_BAD_CURIE, /**< Invalid CURIE (e.g. prefix does not exist) */ + SERD_ERR_INTERNAL /**< Unexpected internal error (should not happen) */ +} SerdStatus; + +/** + RDF syntax type. +*/ +typedef enum { + /** + Turtle - Terse RDF Triple Language (UTF-8). + @see <a href="http://www.w3.org/TeamSubmission/turtle/">Turtle</a> + */ + SERD_TURTLE = 1, + + /** + NTriples - Line-based RDF triples (ASCII). + @see <a href="http://www.w3.org/TR/rdf-testcases#ntriples">NTriples</a> + */ + SERD_NTRIPLES = 2 +} SerdSyntax; + +/** + Flags indication inline abbreviation information for a statement. +*/ +typedef enum { + SERD_EMPTY_S = 1 << 1, /**< Empty blank node subject */ + SERD_EMPTY_O = 1 << 2, /**< Empty blank node object */ + SERD_ANON_S_BEGIN = 1 << 3, /**< Start of anonymous subject */ + SERD_ANON_O_BEGIN = 1 << 4, /**< Start of anonymous object */ + SERD_ANON_CONT = 1 << 5, /**< Continuation of anonymous node */ + SERD_LIST_S_BEGIN = 1 << 6, /**< Start of list subject */ + SERD_LIST_O_BEGIN = 1 << 7, /**< Start of list object */ + SERD_LIST_CONT = 1 << 8 /**< Continuation of list */ +} SerdStatementFlag; + +/** + Bitwise OR of SerdNodeFlag values. +*/ +typedef uint32_t SerdStatementFlags; + +/** + Type of a syntactic RDF node. + + This is more precise than the type of an abstract RDF node. An abstract + node is either a resource, literal, or blank. In syntax there are two ways + to refer to a resource (by URI or CURIE) and two ways to refer to a blank + (by ID or anonymously). Anonymous (inline) blank nodes are expressed using + SerdStatementFlags rather than this type. +*/ +typedef enum { + /** + The type of a nonexistent node. + + This type is useful as a sentinel, but is never emitted by the reader. + */ + SERD_NOTHING = 0, + + /** + Literal value. + + A literal optionally has either a language, or a datatype (not both). + */ + SERD_LITERAL = 1, + + /** + URI (absolute or relative). + + Value is an unquoted URI string, which is either a relative reference + with respect to the current base URI (e.g. "foo/bar"), or an absolute + URI (e.g. "http://example.org/foo"). + @see <a href="http://tools.ietf.org/html/rfc3986">RFC3986</a>. + */ + SERD_URI = 2, + + /** + CURIE, a shortened URI. + + Value is an unquoted CURIE string relative to the current environment, + e.g. "rdf:type". + @see <a href="http://www.w3.org/TR/curie">CURIE Syntax 1.0</a> + */ + SERD_CURIE = 3, + + /** + A blank node. + + Value is a blank node ID, e.g. "id3", which is meaningful only within + this serialisation. + @see <a href="http://www.w3.org/TeamSubmission/turtle#nodeID">Turtle + <tt>nodeID</tt></a> + */ + SERD_BLANK = 4, + +} SerdType; + +/** + Flags indicating certain string properties relevant to serialisation. +*/ +typedef enum { + SERD_HAS_NEWLINE = 1, /**< Contains line breaks ('\\n' or '\\r') */ + SERD_HAS_QUOTE = 1 << 1 /**< Contains quotes ('"') */ +} SerdNodeFlag; + +/** + Bitwise OR of SerdNodeFlag values. +*/ +typedef uint32_t SerdNodeFlags; + +/** + A syntactic RDF node. +*/ +typedef struct { + const uint8_t* buf; /**< Value string */ + size_t n_bytes; /**< Size in bytes (not including null) */ + size_t n_chars; /**< Length in characters (not including null)*/ + SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ + SerdType type; /**< Node type */ +} SerdNode; + +/** + An unterminated string fragment. +*/ +typedef struct { + const uint8_t* buf; /**< Start of chunk */ + size_t len; /**< Length of chunk in bytes */ +} SerdChunk; + +/** + An error description. +*/ +typedef struct { + SerdStatus status; /**< Error code */ + const uint8_t* filename; /**< File where error was encountered, or NULL */ + unsigned line; /**< Line where error was encountered, or 0 */ + unsigned col; /**< Column where error was encountered */ + const char* fmt; /**< Message format string (printf style) */ + va_list* args; /**< Arguments for fmt */ +} SerdError; + +/** + A parsed URI. + + This struct directly refers to chunks in other strings, it does not own any + memory itself. Thus, URIs can be parsed and/or resolved against a base URI + in-place without allocating memory. +*/ +typedef struct { + SerdChunk scheme; /**< Scheme */ + SerdChunk authority; /**< Authority */ + SerdChunk path_base; /**< Path prefix if relative */ + SerdChunk path; /**< Path suffix */ + SerdChunk query; /**< Query */ + SerdChunk fragment; /**< Fragment */ +} SerdURI; + +/** + Syntax style options. + + The style of the writer output can be controlled by ORing together + values from this enumeration. Note that some options are only supported + for some syntaxes (e.g. NTriples does not support abbreviation and is + always ASCII). +*/ +typedef enum { + SERD_STYLE_ABBREVIATED = 1, /**< Abbreviate triples when possible. */ + SERD_STYLE_ASCII = 1 << 1, /**< Escape all non-ASCII characters. */ + SERD_STYLE_RESOLVED = 1 << 2, /**< Resolve URIs against base URI. */ + SERD_STYLE_CURIED = 1 << 3, /**< Shorten URIs into CURIEs. */ + SERD_STYLE_BULK = 1 << 4 /**< Write output in pages. */ +} SerdStyle; + +/** + @name String Utilities + @{ +*/ + +/** + Return a string describing a status code. +*/ +SERD_API +const uint8_t* +serd_strerror(SerdStatus status); + +/** + Measure a UTF-8 string. + @return Length of @c str in characters (except NULL). + @param str A null-terminated UTF-8 string. + @param n_bytes (Output) Set to the size of @c str in bytes (except NULL). + @param flags (Output) Set to the applicable flags. +*/ +SERD_API +size_t +serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags); + +/** + Parse a string to a double. + + The API of this function is identical to the standard C strtod function, + except this function is locale-independent and always matches the lexical + format used in the Turtle grammar (the decimal point is always "."). +*/ +SERD_API +double +serd_strtod(const char* str, char** endptr); + +/** + Decode a base64 string. + This function can be used to deserialise a blob node created with + serd_node_new_blob(). + + @param str Base64 string to decode. + @param len The length of @c str. + @param size Set to the size of the returned blob in bytes. + @return A newly allocated blob which must be freed with free(). +*/ +SERD_API +void* +serd_base64_decode(const uint8_t* str, size_t len, size_t* size); + +/** + @} + @name URI + @{ +*/ + +static const SerdURI SERD_URI_NULL = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; + +/** + Return the local path for @c uri, or NULL if @c uri is not a file URI. + Note this (inappropriately named) function only removes the file scheme if + necessary, and returns @c uri unmodified if it is an absolute path. Percent + encoding and other issues are not handled, to properly convert a file URI to + a path, use serd_file_uri_parse(). +*/ +SERD_API +const uint8_t* +serd_uri_to_path(const uint8_t* uri); + +/** + Get the unescaped path and hostname from a file URI. + @param uri A file URI. + @param hostname If non-NULL, set to the hostname, if present. + @return The path component of the URI. + + Both the returned path and @c hostname (if applicable) are owned by the + caller and must be freed with free(). +*/ +SERD_API +uint8_t* +serd_file_uri_parse(const uint8_t* uri, uint8_t** hostname); + +/** + Return true iff @c utf8 starts with a valid URI scheme. +*/ +SERD_API +bool +serd_uri_string_has_scheme(const uint8_t* utf8); + +/** + Parse @c utf8, writing result to @c out. +*/ +SERD_API +SerdStatus +serd_uri_parse(const uint8_t* utf8, SerdURI* out); + +/** + Set @c out to @c uri resolved against @c base. +*/ +SERD_API +void +serd_uri_resolve(const SerdURI* uri, const SerdURI* base, SerdURI* out); + +/** + Sink function for raw string output. +*/ +typedef size_t (*SerdSink)(const void* buf, size_t len, void* stream); + +/** + Serialise @c uri with a series of calls to @c sink. +*/ +SERD_API +size_t +serd_uri_serialise(const SerdURI* uri, SerdSink sink, void* stream); + +/** + Serialise @c uri relative to @c base with a series of calls to @c sink. + + The @c uri is written as a relative URI iff if it a child of @c base and @c + root. The optional @c root parameter must be a prefix of @c base and can be + used keep up-references ("../") within a certain namespace. +*/ +SERD_API +size_t +serd_uri_serialise_relative(const SerdURI* uri, + const SerdURI* base, + const SerdURI* root, + SerdSink sink, + void* stream); + +/** + @} + @name Node + @{ +*/ + +static const SerdNode SERD_NODE_NULL = { 0, 0, 0, 0, SERD_NOTHING }; + +/** + Make a (shallow) node from @c str. + + This measures, but does not copy, @c str. No memory is allocated. +*/ +SERD_API +SerdNode +serd_node_from_string(SerdType type, const uint8_t* str); + +/** + Make a deep copy of @c node. + + @return a node that the caller must free with @ref serd_node_free. +*/ +SERD_API +SerdNode +serd_node_copy(const SerdNode* node); + +/** + Return true iff @c a is equal to @c b. +*/ +SERD_API +bool +serd_node_equals(const SerdNode* a, const SerdNode* b); + +/** + Simple wrapper for serd_node_new_uri to resolve a URI node. +*/ +SERD_API +SerdNode +serd_node_new_uri_from_node(const SerdNode* uri_node, + const SerdURI* base, + SerdURI* out); + +/** + Simple wrapper for serd_node_new_uri to resolve a URI string. +*/ +SERD_API +SerdNode +serd_node_new_uri_from_string(const uint8_t* str, + const SerdURI* base, + SerdURI* out); + +/** + Create a new file URI node from a file system path and optional hostname. + + Backslashes in Windows paths will be converted and '%' will always be + percent encoded. If @c escape is true, all other invalid characters will be + percent encoded as well. + + If @c path is relative, @c hostname is ignored. + If @c out is not NULL, it will be set to the parsed URI. +*/ +SERD_API +SerdNode +serd_node_new_file_uri(const uint8_t* path, + const uint8_t* hostname, + SerdURI* out, + bool escape); + +/** + Create a new node by serialising @c uri into a new string. + + @param uri The URI to parse and serialise. + + @param base Base URI to resolve @c uri against (or NULL for no resolution). + + @param out Set to the parsing of the new URI (i.e. points only to + memory owned by the new returned node). +*/ +SERD_API +SerdNode +serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out); + +/** + Create a new node by serialising @c d into an xsd:decimal string. + + The resulting node will always contain a `.', start with a digit, and end + with a digit (i.e. will have a leading and/or trailing `0' if necessary). + It will never be in scientific notation. A maximum of @c frac_digits digits + will be written after the decimal point, but trailing zeros will + automatically be omitted (except one if @c d is a round integer). + + Note that about 16 and 8 fractional digits are required to precisely + represent a double and float, respectively. + + @param d The value for the new node. + @param frac_digits The maximum number of digits after the decimal place. +*/ +SERD_API +SerdNode +serd_node_new_decimal(double d, unsigned frac_digits); + +/** + Create a new node by serialising @c i into an xsd:integer string. +*/ +SERD_API +SerdNode +serd_node_new_integer(int64_t i); + +/** + Create a node by serialising @c buf into an xsd:base64Binary string. + This function can be used to make a serialisable node out of arbitrary + binary data, which can be decoded using serd_base64_decode(). + + @param buf Raw binary input data. + @param size Size of @c buf. + @param wrap_lines Wrap lines at 76 characters to conform to RFC 2045. +*/ +SERD_API +SerdNode +serd_node_new_blob(const void* buf, size_t size, bool wrap_lines); + +/** + Free any data owned by @c node. + + Note that if @c node is itself dynamically allocated (which is not the case + for nodes created internally by serd), it will not be freed. +*/ +SERD_API +void +serd_node_free(SerdNode* node); + +/** + @} + @name Event Handlers + @{ +*/ + +/** + Sink (callback) for errors. + + @param handle Handle for user data. + @param error Error description. +*/ +typedef SerdStatus (*SerdErrorSink)(void* handle, + const SerdError* error); + +/** + Sink (callback) for base URI changes. + + Called whenever the base URI of the serialisation changes. +*/ +typedef SerdStatus (*SerdBaseSink)(void* handle, + const SerdNode* uri); + +/** + Sink (callback) for namespace definitions. + + Called whenever a prefix is defined in the serialisation. +*/ +typedef SerdStatus (*SerdPrefixSink)(void* handle, + const SerdNode* name, + const SerdNode* uri); + +/** + Sink (callback) for statements. + + Called for every RDF statement in the serialisation. +*/ +typedef SerdStatus (*SerdStatementSink)(void* handle, + SerdStatementFlags flags, + const SerdNode* graph, + const SerdNode* subject, + const SerdNode* predicate, + const SerdNode* object, + const SerdNode* object_datatype, + const SerdNode* object_lang); + +/** + Sink (callback) for anonymous node end markers. + + This is called to indicate that the anonymous node with the given + @c value will no longer be referred to by any future statements + (i.e. the anonymous serialisation of the node is finished). +*/ +typedef SerdStatus (*SerdEndSink)(void* handle, + const SerdNode* node); + +/** + @} + @name Environment + @{ +*/ + +/** + Create a new environment. +*/ +SERD_API +SerdEnv* +serd_env_new(const SerdNode* base_uri); + +/** + Free @c ns. +*/ +SERD_API +void +serd_env_free(SerdEnv* env); + +/** + Get the current base URI. +*/ +SERD_API +const SerdNode* +serd_env_get_base_uri(const SerdEnv* env, + SerdURI* out); + +/** + Set the current base URI. +*/ +SERD_API +SerdStatus +serd_env_set_base_uri(SerdEnv* env, + const SerdNode* uri); + +/** + Set a namespace prefix. +*/ +SERD_API +SerdStatus +serd_env_set_prefix(SerdEnv* env, + const SerdNode* name, + const SerdNode* uri); + +/** + Set a namespace prefix. +*/ +SERD_API +SerdStatus +serd_env_set_prefix_from_strings(SerdEnv* env, + const uint8_t* name, + const uint8_t* uri); + +/** + Qualify @c uri into a CURIE if possible. +*/ +SERD_API +bool +serd_env_qualify(const SerdEnv* env, + const SerdNode* uri, + SerdNode* prefix, + SerdChunk* suffix); + +/** + Expand @c curie. +*/ +SERD_API +SerdStatus +serd_env_expand(const SerdEnv* env, + const SerdNode* curie, + SerdChunk* uri_prefix, + SerdChunk* uri_suffix); + +/** + Expand @c node, which must be a CURIE or URI, to a full URI. +*/ +SERD_API +SerdNode +serd_env_expand_node(const SerdEnv* env, + const SerdNode* node); + +/** + Call @c func for each prefix defined in @c env. +*/ +SERD_API +void +serd_env_foreach(const SerdEnv* env, + SerdPrefixSink func, + void* handle); + +/** + @} + @name Reader + @{ +*/ + +/** + Create a new RDF reader. +*/ +SERD_API +SerdReader* +serd_reader_new(SerdSyntax syntax, + void* handle, + void (*free_handle)(void*), + SerdBaseSink base_sink, + SerdPrefixSink prefix_sink, + SerdStatementSink statement_sink, + SerdEndSink end_sink); + +/** + Set a function to be called when errors occur during reading. + + The @p error_sink will be called with @p handle as its first argument. If + no error function is set, errors are printed to stderr in GCC style. +*/ +SERD_API +void +serd_reader_set_error_sink(SerdReader* reader, + SerdErrorSink error_sink, + void* handle); + +/** + Return the @c handle passed to @ref serd_reader_new. +*/ +SERD_API +void* +serd_reader_get_handle(const SerdReader* reader); + +/** + Set a prefix to be added to all blank node identifiers. + + This is useful when multiple files are to be parsed into the same output + (e.g. a store, or other files). Since Serd preserves blank node IDs, this + could cause conflicts where two non-equivalent blank nodes are merged, + resulting in corrupt data. By setting a unique blank node prefix for each + parsed file, this can be avoided, while preserving blank node names. +*/ +SERD_API +void +serd_reader_add_blank_prefix(SerdReader* reader, + const uint8_t* prefix); + +/** + Set the URI of the default graph. + + If this is set, the reader will emit quads with the graph set to the given + node for any statements that are not in a named graph (which is currently + all of them since Serd currently does not support any graph syntaxes). +*/ +SERD_API +void +serd_reader_set_default_graph(SerdReader* reader, + const SerdNode* graph); + +/** + Read a file at a given @c uri. +*/ +SERD_API +SerdStatus +serd_reader_read_file(SerdReader* reader, + const uint8_t* uri); + +/** + Start an incremental read from a file handle. + + Iff @p bulk is true, @p file will be read a page at a time. This is more + efficient, but uses a page of memory and means that an entire page of input + must be ready before any callbacks will fire. To react as soon as input + arrives, set @p bulk to false. +*/ +SERD_API +SerdStatus +serd_reader_start_stream(SerdReader* me, + FILE* file, + const uint8_t* name, + bool bulk); + +/** + Read a single "chunk" of data during an incremental read. + + This function will read a single top level description, and return. This + may be a directive, statement, or several statements; essentially it reads + until a '.' is encountered. This is particularly useful for reading + directly from a pipe or socket. +*/ +SERD_API +SerdStatus +serd_reader_read_chunk(SerdReader* me); + +/** + Finish an incremental read from a file handle. +*/ +SERD_API +SerdStatus +serd_reader_end_stream(SerdReader* me); + +/** + Read @c file. +*/ +SERD_API +SerdStatus +serd_reader_read_file_handle(SerdReader* reader, + FILE* file, + const uint8_t* name); + +/** + Read @c utf8. +*/ +SERD_API +SerdStatus +serd_reader_read_string(SerdReader* me, const uint8_t* utf8); + +/** + Free @c reader. +*/ +SERD_API +void +serd_reader_free(SerdReader* reader); + +/** + @} + @name Writer + @{ +*/ + +/** + Create a new RDF writer. +*/ +SERD_API +SerdWriter* +serd_writer_new(SerdSyntax syntax, + SerdStyle style, + SerdEnv* env, + const SerdURI* base_uri, + SerdSink sink, + void* stream); + +/** + Free @c writer. +*/ +SERD_API +void +serd_writer_free(SerdWriter* writer); + +/** + Return the env used by @c writer. +*/ +SERD_API +SerdEnv* +serd_writer_get_env(SerdWriter* writer); + +/** + A convenience sink function for writing to a FILE*. + + This function can be used as a SerdSink when writing to a FILE*. The + @c stream parameter must be a FILE* opened for writing. +*/ +SERD_API +size_t +serd_file_sink(const void* buf, size_t len, void* stream); + +/** + A convenience sink function for writing to a string. + + This function can be used as a SerdSink to write to a SerdChunk which is + resized as necessary with realloc(). The @c stream parameter must point to + an initialized SerdChunk. When the write is finished, the string should be + retrieved with serd_chunk_sink_finish(). +*/ +SERD_API +size_t +serd_chunk_sink(const void* buf, size_t len, void* stream); + +/** + Finish a serialisation to a chunk with serd_chunk_sink(). + + The returned string is the result of the serialisation, which is NULL + terminated (by this function) and owned by the caller. +*/ +SERD_API +uint8_t* +serd_chunk_sink_finish(SerdChunk* stream); + +/** + Set a function to be called when errors occur during writing. + + The @p error_sink will be called with @p handle as its first argument. If + no error function is set, errors are printed to stderr. +*/ +SERD_API +void +serd_writer_set_error_sink(SerdWriter* writer, + SerdErrorSink error_sink, + void* handle); + +/** + Set a prefix to be removed from matching blank node identifiers. +*/ +SERD_API +void +serd_writer_chop_blank_prefix(SerdWriter* writer, + const uint8_t* prefix); + +/** + Set the current output base URI (and emit directive if applicable). + + Note this function can be safely casted to SerdBaseSink. +*/ +SERD_API +SerdStatus +serd_writer_set_base_uri(SerdWriter* writer, + const SerdNode* uri); + +/** + Set the current root URI. + + The root URI should be a prefix of the base URI. The path of the root URI + is the highest path any relative up-reference can refer to. For example, + with root <file:///foo/root> and base <file:///foo/root/base>, + <file:///foo/root> will be written as <../>, but <file:///foo> will be + written non-relatively as <file:///foo>. If the root is not explicitly set, + it defaults to the base URI, so no up-references will be created at all. +*/ +SERD_API +SerdStatus +serd_writer_set_root_uri(SerdWriter* writer, + const SerdNode* uri); + +/** + Set a namespace prefix (and emit directive if applicable). + + Note this function can be safely casted to SerdPrefixSink. +*/ +SERD_API +SerdStatus +serd_writer_set_prefix(SerdWriter* writer, + const SerdNode* name, + const SerdNode* uri); + +/** + Write a statement. + + Note this function can be safely casted to SerdStatementSink. +*/ +SERD_API +SerdStatus +serd_writer_write_statement(SerdWriter* writer, + SerdStatementFlags flags, + const SerdNode* graph, + const SerdNode* subject, + const SerdNode* predicate, + const SerdNode* object, + const SerdNode* object_datatype, + const SerdNode* object_lang); + +/** + Mark the end of an anonymous node's description. + + Note this function can be safely casted to SerdEndSink. +*/ +SERD_API +SerdStatus +serd_writer_end_anon(SerdWriter* writer, + const SerdNode* node); + +/** + Finish a write. +*/ +SERD_API +SerdStatus +serd_writer_finish(SerdWriter* writer); + +/** + @} + @} +*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SERD_SERD_H */
--- a/osx/include/sord-0/sord/sord.h Thu Jan 09 13:23:08 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,627 +0,0 @@ -/* - Copyright 2011-2013 David Robillard <http://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. -*/ - -/** - @file sord.h API for Sord, a lightweight RDF model library. -*/ - -#ifndef SORD_SORD_H -#define SORD_SORD_H - -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> - -#include "serd/serd.h" - -#ifdef SORD_SHARED -# ifdef _WIN32 -# define SORD_LIB_IMPORT __declspec(dllimport) -# define SORD_LIB_EXPORT __declspec(dllexport) -# else -# define SORD_LIB_IMPORT __attribute__((visibility("default"))) -# define SORD_LIB_EXPORT __attribute__((visibility("default"))) -# endif -# ifdef SORD_INTERNAL -# define SORD_API SORD_LIB_EXPORT -# else -# define SORD_API SORD_LIB_IMPORT -# endif -#else -# define SORD_API -#endif - -#ifdef __cplusplus -extern "C" { -#else -# include <stdbool.h> -#endif - -/** - @defgroup sord Sord - A lightweight RDF model library. - - Sord stores RDF (subject object predicate context) quads, where the context - may be omitted (to represent triples in the default graph). - @{ -*/ - -/** - Sord World. - The World represents all library state, including interned strings. -*/ -typedef struct SordWorldImpl SordWorld; - -/** - Sord Model. - - A model is an indexed set of Quads (i.e. it can contain several RDF - graphs). It may be searched using various patterns depending on which - indices are enabled. -*/ -typedef struct SordModelImpl SordModel; - -/** - Model Inserter. - - An inserter is used for writing statements to a model using the Serd sink - interface. This makes it simple to write to a model directly using a - SerdReader, or any other code that writes statements to a SerdStatementSink. -*/ -typedef struct SordInserterImpl SordInserter; - -/** - Model Iterator. -*/ -typedef struct SordIterImpl SordIter; - -/** - RDF Node. - A Node is a component of a Quad. Nodes may be URIs, blank nodes, or - (in the case of quad objects only) string literals. Literal nodes may - have an associate language or datatype (but not both). -*/ -typedef struct SordNodeImpl SordNode; - -/** - Quad of nodes (a statement), or a quad pattern. - - Nodes are ordered (S P O G). The ID of the default graph is 0. -*/ -typedef const SordNode* SordQuad[4]; - -/** - Index into a SordQuad. -*/ -typedef enum { - SORD_SUBJECT = 0, /**< Subject */ - SORD_PREDICATE = 1, /**< Predicate (a.k.a. "key") */ - SORD_OBJECT = 2, /**< Object (a.k.a. "value") */ - SORD_GRAPH = 3 /**< Graph (a.k.a. "context") */ -} SordQuadIndex; - -/** - Type of a node. -*/ -typedef enum { - SORD_URI = 1, /**< URI */ - SORD_BLANK = 2, /**< Blank node identifier */ - SORD_LITERAL = 3 /**< Literal (string with optional lang or datatype) */ -} SordNodeType; - -/** - Indexing option. -*/ -typedef enum { - SORD_SPO = 1, /**< Subject, Predicate, Object */ - SORD_SOP = 1 << 1, /**< Subject, Object, Predicate */ - SORD_OPS = 1 << 2, /**< Object, Predicate, Subject */ - SORD_OSP = 1 << 3, /**< Object, Subject, Predicate */ - SORD_PSO = 1 << 4, /**< Predicate, Subject, Object */ - SORD_POS = 1 << 5 /**< Predicate, Object, Subject */ -} SordIndexOption; - -/** - @name World - @{ -*/ - -/** - Create a new Sord World. - It is safe to use multiple worlds in one process, though no data - (e.g. nodes) can be shared between worlds, and this should be avoided if - possible for performance reasons. -*/ -SORD_API -SordWorld* -sord_world_new(void); - -/** - Free @c world. -*/ -SORD_API -void -sord_world_free(SordWorld* world); - -/** - Set a function to be called when errors occur. - - The @p error_sink will be called with @p handle as its first argument. If - no error function is set, errors are printed to stderr. -*/ -SORD_API -void -sord_world_set_error_sink(SordWorld* world, - SerdErrorSink error_sink, - void* handle); - -/** - @} - @name Node - @{ -*/ - -/** - Get a URI node from a string. - - Note this function measures @c str, which is a common bottleneck. - Use sord_node_from_serd_node instead if @c str is already measured. -*/ -SORD_API -SordNode* -sord_new_uri(SordWorld* world, const uint8_t* uri); - -/** - Get a URI node from a relative URI string. -*/ -SORD_API -SordNode* -sord_new_relative_uri(SordWorld* world, - const uint8_t* str, - const uint8_t* base_uri); - -/** - Get a blank node from a string. - - Note this function measures @c str, which is a common bottleneck. - Use sord_node_from_serd_node instead if @c str is already measured. -*/ -SORD_API -SordNode* -sord_new_blank(SordWorld* world, const uint8_t* str); - -/** - Get a literal node from a string. - - Note this function measures @c str, which is a common bottleneck. - Use sord_node_from_serd_node instead if @c str is already measured. -*/ -SORD_API -SordNode* -sord_new_literal(SordWorld* world, - SordNode* datatype, - const uint8_t* str, - const char* lang); - -/** - Copy a node (obtain a reference). - - Node that since nodes are interned and reference counted, this does not - actually create a deep copy of @c node. -*/ -SORD_API -SordNode* -sord_node_copy(const SordNode* node); - -/** - Free a node (drop a reference). -*/ -SORD_API -void -sord_node_free(SordWorld* world, SordNode* node); - -/** - Return the type of a node (SORD_URI, SORD_BLANK, or SORD_LITERAL). -*/ -SORD_API -SordNodeType -sord_node_get_type(const SordNode* node); - -/** - Return the string value of a node. -*/ -SORD_API -const uint8_t* -sord_node_get_string(const SordNode* node); - -/** - Return the string value of a node, and set @c len to its length. -*/ -SORD_API -const uint8_t* -sord_node_get_string_counted(const SordNode* node, size_t* len); - -/** - Return the language of a literal node (or NULL). -*/ -SORD_API -const char* -sord_node_get_language(const SordNode* node); - -/** - Return the datatype URI of a literal node (or NULL). -*/ -SORD_API -SordNode* -sord_node_get_datatype(const SordNode* node); - -/** - Return the flags (string attributes) of a node. -*/ -SORD_API -SerdNodeFlags -sord_node_get_flags(const SordNode* node); - -/** - Return true iff node can be serialised as an inline object. - - More specifically, this returns true iff the node is the object field - of exactly one statement, and therefore can be inlined since it needn't - be referred to by name. -*/ -SORD_API -bool -sord_node_is_inline_object(const SordNode* node); - -/** - Return true iff @c a is equal to @c b. - - Note this is much faster than comparing the node's strings. -*/ -SORD_API -bool -sord_node_equals(const SordNode* a, - const SordNode* b); - -/** - Return a SordNode as a SerdNode. - - The returned node is shared and must not be freed or modified. -*/ -SORD_API -const SerdNode* -sord_node_to_serd_node(const SordNode* node); - -/** - Create a new SordNode from a SerdNode. - - The returned node must be freed using sord_node_free. -*/ -SORD_API -SordNode* -sord_node_from_serd_node(SordWorld* world, - SerdEnv* env, - const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang); - -/** - @} - @name Model - @{ -*/ - -/** - Create a new model. - - @param world The world in which to make this model. - - @param indices SordIndexOption flags (e.g. SORD_SPO|SORD_OPS). Be sure to - enable an index where the most significant node(s) are not variables in your - queries (e.g. to make (? P O) queries, enable either SORD_OPS or SORD_POS). - - @param graphs If true, store (and index) graph contexts. -*/ -SORD_API -SordModel* -sord_new(SordWorld* world, - unsigned indices, - bool graphs); - -/** - Close and free @c model. -*/ -SORD_API -void -sord_free(SordModel* model); - -/** - Get the world associated with @c model. -*/ -SORD_API -SordWorld* -sord_get_world(SordModel* model); - -/** - Return the number of nodes stored in @c world. - - Nodes are included in this count iff they are a part of a quad in @c world. -*/ -SORD_API -size_t -sord_num_nodes(const SordWorld* world); - -/** - Return the number of quads stored in @c model. -*/ -SORD_API -size_t -sord_num_quads(const SordModel* model); - -/** - Return an iterator to the start of @c model. -*/ -SORD_API -SordIter* -sord_begin(const SordModel* model); - -/** - Search for statements by a quad pattern. - @return an iterator to the first match, or NULL if no matches found. -*/ -SORD_API -SordIter* -sord_find(SordModel* model, const SordQuad pat); - -/** - Search for statements by nodes. - @return an iterator to the first match, or NULL if no matches found. -*/ -SORD_API -SordIter* -sord_search(SordModel* model, - const SordNode* s, - const SordNode* p, - const SordNode* o, - const SordNode* g); -/** - Search for a single node that matches a pattern. - Exactly one of @p s, @p p, @p o must be NULL. - This function is mainly useful for predicates that only have one value. - The returned node must be freed using sord_node_free. - @return the first matching node, or NULL if no matches are found. -*/ -SORD_API -SordNode* -sord_get(SordModel* model, - const SordNode* s, - const SordNode* p, - const SordNode* o, - const SordNode* g); - -/** - Return true iff a statement exists. -*/ -SORD_API -bool -sord_ask(SordModel* model, - const SordNode* s, - const SordNode* p, - const SordNode* o, - const SordNode* g); - -/** - Return the number of matching statements. -*/ -SORD_API -uint64_t -sord_count(SordModel* model, - const SordNode* s, - const SordNode* p, - const SordNode* o, - const SordNode* g); - -/** - Check if @a model contains a triple pattern. -*/ -SORD_API -bool -sord_contains(SordModel* model, const SordQuad pat); - -/** - Add a quad to a model. -*/ -SORD_API -bool -sord_add(SordModel* model, const SordQuad quad); - -/** - Remove a quad from a model. - - Note that is it illegal to remove while iterating over @c model. -*/ -SORD_API -void -sord_remove(SordModel* model, const SordQuad quad); - -/** - @} - @name Inserter - @{ -*/ - -/** - Create an inserter for writing statements to a model. -*/ -SORD_API -SordInserter* -sord_inserter_new(SordModel* model, - SerdEnv* env); - -/** - Free an inserter. -*/ -SORD_API -void -sord_inserter_free(SordInserter* inserter); - -/** - Set the current base URI for writing to the model. - - Note this function can be safely casted to SerdBaseSink. -*/ -SORD_API -SerdStatus -sord_inserter_set_base_uri(SordInserter* inserter, - const SerdNode* uri); - -/** - Set a namespace prefix for writing to the model. - - Note this function can be safely casted to SerdPrefixSink. -*/ -SORD_API -SerdStatus -sord_inserter_set_prefix(SordInserter* inserter, - const SerdNode* name, - const SerdNode* uri); - -/** - Write a statement to the model. - - Note this function can be safely casted to SerdStatementSink. -*/ -SORD_API -SerdStatus -sord_inserter_write_statement(SordInserter* inserter, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang); - -/** - @} - @name Iteration - @{ -*/ - -/** - Set @c quad to the quad pointed to by @c iter. -*/ -SORD_API -void -sord_iter_get(const SordIter* iter, SordQuad quad); - -/** - Return a field of the quad pointed to by @c iter. -*/ -SORD_API -const SordNode* -sord_iter_get_node(const SordIter* iter, SordQuadIndex index); - -/** - Return the store pointed to by @c iter. -*/ -SORD_API -const SordModel* -sord_iter_get_model(SordIter* iter); - -/** - Increment @c iter to point to the next statement. -*/ -SORD_API -bool -sord_iter_next(SordIter* iter); - -/** - Return true iff @c iter is at the end of its range. -*/ -SORD_API -bool -sord_iter_end(const SordIter* iter); - -/** - Free @c iter. -*/ -SORD_API -void -sord_iter_free(SordIter* iter); - -/** - @} - @name Utilities - @{ -*/ - -/** - Match two quads (using ID comparison only). - - This function is a straightforward and fast equivalence match with wildcard - support (ID 0 is a wildcard). It does not actually read node data. - @return true iff @c x and @c y match. -*/ -SORD_API -bool -sord_quad_match(const SordQuad x, const SordQuad y); - -/** - @} - @name Serialisation - @{ -*/ - -/** - Return a reader that will read into @c model. -*/ -SORD_API -SerdReader* -sord_new_reader(SordModel* model, - SerdEnv* env, - SerdSyntax syntax, - SordNode* graph); - -/** - Write a model to a writer. -*/ -SORD_API -bool -sord_write(SordModel* model, - SerdWriter* writer, - SordNode* graph); - -/** - Write a range to a writer. - - This increments @c iter to its end, then frees it. -*/ -SORD_API -bool -sord_write_iter(SordIter* iter, - SerdWriter* writer); - -/** - @} - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SORD_SORD_H */
--- a/osx/include/sord-0/sord/sordmm.hpp Thu Jan 09 13:23:08 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,653 +0,0 @@ -/* - Copyright 2011-2013 David Robillard <http://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. -*/ - -/** - @file sordmm.hpp - Public Sord C++ API. -*/ - -#ifndef SORD_SORDMM_HPP -#define SORD_SORDMM_HPP - -#include <cassert> -#include <cstring> -#include <cstdlib> -#include <iostream> -#include <set> -#include <string> -#include <sstream> - -#include "serd/serd.h" -#include "sord/sord.h" - -#define SORD_NS_XSD "http://www.w3.org/2001/XMLSchema#" - -namespace Sord { - -/** Utility base class to prevent copying. */ -class Noncopyable { -protected: - Noncopyable() {} - ~Noncopyable() {} -private: - Noncopyable(const Noncopyable&); - const Noncopyable& operator=(const Noncopyable&); -}; - -/** C++ wrapper for a Sord object. */ -template <typename T> -class Wrapper { -public: - inline Wrapper(T c_obj = NULL) : _c_obj(c_obj) {} - - inline T c_obj() { return _c_obj; } - inline const T c_obj() const { return _c_obj; } - -protected: - T _c_obj; -}; - -/** Collection of RDF namespaces with prefixes. */ -class Namespaces : public Wrapper<SerdEnv*> { -public: - Namespaces() : Wrapper<SerdEnv*>(serd_env_new(NULL)) {} - ~Namespaces() { serd_env_free(_c_obj); } - - static inline SerdNode string_to_node(SerdType type, const std::string& s) { - SerdNode ret = { - (const uint8_t*)s.c_str(), s.length(), s.length(), 0, type }; - return ret; - } - - inline void add(const std::string& name, - const std::string& uri) { - const SerdNode name_node = string_to_node(SERD_LITERAL, name); - const SerdNode uri_node = string_to_node(SERD_URI, uri); - serd_env_set_prefix(_c_obj, &name_node, &uri_node); - } - - inline std::string qualify(std::string uri) const { - const SerdNode uri_node = string_to_node(SERD_URI, uri); - SerdNode prefix; - SerdChunk suffix; - if (serd_env_qualify(_c_obj, &uri_node, &prefix, &suffix)) { - std::string ret((const char*)prefix.buf, prefix.n_bytes); - ret.append(":").append((const char*)suffix.buf, suffix.len); - return ret; - } - return uri; - } - - inline std::string expand(const std::string& curie) const { - assert(curie.find(":") != std::string::npos); - SerdNode curie_node = string_to_node(SERD_CURIE, curie); - SerdChunk uri_prefix; - SerdChunk uri_suffix; - if (!serd_env_expand(_c_obj, &curie_node, &uri_prefix, &uri_suffix)) { - std::string ret((const char*)uri_prefix.buf, uri_prefix.len); - ret.append((const char*)uri_suffix.buf, uri_suffix.len); - return ret; - } - std::cerr << "CURIE `" << curie << "' has unknown prefix." << std::endl; - return curie; - } -}; - -/** Sord library state. */ -class World : public Noncopyable, public Wrapper<SordWorld*> { -public: - inline World() - : _next_blank_id(0) - { - _c_obj = sord_world_new(); - } - - inline ~World() { - sord_world_free(_c_obj); - } - - inline uint64_t blank_id() { return _next_blank_id++; } - - inline void add_prefix(const std::string& prefix, const std::string& uri) { - _prefixes.add(prefix, uri); - } - - inline const Namespaces& prefixes() const { return _prefixes; } - inline SordWorld* world() { return _c_obj; } - -private: - Namespaces _prefixes; - std::set<std::string> _blank_ids; - uint64_t _next_blank_id; -}; - -/** An RDF Node (resource, literal, etc) - */ -class Node : public Wrapper<SordNode*> { -public: - enum Type { - UNKNOWN = 0, - URI = SORD_URI, - BLANK = SORD_BLANK, - LITERAL = SORD_LITERAL - }; - - inline Node() : Wrapper<SordNode*>(NULL), _world(NULL) {} - - inline Node(World& world, Type t, const std::string& s); - inline Node(World& world); - inline Node(World& world, const SordNode* node); - inline Node(World& world, SordNode* node, bool copy=false); - inline Node(const Node& other); - inline ~Node(); - - inline Type type() const { - return _c_obj ? (Type)sord_node_get_type(_c_obj) : UNKNOWN; - } - - inline const SordNode* get_node() const { return _c_obj; } - inline SordNode* get_node() { return _c_obj; } - - const SerdNode* to_serd_node() { - return sord_node_to_serd_node(_c_obj); - } - - inline bool is_valid() const { return type() != UNKNOWN; } - - inline bool operator<(const Node& other) const { - if (type() != other.type()) { - return type() < other.type(); - } else { - return to_string() < other.to_string(); - } - } - - Node& operator=(const Node& other) { - if (&other != this) { - if (_c_obj) { - sord_node_free(_world->c_obj(), _c_obj); - } - _world = other._world; - _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; - } - return *this; - } - - inline bool operator==(const Node& other) const { - return sord_node_equals(_c_obj, other._c_obj); - } - - inline const uint8_t* to_u_string() const; - inline const char* to_c_string() const; - inline std::string to_string() const; - - inline bool is_literal_type(const char* type_uri) const; - - inline bool is_uri() const { return _c_obj && type() == URI; } - inline bool is_blank() const { return _c_obj && type() == BLANK; } - inline bool is_int() const { return is_literal_type(SORD_NS_XSD "integer"); } - inline bool is_float() const { return is_literal_type(SORD_NS_XSD "decimal"); } - inline bool is_bool() const { return is_literal_type(SORD_NS_XSD "boolean"); } - - inline int to_int() const; - inline float to_float() const; - inline bool to_bool() const; - - inline static Node blank_id(World& world, const std::string base="b") { - const uint64_t num = world.blank_id(); - std::ostringstream ss; - ss << base << num; - return Node(world, Node::BLANK, ss.str()); - } - -private: - World* _world; -}; - -inline std::ostream& -operator<<(std::ostream& os, const Node& node) -{ - return os << node.to_string(); -} - -class URI : public Node { -public: - inline URI(World& world, const std::string& s) - : Node(world, Node::URI, s) {} - inline URI(World& world, const std::string& s, const std::string& base) - : Node(world, sord_new_relative_uri(world.world(), - (const uint8_t*)s.c_str(), - (const uint8_t*)base.c_str())) - {} -}; - -class Curie : public Node { -public: - inline Curie(World& world, const std::string& s) - : Node(world, Node::URI, world.prefixes().expand(s)) {} -}; - -class Literal : public Node { -public: - inline Literal(World& world, const std::string& s) - : Node(world, Node::LITERAL, s) {} - - static inline Node decimal(World& world, double d, unsigned frac_digits) { - const SerdNode val = serd_node_new_decimal(d, 7); - const SerdNode type = serd_node_from_string( - SERD_URI, (const uint8_t*)SORD_NS_XSD "decimal"); - - return Node( - world, - sord_node_from_serd_node( - world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), - false); - } - - static inline Node integer(World& world, int64_t i) { - const SerdNode val = serd_node_new_integer(i); - const SerdNode type = serd_node_from_string( - SERD_URI, (const uint8_t*)SORD_NS_XSD "integer"); - - return Node( - world, - sord_node_from_serd_node( - world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), - false); - } -}; - -inline -Node::Node(World& world, Type type, const std::string& s) - : _world(&world) -{ - switch (type) { - case URI: - _c_obj = sord_new_uri( - world.world(), (const unsigned char*)s.c_str()); - break; - case LITERAL: - _c_obj = sord_new_literal( - world.world(), NULL, (const unsigned char*)s.c_str(), NULL); - break; - case BLANK: - _c_obj = sord_new_blank( - world.world(), (const unsigned char*)s.c_str()); - break; - default: - _c_obj = NULL; - } - - assert(this->type() == type); -} - -inline -Node::Node(World& world) - : _world(&world) -{ - Node me = blank_id(world); - *this = me; -} - -inline -Node::Node(World& world, const SordNode* node) - : _world(&world) -{ - _c_obj = sord_node_copy(node); -} - -inline -Node::Node(World& world, SordNode* node, bool copy) - : _world(&world) -{ - _c_obj = copy ? sord_node_copy(node) : node; -} - -inline -Node::Node(const Node& other) - : Wrapper<SordNode*>() - , _world(other._world) -{ - if (_world) { - _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; - } - - assert((!_c_obj && !other._c_obj) || to_string() == other.to_string()); -} - -inline -Node::~Node() -{ - if (_world) { - sord_node_free(_world->c_obj(), _c_obj); - } -} - -inline std::string -Node::to_string() const -{ - return _c_obj ? (const char*)sord_node_get_string(_c_obj) : ""; -} - -inline const char* -Node::to_c_string() const -{ - return (const char*)sord_node_get_string(_c_obj); -} - -inline const uint8_t* -Node::to_u_string() const -{ - return sord_node_get_string(_c_obj); -} - -inline bool -Node::is_literal_type(const char* type_uri) const -{ - if (_c_obj && sord_node_get_type(_c_obj) == SORD_LITERAL) { - const SordNode* datatype = sord_node_get_datatype(_c_obj); - if (datatype && !strcmp((const char*)sord_node_get_string(datatype), - type_uri)) - return true; - } - return false; -} - -inline int -Node::to_int() const -{ - assert(is_int()); - char* endptr; - return strtol((const char*)sord_node_get_string(_c_obj), &endptr, 10); -} - -inline float -Node::to_float() const -{ - assert(is_float()); - char* endptr; - return serd_strtod((const char*)sord_node_get_string(_c_obj), &endptr); -} - -inline bool -Node::to_bool() const -{ - assert(is_bool()); - return !strcmp((const char*)sord_node_get_string(_c_obj), "true"); -} - -struct Iter : public Wrapper<SordIter*> { - inline Iter(World& world, SordIter* c_obj) - : Wrapper<SordIter*>(c_obj), _world(world) {} - inline ~Iter() { sord_iter_free(_c_obj); } - inline bool end() const { return sord_iter_end(_c_obj); } - inline bool next() const { return sord_iter_next(_c_obj); } - inline Iter& operator++() { - assert(!end()); - next(); - return *this; - } - inline const Node get_subject() const { - SordQuad quad; - sord_iter_get(_c_obj, quad); - return Node(_world, quad[SORD_SUBJECT]); - } - inline const Node get_predicate() const { - SordQuad quad; - sord_iter_get(_c_obj, quad); - return Node(_world, quad[SORD_PREDICATE]); - } - inline const Node get_object() const { - SordQuad quad; - sord_iter_get(_c_obj, quad); - return Node(_world, quad[SORD_OBJECT]); - } - World& _world; -}; - -/** An RDF Model (collection of triples). - */ -class Model : public Noncopyable, public Wrapper<SordModel*> { -public: - inline Model(World& world, - const std::string& base_uri, - unsigned indices = (SORD_SPO | SORD_OPS), - bool graphs = true); - - inline ~Model(); - - inline const Node& base_uri() const { return _base; } - - size_t num_quads() const { return sord_num_quads(_c_obj); } - - inline void load_file(SerdEnv* env, - SerdSyntax syntax, - const std::string& uri, - const std::string& base_uri=""); - - inline void load_string(SerdEnv* env, - SerdSyntax syntax, - const char* str, - size_t len, - const std::string& base_uri); - - inline SerdStatus write_to_file( - const std::string& uri, - SerdSyntax syntax = SERD_TURTLE, - SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED - |SERD_STYLE_CURIED - |SERD_STYLE_RESOLVED)); - - inline std::string write_to_string( - const std::string& base_uri, - SerdSyntax syntax = SERD_TURTLE, - SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED - |SERD_STYLE_CURIED - |SERD_STYLE_RESOLVED)); - - inline void add_statement(const Node& subject, - const Node& predicate, - const Node& object); - - inline Iter find(const Node& subject, - const Node& predicate, - const Node& object); - - inline Node get(const Node& subject, - const Node& predicate, - const Node& object); - - inline World& world() const { return _world; } - -private: - World& _world; - Node _base; - SerdWriter* _writer; - size_t _next_blank_id; -}; - -/** Create an empty in-memory RDF model. - */ -inline -Model::Model(World& world, - const std::string& base_uri, - unsigned indices, - bool graphs) - : _world(world) - , _base(world, Node::URI, base_uri) - , _writer(NULL) -{ - _c_obj = sord_new(_world.world(), indices, graphs); -} - -inline void -Model::load_string(SerdEnv* env, - SerdSyntax syntax, - const char* str, - size_t len, - const std::string& base_uri) -{ - SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); - serd_reader_read_string(reader, (const uint8_t*)str); - serd_reader_free(reader); -} - -inline Model::~Model() -{ - sord_free(_c_obj); -} - -inline void -Model::load_file(SerdEnv* env, - SerdSyntax syntax, - const std::string& data_uri, - const std::string& base_uri) -{ - uint8_t* path = serd_file_uri_parse((const uint8_t*)data_uri.c_str(), NULL); - if (!path) { - fprintf(stderr, "Failed to parse file URI <%s>\n", data_uri.c_str()); - return; - } - - // FIXME: blank prefix parameter? - SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); - serd_reader_read_file(reader, path); - serd_reader_free(reader); - free(path); -} - -inline SerdStatus -Model::write_to_file(const std::string& uri, SerdSyntax syntax, SerdStyle style) -{ - uint8_t* path = serd_file_uri_parse((const uint8_t*)uri.c_str(), NULL); - if (!path) { - fprintf(stderr, "Failed to parse file URI <%s>\n", uri.c_str()); - return SERD_ERR_BAD_ARG; - } - - FILE* const fd = fopen((const char*)path, "w"); - if (!fd) { - fprintf(stderr, "Failed to open file %s\n", path); - free(path); - return SERD_ERR_UNKNOWN; - } - free(path); - - SerdURI base_uri = SERD_URI_NULL; - if (serd_uri_parse((const uint8_t*)uri.c_str(), &base_uri)) { - fprintf(stderr, "Invalid base URI <%s>\n", uri.c_str()); - fclose(fd); - return SERD_ERR_BAD_ARG; - } - - SerdWriter* writer = serd_writer_new(syntax, - style, - _world.prefixes().c_obj(), - &base_uri, - serd_file_sink, - fd); - - serd_env_foreach(_world.prefixes().c_obj(), - (SerdPrefixSink)serd_writer_set_prefix, - writer); - - sord_write(_c_obj, writer, 0); - serd_writer_free(writer); - fclose(fd); - - return SERD_SUCCESS; -} - -static size_t -string_sink(const void* buf, size_t len, void* stream) -{ - std::string* str = (std::string*)stream; - str->append((const char*)buf, len); - return len; -} - -inline std::string -Model::write_to_string(const std::string& base_uri_str, - SerdSyntax syntax, - SerdStyle style) -{ - SerdURI base_uri = SERD_URI_NULL; - if (serd_uri_parse((const uint8_t*)base_uri_str.c_str(), &base_uri)) { - fprintf(stderr, "Invalid base URI <%s>\n", base_uri_str.c_str()); - return ""; - } - - std::string ret; - - SerdWriter* writer = serd_writer_new(syntax, - style, - _world.prefixes().c_obj(), - &base_uri, - string_sink, - &ret); - - serd_env_foreach(_world.prefixes().c_obj(), - (SerdPrefixSink)serd_writer_set_prefix, - writer); - - sord_write(_c_obj, writer, 0); - - serd_writer_free(writer); - return ret; -} - -inline void -Model::add_statement(const Node& subject, - const Node& predicate, - const Node& object) -{ - SordQuad quad = { subject.c_obj(), - predicate.c_obj(), - object.c_obj(), - NULL }; - - sord_add(_c_obj, quad); -} - -inline Iter -Model::find(const Node& subject, - const Node& predicate, - const Node& object) -{ - SordQuad quad = { subject.c_obj(), - predicate.c_obj(), - object.c_obj(), - NULL }; - - return Iter(_world, sord_find(_c_obj, quad)); -} - -inline Node -Model::get(const Node& subject, - const Node& predicate, - const Node& object) -{ - SordNode* c_node = sord_get( - _c_obj, subject.c_obj(), predicate.c_obj(), object.c_obj(), NULL); - Node node(_world, c_node); - sord_node_free(_world.c_obj(), c_node); - return node; -} - -} // namespace Sord - -#endif // SORD_SORDMM_HPP -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/sord/sord.h Thu Jan 09 21:21:48 2014 +0000 @@ -0,0 +1,627 @@ +/* + Copyright 2011-2013 David Robillard <http://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. +*/ + +/** + @file sord.h API for Sord, a lightweight RDF model library. +*/ + +#ifndef SORD_SORD_H +#define SORD_SORD_H + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#include "serd/serd.h" + +#ifdef SORD_SHARED +# ifdef _WIN32 +# define SORD_LIB_IMPORT __declspec(dllimport) +# define SORD_LIB_EXPORT __declspec(dllexport) +# else +# define SORD_LIB_IMPORT __attribute__((visibility("default"))) +# define SORD_LIB_EXPORT __attribute__((visibility("default"))) +# endif +# ifdef SORD_INTERNAL +# define SORD_API SORD_LIB_EXPORT +# else +# define SORD_API SORD_LIB_IMPORT +# endif +#else +# define SORD_API +#endif + +#ifdef __cplusplus +extern "C" { +#else +# include <stdbool.h> +#endif + +/** + @defgroup sord Sord + A lightweight RDF model library. + + Sord stores RDF (subject object predicate context) quads, where the context + may be omitted (to represent triples in the default graph). + @{ +*/ + +/** + Sord World. + The World represents all library state, including interned strings. +*/ +typedef struct SordWorldImpl SordWorld; + +/** + Sord Model. + + A model is an indexed set of Quads (i.e. it can contain several RDF + graphs). It may be searched using various patterns depending on which + indices are enabled. +*/ +typedef struct SordModelImpl SordModel; + +/** + Model Inserter. + + An inserter is used for writing statements to a model using the Serd sink + interface. This makes it simple to write to a model directly using a + SerdReader, or any other code that writes statements to a SerdStatementSink. +*/ +typedef struct SordInserterImpl SordInserter; + +/** + Model Iterator. +*/ +typedef struct SordIterImpl SordIter; + +/** + RDF Node. + A Node is a component of a Quad. Nodes may be URIs, blank nodes, or + (in the case of quad objects only) string literals. Literal nodes may + have an associate language or datatype (but not both). +*/ +typedef struct SordNodeImpl SordNode; + +/** + Quad of nodes (a statement), or a quad pattern. + + Nodes are ordered (S P O G). The ID of the default graph is 0. +*/ +typedef const SordNode* SordQuad[4]; + +/** + Index into a SordQuad. +*/ +typedef enum { + SORD_SUBJECT = 0, /**< Subject */ + SORD_PREDICATE = 1, /**< Predicate (a.k.a. "key") */ + SORD_OBJECT = 2, /**< Object (a.k.a. "value") */ + SORD_GRAPH = 3 /**< Graph (a.k.a. "context") */ +} SordQuadIndex; + +/** + Type of a node. +*/ +typedef enum { + SORD_URI = 1, /**< URI */ + SORD_BLANK = 2, /**< Blank node identifier */ + SORD_LITERAL = 3 /**< Literal (string with optional lang or datatype) */ +} SordNodeType; + +/** + Indexing option. +*/ +typedef enum { + SORD_SPO = 1, /**< Subject, Predicate, Object */ + SORD_SOP = 1 << 1, /**< Subject, Object, Predicate */ + SORD_OPS = 1 << 2, /**< Object, Predicate, Subject */ + SORD_OSP = 1 << 3, /**< Object, Subject, Predicate */ + SORD_PSO = 1 << 4, /**< Predicate, Subject, Object */ + SORD_POS = 1 << 5 /**< Predicate, Object, Subject */ +} SordIndexOption; + +/** + @name World + @{ +*/ + +/** + Create a new Sord World. + It is safe to use multiple worlds in one process, though no data + (e.g. nodes) can be shared between worlds, and this should be avoided if + possible for performance reasons. +*/ +SORD_API +SordWorld* +sord_world_new(void); + +/** + Free @c world. +*/ +SORD_API +void +sord_world_free(SordWorld* world); + +/** + Set a function to be called when errors occur. + + The @p error_sink will be called with @p handle as its first argument. If + no error function is set, errors are printed to stderr. +*/ +SORD_API +void +sord_world_set_error_sink(SordWorld* world, + SerdErrorSink error_sink, + void* handle); + +/** + @} + @name Node + @{ +*/ + +/** + Get a URI node from a string. + + Note this function measures @c str, which is a common bottleneck. + Use sord_node_from_serd_node instead if @c str is already measured. +*/ +SORD_API +SordNode* +sord_new_uri(SordWorld* world, const uint8_t* uri); + +/** + Get a URI node from a relative URI string. +*/ +SORD_API +SordNode* +sord_new_relative_uri(SordWorld* world, + const uint8_t* str, + const uint8_t* base_uri); + +/** + Get a blank node from a string. + + Note this function measures @c str, which is a common bottleneck. + Use sord_node_from_serd_node instead if @c str is already measured. +*/ +SORD_API +SordNode* +sord_new_blank(SordWorld* world, const uint8_t* str); + +/** + Get a literal node from a string. + + Note this function measures @c str, which is a common bottleneck. + Use sord_node_from_serd_node instead if @c str is already measured. +*/ +SORD_API +SordNode* +sord_new_literal(SordWorld* world, + SordNode* datatype, + const uint8_t* str, + const char* lang); + +/** + Copy a node (obtain a reference). + + Node that since nodes are interned and reference counted, this does not + actually create a deep copy of @c node. +*/ +SORD_API +SordNode* +sord_node_copy(const SordNode* node); + +/** + Free a node (drop a reference). +*/ +SORD_API +void +sord_node_free(SordWorld* world, SordNode* node); + +/** + Return the type of a node (SORD_URI, SORD_BLANK, or SORD_LITERAL). +*/ +SORD_API +SordNodeType +sord_node_get_type(const SordNode* node); + +/** + Return the string value of a node. +*/ +SORD_API +const uint8_t* +sord_node_get_string(const SordNode* node); + +/** + Return the string value of a node, and set @c len to its length. +*/ +SORD_API +const uint8_t* +sord_node_get_string_counted(const SordNode* node, size_t* len); + +/** + Return the language of a literal node (or NULL). +*/ +SORD_API +const char* +sord_node_get_language(const SordNode* node); + +/** + Return the datatype URI of a literal node (or NULL). +*/ +SORD_API +SordNode* +sord_node_get_datatype(const SordNode* node); + +/** + Return the flags (string attributes) of a node. +*/ +SORD_API +SerdNodeFlags +sord_node_get_flags(const SordNode* node); + +/** + Return true iff node can be serialised as an inline object. + + More specifically, this returns true iff the node is the object field + of exactly one statement, and therefore can be inlined since it needn't + be referred to by name. +*/ +SORD_API +bool +sord_node_is_inline_object(const SordNode* node); + +/** + Return true iff @c a is equal to @c b. + + Note this is much faster than comparing the node's strings. +*/ +SORD_API +bool +sord_node_equals(const SordNode* a, + const SordNode* b); + +/** + Return a SordNode as a SerdNode. + + The returned node is shared and must not be freed or modified. +*/ +SORD_API +const SerdNode* +sord_node_to_serd_node(const SordNode* node); + +/** + Create a new SordNode from a SerdNode. + + The returned node must be freed using sord_node_free. +*/ +SORD_API +SordNode* +sord_node_from_serd_node(SordWorld* world, + SerdEnv* env, + const SerdNode* node, + const SerdNode* datatype, + const SerdNode* lang); + +/** + @} + @name Model + @{ +*/ + +/** + Create a new model. + + @param world The world in which to make this model. + + @param indices SordIndexOption flags (e.g. SORD_SPO|SORD_OPS). Be sure to + enable an index where the most significant node(s) are not variables in your + queries (e.g. to make (? P O) queries, enable either SORD_OPS or SORD_POS). + + @param graphs If true, store (and index) graph contexts. +*/ +SORD_API +SordModel* +sord_new(SordWorld* world, + unsigned indices, + bool graphs); + +/** + Close and free @c model. +*/ +SORD_API +void +sord_free(SordModel* model); + +/** + Get the world associated with @c model. +*/ +SORD_API +SordWorld* +sord_get_world(SordModel* model); + +/** + Return the number of nodes stored in @c world. + + Nodes are included in this count iff they are a part of a quad in @c world. +*/ +SORD_API +size_t +sord_num_nodes(const SordWorld* world); + +/** + Return the number of quads stored in @c model. +*/ +SORD_API +size_t +sord_num_quads(const SordModel* model); + +/** + Return an iterator to the start of @c model. +*/ +SORD_API +SordIter* +sord_begin(const SordModel* model); + +/** + Search for statements by a quad pattern. + @return an iterator to the first match, or NULL if no matches found. +*/ +SORD_API +SordIter* +sord_find(SordModel* model, const SordQuad pat); + +/** + Search for statements by nodes. + @return an iterator to the first match, or NULL if no matches found. +*/ +SORD_API +SordIter* +sord_search(SordModel* model, + const SordNode* s, + const SordNode* p, + const SordNode* o, + const SordNode* g); +/** + Search for a single node that matches a pattern. + Exactly one of @p s, @p p, @p o must be NULL. + This function is mainly useful for predicates that only have one value. + The returned node must be freed using sord_node_free. + @return the first matching node, or NULL if no matches are found. +*/ +SORD_API +SordNode* +sord_get(SordModel* model, + const SordNode* s, + const SordNode* p, + const SordNode* o, + const SordNode* g); + +/** + Return true iff a statement exists. +*/ +SORD_API +bool +sord_ask(SordModel* model, + const SordNode* s, + const SordNode* p, + const SordNode* o, + const SordNode* g); + +/** + Return the number of matching statements. +*/ +SORD_API +uint64_t +sord_count(SordModel* model, + const SordNode* s, + const SordNode* p, + const SordNode* o, + const SordNode* g); + +/** + Check if @a model contains a triple pattern. +*/ +SORD_API +bool +sord_contains(SordModel* model, const SordQuad pat); + +/** + Add a quad to a model. +*/ +SORD_API +bool +sord_add(SordModel* model, const SordQuad quad); + +/** + Remove a quad from a model. + + Note that is it illegal to remove while iterating over @c model. +*/ +SORD_API +void +sord_remove(SordModel* model, const SordQuad quad); + +/** + @} + @name Inserter + @{ +*/ + +/** + Create an inserter for writing statements to a model. +*/ +SORD_API +SordInserter* +sord_inserter_new(SordModel* model, + SerdEnv* env); + +/** + Free an inserter. +*/ +SORD_API +void +sord_inserter_free(SordInserter* inserter); + +/** + Set the current base URI for writing to the model. + + Note this function can be safely casted to SerdBaseSink. +*/ +SORD_API +SerdStatus +sord_inserter_set_base_uri(SordInserter* inserter, + const SerdNode* uri); + +/** + Set a namespace prefix for writing to the model. + + Note this function can be safely casted to SerdPrefixSink. +*/ +SORD_API +SerdStatus +sord_inserter_set_prefix(SordInserter* inserter, + const SerdNode* name, + const SerdNode* uri); + +/** + Write a statement to the model. + + Note this function can be safely casted to SerdStatementSink. +*/ +SORD_API +SerdStatus +sord_inserter_write_statement(SordInserter* inserter, + SerdStatementFlags flags, + const SerdNode* graph, + const SerdNode* subject, + const SerdNode* predicate, + const SerdNode* object, + const SerdNode* object_datatype, + const SerdNode* object_lang); + +/** + @} + @name Iteration + @{ +*/ + +/** + Set @c quad to the quad pointed to by @c iter. +*/ +SORD_API +void +sord_iter_get(const SordIter* iter, SordQuad quad); + +/** + Return a field of the quad pointed to by @c iter. +*/ +SORD_API +const SordNode* +sord_iter_get_node(const SordIter* iter, SordQuadIndex index); + +/** + Return the store pointed to by @c iter. +*/ +SORD_API +const SordModel* +sord_iter_get_model(SordIter* iter); + +/** + Increment @c iter to point to the next statement. +*/ +SORD_API +bool +sord_iter_next(SordIter* iter); + +/** + Return true iff @c iter is at the end of its range. +*/ +SORD_API +bool +sord_iter_end(const SordIter* iter); + +/** + Free @c iter. +*/ +SORD_API +void +sord_iter_free(SordIter* iter); + +/** + @} + @name Utilities + @{ +*/ + +/** + Match two quads (using ID comparison only). + + This function is a straightforward and fast equivalence match with wildcard + support (ID 0 is a wildcard). It does not actually read node data. + @return true iff @c x and @c y match. +*/ +SORD_API +bool +sord_quad_match(const SordQuad x, const SordQuad y); + +/** + @} + @name Serialisation + @{ +*/ + +/** + Return a reader that will read into @c model. +*/ +SORD_API +SerdReader* +sord_new_reader(SordModel* model, + SerdEnv* env, + SerdSyntax syntax, + SordNode* graph); + +/** + Write a model to a writer. +*/ +SORD_API +bool +sord_write(SordModel* model, + SerdWriter* writer, + SordNode* graph); + +/** + Write a range to a writer. + + This increments @c iter to its end, then frees it. +*/ +SORD_API +bool +sord_write_iter(SordIter* iter, + SerdWriter* writer); + +/** + @} + @} +*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SORD_SORD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/sord/sordmm.hpp Thu Jan 09 21:21:48 2014 +0000 @@ -0,0 +1,653 @@ +/* + Copyright 2011-2013 David Robillard <http://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. +*/ + +/** + @file sordmm.hpp + Public Sord C++ API. +*/ + +#ifndef SORD_SORDMM_HPP +#define SORD_SORDMM_HPP + +#include <cassert> +#include <cstring> +#include <cstdlib> +#include <iostream> +#include <set> +#include <string> +#include <sstream> + +#include "serd/serd.h" +#include "sord/sord.h" + +#define SORD_NS_XSD "http://www.w3.org/2001/XMLSchema#" + +namespace Sord { + +/** Utility base class to prevent copying. */ +class Noncopyable { +protected: + Noncopyable() {} + ~Noncopyable() {} +private: + Noncopyable(const Noncopyable&); + const Noncopyable& operator=(const Noncopyable&); +}; + +/** C++ wrapper for a Sord object. */ +template <typename T> +class Wrapper { +public: + inline Wrapper(T c_obj = NULL) : _c_obj(c_obj) {} + + inline T c_obj() { return _c_obj; } + inline const T c_obj() const { return _c_obj; } + +protected: + T _c_obj; +}; + +/** Collection of RDF namespaces with prefixes. */ +class Namespaces : public Wrapper<SerdEnv*> { +public: + Namespaces() : Wrapper<SerdEnv*>(serd_env_new(NULL)) {} + ~Namespaces() { serd_env_free(_c_obj); } + + static inline SerdNode string_to_node(SerdType type, const std::string& s) { + SerdNode ret = { + (const uint8_t*)s.c_str(), s.length(), s.length(), 0, type }; + return ret; + } + + inline void add(const std::string& name, + const std::string& uri) { + const SerdNode name_node = string_to_node(SERD_LITERAL, name); + const SerdNode uri_node = string_to_node(SERD_URI, uri); + serd_env_set_prefix(_c_obj, &name_node, &uri_node); + } + + inline std::string qualify(std::string uri) const { + const SerdNode uri_node = string_to_node(SERD_URI, uri); + SerdNode prefix; + SerdChunk suffix; + if (serd_env_qualify(_c_obj, &uri_node, &prefix, &suffix)) { + std::string ret((const char*)prefix.buf, prefix.n_bytes); + ret.append(":").append((const char*)suffix.buf, suffix.len); + return ret; + } + return uri; + } + + inline std::string expand(const std::string& curie) const { + assert(curie.find(":") != std::string::npos); + SerdNode curie_node = string_to_node(SERD_CURIE, curie); + SerdChunk uri_prefix; + SerdChunk uri_suffix; + if (!serd_env_expand(_c_obj, &curie_node, &uri_prefix, &uri_suffix)) { + std::string ret((const char*)uri_prefix.buf, uri_prefix.len); + ret.append((const char*)uri_suffix.buf, uri_suffix.len); + return ret; + } + std::cerr << "CURIE `" << curie << "' has unknown prefix." << std::endl; + return curie; + } +}; + +/** Sord library state. */ +class World : public Noncopyable, public Wrapper<SordWorld*> { +public: + inline World() + : _next_blank_id(0) + { + _c_obj = sord_world_new(); + } + + inline ~World() { + sord_world_free(_c_obj); + } + + inline uint64_t blank_id() { return _next_blank_id++; } + + inline void add_prefix(const std::string& prefix, const std::string& uri) { + _prefixes.add(prefix, uri); + } + + inline const Namespaces& prefixes() const { return _prefixes; } + inline SordWorld* world() { return _c_obj; } + +private: + Namespaces _prefixes; + std::set<std::string> _blank_ids; + uint64_t _next_blank_id; +}; + +/** An RDF Node (resource, literal, etc) + */ +class Node : public Wrapper<SordNode*> { +public: + enum Type { + UNKNOWN = 0, + URI = SORD_URI, + BLANK = SORD_BLANK, + LITERAL = SORD_LITERAL + }; + + inline Node() : Wrapper<SordNode*>(NULL), _world(NULL) {} + + inline Node(World& world, Type t, const std::string& s); + inline Node(World& world); + inline Node(World& world, const SordNode* node); + inline Node(World& world, SordNode* node, bool copy=false); + inline Node(const Node& other); + inline ~Node(); + + inline Type type() const { + return _c_obj ? (Type)sord_node_get_type(_c_obj) : UNKNOWN; + } + + inline const SordNode* get_node() const { return _c_obj; } + inline SordNode* get_node() { return _c_obj; } + + const SerdNode* to_serd_node() { + return sord_node_to_serd_node(_c_obj); + } + + inline bool is_valid() const { return type() != UNKNOWN; } + + inline bool operator<(const Node& other) const { + if (type() != other.type()) { + return type() < other.type(); + } else { + return to_string() < other.to_string(); + } + } + + Node& operator=(const Node& other) { + if (&other != this) { + if (_c_obj) { + sord_node_free(_world->c_obj(), _c_obj); + } + _world = other._world; + _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; + } + return *this; + } + + inline bool operator==(const Node& other) const { + return sord_node_equals(_c_obj, other._c_obj); + } + + inline const uint8_t* to_u_string() const; + inline const char* to_c_string() const; + inline std::string to_string() const; + + inline bool is_literal_type(const char* type_uri) const; + + inline bool is_uri() const { return _c_obj && type() == URI; } + inline bool is_blank() const { return _c_obj && type() == BLANK; } + inline bool is_int() const { return is_literal_type(SORD_NS_XSD "integer"); } + inline bool is_float() const { return is_literal_type(SORD_NS_XSD "decimal"); } + inline bool is_bool() const { return is_literal_type(SORD_NS_XSD "boolean"); } + + inline int to_int() const; + inline float to_float() const; + inline bool to_bool() const; + + inline static Node blank_id(World& world, const std::string base="b") { + const uint64_t num = world.blank_id(); + std::ostringstream ss; + ss << base << num; + return Node(world, Node::BLANK, ss.str()); + } + +private: + World* _world; +}; + +inline std::ostream& +operator<<(std::ostream& os, const Node& node) +{ + return os << node.to_string(); +} + +class URI : public Node { +public: + inline URI(World& world, const std::string& s) + : Node(world, Node::URI, s) {} + inline URI(World& world, const std::string& s, const std::string& base) + : Node(world, sord_new_relative_uri(world.world(), + (const uint8_t*)s.c_str(), + (const uint8_t*)base.c_str())) + {} +}; + +class Curie : public Node { +public: + inline Curie(World& world, const std::string& s) + : Node(world, Node::URI, world.prefixes().expand(s)) {} +}; + +class Literal : public Node { +public: + inline Literal(World& world, const std::string& s) + : Node(world, Node::LITERAL, s) {} + + static inline Node decimal(World& world, double d, unsigned frac_digits) { + const SerdNode val = serd_node_new_decimal(d, 7); + const SerdNode type = serd_node_from_string( + SERD_URI, (const uint8_t*)SORD_NS_XSD "decimal"); + + return Node( + world, + sord_node_from_serd_node( + world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), + false); + } + + static inline Node integer(World& world, int64_t i) { + const SerdNode val = serd_node_new_integer(i); + const SerdNode type = serd_node_from_string( + SERD_URI, (const uint8_t*)SORD_NS_XSD "integer"); + + return Node( + world, + sord_node_from_serd_node( + world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), + false); + } +}; + +inline +Node::Node(World& world, Type type, const std::string& s) + : _world(&world) +{ + switch (type) { + case URI: + _c_obj = sord_new_uri( + world.world(), (const unsigned char*)s.c_str()); + break; + case LITERAL: + _c_obj = sord_new_literal( + world.world(), NULL, (const unsigned char*)s.c_str(), NULL); + break; + case BLANK: + _c_obj = sord_new_blank( + world.world(), (const unsigned char*)s.c_str()); + break; + default: + _c_obj = NULL; + } + + assert(this->type() == type); +} + +inline +Node::Node(World& world) + : _world(&world) +{ + Node me = blank_id(world); + *this = me; +} + +inline +Node::Node(World& world, const SordNode* node) + : _world(&world) +{ + _c_obj = sord_node_copy(node); +} + +inline +Node::Node(World& world, SordNode* node, bool copy) + : _world(&world) +{ + _c_obj = copy ? sord_node_copy(node) : node; +} + +inline +Node::Node(const Node& other) + : Wrapper<SordNode*>() + , _world(other._world) +{ + if (_world) { + _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; + } + + assert((!_c_obj && !other._c_obj) || to_string() == other.to_string()); +} + +inline +Node::~Node() +{ + if (_world) { + sord_node_free(_world->c_obj(), _c_obj); + } +} + +inline std::string +Node::to_string() const +{ + return _c_obj ? (const char*)sord_node_get_string(_c_obj) : ""; +} + +inline const char* +Node::to_c_string() const +{ + return (const char*)sord_node_get_string(_c_obj); +} + +inline const uint8_t* +Node::to_u_string() const +{ + return sord_node_get_string(_c_obj); +} + +inline bool +Node::is_literal_type(const char* type_uri) const +{ + if (_c_obj && sord_node_get_type(_c_obj) == SORD_LITERAL) { + const SordNode* datatype = sord_node_get_datatype(_c_obj); + if (datatype && !strcmp((const char*)sord_node_get_string(datatype), + type_uri)) + return true; + } + return false; +} + +inline int +Node::to_int() const +{ + assert(is_int()); + char* endptr; + return strtol((const char*)sord_node_get_string(_c_obj), &endptr, 10); +} + +inline float +Node::to_float() const +{ + assert(is_float()); + char* endptr; + return serd_strtod((const char*)sord_node_get_string(_c_obj), &endptr); +} + +inline bool +Node::to_bool() const +{ + assert(is_bool()); + return !strcmp((const char*)sord_node_get_string(_c_obj), "true"); +} + +struct Iter : public Wrapper<SordIter*> { + inline Iter(World& world, SordIter* c_obj) + : Wrapper<SordIter*>(c_obj), _world(world) {} + inline ~Iter() { sord_iter_free(_c_obj); } + inline bool end() const { return sord_iter_end(_c_obj); } + inline bool next() const { return sord_iter_next(_c_obj); } + inline Iter& operator++() { + assert(!end()); + next(); + return *this; + } + inline const Node get_subject() const { + SordQuad quad; + sord_iter_get(_c_obj, quad); + return Node(_world, quad[SORD_SUBJECT]); + } + inline const Node get_predicate() const { + SordQuad quad; + sord_iter_get(_c_obj, quad); + return Node(_world, quad[SORD_PREDICATE]); + } + inline const Node get_object() const { + SordQuad quad; + sord_iter_get(_c_obj, quad); + return Node(_world, quad[SORD_OBJECT]); + } + World& _world; +}; + +/** An RDF Model (collection of triples). + */ +class Model : public Noncopyable, public Wrapper<SordModel*> { +public: + inline Model(World& world, + const std::string& base_uri, + unsigned indices = (SORD_SPO | SORD_OPS), + bool graphs = true); + + inline ~Model(); + + inline const Node& base_uri() const { return _base; } + + size_t num_quads() const { return sord_num_quads(_c_obj); } + + inline void load_file(SerdEnv* env, + SerdSyntax syntax, + const std::string& uri, + const std::string& base_uri=""); + + inline void load_string(SerdEnv* env, + SerdSyntax syntax, + const char* str, + size_t len, + const std::string& base_uri); + + inline SerdStatus write_to_file( + const std::string& uri, + SerdSyntax syntax = SERD_TURTLE, + SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED + |SERD_STYLE_CURIED + |SERD_STYLE_RESOLVED)); + + inline std::string write_to_string( + const std::string& base_uri, + SerdSyntax syntax = SERD_TURTLE, + SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED + |SERD_STYLE_CURIED + |SERD_STYLE_RESOLVED)); + + inline void add_statement(const Node& subject, + const Node& predicate, + const Node& object); + + inline Iter find(const Node& subject, + const Node& predicate, + const Node& object); + + inline Node get(const Node& subject, + const Node& predicate, + const Node& object); + + inline World& world() const { return _world; } + +private: + World& _world; + Node _base; + SerdWriter* _writer; + size_t _next_blank_id; +}; + +/** Create an empty in-memory RDF model. + */ +inline +Model::Model(World& world, + const std::string& base_uri, + unsigned indices, + bool graphs) + : _world(world) + , _base(world, Node::URI, base_uri) + , _writer(NULL) +{ + _c_obj = sord_new(_world.world(), indices, graphs); +} + +inline void +Model::load_string(SerdEnv* env, + SerdSyntax syntax, + const char* str, + size_t len, + const std::string& base_uri) +{ + SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); + serd_reader_read_string(reader, (const uint8_t*)str); + serd_reader_free(reader); +} + +inline Model::~Model() +{ + sord_free(_c_obj); +} + +inline void +Model::load_file(SerdEnv* env, + SerdSyntax syntax, + const std::string& data_uri, + const std::string& base_uri) +{ + uint8_t* path = serd_file_uri_parse((const uint8_t*)data_uri.c_str(), NULL); + if (!path) { + fprintf(stderr, "Failed to parse file URI <%s>\n", data_uri.c_str()); + return; + } + + // FIXME: blank prefix parameter? + SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); + serd_reader_read_file(reader, path); + serd_reader_free(reader); + free(path); +} + +inline SerdStatus +Model::write_to_file(const std::string& uri, SerdSyntax syntax, SerdStyle style) +{ + uint8_t* path = serd_file_uri_parse((const uint8_t*)uri.c_str(), NULL); + if (!path) { + fprintf(stderr, "Failed to parse file URI <%s>\n", uri.c_str()); + return SERD_ERR_BAD_ARG; + } + + FILE* const fd = fopen((const char*)path, "w"); + if (!fd) { + fprintf(stderr, "Failed to open file %s\n", path); + free(path); + return SERD_ERR_UNKNOWN; + } + free(path); + + SerdURI base_uri = SERD_URI_NULL; + if (serd_uri_parse((const uint8_t*)uri.c_str(), &base_uri)) { + fprintf(stderr, "Invalid base URI <%s>\n", uri.c_str()); + fclose(fd); + return SERD_ERR_BAD_ARG; + } + + SerdWriter* writer = serd_writer_new(syntax, + style, + _world.prefixes().c_obj(), + &base_uri, + serd_file_sink, + fd); + + serd_env_foreach(_world.prefixes().c_obj(), + (SerdPrefixSink)serd_writer_set_prefix, + writer); + + sord_write(_c_obj, writer, 0); + serd_writer_free(writer); + fclose(fd); + + return SERD_SUCCESS; +} + +static size_t +string_sink(const void* buf, size_t len, void* stream) +{ + std::string* str = (std::string*)stream; + str->append((const char*)buf, len); + return len; +} + +inline std::string +Model::write_to_string(const std::string& base_uri_str, + SerdSyntax syntax, + SerdStyle style) +{ + SerdURI base_uri = SERD_URI_NULL; + if (serd_uri_parse((const uint8_t*)base_uri_str.c_str(), &base_uri)) { + fprintf(stderr, "Invalid base URI <%s>\n", base_uri_str.c_str()); + return ""; + } + + std::string ret; + + SerdWriter* writer = serd_writer_new(syntax, + style, + _world.prefixes().c_obj(), + &base_uri, + string_sink, + &ret); + + serd_env_foreach(_world.prefixes().c_obj(), + (SerdPrefixSink)serd_writer_set_prefix, + writer); + + sord_write(_c_obj, writer, 0); + + serd_writer_free(writer); + return ret; +} + +inline void +Model::add_statement(const Node& subject, + const Node& predicate, + const Node& object) +{ + SordQuad quad = { subject.c_obj(), + predicate.c_obj(), + object.c_obj(), + NULL }; + + sord_add(_c_obj, quad); +} + +inline Iter +Model::find(const Node& subject, + const Node& predicate, + const Node& object) +{ + SordQuad quad = { subject.c_obj(), + predicate.c_obj(), + object.c_obj(), + NULL }; + + return Iter(_world, sord_find(_c_obj, quad)); +} + +inline Node +Model::get(const Node& subject, + const Node& predicate, + const Node& object) +{ + SordNode* c_node = sord_get( + _c_obj, subject.c_obj(), predicate.c_obj(), object.c_obj(), NULL); + Node node(_world, c_node); + sord_node_free(_world.c_obj(), c_node); + return node; +} + +} // namespace Sord + +#endif // SORD_SORDMM_HPP +