1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
4 * Toni Spets <toni.spets@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * vim: ts=4 sw=4 noet ai cindent syntax=c
25 #include <libxml/parser.h>
26 #include <libxml/tree.h>
29 #define PARSE_OPTIONS 0
32 void prss_parse_doc(PRSS *result, xmlDocPtr doc);
34 void prss_parse_data(void *result, const char *xml_data)
36 PRSS *data = (PRSS*)result;
38 xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL,
45 prss_parse_doc(data, doc);
49 void free_rss_items(PRSS *data)
51 for (int i = 0; i < data->item_count; i++) {
52 #define CLEAR(a) if (data->items[i].a) { free(data->items[i].a); data->items[i].a = 0; }
66 void prss_free(PRSS *data)
80 #define CLEAR(a) if (data->a) { free(data->a); data->a = 0; }
89 CLEAR(managingEditor);
96 static inline void prss_null_item(PRSS_Item *i)
98 memset(i, 0, sizeof(PRSS_Item));
101 static inline void read_item(PRSS_Item *res, xmlNodePtr data)
105 for (; data; data = data->next) {
108 if (data->type != XML_ELEMENT_NODE) {
111 child = data->children;
117 #define ASSIGN(a) if (strcasecmp((const char*)data->name, #a) == EQUAL) { \
118 if (res->a) free(res->a); \
119 res->a = strdup((const char*)child->content); \
131 static inline void read_element(PRSS *res, xmlNodePtr n)
135 if (n->type != XML_ELEMENT_NODE) {
144 #define ASSIGN(a) if (strcasecmp((const char*)n->name, #a) == EQUAL) { \
145 if (res->a) free(res->a); \
146 res->a = strdup((const char*)child->content); \
154 ASSIGN(lastBuildDate);
157 ASSIGN(managingEditor);
162 if (!strcasecmp((const char*)n->name, "item")) {
163 read_item(&res->items[res->item_count++], n->children);
167 static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
169 xmlNodePtr channel = root->children;
173 DBGP("parsing rss 2.0 or <1 doc");
175 while (channel && (channel->type != XML_ELEMENT_NODE
176 || strcmp((const char *) channel->name, "channel"))) {
177 channel = channel->next;
183 for (n = channel->children; n; n = n->next) {
184 if (n->type == XML_ELEMENT_NODE &&
185 !strcmp((const char *) n->name, "item")) {
190 if (res->version) free(res->version);
191 res->version = strndup("2.0", text_buffer_size);
192 if (res->items) free_rss_items(res);
193 res->items = malloc(items * sizeof(PRSS_Item));
196 for (n = channel->children; n; n = n->next) {
197 read_element(res, n);
202 static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
207 DBGP("parsing rss 1.0 doc");
209 for (n = root->children; n; n = n->next) {
210 if (n->type == XML_ELEMENT_NODE) {
211 if (!strcmp((const char *) n->name, "item")) {
213 } else if (!strcmp((const char *) n->name, "channel")) {
216 for (i = n->children; i; i = i->next) {
217 read_element(res, i);
223 if (res->version) free(res->version);
224 res->version = strndup("1.0", text_buffer_size);
225 if (res->items) free_rss_items(res);
226 res->items = malloc(items * sizeof(PRSS_Item));
229 for (n = root->children; n; n = n->next) {
230 if (n->type == XML_ELEMENT_NODE &&
231 !strcmp((const char *) n->name, "item")) {
232 read_item(&res->items[res->item_count++], n->children);
239 void prss_parse_doc(PRSS *result, xmlDocPtr doc)
241 xmlNodePtr root = xmlDocGetRootElement(doc);
244 if (root->type == XML_ELEMENT_NODE) {
245 if (!strcmp((const char *) root->name, "RDF")) {
247 parse_rss_1_0(result, root);
249 } else if (!strcmp((const char *) root->name, "rss")) {
250 // RSS 2.0 or <1.0 document
251 parse_rss_2_0(result, root);