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.

370 lines
9.8KB

  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 PARSE_CONTEXT_INTERNALS 5
  46. #define PARSE_CONTEXT_INTERNAL 6
  47. #define MAX_STACK_DEPTH 10
  48. struct parse_context
  49. {
  50. struct jack_controller *controller_ptr;
  51. XML_Bool error;
  52. unsigned int element[MAX_STACK_DEPTH];
  53. signed int depth;
  54. jackctl_driver_t *driver;
  55. jackctl_internal_t *internal;
  56. char option[JACK_PARAM_STRING_MAX+1];
  57. int option_used;
  58. char *name;
  59. };
  60. #define context_ptr ((struct parse_context *)data)
  61. void
  62. jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
  63. {
  64. if (context_ptr->error)
  65. {
  66. return;
  67. }
  68. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  69. {
  70. if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
  71. {
  72. jack_error("xml parse max char data length reached");
  73. context_ptr->error = XML_TRUE;
  74. return;
  75. }
  76. memcpy(context_ptr->option + context_ptr->option_used, s, len);
  77. context_ptr->option_used += len;
  78. }
  79. }
  80. void
  81. jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
  82. {
  83. jackctl_driver_t *driver;
  84. jackctl_internal_t *internal;
  85. if (context_ptr->error)
  86. {
  87. return;
  88. }
  89. if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
  90. {
  91. jack_error("xml parse max stack depth reached");
  92. context_ptr->error = XML_TRUE;
  93. return;
  94. }
  95. if (strcmp(el, "jack") == 0)
  96. {
  97. //jack_info("<jack>");
  98. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
  99. return;
  100. }
  101. if (strcmp(el, "engine") == 0)
  102. {
  103. //jack_info("<engine>");
  104. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
  105. return;
  106. }
  107. if (strcmp(el, "drivers") == 0)
  108. {
  109. //jack_info("<drivers>");
  110. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
  111. return;
  112. }
  113. if (strcmp(el, "internals") == 0)
  114. {
  115. //jack_info("<internals>");
  116. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNALS;
  117. return;
  118. }
  119. if (strcmp(el, "driver") == 0)
  120. {
  121. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  122. {
  123. jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
  124. context_ptr->error = XML_TRUE;
  125. return;
  126. }
  127. //jack_info("<driver>");
  128. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
  129. driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
  130. if (driver == NULL)
  131. {
  132. jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
  133. }
  134. else
  135. {
  136. jack_info("setting for driver \"%s\" found", attr[1]);
  137. }
  138. context_ptr->driver = driver;
  139. return;
  140. }
  141. if (strcmp(el, "internal") == 0)
  142. {
  143. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  144. {
  145. jack_error("<internal> XML element must contain exactly one attribute, named \"name\"");
  146. context_ptr->error = XML_TRUE;
  147. return;
  148. }
  149. //jack_info("<internal>");
  150. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNAL;
  151. internal = jack_controller_find_internal(context_ptr->controller_ptr->server, attr[1]);
  152. if (internal == NULL)
  153. {
  154. jack_error("ignoring settings for unknown internal \"%s\"", attr[1]);
  155. }
  156. else
  157. {
  158. jack_info("setting for internal \"%s\" found", attr[1]);
  159. }
  160. context_ptr->internal = internal;
  161. return;
  162. }
  163. if (strcmp(el, "option") == 0)
  164. {
  165. //jack_info("<option>");
  166. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  167. {
  168. jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
  169. context_ptr->error = XML_TRUE;
  170. return;
  171. }
  172. context_ptr->name = strdup(attr[1]);
  173. if (context_ptr->name == NULL)
  174. {
  175. jack_error("strdup() failed");
  176. context_ptr->error = XML_TRUE;
  177. return;
  178. }
  179. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
  180. context_ptr->option_used = 0;
  181. return;
  182. }
  183. jack_error("unknown element \"%s\"", el);
  184. context_ptr->error = XML_TRUE;
  185. }
  186. void
  187. jack_controller_settings_callback_elend(void *data, const char *el)
  188. {
  189. if (context_ptr->error)
  190. {
  191. return;
  192. }
  193. //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
  194. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  195. {
  196. context_ptr->option[context_ptr->option_used] = 0;
  197. if (context_ptr->depth == 2 &&
  198. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  199. context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
  200. {
  201. jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
  202. }
  203. if (context_ptr->depth == 3 &&
  204. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  205. context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
  206. context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
  207. context_ptr->driver != NULL)
  208. {
  209. jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
  210. }
  211. if (context_ptr->depth == 3 &&
  212. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  213. context_ptr->element[1] == PARSE_CONTEXT_INTERNALS &&
  214. context_ptr->element[2] == PARSE_CONTEXT_INTERNAL &&
  215. context_ptr->internal != NULL)
  216. {
  217. jack_controller_settings_set_internal_option(context_ptr->internal, context_ptr->name, context_ptr->option);
  218. }
  219. }
  220. context_ptr->depth--;
  221. if (context_ptr->name != NULL)
  222. {
  223. free(context_ptr->name);
  224. context_ptr->name = NULL;
  225. }
  226. }
  227. #undef context_ptr
  228. void
  229. jack_controller_settings_load(
  230. struct jack_controller * controller_ptr)
  231. {
  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;
  241. conf_len = strlen(JACKDBUS_CONF);
  242. filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
  243. if (filename == NULL)
  244. {
  245. jack_error("Out of memory.");
  246. goto exit;
  247. }
  248. memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
  249. memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
  250. filename[g_jackdbus_config_dir_len + conf_len] = 0;
  251. jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
  252. if (stat(filename, &st) != 0)
  253. {
  254. jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
  255. }
  256. fd = open(filename, O_RDONLY);
  257. if (fd == -1)
  258. {
  259. jack_error("open() failed to open conf filename.");
  260. goto exit_free_filename;
  261. }
  262. parser = XML_ParserCreate(NULL);
  263. if (parser == NULL)
  264. {
  265. jack_error("XML_ParserCreate() failed to create parser object.");
  266. goto exit_close_file;
  267. }
  268. //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
  269. /* we are expecting that conf file has small enough size to fit in memory */
  270. buffer = XML_GetBuffer(parser, st.st_size);
  271. if (buffer == NULL)
  272. {
  273. jack_error("XML_GetBuffer() failed.");
  274. goto exit_free_parser;
  275. }
  276. bytes_read = read(fd, buffer, st.st_size);
  277. if (bytes_read != st.st_size)
  278. {
  279. jack_error("read() returned unexpected result.");
  280. goto exit_free_parser;
  281. }
  282. context.controller_ptr = controller_ptr;
  283. context.error = XML_FALSE;
  284. context.depth = -1;
  285. context.name = NULL;
  286. XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
  287. XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
  288. XML_SetUserData(parser, &context);
  289. xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
  290. if (xmls == XML_STATUS_ERROR)
  291. {
  292. jack_error("XML_ParseBuffer() failed.");
  293. goto exit_free_parser;
  294. }
  295. exit_free_parser:
  296. XML_ParserFree(parser);
  297. exit_close_file:
  298. close(fd);
  299. exit_free_filename:
  300. free(filename);
  301. exit:
  302. return;
  303. }