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.

328 lines
8.2KB

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