]> sjero.net Git - linphone/blob - tools/lpc2xml.c
Add lpc2xml tool and fix xml2lpc validation
[linphone] / tools / lpc2xml.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 "lpc2xml.h"
22 #include <string.h>
23 #include <libxml/xmlsave.h>
24
25
26 #define LPC2XML_BZ 2048
27
28 struct _lpc2xml_context {
29         const LpConfig *lpc;
30         lpc2xml_function cbf;
31         void *ctx;
32         
33         xmlDoc *doc;
34         char errorBuffer[LPC2XML_BZ];
35         char warningBuffer[LPC2XML_BZ];
36 };
37
38
39 lpc2xml_context* lpc2xml_context_new(lpc2xml_function cbf, void *ctx) {
40         lpc2xml_context *xmlCtx = (lpc2xml_context*)malloc(sizeof(lpc2xml_context));
41         if(xmlCtx != NULL) {
42                 xmlCtx->lpc = NULL;
43                 xmlCtx->cbf = cbf;
44                 xmlCtx->ctx = ctx;
45                 
46                 xmlCtx->doc = NULL;
47                 xmlCtx->errorBuffer[0]='\0';
48                 xmlCtx->warningBuffer[0]='\0';
49         }
50         return xmlCtx;
51 }
52
53 void lpc2xml_context_destroy(lpc2xml_context *ctx) {
54         if(ctx->doc != NULL) {
55                 xmlFreeDoc(ctx->doc);
56                 ctx->doc = NULL;
57         }
58         free(ctx);
59 }
60 /*
61 static void lpc2xml_context_clear_logs(lpc2xml_context *ctx) {
62         ctx->errorBuffer[0]='\0';
63         ctx->warningBuffer[0]='\0';
64 }*/
65
66 static void lpc2xml_log(lpc2xml_context *xmlCtx, int level, const char *fmt, ...) {
67         va_list args;   
68         va_start(args, fmt);    
69         if(xmlCtx->cbf != NULL) {
70                 xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args);
71         }
72         va_end(args);
73 }
74 /*
75 static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) {
76         lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx;
77         int sl = strlen(xmlCtx->errorBuffer);
78         va_list args;   
79         va_start(args, fmt);    
80         vsnprintf(xmlCtx->errorBuffer + sl, LPC2XML_BZ-sl, fmt, args);
81         va_end(args);
82 }
83
84 static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) {
85         lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx;
86         int sl = strlen(xmlCtx->warningBuffer);
87         va_list args;   
88         va_start(args, fmt);    
89         vsnprintf(xmlCtx->warningBuffer + sl, LPC2XML_BZ-sl, fmt, args);
90         va_end(args);
91 }*/
92
93 #if 0
94 static void dumpNodes(int level, xmlNode * a_node, lpc2xml_context *ctx) {
95         xmlNode *cur_node = NULL;
96
97         for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
98                 if (cur_node->type == XML_ELEMENT_NODE) {
99                         lpc2xml_log(ctx, LPC2XML_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name);
100                 } else {
101                         lpc2xml_log(ctx, LPC2XML_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
102                 }
103
104                 dumpNodes(level + 1, cur_node->children, ctx);
105         }
106 }
107 #endif
108
109 #if 0
110 static void dumpNode(xmlNode *node, lpc2xml_context *ctx) {
111                 lpc2xml_log(ctx, LPC2XML_DEBUG, "node type: %d, name: %s", node->type, node->name);
112 }
113
114 static void dumpAttr(xmlNode *node, lpc2xml_context *ctx) {
115                 lpc2xml_log(ctx, LPC2XML_DEBUG, "attr name: %s value:%s", node->name, node->children->content);
116 }
117
118 static void dumpContent(xmlNode *node, lpc2xml_context *ctx) {
119                 lpc2xml_log(ctx, LPC2XML_DEBUG, "content: %s", node->children->content);
120 }
121
122
123
124 #endif
125
126 static int processEntry(const char *section, const char *entry, xmlNode *node, lpc2xml_context *ctx) {
127         const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL);
128         if(content == NULL) {
129                 lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Issue when reading the lpc");
130                 return -1;
131         }
132         xmlNodeSetContent(node, (const xmlChar *) content);
133         return 0;
134 }
135
136 struct __processSectionCtx {
137         int ret;
138         const char *section;
139         xmlNode *node;
140         lpc2xml_context *ctx;
141 };
142
143 static void processSection_cb(const char *entry, struct __processSectionCtx *ctx) {
144         if(ctx->ret == 0) {
145                 xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL);
146                 if(node == NULL) {
147                         lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"entry\" element");
148                         ctx->ret = -1;
149                         return;
150                 }
151                 xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)entry);
152                 if(name_attr == NULL) {
153                         lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"entry\" element");
154                         ctx->ret = -1;
155                         return;
156                 }
157                 ctx->ret = processEntry(ctx->section, entry, node, ctx->ctx);
158         }
159 }
160
161 static int processSection(const char *section, xmlNode *node, lpc2xml_context *ctx) {
162         struct __processSectionCtx pc_ctx = {0, section, node, ctx};
163         lp_config_for_each_entry(ctx->lpc, section, (void (*)(const char *, void *))processSection_cb, (void*)&pc_ctx);
164         return pc_ctx.ret;
165 }
166
167
168
169 struct __processConfigCtx {
170         int ret;
171         xmlNode *node;
172         lpc2xml_context *ctx;
173 };
174
175 static void processConfig_cb(const char *section, struct __processConfigCtx *ctx) {
176         if(ctx->ret == 0) {
177                 xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"section", NULL);
178                 if(node == NULL) {
179                         lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element");
180                         ctx->ret = -1;
181                         return;
182                 }
183                 xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)section);
184                 if(name_attr == NULL) {
185                         lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"section\" element");
186                         ctx->ret = -1;
187                         return;
188                 }
189                 ctx->ret = processSection(section, node, ctx->ctx);
190         }
191 }
192
193 static int processConfig(xmlNode *node, lpc2xml_context *ctx) {
194         struct __processConfigCtx pc_ctx = {0, node, ctx};
195         lp_config_for_each_section(ctx->lpc, (void (*)(const char *, void *))processConfig_cb, (void*)&pc_ctx);
196         return pc_ctx.ret;
197 }
198
199 static int processDoc(xmlDoc *doc, lpc2xml_context *ctx) {
200         int ret = 0;
201         xmlNode *root_node = xmlNewNode(NULL, (const xmlChar *)"config");
202         if(root_node == NULL) {
203                 lpc2xml_log(ctx, LPC2XML_ERROR, "Can't create \"config\" element");
204                 return -1;
205         }
206         xmlNs *lpc_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd", (const xmlChar *)"lpc");
207         if(lpc_ns == NULL) {
208                 lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create lpc namespace");
209         } else {
210                 xmlSetNs(root_node, lpc_ns);
211         }
212         xmlNs *xsi_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance", (const xmlChar *)"xsi");
213         if(lpc_ns == NULL) {
214                 lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create xsi namespace");
215         }
216         xmlAttr *schemaLocation = xmlNewNsProp(root_node, xsi_ns, (const xmlChar *)"schemaLocation", (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd lpconfig.xsd ");
217         if(schemaLocation == NULL) {
218                 lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create schemaLocation");
219         }
220         ret = processConfig(root_node, ctx);
221         xmlDocSetRootElement(doc, root_node);
222         return ret;
223 }
224
225 static int internal_convert_lpc2xml(lpc2xml_context *ctx) {
226         int ret = 0;
227         lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation started");
228         if(ctx->doc != NULL) {
229                 xmlFreeDoc(ctx->doc);
230                 ctx->doc = NULL;
231         }
232         xmlDoc *doc = xmlNewDoc((const xmlChar *)"1.0");
233         ret  = processDoc(doc, ctx);
234         if(ret == 0) {
235                 ctx->doc = doc;
236         } else {
237                 xmlFreeDoc(doc);
238         }
239         lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation ended ret:%d", ret);
240         return ret;
241 }
242
243 int lpc2xml_set_lpc(lpc2xml_context* context, const LpConfig *lpc) {
244         context->lpc = lpc;
245         return 0;
246 }
247
248 int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) {
249         int ret = 0;
250         xmlSaveCtxtPtr save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT);
251         ret = internal_convert_lpc2xml(context);
252         if(ret == 0) {
253                 ret = xmlSaveDoc(save_ctx, context->doc);
254         }
255         xmlSaveClose(save_ctx);
256         return ret;
257 }
258
259 int lpc2xml_convert_fd(lpc2xml_context* context, int fd) {
260         int ret = 0;
261         xmlSaveCtxtPtr save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT);
262         ret = internal_convert_lpc2xml(context);
263         if(ret == 0) {
264                 ret = xmlSaveDoc(save_ctx, context->doc);
265         }
266         xmlSaveClose(save_ctx);
267         return ret;
268 }
269
270 int lpc2xml_convert_string(lpc2xml_context* context, unsigned char **content) {
271         int ret = 0;
272         xmlBufferPtr buffer = xmlBufferCreate();
273         xmlSaveCtxtPtr save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT);
274         internal_convert_lpc2xml(context);
275         if(ret == 0) {
276                 ret = xmlSaveDoc(save_ctx, context->doc);
277         }
278         xmlSaveClose(save_ctx);
279         if(ret == 0) {
280                 *content = xmlBufferDetach(buffer);
281         }
282         xmlBufferFree(buffer);
283         return ret;
284 }