Windows: Use widechar instead of char when loading drivers.
[jack2.git] / dbus / xml_expat.c
blobf5a5aa682713b4806b59662856e942f3233cb1a7
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
3 Copyright (C) 2007,2008,2011 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 <assert.h>
33 #include <expat.h>
34 #include <dbus/dbus.h>
36 #include "controller_internal.h"
37 #include "jackdbus.h"
39 bool
40 jack_controller_settings_init()
42 return true;
45 void
46 jack_controller_settings_uninit()
50 struct parse_context
52 struct jack_controller *controller_ptr;
53 XML_Bool error;
54 bool option_value_capture;
55 char option[JACK_PARAM_STRING_MAX+1];
56 int option_used;
57 const char * address[PARAM_ADDRESS_SIZE];
58 int address_index;
59 char * container;
60 char *name;
63 #define context_ptr ((struct parse_context *)data)
65 void
66 jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
68 if (context_ptr->error)
70 return;
73 if (context_ptr->option_value_capture)
75 if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
77 jack_error("xml parse max char data length reached");
78 context_ptr->error = XML_TRUE;
79 return;
82 memcpy(context_ptr->option + context_ptr->option_used, s, len);
83 context_ptr->option_used += len;
87 void
88 jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
90 if (context_ptr->error)
92 return;
95 if (context_ptr->address_index >= PARAM_ADDRESS_SIZE)
97 assert(context_ptr->address_index == PARAM_ADDRESS_SIZE);
98 jack_error("xml param address max depth reached");
99 context_ptr->error = XML_TRUE;
100 return;
103 //jack_info("<%s>", el);
105 if (strcmp(el, "jack") == 0)
107 return;
110 if (strcmp(el, PTNODE_ENGINE) == 0)
112 context_ptr->address[context_ptr->address_index++] = PTNODE_ENGINE;
113 return;
116 if (strcmp(el, PTNODE_DRIVERS) == 0)
118 context_ptr->address[context_ptr->address_index++] = PTNODE_DRIVERS;
119 return;
122 if (strcmp(el, PTNODE_INTERNALS) == 0)
124 context_ptr->address[context_ptr->address_index++] = PTNODE_INTERNALS;
125 return;
128 if (strcmp(el, "driver") == 0 ||
129 strcmp(el, "internal") == 0)
131 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
133 jack_error("<%s> XML element must contain exactly one attribute, named \"name\"", el);
134 context_ptr->error = XML_TRUE;
135 return;
138 context_ptr->container = strdup(attr[1]);
139 if (context_ptr->container == NULL)
141 jack_error("strdup() failed");
142 context_ptr->error = XML_TRUE;
143 return;
146 context_ptr->address[context_ptr->address_index++] = context_ptr->container;
148 return;
151 if (strcmp(el, "option") == 0)
153 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
155 jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
156 context_ptr->error = XML_TRUE;
157 return;
160 context_ptr->name = strdup(attr[1]);
161 if (context_ptr->name == NULL)
163 jack_error("strdup() failed");
164 context_ptr->error = XML_TRUE;
165 return;
168 context_ptr->address[context_ptr->address_index++] = context_ptr->name;
169 context_ptr->option_value_capture = true;
170 context_ptr->option_used = 0;
171 return;
174 jack_error("unknown element \"%s\"", el);
175 context_ptr->error = XML_TRUE;
178 void
179 jack_controller_settings_callback_elend(void *data, const char *el)
181 int i;
183 if (context_ptr->error)
185 return;
188 //jack_info("</%s> (depth = %d)", el, context_ptr->address_index);
190 if (strcmp(el, "option") == 0)
192 assert(context_ptr->option_value_capture);
193 context_ptr->option[context_ptr->option_used] = 0;
195 for (i = context_ptr->address_index; i < PARAM_ADDRESS_SIZE; i++)
197 context_ptr->address[context_ptr->address_index] = NULL;
200 jack_controller_deserialize_parameter_value(context_ptr->controller_ptr, context_ptr->address, context_ptr->option);
202 free(context_ptr->name);
203 context_ptr->name = NULL;
204 context_ptr->option_value_capture = false;
205 context_ptr->address_index--;
207 else if (context_ptr->container != NULL)
209 //jack_info("'%s'", context_ptr->container);
210 free(context_ptr->container);
211 context_ptr->container = NULL;
212 context_ptr->address_index--;
214 else if (strcmp(el, PTNODE_ENGINE) == 0 ||
215 strcmp(el, PTNODE_DRIVERS) == 0 ||
216 strcmp(el, PTNODE_INTERNALS) == 0)
218 context_ptr->address_index--;
220 else
222 //jack_info("no depth decrement");
226 #undef context_ptr
228 void
229 jack_controller_settings_load(
230 struct jack_controller * controller_ptr)
232 XML_Parser parser;
233 int bytes_read;
234 void *buffer;
235 char *filename;
236 size_t conf_len;
237 struct stat st;
238 int fd;
239 enum XML_Status xmls;
240 struct parse_context context;
242 conf_len = strlen(JACKDBUS_CONF);
244 filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
245 if (filename == NULL)
247 jack_error("Out of memory.");
248 goto exit;
251 memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
252 memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
253 filename[g_jackdbus_config_dir_len + conf_len] = 0;
255 jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
257 if (stat(filename, &st) != 0)
259 jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
262 fd = open(filename, O_RDONLY);
263 if (fd == -1)
265 jack_error("open() failed to open conf filename.");
266 goto exit_free_filename;
269 parser = XML_ParserCreate(NULL);
270 if (parser == NULL)
272 jack_error("XML_ParserCreate() failed to create parser object.");
273 goto exit_close_file;
276 //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
278 /* we are expecting that conf file has small enough size to fit in memory */
280 buffer = XML_GetBuffer(parser, st.st_size);
281 if (buffer == NULL)
283 jack_error("XML_GetBuffer() failed.");
284 goto exit_free_parser;
287 bytes_read = read(fd, buffer, st.st_size);
288 if (bytes_read != st.st_size)
290 jack_error("read() returned unexpected result.");
291 goto exit_free_parser;
294 context.controller_ptr = controller_ptr;
295 context.error = XML_FALSE;
296 context.option_value_capture = false;
297 context.address_index = 0;
298 context.name = NULL;
299 context.container = NULL;
301 XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
302 XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
303 XML_SetUserData(parser, &context);
305 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
307 free(context.name);
308 free(context.container);
310 if (xmls == XML_STATUS_ERROR)
312 jack_error("XML_ParseBuffer() failed.");
313 goto exit_free_parser;
316 exit_free_parser:
317 XML_ParserFree(parser);
319 exit_close_file:
320 close(fd);
322 exit_free_filename:
323 free(filename);
325 exit:
326 return;