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.

318 lines
8.2KB

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