]> sjero.net Git - linphone/blob - tools/xml2lpc.c
Update ms2
[linphone] / tools / xml2lpc.c
1 /*
2 linphone
3 Copyright (C) 2012 Belledonne Communications SARL
4 Yann DIORCET (yann.diorcet@linphone.org)
5
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.
10
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.
15
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.
19 */
20
21 #include "xml2lpc.h"
22 #include <string.h>
23 #include <libxml/xmlreader.h>
24
25
26 #define XML2LPC_BZ 2048
27
28 struct _xml2lpc_context {
29         LpConfig *lpc;
30         xml2lpc_function cbf;
31         void *ctx;
32         
33         xmlDoc *doc;
34         xmlDoc *xsd;
35         char errorBuffer[XML2LPC_BZ];
36         char warningBuffer[XML2LPC_BZ];
37 };
38
39
40 xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) {
41         xml2lpc_context *xmlCtx = (xml2lpc_context*)malloc(sizeof(xml2lpc_context));
42         if(xmlCtx != NULL) {
43                 xmlCtx->lpc = NULL;
44                 xmlCtx->cbf = cbf;
45                 xmlCtx->ctx = ctx;
46                 
47                 xmlCtx->doc = NULL;
48                 xmlCtx->xsd = NULL;
49                 xmlCtx->errorBuffer[0]='\0';
50                 xmlCtx->warningBuffer[0]='\0';
51         }
52         return xmlCtx;
53 }
54
55 void xml2lpc_context_destroy(xml2lpc_context *ctx) {
56         if(ctx->doc != NULL) {
57                 xmlFreeDoc(ctx->doc);
58                 ctx->doc = NULL;
59         }
60         if(ctx->xsd != NULL) {
61                 xmlFreeDoc(ctx->xsd);
62                 ctx->xsd = NULL;
63         }
64         free(ctx);
65 }
66
67 static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) {
68         ctx->errorBuffer[0]='\0';
69         ctx->warningBuffer[0]='\0';
70 }
71
72 static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) {
73         va_list args;   
74         va_start(args, fmt);    
75         if(xmlCtx->cbf != NULL) {
76                 xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args);
77         }
78         va_end(args);
79 }
80
81 static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
82         xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
83         int sl = strlen(xmlCtx->errorBuffer);
84         va_list args;   
85         va_start(args, fmt);    
86         vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args);
87         va_end(args);
88 }
89
90 static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) {
91         xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
92         int sl = strlen(xmlCtx->warningBuffer);
93         va_list args;   
94         va_start(args, fmt);    
95         vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args);
96         va_end(args);
97 }
98
99 #if 0
100 static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) {
101     xmlNode *cur_node = NULL;
102
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);
106         } else {
107                 xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
108         }
109
110         dumpNodes(level + 1, cur_node->children, ctx);
111     }
112 }
113 #endif
114
115
116 static void dumpNode(xmlNode *node, xml2lpc_context *ctx) {
117         xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name);
118 }
119
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);
122 }
123
124 static void dumpContent(xmlNode *node, xml2lpc_context *ctx) {
125         xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content);
126 }
127
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;
133
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) {
140                                 overwrite = TRUE;
141                         }
142                 }
143         }
144
145         value = (const char *)element->children->content;
146         dumpContent((xmlNode *)element, ctx);
147
148         if(name != NULL) {
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);
153                 } else {
154                         xml2lpc_log(ctx, XML2LPC_MESSAGE, "Don't touch %s|%s = %s",sectionName, name, str);
155                 }
156         } else {
157                 xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element));
158         }
159         return 0;
160 }
161
162 static int processSection(xmlElement *element, xml2lpc_context *ctx) {
163         xmlNode *cur_node = NULL;
164         xmlNode *cur_attr = NULL;
165         const char *name = NULL;
166
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;
171                 }
172         }
173
174         if(name != NULL) {
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);
180                                 }
181                         }
182                         
183                 }
184         } else {
185                 xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element));
186         }
187
188         return 0;
189 }
190
191 static int processConfig(xmlElement *element, xml2lpc_context *ctx) {
192         xmlNode *cur_node = NULL;
193
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);
199                 }
200                 
201         }
202         return 0;
203 }
204
205 static int processDoc(xmlNode *node, xml2lpc_context *ctx) {
206         dumpNode(node, ctx);
207         
208         if (node->type == XML_ELEMENT_NODE && 
209                 strcmp((const char*)node->name, "config") == 0 ) {
210                 processConfig((xmlElement*)node, ctx);
211         } else {
212                 xml2lpc_log(ctx, XML2LPC_WARNING, "root element is not \"config\", line:%d", xmlGetLineNo(node));
213         }
214         return 0;
215 }
216
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);
223         return ret;
224 }
225
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);
233         if(ret > 0) {
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);
238         } else if(ret < 0) {
239                 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Internal error");
240         }
241         xmlSchemaFreeValidCtxt(validCtx);
242         return ret;
243 }
244
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");
249                 return -1;
250         }
251         if(lpc == NULL) {
252                 xml2lpc_log(xmlCtx, XML2LPC_ERROR, "Invalid lpc");
253         }
254         xmlCtx->lpc = lpc;
255         return internal_convert_xml2lpc(xmlCtx);
256 }
257
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);
263                 xmlCtx->doc = NULL;
264         }
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);
269                 return -1;
270         }
271         return 0;
272 }
273
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);
279                 xmlCtx->doc = NULL;
280         }
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);
285                 return -1;
286         }
287         return 0;
288 }
289
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);
295                 xmlCtx->doc = NULL;
296         }
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);
301                 return -1;
302         }
303         return 0;
304 }
305
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);
311                 xmlCtx->xsd = NULL;
312         }
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);
317                 return -1;
318         }
319         return 0;
320 }
321
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);
327                 xmlCtx->xsd = NULL;
328         }
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);
333                 return -1;
334         }
335         return 0;
336 }
337
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);
343                 xmlCtx->xsd = NULL;
344         }
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);
349                 return -1;
350         }
351         return 0;
352 }