From d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Fri, 17 Oct 2003 15:36:42 +0000 Subject: import of enigma2 --- lib/base/nxml.cpp | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 lib/base/nxml.cpp (limited to 'lib/base/nxml.cpp') diff --git a/lib/base/nxml.cpp b/lib/base/nxml.cpp new file mode 100644 index 00000000..f32880a6 --- /dev/null +++ b/lib/base/nxml.cpp @@ -0,0 +1,339 @@ +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef HAVE_LIBXML2 +#include +#include +#include +#else +#define xmlChar char +#endif /* HAVE_LIBXML2 */ + +#define DE(x) ((struct nc_de_s *) (data+(x))) +#define IDE(x, y) (DE(((unsigned *) (data+(x)->offset))[(y)])) +#define XML_DE ((const xmlChar *) "dirEntry") +#define XML_NS ((const xmlChar *) "http://hq.alert.sk/projects/nconfig") +#define XML_ROOT ((const xmlChar *) "NConfigExport") + +static char *encodeXml(const char *what) +{ + unsigned p = 0, size = 6*strlen(what)+1; + char *ret = (char *)malloc(size); + for (; *what; what++) { + switch (*what) { + case '"': + ret[p++] = '&'; + ret[p++] = 'q'; + ret[p++] = 'u'; + ret[p++] = 'o'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '>': + ret[p++] = '&'; + ret[p++] = 'q'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '<': + ret[p++] = '&'; + ret[p++] = 'l'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '&': + ret[p++] = '&'; + ret[p++] = 'a'; + ret[p++] = 'm'; + ret[p++] = 'p'; + ret[p++] = ';'; + continue; + } + if (*what >= 0x20 || *what == '\n' || *what == '\r' || *what == '\t') + ret[p++] = *what; + else + p += sprintf(ret+p, "&#%d;", *what); + } + ret[p] = '\0'; + return ret; +} + +void NConfig::store(nc_de_s *de, FILE *f) +{ + struct nc_de_s *cc; + for (unsigned i=0; ipages; i++) + if ((cc = IDE(de, i))->type) { + char *encname = encodeXml(data+cc->name); + fprintf(f, "type); + free(encname); + switch (cc->type) { + case NC_DIR: + fprintf(f, "%u\">\n", cc->pages); + store(cc, f); + fprintf(f, "\n", XML_DE); + break; + case NC_STRING: + fprintf(f, "%s\"/>\n", encname = encodeXml(data+cc->offset)); + free(encname); + break; + case NC_INT: + fprintf(f, "%lld\"/>\n", *((signed long long *) (data+cc->offset))); + break; + case NC_UINT: + fprintf(f, "%llu\"/>\n", *((unsigned long long *) (data+cc->offset))); + break; + case NC_DOUBLE: + fprintf(f, "%La\"/>\n", *((long double *) (data+cc->offset))); + break; + case NC_RAW: + { + const char *raw = data+cc->offset; + for (unsigned j=0; jpages; j++) + fprintf(f, "%d%d%d", raw[j] / 100, (raw[j] % 100) / 10, raw[j] % 10); + fprintf(f, "\"/>\n"); + } + } + } +} + +int NConfig::toXML(const char *filename) +{ + if (fd < 0) + return NC_ERR_NFILE; + + FILE *f = fopen(filename, "w"); + if (!f) + return NC_ERR_PERM; + + fprintf(f, "%s", "\n"); + fprintf(f, "\n"); + lockFile(NC_L_RO); + + store(rdir, f); + + unLockFile(); + fprintf(f, "\n", XML_ROOT); + fclose(f); + return NC_ERR_OK; +} + +#ifdef HAVE_LIBXML2 +static xmlSAXHandler sh; +enum stateEnum {noRoot = 0, inRoot, inDir, inEnt, unknown}; + +struct ncParseState { + stateEnum state, pState; + xmlChar *ns; + unsigned depth; + unsigned unDepth; + unsigned force; + NConfig *which; +}; + +static int ncXmlSAXParseFile(xmlSAXHandlerPtr sax, void *user_data, const char *filename) +{ + int ret = 0; + xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename); + if (!ctxt) + return -1; + ctxt->sax = sax; + ctxt->userData = user_data; + xmlParseDocument(ctxt); + ret = ctxt->wellFormed ? 0 : -1; + if (sax) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + return ret; +} + +static xmlEntityPtr ncXmlGetEntity(void *user_data, const CHAR *name) +{ + return xmlGetPredefinedEntity(name); +} + +static void ncXmlStartElement(void *user_data, const CHAR *name, const CHAR **attrs) +{ + struct ncParseState *p = (struct ncParseState *)user_data; +#ifdef NC_DEBUG_XML + fprintf(stderr, "New element %s state=%d %s\n", name, p->state, p->ns); +#endif + if (p->state == unknown) { + p->unDepth++; + return; + } + if (p->state == noRoot) { + while (*attrs) { + if (!xmlStrncmp(*attrs, (const xmlChar *) "xmlns:", 6)) { + if (!xmlStrcmp(attrs[1], XML_NS)) { + p->ns = xmlStrdup((*attrs)+6); + break; + } + } + attrs += 2; + } + char *b = (char *) malloc(xmlStrlen(p->ns)+xmlStrlen(XML_ROOT)+2); + sprintf(b, "%s:%s", p->ns, XML_ROOT); + if (xmlStrcmp(name, (xmlChar *)b)) { +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown %s\n", name); +#endif + p->pState = p->state; + p->state = unknown; + } else + p->state = inRoot; + free(b); + return; + } + if (p->state == inRoot || p->state == inDir) { + const xmlChar *value = NULL, *n = NULL; + int type = 0; + while (*attrs) { + if (!xmlStrcmp(*attrs, (const xmlChar *)"value")) + value = attrs[1]; + if (!xmlStrcmp(*attrs, (const xmlChar *)"name")) + n = attrs[1]; + if (!xmlStrcmp(*attrs, (const xmlChar *)"type")) + type = atoi(attrs[1]); + attrs += 2; + } +#ifdef NC_DEBUG_XML + fprintf(stderr, "%s %s %s %d %d\n", name, n, value, type, p->state); +#endif + char *b = (char *) malloc(xmlStrlen(p->ns)+xmlStrlen(XML_DE)+2); + sprintf(b, "%s:%s", p->ns, XML_DE); + if (xmlStrcmp(name, (xmlChar *)b) || !type || !value || !n) { +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown on mismatch\n"); +#endif + p->pState = p->state; + p->state = unknown; + free(b); + return; + } + free(b); + if (p->force) + p->which->delKey((const char *)n); + + switch (type) { + case NC_DIR: + if (p->which->createDir((const char *)n, strtoul((const char *)value, NULL, 0)) != NC_ERR_OK) { + p->pState = p->state; + p->state = unknown; +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown on failed mkdir\n"); +#endif + return; + } + p->which->chDir((const char *)n); + break; + case NC_STRING: + p->which->setKey((const char *)n, (const char *)value); + break; + case NC_INT: + p->which->setKey((const char *)n, strtoll((const char *)value, NULL, 0)); + break; + case NC_UINT: + p->which->setKey((const char *)n, strtoull((const char *)value, NULL, 0)); + break; + case NC_DOUBLE: + { + long double c; + sscanf((const char *)value, "%La", &c); + p->which->setKey((const char *)n, c); + } + break; + case NC_RAW: + { + unsigned size = xmlStrlen(value) / 3; + char *dec = NULL; + if (size) { + dec = (char *)malloc(size); + for (unsigned i=0, k=0; iwhich->setKey((const char *)n, dec, size); + free(dec); + } + } + if (type == NC_DIR) { + p->state = inDir; + p->depth++; + } else { + p->pState = p->state; + p->state = inEnt; + } + return; + } +} + +static void ncXmlEndElement(void *user_data, const CHAR *name) +{ + struct ncParseState *p = (struct ncParseState *)user_data; +#ifdef NC_DEBUG_XML + fprintf(stderr, "EndElement %s %s %d\n", name, p->ns, p->state); +#endif + if (p->state == inEnt) { + p->state = p->pState; + return; + } + if (p->state == unknown) { + if (p->unDepth) + p->unDepth--; + else + p->state = p->pState; + return; + } + if (p->state == inRoot) { + p->state = noRoot; + free(p->ns); + p->ns = NULL; + return; + } + if (p->state == inDir) { + p->depth--; + if (!p->depth) + p->state = inRoot; + p->which->chDir(".."); + } +} +#endif /* HAVE_LIBXML2 */ + +int NConfig::fromXML(const char *filename, int force) +{ + if (fd < 0) + return NC_ERR_NFILE; + if (omode != NC_O_RW) + return NC_ERR_PERM; +#ifndef HAVE_LIBXML2 + return NC_ERR_NOSUPPORT; +#else + struct ncParseState state = { noRoot, noRoot, NULL, 0, 0, force, this }; + sh.getEntity = ncXmlGetEntity; + sh.startElement = ncXmlStartElement; + sh.endElement = ncXmlEndElement; + + lockFile(NC_L_RW); + cdir = rdir; + int ret = ncXmlSAXParseFile(&sh, &state, filename); + cdir = rdir; + unLockFile(); + + return ret < 0 ? NC_ERR_NVAL : NC_ERR_OK; +#endif /* HAVE_LIBXML2 */ +} + -- cgit v1.2.3