3 Copyright (C) 2012 Belledonne Communications SARL
4 Yann DIORCET (yann.diorcet@linphone.org)
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <libxml/xmlreader.h>
26 #define XML2LPC_BZ 2048
28 struct _xml2lpc_context {
35 char errorBuffer[XML2LPC_BZ];
36 char warningBuffer[XML2LPC_BZ];
40 xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) {
41 xml2lpc_context *xmlCtx = (xml2lpc_context*)malloc(sizeof(xml2lpc_context));
49 xmlCtx->errorBuffer[0]='\0';
50 xmlCtx->warningBuffer[0]='\0';
55 void xml2lpc_context_destroy(xml2lpc_context *ctx) {
56 if(ctx->doc != NULL) {
60 if(ctx->xsd != NULL) {
67 static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) {
68 ctx->errorBuffer[0]='\0';
69 ctx->warningBuffer[0]='\0';
72 static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) {
75 if(xmlCtx->cbf != NULL) {
76 xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args);
81 static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
82 xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
83 int sl = strlen(xmlCtx->errorBuffer);
86 vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args);
90 static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) {
91 xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
92 int sl = strlen(xmlCtx->warningBuffer);
95 vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args);
100 static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) {
101 xmlNode *cur_node = NULL;
103 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
104 if (cur_node->type == XML_ELEMENT_NODE) {
105 xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name);
107 xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
110 dumpNodes(level + 1, cur_node->children, ctx);
116 static void dumpNode(xmlNode *node, xml2lpc_context *ctx) {
117 xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name);
120 static void dumpAttr(xmlNode *node, xml2lpc_context *ctx) {
121 xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content);
124 static void dumpContent(xmlNode *node, xml2lpc_context *ctx) {
125 xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content);
128 static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_context *ctx) {
129 xmlNode *cur_attr = NULL;
130 const char *name = NULL;
131 const char *value = NULL;
132 bool_t overwrite = FALSE;
134 for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) {
135 dumpAttr(cur_attr, ctx);
136 if(strcmp((const char*)cur_attr->name, "name") == 0) {
137 name = (const char*)cur_attr->children->content;
138 } else if(strcmp((const char*)cur_attr->name, "overwrite") == 0) {
139 if(strcmp((const char*)cur_attr->children->content, "true") == 0) {
145 value = (const char *)element->children->content;
146 dumpContent((xmlNode *)element, ctx);
149 const char *str = lp_config_get_string(ctx->lpc, sectionName, name, NULL);
150 if(str == NULL || overwrite) {
151 xml2lpc_log(ctx, XML2LPC_MESSAGE, "Set %s|%s = %s", sectionName, name, value);
152 lp_config_set_string(ctx->lpc, sectionName, name, value);
154 xml2lpc_log(ctx, XML2LPC_MESSAGE, "Don't touch %s|%s = %s",sectionName, name, str);
157 xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element));
162 static int processSection(xmlElement *element, xml2lpc_context *ctx) {
163 xmlNode *cur_node = NULL;
164 xmlNode *cur_attr = NULL;
165 const char *name = NULL;
167 for (cur_attr = (xmlNode *)element->attributes; cur_attr; cur_attr = cur_attr->next) {
168 dumpAttr(cur_attr, ctx);
169 if(strcmp((const char*)cur_attr->name, "name") == 0) {
170 name = (const char*)cur_attr->children->content;
175 for (cur_node = element->children; cur_node; cur_node = cur_node->next) {
176 dumpNode(cur_node, ctx);
177 if (cur_node->type == XML_ELEMENT_NODE) {
178 if(strcmp((const char*)cur_node->name, "entry") == 0 ) {
179 processEntry((xmlElement*)cur_node, name, ctx);
185 xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element));
191 static int processConfig(xmlElement *element, xml2lpc_context *ctx) {
192 xmlNode *cur_node = NULL;
194 for (cur_node = element->children; cur_node; cur_node = cur_node->next) {
195 dumpNode(cur_node, ctx);
196 if (cur_node->type == XML_ELEMENT_NODE &&
197 strcmp((const char*)cur_node->name, "section") == 0 ) {
198 processSection((xmlElement*)cur_node, ctx);
205 static int processDoc(xmlNode *node, xml2lpc_context *ctx) {
208 if (node->type == XML_ELEMENT_NODE &&
209 strcmp((const char*)node->name, "config") == 0 ) {
210 processConfig((xmlElement*)node, ctx);
212 xml2lpc_log(ctx, XML2LPC_WARNING, "root element is not \"config\", line:%d", xmlGetLineNo(node));
217 static int internal_convert_xml2lpc(xml2lpc_context *ctx) {
218 xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started");
219 xmlNode *rootNode = xmlDocGetRootElement(ctx->doc);
220 //dumpNodes(0, rootNode, cbf, ctx);
221 int ret = processDoc(rootNode, ctx);
222 xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret);
226 int xml2lpc_validate(xml2lpc_context *xmlCtx) {
227 xml2lpc_context_clear_logs(xmlCtx);
228 xmlSchemaValidCtxtPtr validCtx;
229 xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd);
230 validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx));
231 xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx);
232 int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc);
234 if(strlen(xmlCtx->warningBuffer) > 0)
235 xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer);
236 if(strlen(xmlCtx->errorBuffer) > 0)
237 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
239 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error");
241 xmlSchemaFreeValidCtxt(validCtx);
245 int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) {
246 xml2lpc_context_clear_logs(xmlCtx);
247 if(xmlCtx->doc == NULL) {
248 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "No doc set");
252 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Invalid lpc");
255 return internal_convert_xml2lpc(xmlCtx);
258 int xml2lpc_set_xml_file(xml2lpc_context* xmlCtx, const char *filename) {
259 xml2lpc_context_clear_logs(xmlCtx);
260 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
261 if(xmlCtx->doc != NULL) {
262 xmlFreeDoc(xmlCtx->doc);
265 xmlCtx->doc = xmlReadFile(filename, NULL, 0);
266 if(xmlCtx->doc == NULL) {
267 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
268 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
274 int xml2lpc_set_xml_fd(xml2lpc_context* xmlCtx, int fd) {
275 xml2lpc_context_clear_logs(xmlCtx);
276 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
277 if(xmlCtx->doc != NULL) {
278 xmlFreeDoc(xmlCtx->doc);
281 xmlCtx->doc = xmlReadFd(fd, 0, NULL, 0);
282 if(xmlCtx->doc == NULL) {
283 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
284 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
290 int xml2lpc_set_xml_string(xml2lpc_context* xmlCtx, const char *content) {
291 xml2lpc_context_clear_logs(xmlCtx);
292 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
293 if(xmlCtx->doc != NULL) {
294 xmlFreeDoc(xmlCtx->doc);
297 xmlCtx->doc = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
298 if(xmlCtx->doc == NULL) {
299 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
300 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
306 int xml2lpc_set_xsd_file(xml2lpc_context* xmlCtx, const char *filename) {
307 xml2lpc_context_clear_logs(xmlCtx);
308 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
309 if(xmlCtx->xsd != NULL) {
310 xmlFreeDoc(xmlCtx->xsd);
313 xmlCtx->xsd = xmlReadFile(filename, NULL, 0);
314 if(xmlCtx->xsd == NULL) {
315 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
316 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
322 int xml2lpc_set_xsd_fd(xml2lpc_context* xmlCtx, int fd) {
323 xml2lpc_context_clear_logs(xmlCtx);
324 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
325 if(xmlCtx->xsd != NULL) {
326 xmlFreeDoc(xmlCtx->xsd);
329 xmlCtx->xsd = xmlReadFd(fd, 0, NULL, 0);
330 if(xmlCtx->xsd == NULL) {
331 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
332 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
338 int xml2lpc_set_xsd_string(xml2lpc_context* xmlCtx, const char *content) {
339 xml2lpc_context_clear_logs(xmlCtx);
340 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
341 if(xmlCtx->xsd != NULL) {
342 xmlFreeDoc(xmlCtx->xsd);
345 xmlCtx->xsd = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
346 if(xmlCtx->xsd == NULL) {
347 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
348 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);