1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-11-19 11:35:12 +00:00
conky/src/prss.cc

249 lines
5.6 KiB
C++
Raw Normal View History

2010-02-09 12:11:56 +00:00
/* -*- mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
* vim: ts=4 sw=4 noet ai cindent syntax=cpp
*
* Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
* Toni Spets <toni.spets@gmail.com>
*
* Permission to use, copy, modify, and 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.
*
* THE 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
2009-07-27 20:47:19 +00:00
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "conky.h"
#include "prss.h"
2009-08-05 04:56:19 +00:00
#include "logging.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#ifndef PARSE_OPTIONS
#define PARSE_OPTIONS 0
#endif
void prss_parse_doc(PRSS *result, xmlDocPtr doc);
2011-02-15 23:33:22 +00:00
PRSS::PRSS(const std::string &xml_data)
: version(NULL), title(NULL), link(NULL), description(NULL), language(NULL),
generator(NULL), managingEditor(NULL), webMaster(NULL), docs(NULL), lastBuildDate(NULL),
pubDate(NULL), copyright(NULL), ttl(NULL), items(NULL), item_count(0)
{
2011-02-15 23:33:22 +00:00
std::unique_ptr<xmlDoc, void (*)(xmlDoc *)> doc(
xmlReadMemory(xml_data.c_str(), xml_data.length(), "", NULL, PARSE_OPTIONS),
xmlFreeDoc);
2009-08-05 04:56:19 +00:00
2011-02-15 23:33:22 +00:00
if (!doc)
throw std::runtime_error("Unable to parse rss data");
2011-02-15 23:33:22 +00:00
prss_parse_doc(this, doc.get());
}
2009-08-05 04:56:19 +00:00
void free_rss_items(PRSS *data)
{
int i;
if(data->items) {
for (i = 0; i < data->item_count; i++) {
#define CLEAR(a) free_and_zero(data->items[i].a);
CLEAR(title);
CLEAR(link);
CLEAR(description);
CLEAR(category);
CLEAR(pubDate);
CLEAR(guid);
2009-08-05 04:56:19 +00:00
#undef CLEAR
}
free_and_zero(data->items);
data->item_count = 0;
}
}
2011-02-15 23:33:22 +00:00
PRSS::~PRSS()
{
2011-02-15 23:33:22 +00:00
free_rss_items(this);
free(version);
free(title);
free(link);
free(description);
free(language);
free(pubDate);
free(lastBuildDate);
free(generator);
free(docs);
free(managingEditor);
free(webMaster);
free(copyright);
free(ttl);
}
2009-08-05 04:56:19 +00:00
static inline void prss_null_item(PRSS_Item *i)
{
memset(i, 0, sizeof(PRSS_Item));
}
static inline void read_item(PRSS_Item *res, xmlNodePtr data)
{
prss_null_item(res);
for (; data; data = data->next) {
xmlNodePtr child;
if (data->type != XML_ELEMENT_NODE) {
continue;
}
child = data->children;
if (!child) {
continue;
}
2009-08-05 04:56:19 +00:00
#define ASSIGN(a) if (strcasecmp((const char*)data->name, #a) == EQUAL) { \
free_and_zero(res->a); \
2009-08-05 04:56:19 +00:00
res->a = strdup((const char*)child->content); \
continue; \
}
2009-08-05 04:56:19 +00:00
ASSIGN(title);
ASSIGN(link);
ASSIGN(description);
ASSIGN(category);
ASSIGN(pubDate);
ASSIGN(guid);
#undef ASSIGN
}
}
static inline void read_element(PRSS *res, xmlNodePtr n)
{
xmlNodePtr child;
if (n->type != XML_ELEMENT_NODE) {
return;
}
child = n->children;
if (!child) {
return;
}
2009-08-05 04:56:19 +00:00
#define ASSIGN(a) if (strcasecmp((const char*)n->name, #a) == EQUAL) { \
free_and_zero(res->a); \
2009-08-05 04:56:19 +00:00
res->a = strdup((const char*)child->content); \
return; \
}
ASSIGN(title);
ASSIGN(link);
ASSIGN(description);
ASSIGN(language);
ASSIGN(pubDate);
ASSIGN(lastBuildDate);
ASSIGN(generator);
ASSIGN(docs);
ASSIGN(managingEditor);
ASSIGN(webMaster);
ASSIGN(copyright);
ASSIGN(ttl);
#undef ASSIGN
if (!strcasecmp((const char*)n->name, "item")) {
read_item(&res->items[res->item_count++], n->children);
}
}
static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
{
xmlNodePtr channel = root->children;
xmlNodePtr n;
int items = 0;
2009-08-05 04:56:19 +00:00
DBGP("parsing rss 2.0 or <1 doc");
while (channel && (channel->type != XML_ELEMENT_NODE
2009-08-05 04:56:19 +00:00
|| strcmp((const char *) channel->name, "channel"))) {
channel = channel->next;
}
if (!channel) {
return 0;
}
for (n = channel->children; n; n = n->next) {
if (n->type == XML_ELEMENT_NODE &&
!strcmp((const char *) n->name, "item")) {
++items;
}
}
free_and_zero(res->version);
2010-08-29 21:50:32 +00:00
res->version = strndup("2.0", text_buffer_size.get(*state));
free_rss_items(res);
2010-02-09 14:24:58 +00:00
res->items = (PRSS_Item*) malloc(items * sizeof(PRSS_Item));
res->item_count = 0;
for (n = channel->children; n; n = n->next) {
read_element(res, n);
}
return 1;
}
static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
{
int items = 0;
xmlNodePtr n;
2009-08-05 04:56:19 +00:00
DBGP("parsing rss 1.0 doc");
for (n = root->children; n; n = n->next) {
if (n->type == XML_ELEMENT_NODE) {
if (!strcmp((const char *) n->name, "item")) {
++items;
} else if (!strcmp((const char *) n->name, "channel")) {
xmlNodePtr i;
for (i = n->children; i; i = i->next) {
read_element(res, i);
}
}
}
}
free_and_zero(res->version);
2010-08-29 21:50:32 +00:00
res->version = strndup("1.0", text_buffer_size.get(*state));
free_rss_items(res);
2010-02-09 14:24:58 +00:00
res->items = (PRSS_Item*) malloc(items * sizeof(PRSS_Item));
res->item_count = 0;
for (n = root->children; n; n = n->next) {
if (n->type == XML_ELEMENT_NODE &&
!strcmp((const char *) n->name, "item")) {
read_item(&res->items[res->item_count++], n->children);
}
}
return 1;
}
void prss_parse_doc(PRSS *result, xmlDocPtr doc)
{
xmlNodePtr root = xmlDocGetRootElement(doc);
do {
if (root->type == XML_ELEMENT_NODE) {
if (!strcmp((const char *) root->name, "RDF")) {
// RSS 1.0 document
parse_rss_1_0(result, root);
return;
} else if (!strcmp((const char *) root->name, "rss")) {
// RSS 2.0 or <1.0 document
parse_rss_2_0(result, root);
return;
}
}
root = root->next;
} while (root);
return;
}