]> sjero.net Git - linphone/blobdiff - tools/xml2lpc.c
Add XML2LPC lib/tool
[linphone] / tools / xml2lpc.c
diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c
new file mode 100644 (file)
index 0000000..ce12eeb
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+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