linphone-ios/coreapi/xml2lpc.c
2017-07-24 11:56:50 +02:00

364 lines
11 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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, xml2lpc_log_level 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;
}