Documentation updates
[runtime.git] / lib / silcutil / silcxml.c
1 /*
2
3   silcxml.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2008 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include <silcruntime.h>
21
22 /* XML parser context */
23 struct SilcXMLParserStruct {
24   void *parser;                        /* Parser implementation */
25   SilcXMLParserHandlerStruct handler;  /* Handler */
26   void *context;                       /* User context */
27   SilcXMLParamsStruct params;          /* Parser parameters */
28 };
29
30 #ifdef HAVE_EXPAT_H
31
32 #include <expat.h>
33
34 /* Map expat error to silc_errno */
35
36 static SilcResult silc_xml_expat_error(XML_Parser parser)
37 {
38   enum XML_Error error = XML_GetErrorCode(parser);
39
40   switch (error) {
41   case XML_ERROR_NONE:
42     return SILC_OK;
43   case XML_ERROR_NO_MEMORY:
44     return SILC_ERR_OUT_OF_MEMORY;
45   case XML_ERROR_UNKNOWN_ENCODING:
46   case XML_ERROR_INCORRECT_ENCODING:
47     return SILC_ERR_BAD_ENCODING;
48   case XML_ERROR_ABORTED:
49     return SILC_ERR_ABORTED;
50   default:
51     return SILC_ERR_SYNTAX;
52   }
53 }
54
55 /* Return error string */
56
57 static const char *silc_xml_get_error(SilcXMLParser parser)
58 {
59   return XML_ErrorString(XML_GetErrorCode(parser->parser));
60 }
61
62 /* Start element */
63
64 static void silc_xml_expat_start_element(void *userData,
65                                          const XML_Char *name,
66                                          const XML_Char **atts)
67 {
68   SilcXMLParser parser = userData;
69   SilcHashTable t = NULL;
70   int i;
71
72   if (atts && atts[0]) {
73     t = silc_hash_table_alloc(NULL, 0, silc_hash_utf8_string, NULL,
74                               silc_hash_utf8_compare, NULL,
75                               NULL, NULL, TRUE);
76     if (!t) {
77       XML_StopParser(parser->parser, FALSE);
78       return;
79     }
80
81     for (i = 0; atts[i]; i += 2)
82       silc_hash_table_add(t, (void *)atts[i], (void *)atts[i + 1]);
83   }
84
85   if (parser->handler.start_element)
86     parser->handler.start_element(parser, name, t, parser->context);
87
88   if (t)
89     silc_hash_table_free(t);
90 }
91
92 /* End element */
93
94 static void silc_xml_expat_end_element(void *userData,
95                                        const XML_Char *name)
96 {
97   SilcXMLParser parser = userData;
98
99   if (parser->handler.end_element)
100     parser->handler.end_element(parser, name, parser->context);
101 }
102
103 /* Characters */
104
105 static void silc_xml_expat_data(void *userData,
106                                 const XML_Char *s,
107                                 int len)
108
109 {
110   SilcXMLParser parser = userData;
111
112   if (parser->handler.data)
113     parser->handler.data(parser, (const unsigned char *)s,
114                          (SilcUInt32)len, parser->context);
115 }
116
117 /* Processing instruction */
118
119 static void silc_xml_expat_pi(void *userData,
120                               const XML_Char *target,
121                               const XML_Char *data)
122 {
123   SilcXMLParser parser = userData;
124
125   if (parser->handler.pi)
126     parser->handler.pi(parser, target, data, parser->context);
127 }
128
129 /* Create parser */
130
131 SilcXMLParser silc_xml_parser_create(SilcXMLParams params,
132                                      SilcXMLParserHandler handler,
133                                      void *context)
134 {
135   SilcXMLParser parser;
136   XML_Parser ep;
137
138   parser = silc_calloc(1, sizeof(*parser));
139   if (!parser)
140     return NULL;
141
142   SILC_LOG_DEBUG(("Allcoated XML parser %p", parser));
143
144   if (params)
145     parser->params = *params;
146   if (handler)
147     parser->handler = *handler;
148   parser->context = context;
149
150   /* Allocate expat parser */
151   if (parser->params.no_namespace)
152     ep = XML_ParserCreate("UTF-8");
153   else
154     ep = XML_ParserCreateNS("UTF-8", '\0');
155
156   if (!ep) {
157     silc_set_errno(SILC_ERR_OUT_OF_MEMORY);
158     silc_free(ep);
159     return NULL;
160   }
161
162   parser->parser = ep;
163
164   /* Set callbacks */
165   XML_SetUserData(ep, parser);
166   XML_SetElementHandler(ep, silc_xml_expat_start_element,
167                         silc_xml_expat_end_element);
168   XML_SetCharacterDataHandler(ep, silc_xml_expat_data);
169   XML_SetProcessingInstructionHandler(ep, silc_xml_expat_pi);
170
171   return parser;
172 }
173
174 /* Free parser */
175
176 void silc_xml_parser_free(SilcXMLParser parser)
177 {
178   if (!parser)
179     return;
180
181   SILC_LOG_DEBUG(("Free XML parser %p", parser));
182
183   if (parser->parser)
184     XML_ParserFree(parser->parser);
185   silc_free(parser);
186 }
187
188 /* Parse */
189
190 SilcBool silc_xml_parse(SilcXMLParser parser,
191                         const unsigned char *data,
192                         SilcUInt32 data_len)
193 {
194   int ret;
195
196   SILC_LOG_DEBUG(("Parse XML data with parser %p", parser));
197
198   if (!parser || !data) {
199     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
200     return FALSE;
201   }
202
203   /* Parse */
204   ret = XML_Parse(parser->parser, (const char *)data, (int)data_len, 1);
205   if (!ret) {
206     silc_set_errno_reason(silc_xml_expat_error(parser->parser),
207                           silc_xml_get_error(parser));
208     return FALSE;
209   }
210
211   return TRUE;
212 }
213
214 /* Parse file */
215
216 SilcBool silc_xml_parse_file(SilcXMLParser parser,
217                              const char *filename)
218 {
219   unsigned char *data;
220   SilcUInt32 data_len;
221   SilcBool ret;
222
223   if (!filename) {
224     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
225     return FALSE;
226   }
227
228   SILC_LOG_DEBUG(("Parse XML file '%s' with parser %p", filename, parser));
229
230   data = silc_file_readfile(filename, &data_len, NULL);
231   if (!data)
232     return FALSE;
233
234   ret = silc_xml_parse(parser, data, data_len);
235   if (!ret) {
236     silc_free(data);
237     silc_set_errno_reason(silc_xml_expat_error(parser->parser),
238                           silc_xml_get_error(parser));
239     silc_set_errno_location(filename,
240                             XML_GetCurrentLineNumber(parser->parser),
241                             XML_GetCurrentColumnNumber(parser->parser));
242     return FALSE;
243   }
244
245   silc_free(data);
246
247   return ret;
248 }
249
250 /* Get attribute */
251
252 const char *silc_xml_get_attribute(SilcXMLParser parser,
253                                    SilcHashTable attributes,
254                                    const char *name)
255 {
256   char *val;
257
258   if (!attributes)
259     return NULL;
260
261   if (!silc_hash_table_find(attributes, (void *)name, NULL, (void *)&val))
262     return NULL;
263
264   return val;
265 }
266
267 /* Return current location */
268
269 void silc_xml_current_location(SilcXMLParser parser,
270                                SilcUInt32 *current_line,
271                                SilcUInt32 *current_column)
272 {
273   if (current_line)
274     *current_line = XML_GetCurrentLineNumber(parser->parser);
275   if (current_column)
276     *current_column = XML_GetCurrentColumnNumber(parser->parser);
277 }
278
279 #endif /* HAVE_EXPAT_H */