jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
8.3KB

  1. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2007,2008 Nedko Arnaudov
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #if defined(HAVE_CONFIG_H)
  16. #include "config.h"
  17. #endif
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <errno.h>
  25. #include <string.h>
  26. #include <expat.h>
  27. #include <dbus/dbus.h>
  28. #include "controller_internal.h"
  29. #include "jackdbus.h"
  30. bool
  31. jack_controller_settings_init()
  32. {
  33. return true;
  34. }
  35. void
  36. jack_controller_settings_uninit()
  37. {
  38. }
  39. #define PARSE_CONTEXT_ROOT 0
  40. #define PARSE_CONTEXT_JACK 1
  41. #define PARSE_CONTEXT_ENGINE 1
  42. #define PARSE_CONTEXT_DRIVERS 2
  43. #define PARSE_CONTEXT_DRIVER 3
  44. #define PARSE_CONTEXT_OPTION 4
  45. #define MAX_STACK_DEPTH 10
  46. struct parse_context
  47. {
  48. struct jack_controller *controller_ptr;
  49. XML_Bool error;
  50. unsigned int element[MAX_STACK_DEPTH];
  51. signed int depth;
  52. jackctl_driver_t *driver;
  53. char option[JACK_PARAM_STRING_MAX+1];
  54. int option_used;
  55. char *name;
  56. };
  57. #define context_ptr ((struct parse_context *)data)
  58. void
  59. jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
  60. {
  61. if (context_ptr->error)
  62. {
  63. return;
  64. }
  65. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  66. {
  67. if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
  68. {
  69. jack_error("xml parse max char data length reached");
  70. context_ptr->error = XML_TRUE;
  71. return;
  72. }
  73. memcpy(context_ptr->option + context_ptr->option_used, s, len);
  74. context_ptr->option_used += len;
  75. }
  76. }
  77. void
  78. jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
  79. {
  80. jackctl_driver_t *driver;
  81. if (context_ptr->error)
  82. {
  83. return;
  84. }
  85. if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
  86. {
  87. jack_error("xml parse max stack depth reached");
  88. context_ptr->error = XML_TRUE;
  89. return;
  90. }
  91. if (strcmp(el, "jack") == 0)
  92. {
  93. //jack_info("<jack>");
  94. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
  95. return;
  96. }
  97. if (strcmp(el, "engine") == 0)
  98. {
  99. //jack_info("<engine>");
  100. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
  101. return;
  102. }
  103. if (strcmp(el, "drivers") == 0)
  104. {
  105. //jack_info("<drivers>");
  106. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
  107. return;
  108. }
  109. if (strcmp(el, "driver") == 0)
  110. {
  111. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  112. {
  113. jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
  114. context_ptr->error = XML_TRUE;
  115. return;
  116. }
  117. //jack_info("<driver>");
  118. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
  119. driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
  120. if (driver == NULL)
  121. {
  122. jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
  123. }
  124. else
  125. {
  126. jack_info("setting for driver \"%s\" found", attr[1]);
  127. }
  128. context_ptr->driver = driver;
  129. return;
  130. }
  131. if (strcmp(el, "option") == 0)
  132. {
  133. //jack_info("<option>");
  134. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  135. {
  136. jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
  137. context_ptr->error = XML_TRUE;
  138. return;
  139. }
  140. context_ptr->name = strdup(attr[1]);
  141. if (context_ptr->name == NULL)
  142. {
  143. jack_error("strdup() failed");
  144. context_ptr->error = XML_TRUE;
  145. return;
  146. }
  147. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
  148. context_ptr->option_used = 0;
  149. return;
  150. }
  151. jack_error("unknown element \"%s\"", el);
  152. context_ptr->error = XML_TRUE;
  153. }
  154. void
  155. jack_controller_settings_callback_elend(void *data, const char *el)
  156. {
  157. if (context_ptr->error)
  158. {
  159. return;
  160. }
  161. //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
  162. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  163. {
  164. context_ptr->option[context_ptr->option_used] = 0;
  165. if (context_ptr->depth == 2 &&
  166. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  167. context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
  168. {
  169. jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
  170. }
  171. if (context_ptr->depth == 3 &&
  172. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  173. context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
  174. context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
  175. context_ptr->driver != NULL)
  176. {
  177. jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
  178. }
  179. }
  180. context_ptr->depth--;
  181. if (context_ptr->name != NULL)
  182. {
  183. free(context_ptr->name);
  184. context_ptr->name = NULL;
  185. }
  186. }
  187. #undef context_ptr
  188. void
  189. jack_controller_settings_load(
  190. struct jack_controller * controller_ptr)
  191. {
  192. XML_Parser parser;
  193. int bytes_read;
  194. void *buffer;
  195. char *filename;
  196. size_t conf_len;
  197. struct stat st;
  198. int fd;
  199. enum XML_Status xmls;
  200. struct parse_context context;
  201. conf_len = strlen(JACKDBUS_CONF);
  202. filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
  203. if (filename == NULL)
  204. {
  205. jack_error("Out of memory.");
  206. goto exit;
  207. }
  208. memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
  209. memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
  210. filename[g_jackdbus_config_dir_len + conf_len] = 0;
  211. jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
  212. if (stat(filename, &st) != 0)
  213. {
  214. jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
  215. }
  216. fd = open(filename, O_RDONLY);
  217. if (fd == -1)
  218. {
  219. jack_error("open() failed to open conf filename.");
  220. goto exit_free_filename;
  221. }
  222. parser = XML_ParserCreate(NULL);
  223. if (parser == NULL)
  224. {
  225. jack_error("XML_ParserCreate() failed to create parser object.");
  226. goto exit_close_file;
  227. }
  228. //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
  229. /* we are expecting that conf file has small enough size to fit in memory */
  230. buffer = XML_GetBuffer(parser, st.st_size);
  231. if (buffer == NULL)
  232. {
  233. jack_error("XML_GetBuffer() failed.");
  234. goto exit_free_parser;
  235. }
  236. bytes_read = read(fd, buffer, st.st_size);
  237. if (bytes_read != st.st_size)
  238. {
  239. jack_error("read() returned unexpected result.");
  240. goto exit_free_parser;
  241. }
  242. context.controller_ptr = controller_ptr;
  243. context.error = XML_FALSE;
  244. context.depth = -1;
  245. context.name = NULL;
  246. XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
  247. XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
  248. XML_SetUserData(parser, &context);
  249. xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
  250. if (xmls == XML_STATUS_ERROR)
  251. {
  252. jack_error("XML_ParseBuffer() failed.");
  253. goto exit_free_parser;
  254. }
  255. exit_free_parser:
  256. XML_ParserFree(parser);
  257. exit_close_file:
  258. close(fd);
  259. exit_free_filename:
  260. free(filename);
  261. exit:
  262. return;
  263. }