forked from mirrors/linphone-iphone
364 lines
10 KiB
C
364 lines
10 KiB
C
/*
|
|
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);
|
|
}
|
|
|
|
static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) {
|
|
ctx->errorBuffer[0]='\0';
|
|
ctx->warningBuffer[0]='\0';
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
|
|
xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
|
|
size_t sl = strlen(xmlCtx->errorBuffer);
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) {
|
|
xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
|
|
size_t sl = strlen(xmlCtx->warningBuffer);
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
#if 0
|
|
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);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
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) {
|
|
if (node->children)
|
|
xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content);
|
|
else
|
|
xml2lpc_log(ctx, XML2LPC_DEBUG, "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;
|
|
}
|
|
}
|
|
}
|
|
|
|
dumpContent((xmlNode *)element, ctx);
|
|
if (element->children)
|
|
value = (const char *)element->children->content;
|
|
else
|
|
value = "";
|
|
|
|
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(xml2lpc_context *ctx) {
|
|
xmlNode *rootNode;
|
|
int ret;
|
|
|
|
xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started");
|
|
rootNode = xmlDocGetRootElement(ctx->doc);
|
|
//dumpNodes(0, rootNode, cbf, ctx);
|
|
ret = processDoc(rootNode, ctx);
|
|
xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
int xml2lpc_validate(xml2lpc_context *xmlCtx) {
|
|
xmlSchemaValidCtxtPtr validCtx;
|
|
xmlSchemaParserCtxtPtr parserCtx;
|
|
int ret;
|
|
|
|
xml2lpc_context_clear_logs(xmlCtx);
|
|
parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd);
|
|
validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx));
|
|
xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx);
|
|
ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc);
|
|
if(ret > 0) {
|
|
if(strlen(xmlCtx->warningBuffer) > 0)
|
|
xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer);
|
|
if(strlen(xmlCtx->errorBuffer) > 0)
|
|
xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
|
|
} else if(ret < 0) {
|
|
xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error");
|
|
}
|
|
xmlSchemaFreeValidCtxt(validCtx);
|
|
return ret;
|
|
}
|
|
|
|
int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) {
|
|
xml2lpc_context_clear_logs(xmlCtx);
|
|
if(xmlCtx->doc == NULL) {
|
|
xml2lpc_log(xmlCtx, XML2LPC_ERROR, "No doc set");
|
|
return -1;
|
|
}
|
|
if(lpc == NULL) {
|
|
xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Invalid lpc");
|
|
}
|
|
xmlCtx->lpc = lpc;
|
|
return internal_convert_xml2lpc(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;
|
|
}
|