328 lines
8.2 KiB
C
328 lines
8.2 KiB
C
/* -*- Mode: C ; c-basic-offset: 4 -*- */
|
|
/*
|
|
Copyright (C) 2007,2008,2011 Nedko Arnaudov
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <expat.h>
|
|
#include <dbus/dbus.h>
|
|
|
|
#include "controller_internal.h"
|
|
#include "jackdbus.h"
|
|
|
|
bool
|
|
jack_controller_settings_init()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void
|
|
jack_controller_settings_uninit()
|
|
{
|
|
}
|
|
|
|
struct parse_context
|
|
{
|
|
struct jack_controller *controller_ptr;
|
|
XML_Bool error;
|
|
bool option_value_capture;
|
|
char option[JACK_PARAM_STRING_MAX+1];
|
|
int option_used;
|
|
const char * address[PARAM_ADDRESS_SIZE];
|
|
int address_index;
|
|
char * container;
|
|
char *name;
|
|
};
|
|
|
|
#define context_ptr ((struct parse_context *)data)
|
|
|
|
void
|
|
jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
|
|
{
|
|
if (context_ptr->error)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (context_ptr->option_value_capture)
|
|
{
|
|
if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
|
|
{
|
|
jack_error("xml parse max char data length reached");
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
memcpy(context_ptr->option + context_ptr->option_used, s, len);
|
|
context_ptr->option_used += len;
|
|
}
|
|
}
|
|
|
|
void
|
|
jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
|
|
{
|
|
if (context_ptr->error)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (context_ptr->address_index >= PARAM_ADDRESS_SIZE)
|
|
{
|
|
assert(context_ptr->address_index == PARAM_ADDRESS_SIZE);
|
|
jack_error("xml param address max depth reached");
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
//jack_info("<%s>", el);
|
|
|
|
if (strcmp(el, "jack") == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (strcmp(el, PTNODE_ENGINE) == 0)
|
|
{
|
|
context_ptr->address[context_ptr->address_index++] = PTNODE_ENGINE;
|
|
return;
|
|
}
|
|
|
|
if (strcmp(el, PTNODE_DRIVERS) == 0)
|
|
{
|
|
context_ptr->address[context_ptr->address_index++] = PTNODE_DRIVERS;
|
|
return;
|
|
}
|
|
|
|
if (strcmp(el, PTNODE_INTERNALS) == 0)
|
|
{
|
|
context_ptr->address[context_ptr->address_index++] = PTNODE_INTERNALS;
|
|
return;
|
|
}
|
|
|
|
if (strcmp(el, "driver") == 0 ||
|
|
strcmp(el, "internal") == 0)
|
|
{
|
|
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
|
|
{
|
|
jack_error("<%s> XML element must contain exactly one attribute, named \"name\"", el);
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
context_ptr->container = strdup(attr[1]);
|
|
if (context_ptr->container == NULL)
|
|
{
|
|
jack_error("strdup() failed");
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
context_ptr->address[context_ptr->address_index++] = context_ptr->container;
|
|
|
|
return;
|
|
}
|
|
|
|
if (strcmp(el, "option") == 0)
|
|
{
|
|
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
|
|
{
|
|
jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
context_ptr->name = strdup(attr[1]);
|
|
if (context_ptr->name == NULL)
|
|
{
|
|
jack_error("strdup() failed");
|
|
context_ptr->error = XML_TRUE;
|
|
return;
|
|
}
|
|
|
|
context_ptr->address[context_ptr->address_index++] = context_ptr->name;
|
|
context_ptr->option_value_capture = true;
|
|
context_ptr->option_used = 0;
|
|
return;
|
|
}
|
|
|
|
jack_error("unknown element \"%s\"", el);
|
|
context_ptr->error = XML_TRUE;
|
|
}
|
|
|
|
void
|
|
jack_controller_settings_callback_elend(void *data, const char *el)
|
|
{
|
|
int i;
|
|
|
|
if (context_ptr->error)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//jack_info("</%s> (depth = %d)", el, context_ptr->address_index);
|
|
|
|
if (strcmp(el, "option") == 0)
|
|
{
|
|
assert(context_ptr->option_value_capture);
|
|
context_ptr->option[context_ptr->option_used] = 0;
|
|
|
|
for (i = context_ptr->address_index; i < PARAM_ADDRESS_SIZE; i++)
|
|
{
|
|
context_ptr->address[context_ptr->address_index] = NULL;
|
|
}
|
|
|
|
jack_controller_deserialize_parameter_value(context_ptr->controller_ptr, context_ptr->address, context_ptr->option);
|
|
|
|
free(context_ptr->name);
|
|
context_ptr->name = NULL;
|
|
context_ptr->option_value_capture = false;
|
|
context_ptr->address_index--;
|
|
}
|
|
else if (context_ptr->container != NULL)
|
|
{
|
|
//jack_info("'%s'", context_ptr->container);
|
|
free(context_ptr->container);
|
|
context_ptr->container = NULL;
|
|
context_ptr->address_index--;
|
|
}
|
|
else if (strcmp(el, PTNODE_ENGINE) == 0 ||
|
|
strcmp(el, PTNODE_DRIVERS) == 0 ||
|
|
strcmp(el, PTNODE_INTERNALS) == 0)
|
|
{
|
|
context_ptr->address_index--;
|
|
}
|
|
else
|
|
{
|
|
//jack_info("no depth decrement");
|
|
}
|
|
}
|
|
|
|
#undef context_ptr
|
|
|
|
void
|
|
jack_controller_settings_load(
|
|
struct jack_controller * controller_ptr)
|
|
{
|
|
XML_Parser parser;
|
|
int bytes_read;
|
|
void *buffer;
|
|
char *filename;
|
|
size_t conf_len;
|
|
struct stat st;
|
|
int fd;
|
|
enum XML_Status xmls;
|
|
struct parse_context context;
|
|
|
|
conf_len = strlen(JACKDBUS_CONF);
|
|
|
|
filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
|
|
if (filename == NULL)
|
|
{
|
|
jack_error("Out of memory.");
|
|
goto exit;
|
|
}
|
|
|
|
memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
|
|
memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
|
|
filename[g_jackdbus_config_dir_len + conf_len] = 0;
|
|
|
|
jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
|
|
|
|
if (stat(filename, &st) != 0)
|
|
{
|
|
jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
|
|
}
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
if (fd == -1)
|
|
{
|
|
jack_error("open() failed to open conf filename.");
|
|
goto exit_free_filename;
|
|
}
|
|
|
|
parser = XML_ParserCreate(NULL);
|
|
if (parser == NULL)
|
|
{
|
|
jack_error("XML_ParserCreate() failed to create parser object.");
|
|
goto exit_close_file;
|
|
}
|
|
|
|
//jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
|
|
|
|
/* we are expecting that conf file has small enough size to fit in memory */
|
|
|
|
buffer = XML_GetBuffer(parser, st.st_size);
|
|
if (buffer == NULL)
|
|
{
|
|
jack_error("XML_GetBuffer() failed.");
|
|
goto exit_free_parser;
|
|
}
|
|
|
|
bytes_read = read(fd, buffer, st.st_size);
|
|
if (bytes_read != st.st_size)
|
|
{
|
|
jack_error("read() returned unexpected result.");
|
|
goto exit_free_parser;
|
|
}
|
|
|
|
context.controller_ptr = controller_ptr;
|
|
context.error = XML_FALSE;
|
|
context.option_value_capture = false;
|
|
context.address_index = 0;
|
|
context.name = NULL;
|
|
context.container = NULL;
|
|
|
|
XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
|
|
XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
|
|
XML_SetUserData(parser, &context);
|
|
|
|
xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
|
|
|
|
free(context.name);
|
|
free(context.container);
|
|
|
|
if (xmls == XML_STATUS_ERROR)
|
|
{
|
|
jack_error("XML_ParseBuffer() failed.");
|
|
goto exit_free_parser;
|
|
}
|
|
|
|
exit_free_parser:
|
|
XML_ParserFree(parser);
|
|
|
|
exit_close_file:
|
|
close(fd);
|
|
|
|
exit_free_filename:
|
|
free(filename);
|
|
|
|
exit:
|
|
return;
|
|
}
|