|
1 /* -*- mode: C; c-file-style: "gnu" -*- */ |
|
2 /* config-loader-libxml.c libxml2 XML loader |
|
3 * |
|
4 * Copyright (C) 2003 Red Hat, Inc. |
|
5 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
6 * Licensed under the Academic Free License version 2.1 |
|
7 * |
|
8 * This program is free software; you can redistribute it and/or modify |
|
9 * it under the terms of the GNU General Public License as published by |
|
10 * the Free Software Foundation; either version 2 of the License, or |
|
11 * (at your option) any later version. |
|
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 * You should have received a copy of the GNU General Public License |
|
19 * along with this program; if not, write to the Free Software |
|
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
21 * |
|
22 */ |
|
23 |
|
24 #include "config-parser.h" |
|
25 #ifndef __SYMBIAN32__ |
|
26 #include <dbus/dbus-internals.h> |
|
27 #else |
|
28 #include "dbus-internals.h" |
|
29 #endif //__SYMBIAN32__ |
|
30 #ifdef __SYMBIAN32__ |
|
31 #include <libxml2_xmlreader.h> |
|
32 |
|
33 #else |
|
34 #include <libxml/xmlreader.h> |
|
35 #include <libxml/parser.h> |
|
36 #include <libxml/globals.h> |
|
37 #include <libxml/xmlmemory.h> |
|
38 #endif |
|
39 #include <errno.h> |
|
40 #include <string.h> |
|
41 |
|
42 /* About the error handling: |
|
43 * - setup a "structured" error handler that catches structural |
|
44 * errors and some oom errors |
|
45 * - assume that a libxml function returning an error code means |
|
46 * out-of-memory |
|
47 */ |
|
48 #define _DBUS_MAYBE_SET_OOM(e) (dbus_error_is_set(e) ? (void)0 : _DBUS_SET_OOM(e)) |
|
49 |
|
50 |
|
51 static dbus_bool_t |
|
52 xml_text_start_element (BusConfigParser *parser, |
|
53 xmlTextReader *reader, |
|
54 DBusError *error) |
|
55 { |
|
56 const char *name; |
|
57 int n_attributes; |
|
58 const char **attribute_names, **attribute_values; |
|
59 dbus_bool_t ret; |
|
60 int i, status, is_empty; |
|
61 |
|
62 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
63 |
|
64 ret = FALSE; |
|
65 attribute_names = NULL; |
|
66 attribute_values = NULL; |
|
67 |
|
68 #ifdef __SYMBIAN32__ |
|
69 name = (const char *) xmlTextReaderConstName (reader); |
|
70 #else |
|
71 name = xmlTextReaderConstName (reader); |
|
72 #endif |
|
73 n_attributes = xmlTextReaderAttributeCount (reader); |
|
74 is_empty = xmlTextReaderIsEmptyElement (reader); |
|
75 |
|
76 if (name == NULL || n_attributes < 0 || is_empty == -1) |
|
77 { |
|
78 _DBUS_MAYBE_SET_OOM (error); |
|
79 goto out; |
|
80 } |
|
81 |
|
82 attribute_names = dbus_new0 (const char *, n_attributes + 1); |
|
83 attribute_values = dbus_new0 (const char *, n_attributes + 1); |
|
84 if (attribute_names == NULL || attribute_values == NULL) |
|
85 { |
|
86 _DBUS_SET_OOM (error); |
|
87 goto out; |
|
88 } |
|
89 i = 0; |
|
90 while ((status = xmlTextReaderMoveToNextAttribute (reader)) == 1) |
|
91 { |
|
92 _dbus_assert (i < n_attributes); |
|
93 #ifdef __SYMBIAN32__ |
|
94 attribute_names[i] = (const char *) xmlTextReaderConstName (reader); |
|
95 attribute_values[i] = (const char *) xmlTextReaderConstValue (reader); |
|
96 #else |
|
97 attribute_names[i] = xmlTextReaderConstName (reader); |
|
98 attribute_values[i] = (xmlTextReaderConstValue (reader); |
|
99 #endif |
|
100 if (attribute_names[i] == NULL || attribute_values[i] == NULL) |
|
101 { |
|
102 _DBUS_MAYBE_SET_OOM (error); |
|
103 goto out; |
|
104 } |
|
105 i++; |
|
106 } |
|
107 if (status == -1) |
|
108 { |
|
109 _DBUS_MAYBE_SET_OOM (error); |
|
110 goto out; |
|
111 } |
|
112 _dbus_assert (i == n_attributes); |
|
113 |
|
114 ret = bus_config_parser_start_element (parser, name, |
|
115 attribute_names, attribute_values, |
|
116 error); |
|
117 if (ret && is_empty == 1) |
|
118 ret = bus_config_parser_end_element (parser, name, error); |
|
119 |
|
120 out: |
|
121 dbus_free (attribute_names); |
|
122 dbus_free (attribute_values); |
|
123 |
|
124 return ret; |
|
125 } |
|
126 |
|
127 static void xml_shut_up (void *ctx, const char *msg, ...) |
|
128 { |
|
129 return; |
|
130 } |
|
131 |
|
132 static void |
|
133 xml_text_reader_error (void *arg, xmlErrorPtr xml_error) |
|
134 { |
|
135 DBusError *error = arg; |
|
136 |
|
137 #if 0 |
|
138 _dbus_verbose ("XML_ERROR level=%d, domain=%d, code=%d, msg=%s\n", |
|
139 xml_error->level, xml_error->domain, |
|
140 xml_error->code, xml_error->message); |
|
141 #endif |
|
142 |
|
143 if (!dbus_error_is_set (error)) |
|
144 { |
|
145 if (xml_error->code == XML_ERR_NO_MEMORY) |
|
146 _DBUS_SET_OOM (error); |
|
147 else if (xml_error->level == XML_ERR_ERROR || |
|
148 xml_error->level == XML_ERR_FATAL) |
|
149 dbus_set_error (error, DBUS_ERROR_FAILED, |
|
150 "Error loading config file: '%s'", |
|
151 xml_error->message); |
|
152 } |
|
153 } |
|
154 |
|
155 |
|
156 BusConfigParser* |
|
157 bus_config_load (const DBusString *file, |
|
158 dbus_bool_t is_toplevel, |
|
159 const BusConfigParser *parent, |
|
160 DBusError *error) |
|
161 |
|
162 { |
|
163 xmlTextReader *reader; |
|
164 BusConfigParser *parser; |
|
165 DBusString dirname, data; |
|
166 DBusError tmp_error; |
|
167 int ret; |
|
168 |
|
169 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
170 |
|
171 parser = NULL; |
|
172 reader = NULL; |
|
173 |
|
174 if (!_dbus_string_init (&dirname)) |
|
175 { |
|
176 _DBUS_SET_OOM (error); |
|
177 return NULL; |
|
178 } |
|
179 |
|
180 if (!_dbus_string_init (&data)) |
|
181 { |
|
182 _DBUS_SET_OOM (error); |
|
183 _dbus_string_free (&dirname); |
|
184 return NULL; |
|
185 } |
|
186 |
|
187 if (is_toplevel) |
|
188 { |
|
189 /* xmlMemSetup only fails if one of the functions is NULL */ |
|
190 /* |
|
191 xmlMemSetup (dbus_free, |
|
192 dbus_malloc, |
|
193 dbus_realloc, |
|
194 _dbus_strdup); |
|
195 */ |
|
196 xmlInitParser (); |
|
197 xmlSetGenericErrorFunc (NULL, xml_shut_up); |
|
198 } |
|
199 |
|
200 if (!_dbus_string_get_dirname (file, &dirname)) |
|
201 { |
|
202 _DBUS_SET_OOM (error); |
|
203 goto failed; |
|
204 } |
|
205 |
|
206 parser = bus_config_parser_new (&dirname, is_toplevel, parent); |
|
207 if (parser == NULL) |
|
208 { |
|
209 _DBUS_SET_OOM (error); |
|
210 goto failed; |
|
211 } |
|
212 |
|
213 if (!_dbus_file_get_contents (&data, file, error)) |
|
214 goto failed; |
|
215 |
|
216 reader = xmlReaderForMemory (_dbus_string_get_const_data (&data), |
|
217 _dbus_string_get_length (&data), |
|
218 NULL, NULL, 0); |
|
219 if (reader == NULL) |
|
220 { |
|
221 _DBUS_SET_OOM (error); |
|
222 goto failed; |
|
223 } |
|
224 |
|
225 xmlTextReaderSetParserProp (reader, XML_PARSER_SUBST_ENTITIES, 1); |
|
226 |
|
227 dbus_error_init (&tmp_error); |
|
228 xmlTextReaderSetStructuredErrorHandler (reader, xml_text_reader_error, &tmp_error); |
|
229 |
|
230 while ((ret = xmlTextReaderRead (reader)) == 1) |
|
231 { |
|
232 int type; |
|
233 |
|
234 if (dbus_error_is_set (&tmp_error)) |
|
235 goto reader_out; |
|
236 |
|
237 type = xmlTextReaderNodeType (reader); |
|
238 if (type == -1) |
|
239 { |
|
240 _DBUS_MAYBE_SET_OOM (&tmp_error); |
|
241 goto reader_out; |
|
242 } |
|
243 |
|
244 switch ((xmlReaderTypes) type) { |
|
245 case XML_READER_TYPE_ELEMENT: |
|
246 xml_text_start_element (parser, reader, &tmp_error); |
|
247 break; |
|
248 |
|
249 case XML_READER_TYPE_TEXT: |
|
250 case XML_READER_TYPE_CDATA: |
|
251 { |
|
252 DBusString content; |
|
253 const char *value; |
|
254 #ifdef __SYMBIAN32__ |
|
255 value = (const char *) xmlTextReaderConstValue (reader); |
|
256 #else |
|
257 value = xmlTextReaderConstValue (reader); |
|
258 #endif |
|
259 if (value != NULL) |
|
260 { |
|
261 _dbus_string_init_const (&content, value); |
|
262 bus_config_parser_content (parser, &content, &tmp_error); |
|
263 } |
|
264 else |
|
265 _DBUS_MAYBE_SET_OOM (&tmp_error); |
|
266 break; |
|
267 } |
|
268 |
|
269 case XML_READER_TYPE_DOCUMENT_TYPE: |
|
270 { |
|
271 const char *name; |
|
272 #ifdef __SYMBIAN32__ |
|
273 name = (const char *) xmlTextReaderConstName (reader); |
|
274 #else |
|
275 name = xmlTextReaderConstName (reader); |
|
276 #endif |
|
277 if (name != NULL) |
|
278 bus_config_parser_check_doctype (parser, name, &tmp_error); |
|
279 else |
|
280 _DBUS_MAYBE_SET_OOM (&tmp_error); |
|
281 break; |
|
282 } |
|
283 |
|
284 case XML_READER_TYPE_END_ELEMENT: |
|
285 { |
|
286 const char *name; |
|
287 #ifdef __SYMBIAN32__ |
|
288 name = (const char *) xmlTextReaderConstName (reader); |
|
289 #else |
|
290 name = xmlTextReaderConstName (reader); |
|
291 #endif |
|
292 if (name != NULL) |
|
293 bus_config_parser_end_element (parser, name, &tmp_error); |
|
294 else |
|
295 _DBUS_MAYBE_SET_OOM (&tmp_error); |
|
296 break; |
|
297 } |
|
298 |
|
299 case XML_READER_TYPE_DOCUMENT: |
|
300 case XML_READER_TYPE_DOCUMENT_FRAGMENT: |
|
301 case XML_READER_TYPE_PROCESSING_INSTRUCTION: |
|
302 case XML_READER_TYPE_COMMENT: |
|
303 case XML_READER_TYPE_ENTITY: |
|
304 case XML_READER_TYPE_NOTATION: |
|
305 case XML_READER_TYPE_WHITESPACE: |
|
306 case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: |
|
307 case XML_READER_TYPE_END_ENTITY: |
|
308 case XML_READER_TYPE_XML_DECLARATION: |
|
309 /* nothing to do, just read on */ |
|
310 break; |
|
311 |
|
312 case XML_READER_TYPE_NONE: |
|
313 case XML_READER_TYPE_ATTRIBUTE: |
|
314 case XML_READER_TYPE_ENTITY_REFERENCE: |
|
315 _dbus_assert_not_reached ("unexpected nodes in XML"); |
|
316 } |
|
317 |
|
318 if (dbus_error_is_set (&tmp_error)) |
|
319 goto reader_out; |
|
320 } |
|
321 |
|
322 if (ret == -1) |
|
323 _DBUS_MAYBE_SET_OOM (&tmp_error); |
|
324 |
|
325 reader_out: |
|
326 xmlFreeTextReader (reader); |
|
327 reader = NULL; |
|
328 if (dbus_error_is_set (&tmp_error)) |
|
329 { |
|
330 dbus_move_error (&tmp_error, error); |
|
331 goto failed; |
|
332 } |
|
333 |
|
334 if (!bus_config_parser_finished (parser, error)) |
|
335 goto failed; |
|
336 _dbus_string_free (&dirname); |
|
337 _dbus_string_free (&data); |
|
338 if (is_toplevel) |
|
339 xmlCleanupParser(); |
|
340 _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
|
341 return parser; |
|
342 |
|
343 failed: |
|
344 _DBUS_ASSERT_ERROR_IS_SET (error); |
|
345 _dbus_string_free (&dirname); |
|
346 _dbus_string_free (&data); |
|
347 if (is_toplevel) |
|
348 xmlCleanupParser(); |
|
349 if (parser) |
|
350 bus_config_parser_unref (parser); |
|
351 _dbus_assert (reader == NULL); /* must go to reader_out first */ |
|
352 return NULL; |
|
353 } |