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.

1269 lines
33KB

  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. }
  261. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  262. /*
  263. Copyright (C) 2007,2008 Nedko Arnaudov
  264. This program is free software; you can redistribute it and/or modify
  265. it under the terms of the GNU General Public License as published by
  266. the Free Software Foundation; either version 2 of the License.
  267. This program is distributed in the hope that it will be useful,
  268. but WITHOUT ANY WARRANTY; without even the implied warranty of
  269. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  270. GNU General Public License for more details.
  271. You should have received a copy of the GNU General Public License
  272. along with this program; if not, write to the Free Software
  273. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  274. */
  275. #include <stdbool.h>
  276. #include <stdint.h>
  277. #include <sys/types.h>
  278. #include <sys/stat.h>
  279. #include <unistd.h>
  280. #include <fcntl.h>
  281. #include <errno.h>
  282. #include <string.h>
  283. #include <expat.h>
  284. #include <dbus/dbus.h>
  285. #include "controller_internal.h"
  286. #include "jackdbus.h"
  287. bool
  288. jack_controller_settings_init()
  289. {
  290. return true;
  291. }
  292. void
  293. jack_controller_settings_uninit()
  294. {
  295. }
  296. #define PARSE_CONTEXT_ROOT 0
  297. #define PARSE_CONTEXT_JACK 1
  298. #define PARSE_CONTEXT_ENGINE 1
  299. #define PARSE_CONTEXT_DRIVERS 2
  300. #define PARSE_CONTEXT_DRIVER 3
  301. #define PARSE_CONTEXT_OPTION 4
  302. #define MAX_STACK_DEPTH 10
  303. struct parse_context
  304. {
  305. struct jack_controller *controller_ptr;
  306. XML_Bool error;
  307. unsigned int element[MAX_STACK_DEPTH];
  308. signed int depth;
  309. jackctl_driver_t *driver;
  310. char option[JACK_PARAM_STRING_MAX+1];
  311. int option_used;
  312. char *name;
  313. };
  314. #define context_ptr ((struct parse_context *)data)
  315. void
  316. jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
  317. {
  318. if (context_ptr->error)
  319. {
  320. return;
  321. }
  322. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  323. {
  324. if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
  325. {
  326. jack_error("xml parse max char data length reached");
  327. context_ptr->error = XML_TRUE;
  328. return;
  329. }
  330. memcpy(context_ptr->option + context_ptr->option_used, s, len);
  331. context_ptr->option_used += len;
  332. }
  333. }
  334. void
  335. jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
  336. {
  337. jackctl_driver_t *driver;
  338. if (context_ptr->error)
  339. {
  340. return;
  341. }
  342. if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
  343. {
  344. jack_error("xml parse max stack depth reached");
  345. context_ptr->error = XML_TRUE;
  346. return;
  347. }
  348. if (strcmp(el, "jack") == 0)
  349. {
  350. //jack_info("<jack>");
  351. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
  352. return;
  353. }
  354. if (strcmp(el, "engine") == 0)
  355. {
  356. //jack_info("<engine>");
  357. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
  358. return;
  359. }
  360. if (strcmp(el, "drivers") == 0)
  361. {
  362. //jack_info("<drivers>");
  363. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
  364. return;
  365. }
  366. if (strcmp(el, "driver") == 0)
  367. {
  368. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  369. {
  370. jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
  371. context_ptr->error = XML_TRUE;
  372. return;
  373. }
  374. //jack_info("<driver>");
  375. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
  376. driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
  377. if (driver == NULL)
  378. {
  379. jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
  380. }
  381. else
  382. {
  383. jack_info("setting for driver \"%s\" found", attr[1]);
  384. }
  385. context_ptr->driver = driver;
  386. return;
  387. }
  388. if (strcmp(el, "option") == 0)
  389. {
  390. //jack_info("<option>");
  391. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  392. {
  393. jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
  394. context_ptr->error = XML_TRUE;
  395. return;
  396. }
  397. context_ptr->name = strdup(attr[1]);
  398. if (context_ptr->name == NULL)
  399. {
  400. jack_error("strdup() failed");
  401. context_ptr->error = XML_TRUE;
  402. return;
  403. }
  404. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
  405. context_ptr->option_used = 0;
  406. return;
  407. }
  408. jack_error("unknown element \"%s\"", el);
  409. context_ptr->error = XML_TRUE;
  410. }
  411. void
  412. jack_controller_settings_callback_elend(void *data, const char *el)
  413. {
  414. if (context_ptr->error)
  415. {
  416. return;
  417. }
  418. //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
  419. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  420. {
  421. context_ptr->option[context_ptr->option_used] = 0;
  422. if (context_ptr->depth == 2 &&
  423. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  424. context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
  425. {
  426. jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
  427. }
  428. if (context_ptr->depth == 3 &&
  429. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  430. context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
  431. context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
  432. context_ptr->driver != NULL)
  433. {
  434. jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
  435. }
  436. }
  437. context_ptr->depth--;
  438. if (context_ptr->name != NULL)
  439. {
  440. free(context_ptr->name);
  441. context_ptr->name = NULL;
  442. }
  443. }
  444. #undef context_ptr
  445. void
  446. jack_controller_settings_load(
  447. struct jack_controller * controller_ptr)
  448. {
  449. XML_Parser parser;
  450. int bytes_read;
  451. void *buffer;
  452. char *filename;
  453. size_t conf_len;
  454. struct stat st;
  455. int fd;
  456. enum XML_Status xmls;
  457. struct parse_context context;
  458. conf_len = strlen(JACKDBUS_CONF);
  459. filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
  460. if (filename == NULL)
  461. {
  462. jack_error("Out of memory.");
  463. goto exit;
  464. }
  465. memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
  466. memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
  467. filename[g_jackdbus_config_dir_len + conf_len] = 0;
  468. jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
  469. if (stat(filename, &st) != 0)
  470. {
  471. jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
  472. }
  473. fd = open(filename, O_RDONLY);
  474. if (fd == -1)
  475. {
  476. jack_error("open() failed to open conf filename.");
  477. goto exit_free_filename;
  478. }
  479. parser = XML_ParserCreate(NULL);
  480. if (parser == NULL)
  481. {
  482. jack_error("XML_ParserCreate() failed to create parser object.");
  483. goto exit_close_file;
  484. }
  485. //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
  486. /* we are expecting that conf file has small enough size to fit in memory */
  487. buffer = XML_GetBuffer(parser, st.st_size);
  488. if (buffer == NULL)
  489. {
  490. jack_error("XML_GetBuffer() failed.");
  491. goto exit_free_parser;
  492. }
  493. bytes_read = read(fd, buffer, st.st_size);
  494. if (bytes_read != st.st_size)
  495. {
  496. jack_error("read() returned unexpected result.");
  497. goto exit_free_parser;
  498. }
  499. context.controller_ptr = controller_ptr;
  500. context.error = XML_FALSE;
  501. context.depth = -1;
  502. context.name = NULL;
  503. XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
  504. XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
  505. XML_SetUserData(parser, &context);
  506. xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
  507. if (xmls == XML_STATUS_ERROR)
  508. {
  509. jack_error("XML_ParseBuffer() failed.");
  510. goto exit_free_parser;
  511. }
  512. exit_free_parser:
  513. XML_ParserFree(parser);
  514. exit_close_file:
  515. close(fd);
  516. exit_free_filename:
  517. free(filename);
  518. exit:
  519. return;
  520. }
  521. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  522. /*
  523. Copyright (C) 2007,2008 Nedko Arnaudov
  524. This program is free software; you can redistribute it and/or modify
  525. it under the terms of the GNU General Public License as published by
  526. the Free Software Foundation; either version 2 of the License.
  527. This program is distributed in the hope that it will be useful,
  528. but WITHOUT ANY WARRANTY; without even the implied warranty of
  529. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  530. GNU General Public License for more details.
  531. You should have received a copy of the GNU General Public License
  532. along with this program; if not, write to the Free Software
  533. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  534. */
  535. #include <stdbool.h>
  536. #include <stdint.h>
  537. #include <sys/types.h>
  538. #include <sys/stat.h>
  539. #include <unistd.h>
  540. #include <fcntl.h>
  541. #include <errno.h>
  542. #include <string.h>
  543. #include <expat.h>
  544. #include <dbus/dbus.h>
  545. #include "controller_internal.h"
  546. #include "jackdbus.h"
  547. bool
  548. jack_controller_settings_init()
  549. {
  550. return true;
  551. }
  552. void
  553. jack_controller_settings_uninit()
  554. {
  555. }
  556. #define PARSE_CONTEXT_ROOT 0
  557. #define PARSE_CONTEXT_JACK 1
  558. #define PARSE_CONTEXT_ENGINE 1
  559. #define PARSE_CONTEXT_DRIVERS 2
  560. #define PARSE_CONTEXT_DRIVER 3
  561. #define PARSE_CONTEXT_OPTION 4
  562. #define MAX_STACK_DEPTH 10
  563. struct parse_context
  564. {
  565. struct jack_controller *controller_ptr;
  566. XML_Bool error;
  567. unsigned int element[MAX_STACK_DEPTH];
  568. signed int depth;
  569. jackctl_driver_t *driver;
  570. char option[JACK_PARAM_STRING_MAX+1];
  571. int option_used;
  572. char *name;
  573. };
  574. #define context_ptr ((struct parse_context *)data)
  575. void
  576. jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
  577. {
  578. if (context_ptr->error)
  579. {
  580. return;
  581. }
  582. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  583. {
  584. if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
  585. {
  586. jack_error("xml parse max char data length reached");
  587. context_ptr->error = XML_TRUE;
  588. return;
  589. }
  590. memcpy(context_ptr->option + context_ptr->option_used, s, len);
  591. context_ptr->option_used += len;
  592. }
  593. }
  594. void
  595. jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
  596. {
  597. jackctl_driver_t *driver;
  598. if (context_ptr->error)
  599. {
  600. return;
  601. }
  602. if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
  603. {
  604. jack_error("xml parse max stack depth reached");
  605. context_ptr->error = XML_TRUE;
  606. return;
  607. }
  608. if (strcmp(el, "jack") == 0)
  609. {
  610. //jack_info("<jack>");
  611. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
  612. return;
  613. }
  614. if (strcmp(el, "engine") == 0)
  615. {
  616. //jack_info("<engine>");
  617. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
  618. return;
  619. }
  620. if (strcmp(el, "drivers") == 0)
  621. {
  622. //jack_info("<drivers>");
  623. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
  624. return;
  625. }
  626. if (strcmp(el, "driver") == 0)
  627. {
  628. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  629. {
  630. jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
  631. context_ptr->error = XML_TRUE;
  632. return;
  633. }
  634. //jack_info("<driver>");
  635. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
  636. driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
  637. if (driver == NULL)
  638. {
  639. jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
  640. }
  641. else
  642. {
  643. jack_info("setting for driver \"%s\" found", attr[1]);
  644. }
  645. context_ptr->driver = driver;
  646. return;
  647. }
  648. if (strcmp(el, "option") == 0)
  649. {
  650. //jack_info("<option>");
  651. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  652. {
  653. jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
  654. context_ptr->error = XML_TRUE;
  655. return;
  656. }
  657. context_ptr->name = strdup(attr[1]);
  658. if (context_ptr->name == NULL)
  659. {
  660. jack_error("strdup() failed");
  661. context_ptr->error = XML_TRUE;
  662. return;
  663. }
  664. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
  665. context_ptr->option_used = 0;
  666. return;
  667. }
  668. jack_error("unknown element \"%s\"", el);
  669. context_ptr->error = XML_TRUE;
  670. }
  671. void
  672. jack_controller_settings_callback_elend(void *data, const char *el)
  673. {
  674. if (context_ptr->error)
  675. {
  676. return;
  677. }
  678. //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
  679. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  680. {
  681. context_ptr->option[context_ptr->option_used] = 0;
  682. if (context_ptr->depth == 2 &&
  683. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  684. context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
  685. {
  686. jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
  687. }
  688. if (context_ptr->depth == 3 &&
  689. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  690. context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
  691. context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
  692. context_ptr->driver != NULL)
  693. {
  694. jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
  695. }
  696. }
  697. context_ptr->depth--;
  698. if (context_ptr->name != NULL)
  699. {
  700. free(context_ptr->name);
  701. context_ptr->name = NULL;
  702. }
  703. }
  704. #undef context_ptr
  705. void
  706. jack_controller_settings_load(
  707. struct jack_controller * controller_ptr)
  708. {
  709. XML_Parser parser;
  710. int bytes_read;
  711. void *buffer;
  712. char *filename;
  713. size_t conf_len;
  714. struct stat st;
  715. int fd;
  716. enum XML_Status xmls;
  717. struct parse_context context;
  718. conf_len = strlen(JACKDBUS_CONF);
  719. filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
  720. if (filename == NULL)
  721. {
  722. jack_error("Out of memory.");
  723. goto exit;
  724. }
  725. memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
  726. memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
  727. filename[g_jackdbus_config_dir_len + conf_len] = 0;
  728. jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
  729. if (stat(filename, &st) != 0)
  730. {
  731. jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
  732. }
  733. fd = open(filename, O_RDONLY);
  734. if (fd == -1)
  735. {
  736. jack_error("open() failed to open conf filename.");
  737. goto exit_free_filename;
  738. }
  739. parser = XML_ParserCreate(NULL);
  740. if (parser == NULL)
  741. {
  742. jack_error("XML_ParserCreate() failed to create parser object.");
  743. goto exit_close_file;
  744. }
  745. //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
  746. /* we are expecting that conf file has small enough size to fit in memory */
  747. buffer = XML_GetBuffer(parser, st.st_size);
  748. if (buffer == NULL)
  749. {
  750. jack_error("XML_GetBuffer() failed.");
  751. goto exit_free_parser;
  752. }
  753. bytes_read = read(fd, buffer, st.st_size);
  754. if (bytes_read != st.st_size)
  755. {
  756. jack_error("read() returned unexpected result.");
  757. goto exit_free_parser;
  758. }
  759. context.controller_ptr = controller_ptr;
  760. context.error = XML_FALSE;
  761. context.depth = -1;
  762. context.name = NULL;
  763. XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
  764. XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
  765. XML_SetUserData(parser, &context);
  766. xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
  767. if (xmls == XML_STATUS_ERROR)
  768. {
  769. jack_error("XML_ParseBuffer() failed.");
  770. goto exit_free_parser;
  771. }
  772. exit_free_parser:
  773. XML_ParserFree(parser);
  774. exit_close_file:
  775. close(fd);
  776. exit_free_filename:
  777. free(filename);
  778. exit:
  779. return;
  780. }
  781. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  782. /*
  783. Copyright (C) 2007,2008 Nedko Arnaudov
  784. This program is free software; you can redistribute it and/or modify
  785. it under the terms of the GNU General Public License as published by
  786. the Free Software Foundation; either version 2 of the License.
  787. This program is distributed in the hope that it will be useful,
  788. but WITHOUT ANY WARRANTY; without even the implied warranty of
  789. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  790. GNU General Public License for more details.
  791. You should have received a copy of the GNU General Public License
  792. along with this program; if not, write to the Free Software
  793. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  794. */
  795. #include <stdbool.h>
  796. #include <stdint.h>
  797. #include <sys/types.h>
  798. #include <sys/stat.h>
  799. #include <unistd.h>
  800. #include <fcntl.h>
  801. #include <errno.h>
  802. #include <string.h>
  803. #include <expat.h>
  804. #include <dbus/dbus.h>
  805. #include "controller_internal.h"
  806. #include "jackdbus.h"
  807. bool
  808. jack_controller_settings_init()
  809. {
  810. return true;
  811. }
  812. void
  813. jack_controller_settings_uninit()
  814. {
  815. }
  816. #define PARSE_CONTEXT_ROOT 0
  817. #define PARSE_CONTEXT_JACK 1
  818. #define PARSE_CONTEXT_ENGINE 1
  819. #define PARSE_CONTEXT_DRIVERS 2
  820. #define PARSE_CONTEXT_DRIVER 3
  821. #define PARSE_CONTEXT_OPTION 4
  822. #define MAX_STACK_DEPTH 10
  823. struct parse_context
  824. {
  825. struct jack_controller *controller_ptr;
  826. XML_Bool error;
  827. unsigned int element[MAX_STACK_DEPTH];
  828. signed int depth;
  829. jackctl_driver_t *driver;
  830. char option[JACK_PARAM_STRING_MAX+1];
  831. int option_used;
  832. char *name;
  833. };
  834. #define context_ptr ((struct parse_context *)data)
  835. void
  836. jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
  837. {
  838. if (context_ptr->error)
  839. {
  840. return;
  841. }
  842. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  843. {
  844. if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
  845. {
  846. jack_error("xml parse max char data length reached");
  847. context_ptr->error = XML_TRUE;
  848. return;
  849. }
  850. memcpy(context_ptr->option + context_ptr->option_used, s, len);
  851. context_ptr->option_used += len;
  852. }
  853. }
  854. void
  855. jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
  856. {
  857. jackctl_driver_t *driver;
  858. if (context_ptr->error)
  859. {
  860. return;
  861. }
  862. if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
  863. {
  864. jack_error("xml parse max stack depth reached");
  865. context_ptr->error = XML_TRUE;
  866. return;
  867. }
  868. if (strcmp(el, "jack") == 0)
  869. {
  870. //jack_info("<jack>");
  871. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
  872. return;
  873. }
  874. if (strcmp(el, "engine") == 0)
  875. {
  876. //jack_info("<engine>");
  877. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
  878. return;
  879. }
  880. if (strcmp(el, "drivers") == 0)
  881. {
  882. //jack_info("<drivers>");
  883. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
  884. return;
  885. }
  886. if (strcmp(el, "driver") == 0)
  887. {
  888. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  889. {
  890. jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
  891. context_ptr->error = XML_TRUE;
  892. return;
  893. }
  894. //jack_info("<driver>");
  895. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
  896. driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
  897. if (driver == NULL)
  898. {
  899. jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
  900. }
  901. else
  902. {
  903. jack_info("setting for driver \"%s\" found", attr[1]);
  904. }
  905. context_ptr->driver = driver;
  906. return;
  907. }
  908. if (strcmp(el, "option") == 0)
  909. {
  910. //jack_info("<option>");
  911. if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
  912. {
  913. jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
  914. context_ptr->error = XML_TRUE;
  915. return;
  916. }
  917. context_ptr->name = strdup(attr[1]);
  918. if (context_ptr->name == NULL)
  919. {
  920. jack_error("strdup() failed");
  921. context_ptr->error = XML_TRUE;
  922. return;
  923. }
  924. context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
  925. context_ptr->option_used = 0;
  926. return;
  927. }
  928. jack_error("unknown element \"%s\"", el);
  929. context_ptr->error = XML_TRUE;
  930. }
  931. void
  932. jack_controller_settings_callback_elend(void *data, const char *el)
  933. {
  934. if (context_ptr->error)
  935. {
  936. return;
  937. }
  938. //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
  939. if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
  940. {
  941. context_ptr->option[context_ptr->option_used] = 0;
  942. if (context_ptr->depth == 2 &&
  943. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  944. context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
  945. {
  946. jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
  947. }
  948. if (context_ptr->depth == 3 &&
  949. context_ptr->element[0] == PARSE_CONTEXT_JACK &&
  950. context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
  951. context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
  952. context_ptr->driver != NULL)
  953. {
  954. jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
  955. }
  956. }
  957. context_ptr->depth--;
  958. if (context_ptr->name != NULL)
  959. {
  960. free(context_ptr->name);
  961. context_ptr->name = NULL;
  962. }
  963. }
  964. #undef context_ptr
  965. void
  966. jack_controller_settings_load(
  967. struct jack_controller * controller_ptr)
  968. {
  969. XML_Parser parser;
  970. int bytes_read;
  971. void *buffer;
  972. char *filename;
  973. size_t conf_len;
  974. struct stat st;
  975. int fd;
  976. enum XML_Status xmls;
  977. struct parse_context context;
  978. conf_len = strlen(JACKDBUS_CONF);
  979. filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
  980. if (filename == NULL)
  981. {
  982. jack_error("Out of memory.");
  983. goto exit;
  984. }
  985. memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
  986. memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
  987. filename[g_jackdbus_config_dir_len + conf_len] = 0;
  988. jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
  989. if (stat(filename, &st) != 0)
  990. {
  991. jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
  992. }
  993. fd = open(filename, O_RDONLY);
  994. if (fd == -1)
  995. {
  996. jack_error("open() failed to open conf filename.");
  997. goto exit_free_filename;
  998. }
  999. parser = XML_ParserCreate(NULL);
  1000. if (parser == NULL)
  1001. {
  1002. jack_error("XML_ParserCreate() failed to create parser object.");
  1003. goto exit_close_file;
  1004. }
  1005. //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
  1006. /* we are expecting that conf file has small enough size to fit in memory */
  1007. buffer = XML_GetBuffer(parser, st.st_size);
  1008. if (buffer == NULL)
  1009. {
  1010. jack_error("XML_GetBuffer() failed.");
  1011. goto exit_free_parser;
  1012. }
  1013. bytes_read = read(fd, buffer, st.st_size);
  1014. if (bytes_read != st.st_size)
  1015. {
  1016. jack_error("read() returned unexpected result.");
  1017. goto exit_free_parser;
  1018. }
  1019. context.controller_ptr = controller_ptr;
  1020. context.error = XML_FALSE;
  1021. context.depth = -1;
  1022. context.name = NULL;
  1023. XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
  1024. XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
  1025. XML_SetUserData(parser, &context);
  1026. xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
  1027. if (xmls == XML_STATUS_ERROR)
  1028. {
  1029. jack_error("XML_ParseBuffer() failed.");
  1030. goto exit_free_parser;
  1031. }
  1032. exit_free_parser:
  1033. XML_ParserFree(parser);
  1034. exit_close_file:
  1035. close(fd);
  1036. exit_free_filename:
  1037. free(filename);
  1038. exit:
  1039. return;
  1040. }