diff --git a/src/Makefile.am b/src/Makefile.am index 6251d2db..7cefbf6e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,7 +36,7 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ mp3-scanner.h mp3-scanner.c rend-unix.h strcasestr.c strcasestr.h \ strsep.c dynamic-art.c dynamic-art.h query.c query.h ssc.c ssc.h \ db-generic.c db-generic.h dispatch.c dispatch.h wma.c \ - scan-xml.c ezxml.c ezxml.h \ + scan-xml.c rxml.c rxml.h \ $(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \ $(SQLITEDB) diff --git a/src/ezxml.c b/src/ezxml.c deleted file mode 100644 index a29722ed..00000000 --- a/src/ezxml.c +++ /dev/null @@ -1,712 +0,0 @@ -/* ezxml.c - * - * Copyright 2005 Aaron Voisine - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#ifndef EZXML_NOMMAP -#include -#endif // EZXML_NOMMAP -#include -#include "ezxml.h" - -#define EZXML_TXTM 0x80 // flag value meaning txt was malloced -#define EZXML_WS "\t\r\n " // whitespace - -typedef struct ezxml_root *ezxml_root_t; -struct ezxml_root { // additional data for the root tag - struct ezxml xml; // is a super-struct built on top of ezxml struct - ezxml_t cur; // current xml tree insertion point - void *m; // original xml string - size_t len; // length of allocated memory for mmap, or -1 for malloc - void *u; // UTF-8 conversion of string if original was UTF-16 - const char *err; // error string - char ***pi; // processing instructions -}; - -const char *EZXML_NOATTR[] = { NULL }; // empty tag attribute list - -// called when parser finds close of tag -#define ezxml_close_tag(root) root->cur = root->cur->parent; - -// returns the first child tag with the given name or NULL if not found -ezxml_t ezxml_child(ezxml_t xml, const char *name) -{ - xml = (xml) ? xml->child : NULL; - while (xml && strcmp(name, xml->name)) xml = xml->sibling; - return xml; -} - -// returns the Nth tag with the same name in the same subsection or NULL if not -// found -ezxml_t ezxml_idx(ezxml_t xml, int idx) -{ - for (; xml && idx; idx--) xml = xml->next; - return xml; -} - -// returns the value of the requested tag attribute or NULL if not found -const char *ezxml_attr(ezxml_t xml, const char *attr) -{ - int i = 0; - - if (! xml) return NULL; - while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2; - return (xml->attr[i]) ? xml->attr[i + 1] : NULL; -} - -// same as ezxml_get but takes an alredy initialized va_list -ezxml_t ezxml_vget(ezxml_t xml, va_list ap) -{ - char *name = va_arg(ap, char *); - int idx = -1; - - if (name && *name) { - idx = va_arg(ap, int); - xml = ezxml_child(xml, name); - } - - return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap); -} - -// Traverses the xml tree to retrive a specific subtag. Takes a variable -// length list of tag names and indexes. The argument list must be terminated -// by either an index of -1 or an empty string tag name. Example: -// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); -// This retrieves the title of the 3rd book on the 1st shelf of library. -// Returns NULL if not found. -ezxml_t ezxml_get(ezxml_t xml, ...) -{ - va_list ap; - ezxml_t ret; - - va_start(ap, xml); - ret = ezxml_vget(xml, ap); - va_end(ap); - return ret; -} - -// returns a NULL terminated array of processing instructions for the given -// target -const char **ezxml_pi(ezxml_t xml, const char *target) -{ - static const char *nopi = NULL; - ezxml_root_t root; - int i = 0; - - while (xml->parent) xml = xml->parent; - root = (ezxml_root_t)xml; - - if (! root->pi) return &nopi; - while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; - return (root->pi[i]) ? (const char **)root->pi[i] + 1 : &nopi; -} - -// Converts \r or \r\n to a single \n. If decode is non-zero, decodes ampersand -// sequences in place. Returns s. -char *ezxml_decode(char *s, int decode) -{ - int b; - char *e, *ret = s; - long c, d; - - for (;;) { - while (*s && *s != '\r' && *s != '&') s++; - - if (! *s) return ret; - else if (*s == '\r') { - *(s++) = '\n'; - if (*s == '\n') memmove(s, (s + 1), strlen(s)); - continue; - } - else if (! decode) { s++; continue; } - else if (! strncmp(s, "<", 4)) *(s++) = '<'; - else if (! strncmp(s, ">", 4)) *(s++) = '>'; - else if (! strncmp(s, """, 6)) *(s++) = '"'; - else if (! strncmp(s, "'", 6)) *(s++) = '\''; - else if (! strncmp(s, "&", 5)) s++; - else if (! strncmp(s, "&#", 2)) { - if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16 - else c = strtol(s + 2, &e, 10); // base 10 - if (! c || *e != ';') { s++; continue; } // not a &#nnn; sequence - - if (c < 0x80) *(s++) = c; // US-ASCII subset - else { // multi-byte UTF-8 sequence - for (b = 0, d = c; d; d /= 2) b++; // number of bits in c - b = (b - 2) / 5; // number of bytes in payload - *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head - while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload - } - } - else { s++; continue; } - - memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';'))); - } -} - -// called when parser finds start of new tag -void ezxml_open_tag(ezxml_root_t root, char *name, char **attr) -{ - ezxml_t xml = root->cur; - - if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt)); - else xml->name = name; - - xml->attr = (const char **)attr; - root->cur = xml; -} - -// called when parser finds character content between open and closing tag -void ezxml_char_content(ezxml_root_t root, char *s, size_t len, short decode) -{ - ezxml_t xml = root->cur; - size_t l; - - if (! xml || ! xml->name || ! len) return; - - s[len] = '\0'; - ezxml_decode(s, decode); - - if (! *(xml->txt)) xml->txt = s; - else { // allocate our own memory and make a copy - l = strlen(xml->txt); - if (! (xml->flags & EZXML_TXTM)) { - xml->txt = strcpy(malloc(l + len + 1), xml->txt); - xml->flags |= EZXML_TXTM; - } - else xml->txt = realloc(xml->txt, l + len + 1); - strcpy(xml->txt + l, s); - } -} - -// called when the parser finds an xml processing instruction -void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len) -{ - int i = 0, j = 1; - char *target = s; - - s[len] = '\0'; // null terminate instruction - *(s += strcspn(s, EZXML_WS)) = '\0'; // null terminate target - s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target - - if (! root->pi) *(root->pi = malloc(sizeof(char**))) = NULL; - - while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; - if (! root->pi[i]) { // new target - root->pi = realloc(root->pi, sizeof(char **) * (i + 2)); - root->pi[i] = malloc(sizeof(char *) * 2); - root->pi[i][0] = target; - root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list - } - - while (root->pi[i][j]) j++; - root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 2)); - root->pi[i][j] = s; - root->pi[i][j + 1] = NULL; -} - -// set an error string and return root -ezxml_t ezxml_seterr(ezxml_root_t root, const char *err) -{ - root->err = err; - return (ezxml_t)root; -} - -// converts a UTF-16 string to UTF-8, returns a new string the must be freed or -// NULL if no conversion was needed -char *ezxml_to_utf8(char **s, size_t *len) -{ - char *u; - size_t l = 0, sl, max = *len; - long c, c2; - int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1; - - if (be == -1) return NULL; // not UTF-16 - - u = malloc(max); - for (sl = 2; sl < *len - 1; sl += 2) { - c = (be) ? ((long)(*s)[sl] << 8) | (*s)[sl + 1] : // big-endian - ((long)(*s)[sl + 1] << 8) | (*s)[sl]; // little-endian - if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half - c2 = (be) ? ((long)(*s)[sl] << 8) | (*s)[sl + 1] : // big-endian - ((long)(*s)[sl + 1] << 8) | (*s)[sl]; // little-endian - c = (((c & 0x3FF) << 10) | (c2 & 0x3FF)) + 0x10000; - } - - while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE); - if (c < 0x80) u[l++] = c; // US-ASCII subset - else { // multi-byte UTF-8 sequence - for (b = 0, c2 = c; c2; c2 /= 2) b++; // bits in c - b = (b - 2) / 5; // bytes in payload; - u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head - while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload - } - } - - return *s = realloc(u, *len = l); -} - -// parse the given xml string and return an ezxml structure -ezxml_t ezxml_parse_str(char *s, size_t len) -{ - ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL); - char *d, **attr, q, e; - int l; - - root->m = s; - if (! len) return ezxml_seterr(root, "root tag missing"); - root->u = ezxml_to_utf8(&s, &len); - - e = s[len - 1]; - s[len - 1] = '\0'; - - while (*s && *s != '<') s++; // find first tag - if (! *s) return ezxml_seterr(root, "root tag missing"); - - for (;;) { - attr = (char **)EZXML_NOATTR; - d = ++s; - - if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag - if (! root->cur) return ezxml_seterr(root, "unmatched closing tag"); - - s += strcspn(s, EZXML_WS "/>"); - while (isspace(*s)) *(s++) = '\0'; - - l = 0; - while (*s && *s != '/' && *s != '>') { // new tag attribute - attr = (! l) ? malloc(3 * sizeof(char *)) : - realloc(attr, (l + 3) * sizeof(char *)); - attr[l] = s; - - s += strcspn(s, EZXML_WS "=/>"); - if (*s == '=' || isspace(*s)) { - *(s++) = '\0'; - q = *(s += strspn(s, EZXML_WS "=")); - if (q == '"' || q == '\'') { // attribute value - attr[l + 1] = ++s; - while (*s && *s != q) s++; - if (*s) *(s++) = '\0'; - else { - free(attr); - return ezxml_seterr(root, (q == '"') ? - "missing \"" : "missing '"); - } - ezxml_decode(attr[l + 1], 1); - } - else attr[l + 1] = ""; - } - else attr[l + 1] = ""; - - attr[(l += 2)] = NULL; - while (isspace(*s)) s++; - } - - if (*s == '/') { // self closing tag - *(s++) = '\0'; - if ((*s && *s != '>') || (! *s && e != '>')) { - if (l) free(attr); - return ezxml_seterr(root, "missing >"); - } - ezxml_open_tag(root, d, attr); - ezxml_close_tag(root); - } - else if (*s == '>' || (! *s && e == '>')) { // open tag - q = *s; - *s = '\0'; - ezxml_open_tag(root, d, attr); - *s = q; - } - else { - if (l) free(attr); - return ezxml_seterr(root, "missing >"); - } - } - else if (*s == '/') { // close tag - if (! root->cur) return ezxml_seterr(root, "unmatched closing tag"); - ezxml_close_tag(root); - while (*s && *s != '>') s++; - if (! *s && e != '>') return ezxml_seterr(root, "missing >"); - } - else if (! strncmp(s, "!--", 3)) { // comment - do { s = strstr(s, "--"); } while (s && *(s += 2) && *s != '>'); - if (! s || (! *s && e != '>')) - return ezxml_seterr(root, "unclosed