Merge branch 'master' into port_register_notification_defer
[jack2.git] / dbus / xml_expat.c
blob1ee1bd2e5fd18c48604a1638f24a52ea28d1639a
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
3 Copyright (C) 2007,2008 Nedko Arnaudov
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #if defined(HAVE_CONFIG_H)
21 #include "config.h"
22 #endif
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <expat.h>
33 #include <dbus/dbus.h>
35 #include "controller_internal.h"
36 #include "jackdbus.h"
38 bool
39 jack_controller_settings_init()
41 return true;
44 void
45 jack_controller_settings_uninit()
49 #define PARSE_CONTEXT_ROOT 0
50 #define PARSE_CONTEXT_JACK 1
51 #define PARSE_CONTEXT_ENGINE 1
52 #define PARSE_CONTEXT_DRIVERS 2
53 #define PARSE_CONTEXT_DRIVER 3
54 #define PARSE_CONTEXT_OPTION 4
55 #define PARSE_CONTEXT_INTERNALS 5
56 #define PARSE_CONTEXT_INTERNAL 6
58 #define MAX_STACK_DEPTH 10
60 struct parse_context
62 struct jack_controller *controller_ptr;
63 XML_Bool error;
64 unsigned int element[MAX_STACK_DEPTH];
65 signed int depth;
66 jackctl_driver_t *driver;
67 jackctl_internal_t *internal;
68 char option[JACK_PARAM_STRING_MAX+1];
69 int option_used;
70 char *name;
73 #define context_ptr ((struct parse_context *)data)
75 void
76 jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
78 if (context_ptr->error)
80 return;
83 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
85 if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
87 jack_error("xml parse max char data length reached");
88 context_ptr->error = XML_TRUE;
89 return;
92 memcpy(context_ptr->option + context_ptr->option_used, s, len);
93 context_ptr->option_used += len;
97 void
98 jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
100 jackctl_driver_t *driver;
101 jackctl_internal_t *internal;
103 if (context_ptr->error)
105 return;
108 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
110 jack_error("xml parse max stack depth reached");
111 context_ptr->error = XML_TRUE;
112 return;
115 if (strcmp(el, "jack") == 0)
117 //jack_info("<jack>");
118 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
119 return;
122 if (strcmp(el, "engine") == 0)
124 //jack_info("<engine>");
125 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
126 return;
129 if (strcmp(el, "drivers") == 0)
131 //jack_info("<drivers>");
132 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
133 return;
136 if (strcmp(el, "internals") == 0)
138 //jack_info("<internals>");
139 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNALS;
140 return;
143 if (strcmp(el, "driver") == 0)
145 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
147 jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
148 context_ptr->error = XML_TRUE;
149 return;
152 //jack_info("<driver>");
153 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
155 driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
156 if (driver == NULL)
158 jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
160 else
162 jack_info("setting for driver \"%s\" found", attr[1]);
165 context_ptr->driver = driver;
167 return;
170 if (strcmp(el, "internal") == 0)
172 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
174 jack_error("<internal> XML element must contain exactly one attribute, named \"name\"");
175 context_ptr->error = XML_TRUE;
176 return;
179 //jack_info("<internal>");
180 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNAL;
182 internal = jack_controller_find_internal(context_ptr->controller_ptr->server, attr[1]);
183 if (internal == NULL)
185 jack_error("ignoring settings for unknown internal \"%s\"", attr[1]);
187 else
189 jack_info("setting for internal \"%s\" found", attr[1]);
192 context_ptr->internal = internal;
194 return;
198 if (strcmp(el, "option") == 0)
200 //jack_info("<option>");
201 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
203 jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
204 context_ptr->error = XML_TRUE;
205 return;
208 context_ptr->name = strdup(attr[1]);
209 if (context_ptr->name == NULL)
211 jack_error("strdup() failed");
212 context_ptr->error = XML_TRUE;
213 return;
216 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
217 context_ptr->option_used = 0;
218 return;
221 jack_error("unknown element \"%s\"", el);
222 context_ptr->error = XML_TRUE;
225 void
226 jack_controller_settings_callback_elend(void *data, const char *el)
228 if (context_ptr->error)
230 return;
233 //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
235 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
237 context_ptr->option[context_ptr->option_used] = 0;
239 if (context_ptr->depth == 2 &&
240 context_ptr->element[0] == PARSE_CONTEXT_JACK &&
241 context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
243 jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
246 if (context_ptr->depth == 3 &&
247 context_ptr->element[0] == PARSE_CONTEXT_JACK &&
248 context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
249 context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
250 context_ptr->driver != NULL)
252 jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
255 if (context_ptr->depth == 3 &&
256 context_ptr->element[0] == PARSE_CONTEXT_JACK &&
257 context_ptr->element[1] == PARSE_CONTEXT_INTERNALS &&
258 context_ptr->element[2] == PARSE_CONTEXT_INTERNAL &&
259 context_ptr->internal != NULL)
261 jack_controller_settings_set_internal_option(context_ptr->internal, context_ptr->name, context_ptr->option);
265 context_ptr->depth--;
267 if (context_ptr->name != NULL)
269 free(context_ptr->name);
270 context_ptr->name = NULL;
274 #undef context_ptr
276 void
277 jack_controller_settings_load(
278 struct jack_controller * controller_ptr)
280 XML_Parser parser;
281 int bytes_read;
282 void *buffer;
283 char *filename;
284 size_t conf_len;
285 struct stat st;
286 int fd;
287 enum XML_Status xmls;
288 struct parse_context context;
290 conf_len = strlen(JACKDBUS_CONF);
292 filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
293 if (filename == NULL)
295 jack_error("Out of memory.");
296 goto exit;
299 memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
300 memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
301 filename[g_jackdbus_config_dir_len + conf_len] = 0;
303 jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
305 if (stat(filename, &st) != 0)
307 jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
310 fd = open(filename, O_RDONLY);
311 if (fd == -1)
313 jack_error("open() failed to open conf filename.");
314 goto exit_free_filename;
317 parser = XML_ParserCreate(NULL);
318 if (parser == NULL)
320 jack_error("XML_ParserCreate() failed to create parser object.");
321 goto exit_close_file;
324 //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
326 /* we are expecting that conf file has small enough size to fit in memory */
328 buffer = XML_GetBuffer(parser, st.st_size);
329 if (buffer == NULL)
331 jack_error("XML_GetBuffer() failed.");
332 goto exit_free_parser;
335 bytes_read = read(fd, buffer, st.st_size);
336 if (bytes_read != st.st_size)
338 jack_error("read() returned unexpected result.");
339 goto exit_free_parser;
342 context.controller_ptr = controller_ptr;
343 context.error = XML_FALSE;
344 context.depth = -1;
345 context.name = NULL;
347 XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
348 XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
349 XML_SetUserData(parser, &context);
351 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
352 if (xmls == XML_STATUS_ERROR)
354 jack_error("XML_ParseBuffer() failed.");
355 goto exit_free_parser;
358 exit_free_parser:
359 XML_ParserFree(parser);
361 exit_close_file:
362 close(fd);
364 exit_free_filename:
365 free(filename);
367 exit:
368 return;