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(xmlDoc *doc, xml2lpc_context *ctx) {
218 xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started");
219 xmlNode *rootNode = xmlDocGetRootElement(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 xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer);
235 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
237 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error");
239 xmlSchemaFreeValidCtxt(validCtx);
243 int xml2lpc_convert(xml2lpc_context *xmlCtx, LpConfig *lpc) {
244 xml2lpc_context_clear_logs(xmlCtx);
246 return internal_convert_xml2lpc(xmlCtx->doc, xmlCtx);
249 int xml2lpc_set_xml_file(xml2lpc_context* xmlCtx, const char *filename) {
250 xml2lpc_context_clear_logs(xmlCtx);
251 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
252 if(xmlCtx->doc != NULL) {
253 xmlFreeDoc(xmlCtx->doc);
256 xmlCtx->doc = xmlReadFile(filename, NULL, 0);
257 if(xmlCtx->doc == NULL) {
258 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
259 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
265 int xml2lpc_set_xml_fd(xml2lpc_context* xmlCtx, int fd) {
266 xml2lpc_context_clear_logs(xmlCtx);
267 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
268 if(xmlCtx->doc != NULL) {
269 xmlFreeDoc(xmlCtx->doc);
272 xmlCtx->doc = xmlReadFd(fd, 0, NULL, 0);
273 if(xmlCtx->doc == NULL) {
274 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
275 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
281 int xml2lpc_set_xml_string(xml2lpc_context* xmlCtx, const char *content) {
282 xml2lpc_context_clear_logs(xmlCtx);
283 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
284 if(xmlCtx->doc != NULL) {
285 xmlFreeDoc(xmlCtx->doc);
288 xmlCtx->doc = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
289 if(xmlCtx->doc == NULL) {
290 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
291 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
297 int xml2lpc_set_xsd_file(xml2lpc_context* xmlCtx, const char *filename) {
298 xml2lpc_context_clear_logs(xmlCtx);
299 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
300 if(xmlCtx->xsd != NULL) {
301 xmlFreeDoc(xmlCtx->xsd);
304 xmlCtx->xsd = xmlReadFile(filename, NULL, 0);
305 if(xmlCtx->xsd == NULL) {
306 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse file \"%s\"", filename);
307 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
313 int xml2lpc_set_xsd_fd(xml2lpc_context* xmlCtx, int fd) {
314 xml2lpc_context_clear_logs(xmlCtx);
315 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
316 if(xmlCtx->xsd != NULL) {
317 xmlFreeDoc(xmlCtx->xsd);
320 xmlCtx->xsd = xmlReadFd(fd, 0, NULL, 0);
321 if(xmlCtx->xsd == NULL) {
322 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't open/parse fd \"%d\"", fd);
323 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);
329 int xml2lpc_set_xsd_string(xml2lpc_context* xmlCtx, const char *content) {
330 xml2lpc_context_clear_logs(xmlCtx);
331 xmlSetGenericErrorFunc(xmlCtx, xml2lpc_genericxml_error);
332 if(xmlCtx->xsd != NULL) {
333 xmlFreeDoc(xmlCtx->xsd);
336 xmlCtx->xsd = xmlReadDoc((const unsigned char*)content, 0, NULL, 0);
337 if(xmlCtx->xsd == NULL) {
338 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Can't parse string");
339 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "%s", xmlCtx->errorBuffer);