cannam@226: /*
cannam@226:   Copyright 2011-2015 David Robillard <http://drobilla.net>
cannam@226: 
cannam@226:   Permission to use, copy, modify, and/or distribute this software for any
cannam@226:   purpose with or without fee is hereby granted, provided that the above
cannam@226:   copyright notice and this permission notice appear in all copies.
cannam@226: 
cannam@226:   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
cannam@226:   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
cannam@226:   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
cannam@226:   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
cannam@226:   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
cannam@226:   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
cannam@226:   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
cannam@226: */
cannam@226: 
cannam@226: #include <assert.h>
cannam@226: #include <stdlib.h>
cannam@226: #include <string.h>
cannam@226: 
cannam@226: #include "serd/serd.h"
cannam@226: 
cannam@226: #include "sord_config.h"
cannam@226: #include "sord_internal.h"
cannam@226: 
cannam@226: struct SordInserterImpl {
cannam@226: 	SordModel* model;
cannam@226: 	SerdEnv*   env;
cannam@226: };
cannam@226: 
cannam@226: SordInserter*
cannam@226: sord_inserter_new(SordModel* model,
cannam@226:                   SerdEnv*   env)
cannam@226: {
cannam@226: 	SordInserter* inserter = (SordInserter*)malloc(sizeof(SordInserter));
cannam@226: 	inserter->model = model;
cannam@226: 	inserter->env   = env;
cannam@226: 	return inserter;
cannam@226: }
cannam@226: 
cannam@226: void
cannam@226: sord_inserter_free(SordInserter* inserter)
cannam@226: {
cannam@226: 	free(inserter);
cannam@226: }
cannam@226: 
cannam@226: SerdStatus
cannam@226: sord_inserter_set_base_uri(SordInserter*   inserter,
cannam@226:                            const SerdNode* uri_node)
cannam@226: {
cannam@226: 	return serd_env_set_base_uri(inserter->env, uri_node);
cannam@226: }
cannam@226: 
cannam@226: SerdStatus
cannam@226: sord_inserter_set_prefix(SordInserter*   inserter,
cannam@226:                          const SerdNode* name,
cannam@226:                          const SerdNode* uri_node)
cannam@226: {
cannam@226: 	return serd_env_set_prefix(inserter->env, name, uri_node);
cannam@226: }
cannam@226: 
cannam@226: SerdStatus
cannam@226: sord_inserter_write_statement(SordInserter*      inserter,
cannam@226:                               SerdStatementFlags flags,
cannam@226:                               const SerdNode*    graph,
cannam@226:                               const SerdNode*    subject,
cannam@226:                               const SerdNode*    predicate,
cannam@226:                               const SerdNode*    object,
cannam@226:                               const SerdNode*    object_datatype,
cannam@226:                               const SerdNode*    object_lang)
cannam@226: {
cannam@226: 	SordWorld* world = sord_get_world(inserter->model);
cannam@226: 	SerdEnv*   env   = inserter->env;
cannam@226: 
cannam@226: 	SordNode* g = sord_node_from_serd_node(world, env, graph, NULL, NULL);
cannam@226: 	SordNode* s = sord_node_from_serd_node(world, env, subject, NULL, NULL);
cannam@226: 	SordNode* p = sord_node_from_serd_node(world, env, predicate, NULL, NULL);
cannam@226: 	SordNode* o = sord_node_from_serd_node(world, env, object,
cannam@226: 	                                       object_datatype, object_lang);
cannam@226: 
cannam@226: 	if (!s || !p || !o) {
cannam@226: 		return SERD_ERR_BAD_ARG;
cannam@226: 	}
cannam@226: 
cannam@226: 	const SordQuad tup = { s, p, o, g };
cannam@226: 	sord_add(inserter->model, tup);
cannam@226: 
cannam@226: 	sord_node_free(world, o);
cannam@226: 	sord_node_free(world, p);
cannam@226: 	sord_node_free(world, s);
cannam@226: 	sord_node_free(world, g);
cannam@226: 
cannam@226: 	return SERD_SUCCESS;
cannam@226: }
cannam@226: 
cannam@226: SORD_API
cannam@226: SerdReader*
cannam@226: sord_new_reader(SordModel* model,
cannam@226:                 SerdEnv*   env,
cannam@226:                 SerdSyntax syntax,
cannam@226:                 SordNode*  graph)
cannam@226: {
cannam@226: 	SordInserter* inserter = sord_inserter_new(model, env);
cannam@226: 
cannam@226: 	SerdReader* reader = serd_reader_new(
cannam@226: 		syntax, inserter, (void (*)(void*))sord_inserter_free,
cannam@226: 		(SerdBaseSink)sord_inserter_set_base_uri,
cannam@226: 		(SerdPrefixSink)sord_inserter_set_prefix,
cannam@226: 		(SerdStatementSink)sord_inserter_write_statement,
cannam@226: 		NULL);
cannam@226: 
cannam@226: 	if (graph) {
cannam@226: 		serd_reader_set_default_graph(reader, sord_node_to_serd_node(graph));
cannam@226: 	}
cannam@226: 
cannam@226: 	return reader;
cannam@226: }
cannam@226: 
cannam@226: static SerdStatus
cannam@226: write_statement(SordModel*         sord,
cannam@226:                 SerdWriter*        writer,
cannam@226:                 SordQuad           tup,
cannam@226:                 SerdStatementFlags flags)
cannam@226: {
cannam@226: 	const SordNode* s  = tup[SORD_SUBJECT];
cannam@226: 	const SordNode* p  = tup[SORD_PREDICATE];
cannam@226: 	const SordNode* o  = tup[SORD_OBJECT];
cannam@226: 	const SordNode* d  = sord_node_get_datatype(o);
cannam@226: 	const SerdNode* ss = sord_node_to_serd_node(s);
cannam@226: 	const SerdNode* sp = sord_node_to_serd_node(p);
cannam@226: 	const SerdNode* so = sord_node_to_serd_node(o);
cannam@226: 	const SerdNode* sd = sord_node_to_serd_node(d);
cannam@226: 
cannam@226: 	const char* lang_str = sord_node_get_language(o);
cannam@226: 	size_t      lang_len = lang_str ? strlen(lang_str) : 0;
cannam@226: 	SerdNode    language = SERD_NODE_NULL;
cannam@226: 	if (lang_str) {
cannam@226: 		language.type    = SERD_LITERAL;
cannam@226: 		language.n_bytes = lang_len;
cannam@226: 		language.n_chars = lang_len;
cannam@226: 		language.buf     = (const uint8_t*)lang_str;
cannam@226: 	};
cannam@226: 
cannam@226: 	// TODO: Subject abbreviation
cannam@226: 
cannam@226: 	if (sord_node_is_inline_object(s) && !(flags & SERD_ANON_CONT)) {
cannam@226: 		return SERD_SUCCESS;
cannam@226: 	}
cannam@226: 
cannam@226: 	SerdStatus st = SERD_SUCCESS;
cannam@226: 	if (sord_node_is_inline_object(o)) {
cannam@226: 		SordQuad  sub_pat  = { o, 0, 0, 0 };
cannam@226: 		SordIter* sub_iter = sord_find(sord, sub_pat);
cannam@226: 
cannam@226: 		SerdStatementFlags start_flags = flags
cannam@226: 			| ((sub_iter) ? SERD_ANON_O_BEGIN : SERD_EMPTY_O);
cannam@226: 
cannam@226: 		st = serd_writer_write_statement(
cannam@226: 			writer, start_flags, NULL, ss, sp, so, sd, &language);
cannam@226: 
cannam@226: 		if (!st && sub_iter) {
cannam@226: 			flags |= SERD_ANON_CONT;
cannam@226: 			for (; !st && !sord_iter_end(sub_iter); sord_iter_next(sub_iter)) {
cannam@226: 				SordQuad sub_tup;
cannam@226: 				sord_iter_get(sub_iter, sub_tup);
cannam@226: 				st = write_statement(sord, writer, sub_tup, flags);
cannam@226: 			}
cannam@226: 			sord_iter_free(sub_iter);
cannam@226: 			serd_writer_end_anon(writer, so);
cannam@226: 		}
cannam@226: 	} else {
cannam@226: 		st = serd_writer_write_statement(
cannam@226: 			writer, flags, NULL, ss, sp, so, sd, &language);
cannam@226: 	}
cannam@226: 
cannam@226: 	return st;
cannam@226: }
cannam@226: 
cannam@226: bool
cannam@226: sord_write(SordModel*  model,
cannam@226:            SerdWriter* writer,
cannam@226:            SordNode*   graph)
cannam@226: {
cannam@226: 	SordQuad  pat  = { 0, 0, 0, graph };
cannam@226: 	SordIter* iter = sord_find(model, pat);
cannam@226: 	return sord_write_iter(iter, writer);
cannam@226: }
cannam@226: 
cannam@226: bool
cannam@226: sord_write_iter(SordIter*   iter,
cannam@226:                 SerdWriter* writer)
cannam@226: {
cannam@226: 	if (!iter) {
cannam@226: 		return false;
cannam@226: 	}
cannam@226: 
cannam@226: 	SordModel* model = (SordModel*)sord_iter_get_model(iter);
cannam@226: 	SerdStatus st    = SERD_SUCCESS;
cannam@226: 	for (; !st && !sord_iter_end(iter); sord_iter_next(iter)) {
cannam@226: 		SordQuad tup;
cannam@226: 		sord_iter_get(iter, tup);
cannam@226: 		st = write_statement(model, writer, tup, 0);
cannam@226: 	}
cannam@226: 	sord_iter_free(iter);
cannam@226: 
cannam@226: 	return !st;
cannam@226: }