/* mRss - Copyright (C) 2005-2007 bakunin - Andrea Marchesini * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include #else # error Use configure; make; make install #endif #include "mrss.h" #include "mrss_internal.h" static void __mrss_write_string (void (*func) (void *, char *, ...), void *obj, char *str) { int i; int len; char buf[1024]; int j; #define __NXML_CHECK_BUF \ if(j==sizeof(buf)-1) { buf[j]=0; func(obj, "%s",buf); j=0; } if (!str) return; len = strlen (str); for (j = i = 0; i < len; i++) { if (str[i] == '\r') continue; else if (str[i] == '<') { buf[j++] = '&'; __NXML_CHECK_BUF; buf[j++] = 'l'; __NXML_CHECK_BUF; buf[j++] = 't'; __NXML_CHECK_BUF; buf[j++] = ';'; __NXML_CHECK_BUF; } else if (str[i] == '>') { buf[j++] = '&'; __NXML_CHECK_BUF; buf[j++] = 'g'; __NXML_CHECK_BUF; buf[j++] = 't'; __NXML_CHECK_BUF; buf[j++] = ';'; __NXML_CHECK_BUF; } else if (str[i] == '&') { buf[j++] = '&'; __NXML_CHECK_BUF; buf[j++] = 'a'; __NXML_CHECK_BUF; buf[j++] = 'm'; __NXML_CHECK_BUF; buf[j++] = 'p'; __NXML_CHECK_BUF; buf[j++] = ';'; __NXML_CHECK_BUF; } else if (str[i] == '\'') { buf[j++] = '&'; __NXML_CHECK_BUF; buf[j++] = 'a'; __NXML_CHECK_BUF; buf[j++] = 'p'; __NXML_CHECK_BUF; buf[j++] = 'o'; __NXML_CHECK_BUF; buf[j++] = 's'; __NXML_CHECK_BUF; buf[j++] = ';'; __NXML_CHECK_BUF; } else if (str[i] == '\'') { buf[j++] = '&'; __NXML_CHECK_BUF; buf[j++] = 'q'; __NXML_CHECK_BUF; buf[j++] = 'u'; __NXML_CHECK_BUF; buf[j++] = 'o'; __NXML_CHECK_BUF; buf[j++] = 't'; __NXML_CHECK_BUF; buf[j++] = ';'; __NXML_CHECK_BUF; } else { buf[j++] = str[i]; __NXML_CHECK_BUF; } } if (j) { buf[j] = 0; func (obj, "%s", buf); j = 0; } } static void __mrss_write_real_image (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { if (mrss->image_title || mrss->image_url || mrss->image_link || mrss->image_width || mrss->image_height || mrss->description) { func (obj, " %s\n", mrss->version == MRSS_VERSION_1_0 ? "" : " "); if (mrss->image_title) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->image_title); func (obj, "\n"); } if (mrss->image_url) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->image_url); func (obj, "\n"); } if (mrss->image_link) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->image_link); func (obj, "\n"); } if (mrss->version != MRSS_VERSION_1_0) { if (mrss->image_width) func (obj, " %d\n", mrss->image_width); if (mrss->image_height) func (obj, " %d\n", mrss->image_height); if (mrss->image_description) { func (obj, " "); __mrss_write_string (func, obj, mrss->image_description); func (obj, "\n"); } } func (obj, " %s\n", mrss->version == MRSS_VERSION_1_0 ? "" : " "); } } static void __mrss_write_real_textinput (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { if (mrss->textinput_title || mrss->textinput_description || mrss->textinput_name || mrss->textinput_link) { func (obj, " %s\n", mrss->version == MRSS_VERSION_1_0 ? "" : " "); if (mrss->textinput_title) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->textinput_title); func (obj, "\n"); } if (mrss->textinput_description) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->textinput_description); func (obj, "\n"); } if (mrss->textinput_name) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->textinput_name); func (obj, "\n"); } if (mrss->textinput_link) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, mrss->textinput_link); func (obj, "\n"); } func (obj, " \n"); } } static void __mrss_write_real_cloud (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { if ((mrss->version == MRSS_VERSION_0_92 || mrss->version == MRSS_VERSION_2_0) && (mrss->cloud || mrss->cloud_domain || mrss->cloud_port || mrss->cloud_path || mrss-> cloud_registerProcedure || mrss->cloud_protocol)) { func (obj, " cloud_domain) { func (obj, " domain=\""); __mrss_write_string (func, obj, mrss->cloud_domain); func (obj, "\""); } if (mrss->cloud_port) func (obj, " port=\"%d\"", mrss->cloud_port); if (mrss->cloud_path) { func (obj, " path=\""); __mrss_write_string (func, obj, mrss->cloud_path); func (obj, "\""); } if (mrss->cloud_registerProcedure) { func (obj, " registerProcedure=\""); __mrss_write_string (func, obj, mrss->cloud_registerProcedure); func (obj, "\""); } if (mrss->cloud_protocol) { func (obj, " protocol=\""); __mrss_write_string (func, obj, mrss->cloud_protocol); func (obj, "\""); } if (mrss->cloud) func (obj, ">%s\n", mrss->cloud); else func (obj, " />\n", mrss->cloud); } } static void __mrss_write_real_skipHours (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { if (mrss->skipHours && mrss->version != MRSS_VERSION_1_0) { mrss_hour_t *hour; func (obj, " \n"); hour = mrss->skipHours; while (hour) { func (obj, " "); __mrss_write_string (func, obj, hour->hour); func (obj, "\n"); hour = hour->next; } func (obj, " \n"); } } static void __mrss_write_real_skipDays (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { if (mrss->skipDays && mrss->version != MRSS_VERSION_1_0) { mrss_day_t *day; func (obj, " \n"); day = mrss->skipDays; while (day) { func (obj, " "); __mrss_write_string (func, obj, day->day); func (obj, "\n"); day = day->next; } func (obj, " \n"); } } static void __mrss_write_real_category (mrss_t * mrss, mrss_category_t * category, void (*func) (void *, char *, ...), void *obj) { if ((mrss->version == MRSS_VERSION_0_92 || mrss->version == MRSS_VERSION_2_0) && mrss->category) { while (category) { func (obj, " domain) { func (obj, " domain=\""); __mrss_write_string (func, obj, category->domain); func (obj, "\""); } func (obj, ">"); __mrss_write_string (func, obj, category->category); func (obj, "\n"); category = category->next; } } } static void __mrss_write_real_tag (mrss_tag_t * tag, void (*func) (void *, char *, ...), void *obj, int index) { mrss_attribute_t *attribute; struct mrss_ns_t { char *ns; struct mrss_ns_t *next; } *namespaces = NULL, *nstmp; int i; while (tag) { if (tag->ns) { if (!(namespaces = calloc (1, sizeof (struct mrss_ns_t)))) return; namespaces->ns = tag->ns; } for (attribute = tag->attributes; attribute; attribute = attribute->next) { if (attribute->ns) { for (nstmp = namespaces; nstmp; nstmp = nstmp->next) if (!strcmp (nstmp->ns, attribute->ns)) break; if (nstmp) continue; if (!(nstmp = calloc (1, sizeof (struct mrss_ns_t)))) return; nstmp->ns = attribute->ns; nstmp->next = namespaces->next; namespaces->next = nstmp; } } for (i = 0; i < index; i++) func (obj, " "); if (tag->ns) func (obj, " name); else func (obj, " <%s", tag->name); for (i = 0, nstmp = namespaces; nstmp; nstmp = nstmp->next) func (obj, " xmlns:ns%d=\"%s\"", i++, nstmp->ns); for (attribute = tag->attributes; attribute; attribute = attribute->next) { if (attribute->ns) { for (i = 0, nstmp = namespaces; nstmp; i++, nstmp = nstmp->next) { if (!strcmp (nstmp->ns, attribute->ns)) { func (obj, " ns%d:%s=\"%s\"", i, attribute->name, attribute->value); break; } } } else func (obj, " %s=\"%s\"", attribute->name, attribute->value); } if (tag->value) { func (obj, ">"); __mrss_write_string (func, obj, tag->value); } if (tag->children) { if (!tag->value) func (obj, ">\n"); func (obj, "\n"); __mrss_write_real_tag (tag->children, func, obj, index + 1); } if (tag->children || tag->value) { if (tag->children) for (i = 0; i < index; i++) func (obj, " "); if (tag->ns) func (obj, "\n", tag->name); else func (obj, "\n", tag->name); } else func (obj, "/>\n"); while (namespaces) { nstmp = namespaces; namespaces = namespaces->next; free (nstmp); } tag = tag->next; } } static void __mrss_write_real_item (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { mrss_item_t *item = mrss->item; while (item) { func (obj, " %s\n", mrss->version == MRSS_VERSION_1_0 ? "" : " "); if (item->title) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, item->title); func (obj, "\n"); } if (item->link) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, item->link); func (obj, "\n"); } if (item->description) { func (obj, " %s", mrss->version == MRSS_VERSION_1_0 ? "" : " "); __mrss_write_string (func, obj, item->description); func (obj, "\n"); } if (mrss->version == MRSS_VERSION_2_0) { if (item->author) { func (obj, " "); __mrss_write_string (func, obj, item->author); func (obj, "\n"); } if (item->comments) { func (obj, " "); __mrss_write_string (func, obj, item->comments); func (obj, "\n"); } if (item->pubDate) { func (obj, " "); __mrss_write_string (func, obj, item->pubDate); func (obj, "\n"); } if (item->guid) { func (obj, " ", item->guid_isPermaLink ? "true" : "false"); __mrss_write_string (func, obj, item->guid); func (obj, "\n"); } } if (mrss->version == MRSS_VERSION_2_0 || mrss->version == MRSS_VERSION_0_92) { if (item->source || item->source_url) { func (obj, " source_url) { func (obj, " url=\""); __mrss_write_string (func, obj, item->source_url); func (obj, "\""); } if (item->source) { func (obj, ">"); __mrss_write_string (func, obj, item->source); func (obj, "\n"); } else func (obj, " />\n"); } } if (item->enclosure || item->enclosure_length || item->enclosure_type) { func (obj, " enclosure_url) { func (obj, " url=\""); __mrss_write_string (func, obj, item->enclosure_url); func (obj, "\""); } if (item->enclosure_length) func (obj, " length=\"%d\"", item->enclosure_length); if (item->enclosure_type) { func (obj, " type=\""); __mrss_write_string (func, obj, item->enclosure_type); func (obj, "\""); } if (item->enclosure) { func (obj, ">"); __mrss_write_string (func, obj, item->enclosure); func (obj, "\n"); } else func (obj, " />\n"); } __mrss_write_real_category (mrss, item->category, func, obj); if (item->other_tags) __mrss_write_real_tag (item->other_tags, func, obj, 1); func (obj, " %s\n", mrss->version == MRSS_VERSION_1_0 ? "" : " "); item = item->next; } } static void __mrss_write_real_atom_category (mrss_category_t * category, void (*func) (void *, char *, ...), void *obj) { while (category) { func (obj, " domain) { func (obj, " scheme=\""); __mrss_write_string (func, obj, category->domain); func (obj, "\""); } if (category->category) { func (obj, " term=\""); __mrss_write_string (func, obj, category->category); func (obj, "\""); } if (category->label) { func (obj, " label=\""); __mrss_write_string (func, obj, category->label); func (obj, "\""); } func (obj, "/>\n"); category = category->next; } } static void __mrss_write_real_atom_entry (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { mrss_item_t *item = mrss->item; while (item) { func (obj, " \n"); if (item->title) { func (obj, " "); __mrss_write_string (func, obj, item->title); func (obj, "\n"); } if (item->link) { func (obj, " "); __mrss_write_string (func, obj, item->link); func (obj, "\n"); } if (item->description) { func (obj, " "); __mrss_write_string (func, obj, item->description); func (obj, "\n"); } if (item->copyright) { func (obj, " "); __mrss_write_string (func, obj, item->copyright); func (obj, "\n"); } if (item->author) { func (obj, " \n"); func (obj, " "); __mrss_write_string (func, obj, item->author); func (obj, "\n"); if (item->author_email) { func (obj, " "); __mrss_write_string (func, obj, item->author_email); func (obj, "\n"); } if (item->author_uri) { func (obj, " "); __mrss_write_string (func, obj, item->author_uri); func (obj, "\n"); } func (obj, " \n"); } if (item->contributor) { func (obj, " \n"); func (obj, " "); __mrss_write_string (func, obj, item->contributor); func (obj, "\n"); if (item->contributor_email) { func (obj, " "); __mrss_write_string (func, obj, item->contributor_email); func (obj, "\n"); } if (item->contributor_uri) { func (obj, " "); __mrss_write_string (func, obj, item->contributor_uri); func (obj, "\n"); } func (obj, " \n"); } /* TODO */ if (mrss->pubDate) { if (mrss->version == MRSS_VERSION_ATOM_1_0) { func (obj, " "); __mrss_write_string (func, obj, item->pubDate); func (obj, "\n"); } else { func (obj, " "); __mrss_write_string (func, obj, item->pubDate); func (obj, "\n"); } } if (item->guid) { func (obj, " "); __mrss_write_string (func, obj, item->guid); func (obj, "\n"); } __mrss_write_real_atom_category (item->category, func, obj); if (item->other_tags) __mrss_write_real_tag (item->other_tags, func, obj, 1); func (obj, " \n"); item = item->next; } } static mrss_error_t __mrss_write_atom (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { func (obj, "language) func (obj, " xml:lang=\"%s\"", mrss->language); if (mrss->version == MRSS_VERSION_ATOM_0_3) func (obj, " version=\"0.3\""); func (obj, ">\n"); func (obj, " "); __mrss_write_string (func, obj, mrss->title); func (obj, "\n"); if (mrss->description) { if (mrss->version == MRSS_VERSION_ATOM_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->description); func (obj, "\n"); } else { func (obj, " "); __mrss_write_string (func, obj, mrss->description); func (obj, "\n"); } } if (mrss->link) { func (obj, " link); func (obj, "\"/>\n"); } if (mrss->id) { func (obj, " "); __mrss_write_string (func, obj, mrss->id); func (obj, "\n"); } if (mrss->copyright) { func (obj, " "); __mrss_write_string (func, obj, mrss->copyright); func (obj, "\n"); } /* TODO */ if (mrss->lastBuildDate) { func (obj, " "); __mrss_write_string (func, obj, mrss->lastBuildDate); func (obj, "\n"); } if (mrss->managingeditor) { func (obj, " \n"); func (obj, " "); __mrss_write_string (func, obj, mrss->managingeditor); func (obj, "\n"); if (mrss->managingeditor_email) { func (obj, " "); __mrss_write_string (func, obj, mrss->managingeditor_email); func (obj, "\n"); } if (mrss->managingeditor_uri) { func (obj, " "); __mrss_write_string (func, obj, mrss->managingeditor_uri); func (obj, "\n"); } func (obj, " \n"); } if (mrss->generator) { func (obj, " generator_uri) { func (obj, " uri=\""); __mrss_write_string (func, obj, mrss->generator_uri); func (obj, "\""); } if (mrss->generator_version) { func (obj, " version=\""); __mrss_write_string (func, obj, mrss->generator_version); func (obj, "\""); } func (obj, ">"); __mrss_write_string (func, obj, mrss->generator); func (obj, "\n"); } if (mrss->image_url) { func (obj, " "); __mrss_write_string (func, obj, mrss->image_url); func (obj, "\n"); } if (mrss->image_logo) { func (obj, " "); __mrss_write_string (func, obj, mrss->image_logo); func (obj, "\n"); } __mrss_write_real_atom_category (mrss->category, func, obj); __mrss_write_real_atom_entry (mrss, func, obj); if (mrss->other_tags) __mrss_write_real_tag (mrss->other_tags, func, obj, 0); func (obj, "\n"); return MRSS_OK; } static mrss_error_t __mrss_write_real (mrss_t * mrss, void (*func) (void *, char *, ...), void *obj) { func (obj, "\n"); if (mrss->version == MRSS_VERSION_1_0) func (obj, "\n"); else if (mrss->version == MRSS_VERSION_ATOM_1_0 || mrss->version == MRSS_VERSION_ATOM_0_3) return __mrss_write_atom (mrss, func, obj); else { func (obj, "version) { case MRSS_VERSION_0_91: func (obj, "0.91"); break; case MRSS_VERSION_0_92: func (obj, "0.92"); break; case MRSS_VERSION_2_0: func (obj, "2.0"); break; default: break; } func (obj, "\">\n"); } if (mrss->version == MRSS_VERSION_1_0 && mrss->about) { func (obj, " about); func (obj, "\">\n"); } else func (obj, " \n"); if (mrss->title) { func (obj, " "); __mrss_write_string (func, obj, mrss->title); func (obj, "\n"); } if (mrss->description) { func (obj, " "); __mrss_write_string (func, obj, mrss->description); func (obj, "\n"); } if (mrss->link) { func (obj, " "); __mrss_write_string (func, obj, mrss->link); func (obj, "\n"); } if (mrss->language && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->language); func (obj, "\n"); } if (mrss->rating && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->rating); func (obj, "\n"); } if (mrss->copyright && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->copyright); func (obj, "\n"); } if (mrss->pubDate && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->pubDate); func (obj, "\n"); } if (mrss->lastBuildDate && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->lastBuildDate); func (obj, "\n"); } if (mrss->docs && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->docs); func (obj, "\n"); } if (mrss->managingeditor && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->managingeditor); func (obj, "\n"); } if (mrss->webMaster && mrss->version != MRSS_VERSION_1_0) { func (obj, " "); __mrss_write_string (func, obj, mrss->webMaster); func (obj, "\n"); } if (mrss->version == MRSS_VERSION_2_0) { if (mrss->generator) { func (obj, " "); __mrss_write_string (func, obj, mrss->generator); func (obj, "\n"); } if (mrss->ttl) func (obj, " %d\n", mrss->ttl); } if (mrss->version == MRSS_VERSION_1_0) { if (mrss->image_url) { func (obj, " image_url); func (obj, "\" />\n"); } if (mrss->textinput_link) { func (obj, " textinput_link); func (obj, "\" />\n"); } if (mrss->item) { mrss_item_t *item = mrss->item; func (obj, " \n" " \n"); while (item) { func (obj, " link); func (obj, "\" />\n"); item = item->next; } func (obj, " \n" " \n"); } func (obj, " \n"); } __mrss_write_real_image (mrss, func, obj); __mrss_write_real_textinput (mrss, func, obj); __mrss_write_real_cloud (mrss, func, obj); __mrss_write_real_skipHours (mrss, func, obj); __mrss_write_real_skipDays (mrss, func, obj); __mrss_write_real_category (mrss, mrss->category, func, obj); if (mrss->other_tags) __mrss_write_real_tag (mrss->other_tags, func, obj, 1); __mrss_write_real_item (mrss, func, obj); if (mrss->version != MRSS_VERSION_1_0) func (obj, " \n" "\n"); else func (obj, "\n"); return MRSS_OK; } static void __mrss_file_write (void *obj, char *str, ...) { va_list va; va_start (va, str); vfprintf ((FILE *) obj, str, va); va_end (va); } static void __mrss_buffer_write (void *obj, char *str, ...) { va_list va; char s[4096]; int len; char **buffer = (char **) obj; va_start (va, str); len = vsnprintf (s, sizeof (s), str, va); va_end (va); if (!*buffer) { if (!(*buffer = (char *) malloc (sizeof (char) * (len + 1)))) return; strncpy (*buffer, s, len + 1); } else { if (!(*buffer = (char *) realloc (*buffer, sizeof (char) * (strlen (*buffer) + len + 1)))) return; strncat (*buffer, s, len + 1); } } /*************************** EXTERNAL FUNCTION ******************************/ mrss_error_t mrss_write_file (mrss_t * mrss, char *file) { FILE *fl; mrss_error_t ret; if (!mrss || !file) return MRSS_ERR_DATA; if (!(fl = fopen (file, "wb"))) return MRSS_ERR_POSIX; ret = __mrss_write_real (mrss, __mrss_file_write, fl); fclose (fl); return ret; } mrss_error_t mrss_write_buffer (mrss_t * mrss, char **buffer) { if (!mrss || !buffer) return MRSS_ERR_DATA; return __mrss_write_real (mrss, __mrss_buffer_write, buffer); } /* EOF */