summaryrefslogtreecommitdiffstats
path: root/src/raptor_rss_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/raptor_rss_common.c')
-rw-r--r--src/raptor_rss_common.c732
1 files changed, 732 insertions, 0 deletions
diff --git a/src/raptor_rss_common.c b/src/raptor_rss_common.c
new file mode 100644
index 0000000..b6db424
--- /dev/null
+++ b/src/raptor_rss_common.c
@@ -0,0 +1,732 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * raptor_rss_common.c - Raptor Feeds (RSS and Atom) common code
+ *
+ * Copyright (C) 2003-2009, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-2005, University of Bristol, UK http://www.bristol.ac.uk/
+ *
+ * This package is Free Software and part of Redland http://librdf.org/
+ *
+ * It is licensed under the following three licenses as alternatives:
+ * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
+ * 2. GNU General Public License (GPL) V2 or any newer version
+ * 3. Apache License, V2.0 or any newer version
+ *
+ * You may not use this file except in compliance with at least one of
+ * the above three licenses.
+ *
+ * See LICENSE.html or LICENSE.txt at the top of this package for the
+ * complete terms and further detail along with the license texts for
+ * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <raptor_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+
+/* Raptor includes */
+#include "raptor2.h"
+#include "raptor_internal.h"
+#include "raptor_rss.h"
+
+
+static int raptor_rss_field_conversion_date_uplift(raptor_rss_field* from_field, raptor_rss_field* to_field);
+
+
+const raptor_rss_namespace_info raptor_rss_namespaces_info[RAPTOR_RSS_NAMESPACES_SIZE]={
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { RSS0_91_NAMESPACE_URI, "rss091", },
+ { RSS0_9_NAMESPACE_URI, NULL, },
+ { RSS1_0_NAMESPACE_URI, "rss", },
+ { ATOM0_3_NAMESPACE_URI, NULL, },
+ { DC_NAMESPACE_URI, "dc", },
+ { RSS2_0_ENC_NAMESPACE_URI, "enc", },
+ { RSS1_1_NAMESPACE_URI, NULL, },
+ { CONTENT_NAMESPACE_URI, "content", },
+ { ATOM1_0_NAMESPACE_URI, "atom", },
+ { RDF_NAMESPACE_URI, "rdf", },
+ { ATOMTRIPLES_NAMESPACE_URI, "at", },
+ { ITUNES_NAMESPACE_URI, "itunes", },
+};
+
+
+const raptor_rss_item_info raptor_rss_items_info[RAPTOR_RSS_COMMON_SIZE+1]={
+ { "channel", RSS1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "image", RSS1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "textinput", RSS1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "item", RSS1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "author", ATOM1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_RDF_ATOM_AUTHOR_CLASS, RAPTOR_RSS_FIELD_ATOM_AUTHOR },
+ { "Link", ATOM1_0_NS, RAPTOR_RSS_ITEM_BLOCK, RAPTOR_RSS_RDF_ATOM_LINK_CLASS, RAPTOR_RSS_FIELD_ATOM_LINK },
+ { "owner" , ITUNES_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_ITUNES_OWNER, RAPTOR_RSS_FIELD_ITUNES_OWNER },
+ { "skipHours", RSS0_91_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "skipDays", RSS0_91_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "Enclosure", RSS2_0_ENC_NS, RAPTOR_RSS_ITEM_BLOCK, RAPTOR_RSS_RDF_ENCLOSURE_CLASS, RAPTOR_RSS_RDF_ENCLOSURE },
+ { "category", ATOM1_0_NS, RAPTOR_RSS_ITEM_BLOCK, RAPTOR_RSS_RDF_ATOM_CATEGORY_CLASS, RAPTOR_RSS_FIELD_ATOM_CATEGORY },
+ { "source" , RSS2_0_NS, RAPTOR_RSS_ITEM_BLOCK, RAPTOR_RSS_FIELD_SOURCE, RAPTOR_RSS_FIELD_NONE },
+ { "feed", ATOM1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "entry", ATOM1_0_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE },
+ { "<none>", RSS_UNKNOWN_NS, RAPTOR_RSS_ITEM_CONTAINER, RAPTOR_RSS_FIELD_NONE, RAPTOR_RSS_FIELD_NONE }
+};
+
+
+const raptor_rss_field_info raptor_rss_fields_info[RAPTOR_RSS_FIELDS_SIZE+2]={
+ { "title", RSS1_0_NS, 0 },
+ { "link", RSS1_0_NS, 0 }, /* Actually a URI but RSS 1.0 spec wants this as an (XML & RDF) literal */
+ { "description", RSS1_0_NS, 0 },
+ { "url", RSS1_0_NS, 0 },
+ { "name", RSS1_0_NS, 0 },
+ { "language", RSS0_91_NS, 0 },
+ { "rating", RSS0_91_NS, 0 },
+ { "copyright", RSS0_91_NS, 0 },
+ { "pubDate", RSS0_91_NS, 0 },
+ { "lastBuildDate", RSS0_91_NS, 0 },
+ { "docs", RSS0_91_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "managingEditor", RSS0_91_NS, 0 },
+ { "webMaster", RSS0_91_NS, 0 },
+ { "cloud", RSS0_92_NS, 0 },
+ { "ttl", RSS2_0_NS, 0 },
+ { "width", RSS0_91_NS, 0 },
+ { "height", RSS0_91_NS, 0 },
+ { "hour", RSS0_91_NS, 0 },
+ { "day", RSS0_91_NS, 0 },
+ { "generator", RSS0_92_NS, 0 },
+ { "source", RSS0_92_NS, 0 },
+ { "author", RSS2_0_NS, 0 },
+ { "guid", RSS2_0_NS, 0 },
+ { "enclosure", RSS2_0_NS, RAPTOR_RSS_INFO_FLAG_BLOCK_VALUE, RAPTOR_RSS_ENCLOSURE }, /* enclosure in RSS */
+ { "enclosure", RSS2_0_ENC_NS, 0 }, /* RDF output predicate, not an RSS field */
+ { "Enclosure", RSS2_0_ENC_NS, 0 }, /* RDF output class, not an RSS field */
+ { "url", RSS2_0_ENC_NS, 0 }, /* In RDF output, not an RSS field */
+ { "length", RSS2_0_ENC_NS, 0 }, /* In RDF output, not an RSS field */
+ { "type", RSS2_0_ENC_NS, 0 }, /* In RDF output, not an RSS field */
+ { "length", RSS2_0_NS, 0 },
+ { "type", RSS2_0_NS, 0 },
+ { "category", RSS0_92_NS, 0 },
+ { "comments", RSS0_92_NS, 0 },
+ { "items", RSS1_0_NS, 0 },
+ { "image", RSS1_0_NS, 0 },
+ { "textinput", RSS1_0_NS, 0 },
+
+ { "copyright", ATOM0_3_NS, 0 },
+ { "created", ATOM0_3_NS, 0 },
+ { "issued", ATOM0_3_NS, 0 },
+ { "modified", ATOM0_3_NS, 0 },
+ { "tagline", ATOM0_3_NS, 0 },
+
+ /* atom 1.0 required fields */
+ { "id", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "title", ATOM1_0_NS, 0 },
+ { "updated", ATOM1_0_NS, 0 },
+ /* atom 1.0 optional fields */
+ { "author", ATOM1_0_NS, 0, RAPTOR_ATOM_AUTHOR },
+ { "category", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_BLOCK_VALUE, RAPTOR_ATOM_CATEGORY },
+ { "content", ATOM1_0_NS, 0 },
+ { "contributor", ATOM1_0_NS, 0 },
+ { "email", ATOM1_0_NS, 0 },
+ { "entry", ATOM1_0_NS, 0 },
+ { "feed", ATOM1_0_NS, 0 },
+ { "generator", ATOM1_0_NS, 0 },
+ { "icon", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "link", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_BLOCK_VALUE, RAPTOR_ATOM_LINK },
+ { "logo", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "name", ATOM1_0_NS, 0 },
+ { "published", ATOM1_0_NS, 0 },
+ { "rights", ATOM1_0_NS, 0 },
+ { "source", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_BLOCK_VALUE, RAPTOR_RSS_SOURCE },
+ { "subtitle", ATOM1_0_NS, 0 },
+ { "summary", ATOM1_0_NS, 0 },
+ { "uri", ATOM1_0_NS, 0 },
+
+ { "Author", ATOM1_0_NS, 0 },
+ { "Category", ATOM1_0_NS, 0 },
+ { "Link", ATOM1_0_NS, 0 },
+
+ { "label", ATOM1_0_NS, 0 },
+ { "scheme", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "term", ATOM1_0_NS, 0 },
+ { "href", ATOM1_0_NS, RAPTOR_RSS_INFO_FLAG_URI_VALUE },
+ { "rel", ATOM1_0_NS, 0 },
+ { "type", ATOM1_0_NS, 0 },
+ { "hreflang", ATOM1_0_NS, 0 },
+ { "length", ATOM1_0_NS, 0 },
+
+ { "title", DC_NS, 0 },
+ { "contributor", DC_NS, 0 },
+ { "creator", DC_NS, 0 },
+ { "publisher", DC_NS, 0 },
+ { "subject", DC_NS, 0 },
+ { "description", DC_NS, 0 },
+ { "date", DC_NS, 0 },
+ { "type", DC_NS, 0 },
+ { "format", DC_NS, 0 },
+ { "identifier", DC_NS, 0 },
+ { "language", DC_NS, 0 },
+ { "relation", DC_NS, 0 },
+ { "source", DC_NS, 0 },
+ { "coverage", DC_NS, 0 },
+ { "rights", DC_NS, 0 },
+
+ { "encoded", CONTENT_NS, 0 },
+
+ { "contentType", ATOMTRIPLES_NS, 0 },
+
+ { "author", ITUNES_NS, 0 },
+ { "subtitle", ITUNES_NS, 0 },
+ { "summary", ITUNES_NS, 0 },
+ { "keywords", ITUNES_NS, 0 },
+ { "explicit", ITUNES_NS, 0 },
+ { "image", ITUNES_NS, 0 },
+ { "name", ITUNES_NS, 0 },
+ { "owner", ITUNES_NS, 0 },
+ { "block", ITUNES_NS, 0 },
+ { "category", ITUNES_NS, 0 },
+ { "email", ITUNES_NS, 0 },
+
+
+ { "<unknown>", RSS_UNKNOWN_NS, 0 },
+ { "<none>", RSS_UNKNOWN_NS, 0 }
+};
+
+
+/* FIeld mappings from atom fields to RSS/DC */
+const raptor_field_pair raptor_atom_to_rss[]={
+ /* rss clone of atom fields */
+ { RAPTOR_RSS_FIELD_ATOM_SUMMARY, RAPTOR_RSS_FIELD_DESCRIPTION },
+ { RAPTOR_RSS_FIELD_ATOM_ID, RAPTOR_RSS_FIELD_LINK },
+ { RAPTOR_RSS_FIELD_ATOM_UPDATED, RAPTOR_RSS_FIELD_DC_DATE },
+ { RAPTOR_RSS_FIELD_ATOM_RIGHTS, RAPTOR_RSS_FIELD_DC_RIGHTS },
+ { RAPTOR_RSS_FIELD_ATOM_TITLE, RAPTOR_RSS_FIELD_TITLE },
+ { RAPTOR_RSS_FIELD_ATOM_SUMMARY, RAPTOR_RSS_FIELD_CONTENT_ENCODED },
+
+ /* atom 0.3 to atom 1.0 */
+ { RAPTOR_RSS_FIELD_ATOM_COPYRIGHT, RAPTOR_RSS_FIELD_ATOM_RIGHTS },
+ { RAPTOR_RSS_FIELD_ATOM_TAGLINE, RAPTOR_RSS_FIELD_ATOM_SUBTITLE },
+
+#if 0
+ /* other old atom 0.3 fields - IGNORED */
+ { RAPTOR_RSS_FIELD_ATOM_CREATED, RAPTOR_RSS_FIELD_UNKNOWN },
+ { RAPTOR_RSS_FIELD_ATOM_ISSUED, RAPTOR_RSS_FIELD_UNKNOWN },
+ { RAPTOR_RSS_FIELD_ATOM_MODIFIED, RAPTOR_RSS_FIELD_UNKNOWN },
+#endif
+
+#ifdef RAPTOR_PARSEDATE_FUNCTION
+ /* convert to ISO date */
+ { RAPTOR_RSS_FIELD_PUBDATE, RAPTOR_RSS_FIELD_DC_DATE,
+ &raptor_rss_field_conversion_date_uplift },
+#endif
+
+ /* rss content encoded */
+ { RAPTOR_RSS_FIELD_DESCRIPTION, RAPTOR_RSS_FIELD_CONTENT_ENCODED },
+
+ { RAPTOR_RSS_FIELD_UNKNOWN, RAPTOR_RSS_FIELD_UNKNOWN }
+};
+
+
+const raptor_rss_block_field_info raptor_rss_block_fields_info[RAPTOR_RSS_BLOCKS_SIZE+1] = {
+ /*
+ RSS 2 <enclosure> - optional element inside <item>
+ attributes:
+ url (required): where the enclosure is located. url
+ length (required): how big enclosure it is in bytes. integer
+ type (required): what enclosure type is as a standard MIME type. string
+ content: empty
+ */
+ { RAPTOR_RSS_ENCLOSURE, "url", RSS_BLOCK_FIELD_TYPE_URL, 0, RAPTOR_RSS_RDF_ENCLOSURE_URL },
+ { RAPTOR_RSS_ENCLOSURE, "length", RSS_BLOCK_FIELD_TYPE_STRING, 0, RAPTOR_RSS_RDF_ENCLOSURE_LENGTH },
+ { RAPTOR_RSS_ENCLOSURE, "type", RSS_BLOCK_FIELD_TYPE_STRING, 1, RAPTOR_RSS_RDF_ENCLOSURE_TYPE },
+
+ /*
+ RSS 2 <source> - optional element inside <item>
+ attributes:
+ url (required): location of source. url
+ content: source name. string
+ */
+ { RAPTOR_RSS_SOURCE, "url", RSS_BLOCK_FIELD_TYPE_URL, 0 },
+
+ /*
+ Atom <category> - optional element inside <entry>
+ attributes:
+ term (required): the category. string
+ scheme (optional): categorization scheme. url
+ label (optional): human-readable label. string
+ content: empty
+ */
+ { RAPTOR_ATOM_CATEGORY, "term", RSS_BLOCK_FIELD_TYPE_STRING, 0, RAPTOR_RSS_FIELD_ATOM_TERM },
+ { RAPTOR_ATOM_CATEGORY, "scheme", RSS_BLOCK_FIELD_TYPE_URL, 0, RAPTOR_RSS_FIELD_ATOM_SCHEME },
+ { RAPTOR_ATOM_CATEGORY, "label", RSS_BLOCK_FIELD_TYPE_STRING, 1, RAPTOR_RSS_FIELD_ATOM_LABEL },
+
+ /*
+ Atom <link> - optional element inside <entry>
+ attributes:
+ href (required): . url
+ rel (optional): . string
+ type (optional): . string
+ hreflang (optional): . string
+ title (optional): . string
+ length (optional): . string
+ content: empty
+ */
+ { RAPTOR_ATOM_LINK, "href", RSS_BLOCK_FIELD_TYPE_URL, RAPTOR_RSS_LINK_HREF_URL_OFFSET, RAPTOR_RSS_FIELD_ATOM_HREF },
+ { RAPTOR_ATOM_LINK, "rel", RSS_BLOCK_FIELD_TYPE_STRING, RAPTOR_RSS_LINK_REL_STRING_OFFSET, RAPTOR_RSS_FIELD_ATOM_REL },
+ { RAPTOR_ATOM_LINK, "type", RSS_BLOCK_FIELD_TYPE_STRING, 1, RAPTOR_RSS_FIELD_ATOM_TYPE },
+ { RAPTOR_ATOM_LINK, "hreflang", RSS_BLOCK_FIELD_TYPE_STRING, 2, RAPTOR_RSS_FIELD_ATOM_HREFLANG },
+ { RAPTOR_ATOM_LINK, "title", RSS_BLOCK_FIELD_TYPE_STRING, 3, RAPTOR_RSS_FIELD_ATOM_TITLE },
+ { RAPTOR_ATOM_LINK, "length", RSS_BLOCK_FIELD_TYPE_STRING, 4, RAPTOR_RSS_FIELD_ATOM_LENGTH },
+ { RAPTOR_ATOM_LINK, NULL, RSS_BLOCK_FIELD_TYPE_URL, 0, RAPTOR_RSS_FIELD_ATOM_HREF },
+
+ /* sentinel */
+ { RAPTOR_RSS_NONE, NULL, 0, 0 }
+};
+
+
+const unsigned char * const raptor_atom_namespace_uri = (const unsigned char *)"http://www.w3.org/2005/Atom";
+
+
+
+int
+raptor_rss_common_init(raptor_world* world) {
+ int i;
+ raptor_uri *namespace_uri;
+
+ if(world->rss_common_initialised++)
+ return 0;
+
+ world->rss_namespaces_info_uris = RAPTOR_CALLOC(raptor_uri**,
+ RAPTOR_RSS_NAMESPACES_SIZE,
+ sizeof(raptor_uri*));
+ if(!world->rss_namespaces_info_uris)
+ return -1;
+ for(i = 0; i < RAPTOR_RSS_NAMESPACES_SIZE;i++) {
+ const char *uri_string = raptor_rss_namespaces_info[i].uri_string;
+ if(uri_string) {
+ world->rss_namespaces_info_uris[i] = raptor_new_uri(world, (const unsigned char*)uri_string);
+ if(!world->rss_namespaces_info_uris[i])
+ return -1;
+ }
+ }
+
+ world->rss_types_info_uris = RAPTOR_CALLOC(raptor_uri**,
+ RAPTOR_RSS_COMMON_SIZE,
+ sizeof(raptor_uri*));
+ if(!world->rss_types_info_uris)
+ return -1;
+ for(i = 0; i< RAPTOR_RSS_COMMON_SIZE; i++) {
+ int n = raptor_rss_items_info[i].nspace;
+ namespace_uri = world->rss_namespaces_info_uris[n];
+ if(namespace_uri) {
+ world->rss_types_info_uris[i] = raptor_new_uri_from_uri_local_name(world, namespace_uri, (const unsigned char*)raptor_rss_items_info[i].name);
+ if(!world->rss_types_info_uris[i])
+ return -1;
+ }
+ }
+
+ world->rss_fields_info_uris = RAPTOR_CALLOC(raptor_uri**,
+ RAPTOR_RSS_FIELDS_SIZE,
+ sizeof(raptor_uri*));
+ if(!world->rss_fields_info_uris)
+ return -1;
+ for(i = 0; i< RAPTOR_RSS_FIELDS_SIZE; i++) {
+ namespace_uri = world->rss_namespaces_info_uris[raptor_rss_fields_info[i].nspace];
+ if(namespace_uri) {
+ world->rss_fields_info_uris[i] = raptor_new_uri_from_uri_local_name(world, namespace_uri,
+ (const unsigned char*)raptor_rss_fields_info[i].name);
+ if(!world->rss_fields_info_uris[i])
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+void
+raptor_rss_common_terminate(raptor_world* world) {
+ int i;
+ if(--world->rss_common_initialised)
+ return;
+
+ if(world->rss_types_info_uris) {
+ for(i = 0; i< RAPTOR_RSS_COMMON_SIZE; i++) {
+ if(world->rss_types_info_uris[i])
+ raptor_free_uri(world->rss_types_info_uris[i]);
+ }
+ RAPTOR_FREE(raptor_uri* array, world->rss_types_info_uris);
+ world->rss_types_info_uris = NULL;
+ }
+
+ if(world->rss_fields_info_uris) {
+ for(i = 0; i< RAPTOR_RSS_FIELDS_SIZE; i++) {
+ if(world->rss_fields_info_uris[i])
+ raptor_free_uri(world->rss_fields_info_uris[i]);
+ }
+ RAPTOR_FREE(raptor_uri* array, world->rss_fields_info_uris);
+ world->rss_fields_info_uris = NULL;
+ }
+
+ if(world->rss_namespaces_info_uris) {
+ for(i = 0; i < RAPTOR_RSS_NAMESPACES_SIZE;i++) {
+ if(world->rss_namespaces_info_uris[i])
+ raptor_free_uri(world->rss_namespaces_info_uris[i]);
+ }
+ RAPTOR_FREE(raptor_uri* array, world->rss_namespaces_info_uris);
+ world->rss_namespaces_info_uris = NULL;
+ }
+}
+
+
+void
+raptor_rss_model_init(raptor_world* world, raptor_rss_model* rss_model)
+{
+ memset(rss_model->common, 0,
+ sizeof(raptor_rss_item*) * RAPTOR_RSS_COMMON_SIZE);
+
+ rss_model->world = world;
+
+ rss_model->last = rss_model->items = NULL;
+ rss_model->items_count = 0;
+
+ RAPTOR_RSS_RSS_items_URI(rss_model) = raptor_new_uri_relative_to_base(world, world->rss_namespaces_info_uris[RSS1_0_NS], (const unsigned char*)"items");
+}
+
+
+void
+raptor_rss_model_clear(raptor_rss_model* rss_model)
+{
+ int i;
+ raptor_rss_item* item;
+
+ for(i = 0; i< RAPTOR_RSS_COMMON_SIZE; i++) {
+ item = rss_model->common[i];
+ while(item) {
+ raptor_rss_item *next = item->next;
+ raptor_free_rss_item(item);
+ item = next;
+ }
+ }
+
+ item = rss_model->items;
+ while(item) {
+ raptor_rss_item *next = item->next;
+
+ raptor_free_rss_item(item);
+ item = next;
+ }
+ rss_model->last = rss_model->items = NULL;
+
+ for(i = 0; i< RAPTOR_RSS_N_CONCEPTS; i++) {
+ raptor_uri* concept_uri = rss_model->concepts[i];
+ if(concept_uri) {
+ raptor_free_uri(concept_uri);
+ rss_model->concepts[i] = NULL;
+ }
+ }
+}
+
+
+raptor_rss_item*
+raptor_new_rss_item(raptor_world* world)
+{
+ raptor_rss_item* item;
+
+ item = RAPTOR_CALLOC(raptor_rss_item*, 1, sizeof(*item));
+ if(!item)
+ return NULL;
+
+ item->world = world;
+ item->triples = raptor_new_sequence((raptor_data_free_handler)raptor_free_statement, (raptor_data_print_handler)raptor_statement_print);
+ if(!item->triples) {
+ RAPTOR_FREE(raptor_rss_item, item);
+ return NULL;
+ }
+ return item;
+}
+
+
+int
+raptor_rss_model_add_item(raptor_rss_model* rss_model)
+{
+ raptor_rss_item* item;
+
+ item = raptor_new_rss_item(rss_model->world);
+ if(!item)
+ return 1;
+
+ /* new list */
+ if(!rss_model->items)
+ rss_model->items = item;
+
+ /* join last item to this one */
+ if(rss_model->last)
+ rss_model->last->next = item;
+
+ /* this is now the last item */
+ rss_model->last = item;
+ rss_model->items_count++;
+
+ RAPTOR_DEBUG2("Added item %d\n", rss_model->items_count);
+
+ return 0;
+}
+
+
+raptor_rss_item*
+raptor_rss_model_add_common(raptor_rss_model* rss_model,
+ raptor_rss_type type)
+{
+ raptor_rss_item* item;
+
+ item = raptor_new_rss_item(rss_model->world);
+ if(!item)
+ return NULL;
+
+ if(rss_model->common[type] == NULL) {
+ RAPTOR_DEBUG3("Adding common type %u - %s\n", type,
+ raptor_rss_items_info[type].name);
+ rss_model->common[type] = item;
+ } else {
+ raptor_rss_item* next;
+ RAPTOR_DEBUG3("Appending common type %u - %s\n", type,
+ raptor_rss_items_info[type].name);
+ for(next = rss_model->common[type]; next->next; next = next->next)
+ ;
+ next->next = item;
+ }
+ return item;
+}
+
+
+raptor_rss_item*
+raptor_rss_model_get_common(raptor_rss_model* rss_model, raptor_rss_type type)
+{
+ raptor_rss_item* item;
+ for(item = rss_model->common[type];
+ item && item->next;
+ item = item->next) ;
+ return item;
+}
+
+
+void
+raptor_free_rss_item(raptor_rss_item* item)
+{
+ int i;
+ for(i = 0; i< RAPTOR_RSS_FIELDS_SIZE; i++) {
+ if(item->fields[i])
+ raptor_rss_field_free(item->fields[i]);
+ }
+ if(item->blocks)
+ raptor_free_rss_block(item->blocks);
+ if(item->uri)
+ raptor_free_uri(item->uri);
+ if(item->term)
+ raptor_free_term(item->term);
+ if(item->triples)
+ raptor_free_sequence(item->triples);
+
+ RAPTOR_FREE(raptor_rss_item, item);
+}
+
+
+void
+raptor_rss_item_add_block(raptor_rss_item* item,
+ raptor_rss_block *block)
+{
+ if(!item->blocks) {
+ RAPTOR_DEBUG1("Adding first block\n");
+ item->blocks = block;
+ } else {
+ raptor_rss_block *cur;
+
+ RAPTOR_DEBUG1("Adding subsequent block\n");
+ for(cur = item->blocks; cur->next; cur = cur->next)
+ ;
+ cur->next = block;
+ }
+}
+
+
+void
+raptor_rss_item_add_field(raptor_rss_item* item, int type,
+ raptor_rss_field* field)
+{
+ if(!item->fields[type]) {
+ RAPTOR_DEBUG3("Adding first type %d field %s\n", type, raptor_rss_fields_info[type].name);
+ item->fields_count++;
+ item->fields[type] = field;
+ } else {
+ raptor_rss_field* cur;
+
+ RAPTOR_DEBUG1("Adding subsequent field\n");
+ for(cur = item->fields[type]; cur->next; cur = cur->next) ;
+ cur->next = field;
+ }
+}
+
+
+int
+raptor_rss_item_equals_statement_subject(const raptor_rss_item *item,
+ const raptor_statement *statement)
+{
+ return raptor_term_equals(statement->subject, item->term);
+}
+
+
+int
+raptor_rss_item_set_uri(raptor_rss_item *item, raptor_uri* uri)
+{
+ RAPTOR_DEBUG3("Set node %p to URI <%s>\n", RAPTOR_VOIDP(item),
+ raptor_uri_as_string(uri));
+
+ item->uri = raptor_uri_copy(uri);
+ if(!item->uri)
+ return 1;
+
+ item->term = raptor_new_term_from_uri(item->world, item->uri);
+ return 0;
+}
+
+
+/*
+ * raptor_new_rss_block:
+ * @world: world
+ * @type: RSS block type
+ * @block_term: Block subject term (shared)
+ *
+ * INTERNAL - Create a new RSS Block such as <author> etc
+ *
+ * Return value: new RSS block or NULL on failure
+ */
+raptor_rss_block*
+raptor_new_rss_block(raptor_world* world, raptor_rss_type type,
+ raptor_term* block_term)
+{
+ raptor_rss_block *block;
+ block = RAPTOR_CALLOC(raptor_rss_block*, 1, sizeof(*block));
+
+ if(block) {
+ block->rss_type = type;
+ block->node_type = world->rss_types_info_uris[type];
+ block->identifier = raptor_term_copy(block_term);
+ }
+
+ return block;
+}
+
+
+void
+raptor_free_rss_block(raptor_rss_block *block)
+{
+ int i;
+
+ for(i = 0; i < RSS_BLOCK_MAX_URLS; i++) {
+ if(block->urls[i])
+ raptor_free_uri(block->urls[i]);
+ }
+
+ for(i = 0; i < RSS_BLOCK_MAX_STRINGS; i++) {
+ if(block->strings[i])
+ RAPTOR_FREE(char*, block->strings[i]);
+ }
+
+ if(block->next)
+ raptor_free_rss_block(block->next);
+
+ if(block->identifier)
+ raptor_free_term(block->identifier);
+
+ RAPTOR_FREE(raptor_rss_block, block);
+}
+
+
+raptor_rss_field*
+raptor_rss_new_field(raptor_world* world)
+{
+ raptor_rss_field* field = RAPTOR_CALLOC(raptor_rss_field*, 1, sizeof(*field));
+ if(field)
+ field->world = world;
+ return field;
+}
+
+
+void
+raptor_rss_field_free(raptor_rss_field* field)
+{
+ if(field->value)
+ RAPTOR_FREE(char*, field->value);
+ if(field->uri)
+ raptor_free_uri(field->uri);
+ if(field->next)
+ raptor_rss_field_free(field->next);
+ RAPTOR_FREE(raptor_rss_field, field);
+}
+
+
+#define RAPTOR_ISO_DATE_FORMAT "%Y-%m-%dT%H:%M:%SZ"
+
+int
+raptor_rss_format_iso_date(char* buffer, size_t len, time_t unix_time)
+{
+ struct tm* structured_time;
+
+ if(len < RAPTOR_ISO_DATE_LEN)
+ return 1;
+
+ structured_time = gmtime(&unix_time);
+ strftime(buffer, len+1, RAPTOR_ISO_DATE_FORMAT, structured_time);
+
+ return 0;
+}
+
+
+int
+raptor_rss_set_date_field(raptor_rss_field* field, time_t unix_time)
+{
+ size_t len = RAPTOR_ISO_DATE_LEN;
+
+ if(field->value)
+ RAPTOR_FREE(char*, field->value);
+ field->value = RAPTOR_MALLOC(unsigned char*, len + 1);
+ if(!field->value)
+ return 1;
+
+ if(raptor_rss_format_iso_date((char*)field->value, len, unix_time)) {
+ RAPTOR_FREE(char*, field->value);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+raptor_rss_field_conversion_date_uplift(raptor_rss_field* from_field,
+ raptor_rss_field* to_field)
+{
+#ifdef RAPTOR_PARSEDATE_FUNCTION
+ time_t unix_time;
+ char *date_string = (char*)from_field->value;
+
+ if(!date_string)
+ return 1;
+
+ unix_time = RAPTOR_PARSEDATE_FUNCTION(date_string, NULL);
+ if(unix_time < 0)
+ return 1;
+
+ return raptor_rss_set_date_field(to_field, unix_time);
+#else
+ return 1;
+#endif
+}