--- /dev/null
+/*
+linphone
+Copyright (C) 2012 Belledonne Communications SARL
+Yann DIORCET (yann.diorcet@linphone.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "xml2lpc.h"
+#include <string.h>
+#include <libxml/xmlreader.h>
+
+
+#define XML2LPC_BZ 2048
+
+struct _xml2lpc_context {
+ LpConfig *lpc;
+ xml2lpc_function cbf;
+ void *ctx;
+
+ xmlDoc *doc;
+ xmlDoc *xsd;
+ char errorBuffer[XML2LPC_BZ];
+ char warningBuffer[XML2LPC_BZ];
+};
+
+
+xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) {
+ xml2lpc_context *xmlCtx = (xml2lpc_context*)malloc(sizeof(xml2lpc_context));
+ if(xmlCtx != NULL) {
+ xmlCtx->lpc = NULL;
+ xmlCtx->cbf = cbf;
+ xmlCtx->ctx = ctx;
+
+ xmlCtx->doc = NULL;
+ xmlCtx->xsd = NULL;
+ xmlCtx->errorBuffer[0]='\0';
+ xmlCtx->warningBuffer[0]='\0';
+ }
+ return xmlCtx;
+}
+
+void xml2lpc_context_destroy(xml2lpc_context *ctx) {
+ if(ctx->doc != NULL) {
+ xmlFreeDoc(ctx->doc);
+ ctx->doc = NULL;
+ }
+ if(ctx->xsd != NULL) {
+ xmlFreeDoc(ctx->xsd);
+ ctx->xsd = NULL;
+ }
+ free(ctx);
+}
+
+void xml2lpc_context_clear_logs(xml2lpc_context *ctx) {
+ ctx->errorBuffer[0]='\0';
+ ctx->warningBuffer[0]='\0';
+}
+
+void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ if(xmlCtx->cbf != NULL) {
+ xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args);
+ }
+ va_end(args);
+}
+
+void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
+ xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
+ int sl = strlen(xmlCtx->errorBuffer);
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args);
+ va_end(args);
+}
+
+void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) {
+ xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
+ int sl = strlen(xmlCtx->warningBuffer);
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args);
+ va_end(args);
+}
+
+static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) {
+ xmlNode *cur_node = NULL;
+
+ for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name);
+ } else {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
+ }
+
+ dumpNodes(level + 1, cur_node->children, ctx);
+ }
+}
+
+
+static void dumpNode(xmlNode *node, xml2lpc_context *ctx) {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name);
+}
+
+static void dumpAttr(xmlNode *node, xml2lpc_context *ctx) {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content);
+}
+
+static void dumpContent(xmlNode *node, xml2lpc_context *ctx) {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content);
+}
+
+static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_context *ctx) {
+ xmlNode *cur_attr = NULL;
+ const char *name = NULL;
+ const char *value = NULL;
+ bool_t overwrite = FALSE;
+
+ for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) {
+ dumpAttr(cur_attr, ctx);
+ if(strcmp((const char*)cur_attr->name, "name") == 0) {
+ name = (const char*)cur_attr->children->content;
+ } else if(strcmp((const char*)cur_attr->name, "overwrite") == 0) {
+ if(strcmp((const char*)cur_attr->children->content, "true") == 0) {
+ overwrite = TRUE;
+ }
+ }
+ }
+
+ value = (const char *)element->children->content;
+ dumpContent((xmlNode *)element, ctx);
+
+ if(name != NULL) {
+ const char *str = lp_config_get_string(ctx->lpc, sectionName, name, NULL);
+ if(str == NULL || overwrite) {
+ xml2lpc_log(ctx, XML2LPC_MESSAGE, "Set %s|%s = %s",sectionName, name, value);
+ lp_config_set_string(ctx->lpc, sectionName, name, value);
+ } else {
+ xml2lpc_log(ctx, XML2LPC_MESSAGE, "Don't touch %s|%s = %s",sectionName, name, str);
+ }
+ } else {
+ xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element));
+ }
+ return 0;
+}
+
+static int processSection(xmlElement *element, xml2lpc_context *ctx) {
+ xmlNode *cur_node = NULL;
+ xmlNode *cur_attr = NULL;
+ const char *name = NULL;
+
+ for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) {
+ dumpAttr(cur_attr, ctx);
+ if(strcmp((const char*)cur_attr->name, "name") == 0) {
+ name = (const char*)cur_attr->children->content;
+ }
+ }
+
+ if(name != NULL) {
+ for (cur_node = element->children; cur_node; cur_node = cur_node->next) {
+ dumpNode(cur_node, ctx);
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ if(strcmp((const char*)cur_node->name, "entry") == 0 ) {
+ processEntry((xmlElement*)cur_node, name, ctx);
+ }
+ }
+
+ }
+ } else {
+ xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element));
+ }
+
+ return 0;
+}
+
+static int processConfig(xmlElement *element, xml2lpc_context *ctx) {
+ xmlNode *cur_node = NULL;
+
+ for (cur_node = element->children; cur_node; cur_node = cur_node->next) {
+ dumpNode(cur_node, ctx);
+ if (cur_node->type == XML_ELEMENT_NODE &&
+ strcmp((const char*)cur_node->name, "section") == 0 ) {
+ processSection((xmlElement*)cur_node, ctx);
+ }
+
+ }
+ return 0;
+}
+
+static int processDoc(xmlNode *node, xml2lpc_context *ctx) {
+ dumpNode(node, ctx);
+
+ if (node->type == XML_ELEMENT_NODE &&
+ strcmp((const char*)node->name, "config") == 0 ) {
+ processConfig((xmlElement*)node, ctx);
+ } else {
+ xml2lpc_log(ctx, XML2LPC_WARNING, "root element is not \"config\", line:%d", xmlGetLineNo(node));
+ }
+ return 0;
+}
+
+static int internal_convert_xml2lpc(xmlDoc *doc, xml2lpc_context *ctx) {
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started");
+ xmlNode *rootNode = xmlDocGetRootElement(doc);
+ //dumpNodes(0, rootNode, cbf, ctx);
+ int ret = processDoc(rootNode, ctx);
+ xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret);
+ return ret;
+}
+
+int xml2lpc_validate(xml2lpc_context *xmlCtx) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSchemaValidCtxtPtr validCtx;
+ xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd);
+ validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx));
+ xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx);
+ int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc);
+ if(ret >0) {
+ xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer);
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ } else {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error");
+ }
+ xmlSchemaFreeValidCtxt(validCtx);
+ return ret;
+}
+
+int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlCtx->lpc = lpc;
+ return internal_convert_xml2lpc(xmlCtx->doc, xmlCtx);
+}
+
+int xml2lpc_set_xml_file(xml2lpc_context* xmlCtx, const char *filename) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->doc != NULL) {
+ xmlFreeDoc(xmlCtx->doc);
+ xmlCtx->doc = NULL;
+ }
+ xmlCtx->doc = xmlReadFile(filename, NULL, 0);
+ if(xmlCtx->doc == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
+
+int xml2lpc_set_xml_fd(xml2lpc_context* xmlCtx, int fd) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->doc != NULL) {
+ xmlFreeDoc(xmlCtx->doc);
+ xmlCtx->doc = NULL;
+ }
+ xmlCtx->doc = xmlReadFd(fd, 0, NULL, 0);
+ if(xmlCtx->doc == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
+
+int xml2lpc_set_xml_string(xml2lpc_context* xmlCtx, const char *content) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->doc != NULL) {
+ xmlFreeDoc(xmlCtx->doc);
+ xmlCtx->doc = NULL;
+ }
+ xmlCtx->doc = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
+ if(xmlCtx->doc == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
+
+int xml2lpc_set_xsd_file(xml2lpc_context* xmlCtx, const char *filename) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->xsd != NULL) {
+ xmlFreeDoc(xmlCtx->xsd);
+ xmlCtx->xsd = NULL;
+ }
+ xmlCtx->xsd = xmlReadFile(filename, NULL, 0);
+ if(xmlCtx->xsd == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
+
+int xml2lpc_set_xsd_fd(xml2lpc_context* xmlCtx, int fd) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->xsd != NULL) {
+ xmlFreeDoc(xmlCtx->xsd);
+ xmlCtx->xsd = NULL;
+ }
+ xmlCtx->xsd = xmlReadFd(fd, 0, NULL, 0);
+ if(xmlCtx->xsd == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
+
+int xml2lpc_set_xsd_string(xml2lpc_context* xmlCtx, const char *content) {
+ xml2lpc_context_clear_logs(xmlCtx);
+ xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
+ if(xmlCtx->xsd != NULL) {
+ xmlFreeDoc(xmlCtx->xsd);
+ xmlCtx->xsd = NULL;
+ }
+ xmlCtx->xsd = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
+ if(xmlCtx->xsd == NULL) {
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
+ xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
+ return -1;
+ }
+ return 0;
+}
\ No newline at end of file