linphone-iphone/coreapi/lpc2xml.c
2016-01-20 17:33:23 +01:00

316 lines
9.4 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 "lpc2xml.h"
#include <string.h>
#include <libxml/xmlsave.h>
#include <libxml/xmlversion.h>
#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;
size_t 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);
}
*/
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, LPC2XML_ERROR, "Issue when reading the lpc");
return -1;
}
lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content);
// xmlNodeSetContent expects special characters to be escaped, xmlNodeAddContent doesn't (and escapes what needs to be)
xmlNodeSetContent(node, (const xmlChar *) "");
xmlNodeAddContent(node, (const xmlChar *) content);
if (lp_config_get_overwrite_flag_for_entry(ctx->lpc, section, entry) || lp_config_get_overwrite_flag_for_section(ctx->lpc, section)) {
xmlSetProp(node, (const xmlChar *)"overwrite", (const xmlChar *) "true");
}
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) {
const char *comment = "#";
xmlNode *node;
xmlAttr *name_attr;
if (strncmp(comment, entry, strlen(comment)) == 0) {
lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry);
ctx->ret = 0;
return;
}
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;
}
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);
xmlAttr *name_attr;
if(node == NULL) {
lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element");
ctx->ret = -1;
return;
}
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;
xmlNs *xsi_ns;
xmlNs *lpc_ns;
xmlAttr *schemaLocation;
xmlNode *root_node = xmlNewNode(NULL, (const xmlChar *)"config");
if(root_node == NULL) {
lpc2xml_log(ctx, LPC2XML_ERROR, "Can't create \"config\" element");
return -1;
}
lpc_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd", NULL);
if(lpc_ns == NULL) {
lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create lpc namespace");
} else {
xmlSetNs(root_node, lpc_ns);
}
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");
}
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;
xmlDoc *doc;
lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation started");
if(ctx->doc != NULL) {
xmlFreeDoc(ctx->doc);
ctx->doc = NULL;
}
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 = -1;
xmlSaveCtxtPtr save_ctx;
lpc2xml_context_clear_logs(context);
xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error);
save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT);
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
}
xmlSaveClose(save_ctx);
} else {
lpc2xml_log(context, LPC2XML_ERROR, "Can't open file:%s", filename);
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
return ret;
}
int lpc2xml_convert_fd(lpc2xml_context* context, int fd) {
int ret = -1;
xmlSaveCtxtPtr save_ctx;
lpc2xml_context_clear_logs(context);
xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error);
save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT);
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
}
xmlSaveClose(save_ctx);
} else {
lpc2xml_log(context, LPC2XML_ERROR, "Can't open fd:%d", fd);
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
return ret;
}
int lpc2xml_convert_string(lpc2xml_context* context, char **content) {
int ret = -1;
xmlBufferPtr buffer = xmlBufferCreate();
xmlSaveCtxtPtr save_ctx;
lpc2xml_context_clear_logs(context);
xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error);
save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT);
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
}
xmlSaveClose(save_ctx);
} else {
lpc2xml_log(context, LPC2XML_ERROR, "Can't initialize internal buffer");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
}
if(ret == 0) {
#if LIBXML_VERSION >= 20800
*content = (char *)xmlBufferDetach(buffer);
#else
*content = strdup((const char *)xmlBufferContent(buffer));
#endif
}
xmlBufferFree(buffer);
return ret;
}