From 66b6427d96cce8f306fba21f17c99b073056f567 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 16 Jan 2013 14:36:31 +0100 Subject: [PATCH] Add lpc2xml tool and fix xml2lpc validation --- tools/Makefile.am | 21 +++- tools/lpc2xml.c | 284 +++++++++++++++++++++++++++++++++++++++++++ tools/lpc2xml.h | 46 +++++++ tools/lpc2xml_test.c | 67 ++++++++++ tools/xml2lpc.c | 16 +-- 5 files changed, 424 insertions(+), 10 deletions(-) create mode 100644 tools/lpc2xml.c create mode 100644 tools/lpc2xml.h create mode 100644 tools/lpc2xml_test.c diff --git a/tools/Makefile.am b/tools/Makefile.am index e906e29b..ffb46921 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -13,29 +13,46 @@ COMMON_CFLAGS=\ if BUILD_TOOLS -lib_LTLIBRARIES=libxml2lpc.la +lib_LTLIBRARIES=libxml2lpc.la liblpc2xml.la libxml2lpc_la_SOURCES=\ xml2lpc.c \ xml2lpc.h +liblpc2xml_la_SOURCES=\ + lpc2xml.c \ + lpc2xml.h + libxml2lpc_la_CFLAGS=$(COMMON_CFLAGS) libxml2lpc_la_LIBADD=\ $(top_builddir)/coreapi/liblinphone.la \ $(LIBXML2_LIBS) +liblpc2xml_la_CFLAGS=$(COMMON_CFLAGS) +liblpc2xml_la_LIBADD=\ + $(top_builddir)/coreapi/liblinphone.la \ + $(LIBXML2_LIBS) + libxml2lpc_la_LDFLAGS=-no-undefined +liblpc2xml_la_LDFLAGS=-no-undefined -bin_PROGRAMS=xml2lpc_test +bin_PROGRAMS=xml2lpc_test lpc2xml_test xml2lpc_test_SOURCES=\ xml2lpc_test.c +lpc2xml_test_SOURCES=\ + lpc2xml_test.c + xml2lpc_test_CFLAGS=$(COMMON_CFLAGS) xml2lpc_test_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ libxml2lpc.la +lpc2xml_test_CFLAGS=$(COMMON_CFLAGS) +lpc2xml_test_LDADD=\ + $(top_builddir)/coreapi/liblinphone.la \ + liblpc2xml.la endif diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c new file mode 100644 index 00000000..cd0df72d --- /dev/null +++ b/tools/lpc2xml.c @@ -0,0 +1,284 @@ +/* +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 "lpc2xml.h" +#include +#include + + +#define LPC2XML_BZ 2048 + +struct _lpc2xml_context { + const LpConfig *lpc; + lpc2xml_function cbf; + void *ctx; + + xmlDoc *doc; + char errorBuffer[LPC2XML_BZ]; + char warningBuffer[LPC2XML_BZ]; +}; + + +lpc2xml_context* lpc2xml_context_new(lpc2xml_function cbf, void *ctx) { + lpc2xml_context *xmlCtx = (lpc2xml_context*)malloc(sizeof(lpc2xml_context)); + if(xmlCtx != NULL) { + xmlCtx->lpc = NULL; + xmlCtx->cbf = cbf; + xmlCtx->ctx = ctx; + + xmlCtx->doc = NULL; + xmlCtx->errorBuffer[0]='\0'; + xmlCtx->warningBuffer[0]='\0'; + } + return xmlCtx; +} + +void lpc2xml_context_destroy(lpc2xml_context *ctx) { + if(ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + free(ctx); +} +/* +static void lpc2xml_context_clear_logs(lpc2xml_context *ctx) { + ctx->errorBuffer[0]='\0'; + ctx->warningBuffer[0]='\0'; +}*/ + +static void lpc2xml_log(lpc2xml_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); +} +/* +static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) { + lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, LPC2XML_BZ-sl, fmt, args); + va_end(args); +} + +static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) { + lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; + int sl = strlen(xmlCtx->warningBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->warningBuffer + sl, LPC2XML_BZ-sl, fmt, args); + va_end(args); +}*/ + +#if 0 +static void dumpNodes(int level, xmlNode * a_node, lpc2xml_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) { + lpc2xml_log(ctx, LPC2XML_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name); + } else { + lpc2xml_log(ctx, LPC2XML_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name); + } + + dumpNodes(level + 1, cur_node->children, ctx); + } +} +#endif + +#if 0 +static void dumpNode(xmlNode *node, lpc2xml_context *ctx) { + lpc2xml_log(ctx, LPC2XML_DEBUG, "node type: %d, name: %s", node->type, node->name); +} + +static void dumpAttr(xmlNode *node, lpc2xml_context *ctx) { + lpc2xml_log(ctx, LPC2XML_DEBUG, "attr name: %s value:%s", node->name, node->children->content); +} + +static void dumpContent(xmlNode *node, lpc2xml_context *ctx) { + lpc2xml_log(ctx, LPC2XML_DEBUG, "content: %s", node->children->content); +} + + + +#endif + +static int processEntry(const char *section, const char *entry, xmlNode *node, lpc2xml_context *ctx) { + const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL); + if(content == NULL) { + lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Issue when reading the lpc"); + return -1; + } + xmlNodeSetContent(node, (const xmlChar *) content); + return 0; +} + +struct __processSectionCtx { + int ret; + const char *section; + xmlNode *node; + lpc2xml_context *ctx; +}; + +static void processSection_cb(const char *entry, struct __processSectionCtx *ctx) { + if(ctx->ret == 0) { + xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL); + if(node == NULL) { + lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"entry\" element"); + ctx->ret = -1; + return; + } + xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)entry); + if(name_attr == NULL) { + lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"entry\" element"); + ctx->ret = -1; + return; + } + ctx->ret = processEntry(ctx->section, entry, node, ctx->ctx); + } +} + +static int processSection(const char *section, xmlNode *node, lpc2xml_context *ctx) { + struct __processSectionCtx pc_ctx = {0, section, node, ctx}; + lp_config_for_each_entry(ctx->lpc, section, (void (*)(const char *, void *))processSection_cb, (void*)&pc_ctx); + return pc_ctx.ret; +} + + + +struct __processConfigCtx { + int ret; + xmlNode *node; + lpc2xml_context *ctx; +}; + +static void processConfig_cb(const char *section, struct __processConfigCtx *ctx) { + if(ctx->ret == 0) { + xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"section", NULL); + if(node == NULL) { + lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element"); + ctx->ret = -1; + return; + } + xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)section); + if(name_attr == NULL) { + lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"section\" element"); + ctx->ret = -1; + return; + } + ctx->ret = processSection(section, node, ctx->ctx); + } +} + +static int processConfig(xmlNode *node, lpc2xml_context *ctx) { + struct __processConfigCtx pc_ctx = {0, node, ctx}; + lp_config_for_each_section(ctx->lpc, (void (*)(const char *, void *))processConfig_cb, (void*)&pc_ctx); + return pc_ctx.ret; +} + +static int processDoc(xmlDoc *doc, lpc2xml_context *ctx) { + int ret = 0; + xmlNode *root_node = xmlNewNode(NULL, (const xmlChar *)"config"); + if(root_node == NULL) { + lpc2xml_log(ctx, LPC2XML_ERROR, "Can't create \"config\" element"); + return -1; + } + xmlNs *lpc_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd", (const xmlChar *)"lpc"); + if(lpc_ns == NULL) { + lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create lpc namespace"); + } else { + xmlSetNs(root_node, lpc_ns); + } + xmlNs *xsi_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance", (const xmlChar *)"xsi"); + if(lpc_ns == NULL) { + lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create xsi namespace"); + } + xmlAttr *schemaLocation = xmlNewNsProp(root_node, xsi_ns, (const xmlChar *)"schemaLocation", (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd lpconfig.xsd "); + if(schemaLocation == NULL) { + lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create schemaLocation"); + } + ret = processConfig(root_node, ctx); + xmlDocSetRootElement(doc, root_node); + return ret; +} + +static int internal_convert_lpc2xml(lpc2xml_context *ctx) { + int ret = 0; + lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation started"); + if(ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + xmlDoc *doc = xmlNewDoc((const xmlChar *)"1.0"); + ret = processDoc(doc, ctx); + if(ret == 0) { + ctx->doc = doc; + } else { + xmlFreeDoc(doc); + } + lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation ended ret:%d", ret); + return ret; +} + +int lpc2xml_set_lpc(lpc2xml_context* context, const LpConfig *lpc) { + context->lpc = lpc; + return 0; +} + +int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) { + int ret = 0; + xmlSaveCtxtPtr save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT); + ret = internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + } + xmlSaveClose(save_ctx); + return ret; +} + +int lpc2xml_convert_fd(lpc2xml_context* context, int fd) { + int ret = 0; + xmlSaveCtxtPtr save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT); + ret = internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + } + xmlSaveClose(save_ctx); + return ret; +} + +int lpc2xml_convert_string(lpc2xml_context* context, unsigned char **content) { + int ret = 0; + xmlBufferPtr buffer = xmlBufferCreate(); + xmlSaveCtxtPtr save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT); + internal_convert_lpc2xml(context); + if(ret == 0) { + ret = xmlSaveDoc(save_ctx, context->doc); + } + xmlSaveClose(save_ctx); + if(ret == 0) { + *content = xmlBufferDetach(buffer); + } + xmlBufferFree(buffer); + return ret; +} diff --git a/tools/lpc2xml.h b/tools/lpc2xml.h new file mode 100644 index 00000000..f1583109 --- /dev/null +++ b/tools/lpc2xml.h @@ -0,0 +1,46 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications SARL + +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. +*/ + +#ifndef LPC2XML_H_ +#define LPC2XML_H_ + +#include "lpconfig.h" + +typedef struct _lpc2xml_context lpc2xml_context; + +typedef enum _lpc2xml_log_level { + LPC2XML_DEBUG = 0, + LPC2XML_MESSAGE, + LPC2XML_WARNING, + LPC2XML_ERROR +} lpc2xml_log_level; + +typedef void(*lpc2xml_function)(void *ctx, lpc2xml_log_level level, const char *fmt, va_list list); + +lpc2xml_context* lpc2xml_context_new(lpc2xml_function cbf, void *ctx); +void lpc2xml_context_destroy(lpc2xml_context*); + +int lpc2xml_set_lpc(lpc2xml_context* context, const LpConfig *lpc); + +int lpc2xml_convert_file(lpc2xml_context* context, const char *filename); +int lpc2xml_convert_fd(lpc2xml_context* context, int fd); +int lpc2xml_convert_string(lpc2xml_context* context, unsigned char **content); + + +#endif //LPC2XML_H_ diff --git a/tools/lpc2xml_test.c b/tools/lpc2xml_test.c new file mode 100644 index 00000000..cdad72f9 --- /dev/null +++ b/tools/lpc2xml_test.c @@ -0,0 +1,67 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications SARL + +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 +#include "lpc2xml.h" + +void cb_function(void *ctx, lpc2xml_log_level level, const char *msg, va_list list) { + const char *header = ""; + switch(level) { + case LPC2XML_DEBUG: + header = "DEBUG"; + break; + case LPC2XML_MESSAGE: + header = "MESSAGE"; + break; + case LPC2XML_WARNING: + header = "WARNING"; + break; + case LPC2XML_ERROR: + header = "ERROR"; + break; + } + fprintf(stdout, "%s - ", header); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); +} + +void show_usage(int argc, char *argv[]) { + fprintf(stderr, "usage %s convert \n", + argv[0]); +} + +int main(int argc, char *argv[]) { + if(argc != 4) { + show_usage(argc, argv); + return -1; + } + + lpc2xml_context *ctx = lpc2xml_context_new(cb_function, NULL); + LpConfig *lpc = lp_config_new(argv[2]); + lpc2xml_set_lpc(ctx, lpc); + if(strcmp("convert", argv[1]) == 0) { + lpc2xml_convert_file(ctx, argv[3]); + } else { + show_usage(argc, argv); + } + lp_config_destroy(lpc); + lpc2xml_context_destroy(ctx); + return 0; +} + diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c index d5e2160a..9d720f1f 100644 --- a/tools/xml2lpc.c +++ b/tools/xml2lpc.c @@ -78,7 +78,7 @@ static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ... va_end(args); } -static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { +static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; int sl = strlen(xmlCtx->errorBuffer); va_list args; @@ -87,7 +87,7 @@ static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { va_end(args); } -static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) { +static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) { xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; int sl = strlen(xmlCtx->warningBuffer); va_list args; @@ -214,11 +214,11 @@ static int processDoc(xmlNode *node, xml2lpc_context *ctx) { return 0; } -static int internal_convert_xml2lpc(xmlDoc *doc, xml2lpc_context *ctx) { +static int internal_convert_xml2lpc(xml2lpc_context *ctx) { xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started"); - xmlNode *rootNode = xmlDocGetRootElement(doc); + xmlNode *rootNode = xmlDocGetRootElement(ctx->doc); //dumpNodes(0, rootNode, cbf, ctx); - int ret = processDoc(rootNode, ctx); + int ret = processDoc(rootNode, ctx); xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret); return ret; } @@ -230,10 +230,10 @@ int xml2lpc_validate(xml2lpc_context *xmlCtx) { validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx)); xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx); int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); - if(ret >0) { + if(ret > 0) { xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer); xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer); - } else { + } else if(ret < 0) { xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error"); } xmlSchemaFreeValidCtxt(validCtx); @@ -243,7 +243,7 @@ int xml2lpc_validate(xml2lpc_context *xmlCtx) { int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) { xml2lpc_context_clear_logs(xmlCtx); xmlCtx->lpc = lpc; - return internal_convert_xml2lpc(xmlCtx->doc, xmlCtx); + return internal_convert_xml2lpc(xmlCtx); } int xml2lpc_set_xml_file(xml2lpc_context* xmlCtx, const char *filename) { -- 2.39.2