--- doc/messaging_api.txt | 5 ++ src/map-file | 4 + src/pulse/message-params.c | 202 +++++++++++++++++++++++++++++++++++++++++++++ src/pulse/message-params.h | 12 +++ 4 files changed, 223 insertions(+) diff --git a/doc/messaging_api.txt b/doc/messaging_api.txt index d080b783..57a92f58 100644 --- a/doc/messaging_api.txt +++ b/doc/messaging_api.txt @@ -53,6 +53,11 @@ pa_message_param_read_double() - read a double from a parameter list pa_message_param_read_int64() - read an integer from a parameter list pa_message_param_read_uint64() - read an unsigned from a parameter list pa_message_param_read_bool() - read a boolean from a parameter list +pa_message_param_read_double_array() - read an array of double from list +pa_message_param_read_int64_array() - read an array of int64 from list +pa_message_param_read_uint64_array() - read an array of uint64 from list +pa_message_param_read_string_array() - read an array of strings from a list + All read functions return 1 on success, 0 if end of string is found and -1 on parse error. Additionally, for the numeric/boolean read functions, 2 is returned diff --git a/src/map-file b/src/map-file index ab8c21c6..88d892ef 100644 --- a/src/map-file +++ b/src/map-file @@ -230,9 +230,13 @@ pa_message_param_end_list; pa_message_param_new; pa_message_param_read_bool; pa_message_param_read_double; +pa_message_param_read_double_array; pa_message_param_read_int64; +pa_message_param_read_int64_array; pa_message_param_read_string; +pa_message_param_read_string_array; pa_message_param_read_uint64; +pa_message_param_read_uint64_array; pa_message_param_split_list; pa_message_param_to_string; pa_message_param_write_bool; diff --git a/src/pulse/message-params.c b/src/pulse/message-params.c index 93972399..b9846863 100644 --- a/src/pulse/message-params.c +++ b/src/pulse/message-params.c @@ -38,6 +38,8 @@ struct pa_message_param { pa_strbuf *buffer; }; +/* Helper functions */ + /* Remove escaping from a string */ static char *unescape(char *value) { char *tmp; @@ -62,6 +64,59 @@ static char *unescape(char *value) { return value; } +/* Count number of top level elements in parameter list */ +static int count_elements(const char *c) { + const char *s; + uint32_t element_count; + bool found_element, found_backslash; + int open_braces; + + if (!c || *c == 0) + return PA_PARAM_LIST_END; + + element_count = 0; + open_braces = 0; + found_element = false; + found_backslash = false; + s = c; + + /* Count elements in list */ + while (*s != 0) { + + /* Skip escaped curly braces. */ + if (*s == '\\') { + found_backslash = true; + s++; + continue; + } + + if (*s == '{' && !found_backslash) { + found_element = true; + open_braces++; + } + if (*s == '}' && !found_backslash) + open_braces--; + + /* unexpected closing brace, parse error */ + if (open_braces < 0) + return PA_PARAM_PARSE_ERROR; + + if (open_braces == 0 && found_element) { + element_count++; + found_element = false; + } + + found_backslash = false; + s++; + } + + /* missing closing brace, parse error */ + if (open_braces > 0) + return PA_PARAM_PARSE_ERROR; + + return element_count; +} + /* Read functions */ /* Split the specified string into elements. An element is defined as @@ -300,6 +355,153 @@ int pa_message_param_read_bool(char *c, bool *result, void **state) { return PA_PARAM_OK; } +/* Converts a parameter list to a string array. Escaping is removed + * from a string if the string does not contain a list. If allocate + * is true, new strings will be allocated, otherwise pointers to + * sub-strings within c will be returned. */ +int pa_message_param_read_string_array(char *c, char ***parameter_list, bool allocate) { + char *start_pos; + void *state = NULL; + uint32_t element_count, i; + bool is_unpacked; + int err; + + pa_assert(parameter_list); + + *parameter_list = NULL; + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + *parameter_list = pa_xmalloc0(element_count * sizeof(char *)); + + i = 0; + while ((err = pa_message_param_split_list(c, &start_pos, &is_unpacked, &state)) > 0) { + (*parameter_list)[i] = start_pos; + if (is_unpacked) + (*parameter_list)[i] = unescape(start_pos); + + /* If new strings are allocated, they must be freed by the caller */ + if (allocate) + (*parameter_list)[i] = pa_xstrdup((*parameter_list)[i]); + + i++; + } + + if (err < 0) { + if (allocate) { + for (i = 0; i < element_count; i++) + pa_xfree((*parameter_list)[i]); + } + pa_xfree(*parameter_list); + *parameter_list = NULL; + return PA_PARAM_PARSE_ERROR; + } + + return element_count; +} + +/* Converts a parameter list to a double array. */ +int pa_message_param_read_double_array(char *c, double **parameter_list) { + double value; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(parameter_list); + + *parameter_list = NULL; + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + *parameter_list = pa_xmalloc(element_count * sizeof(double)); + + i = 0; + while ((err = pa_message_param_read_double(c, &value, &state)) > 0) { + (*parameter_list)[i] = value; + i++; + } + + if (err < 0) { + pa_xfree(*parameter_list); + *parameter_list = NULL; + return PA_PARAM_PARSE_ERROR; + } + + return element_count; +} + +/* Converts a parameter list to an int64 array. */ +int pa_message_param_read_int64_array(char *c, int64_t **parameter_list) { + int64_t value; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(parameter_list); + + *parameter_list = NULL; + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + *parameter_list = pa_xmalloc(element_count * sizeof(int64_t)); + + i = 0; + while ((err = pa_message_param_read_int64(c, &value, &state)) > 0) { + (*parameter_list)[i] = value; + i++; + } + + if (err < 0) { + pa_xfree(*parameter_list); + *parameter_list = NULL; + return PA_PARAM_PARSE_ERROR; + } + + return element_count; +} + +/* Converts a parameter list to an uint64 array. */ +int pa_message_param_read_uint64_array(char *c, uint64_t **parameter_list) { + uint64_t value; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(parameter_list); + + *parameter_list = NULL; + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + *parameter_list = pa_xmalloc(element_count * sizeof(uint64_t)); + + i = 0; + while ((err = pa_message_param_read_uint64(c, &value, &state)) > 0) { + (*parameter_list)[i] = value; + i++; + } + + if (err < 0) { + pa_xfree(*parameter_list); + *parameter_list = NULL; + return PA_PARAM_PARSE_ERROR; + } + + return element_count; +} + /* Write functions. The functions are wrapper functions around pa_strbuf, * so that the client does not need to use pa_strbuf directly. */ diff --git a/src/pulse/message-params.h b/src/pulse/message-params.h index f865e236..3ab1e418 100644 --- a/src/pulse/message-params.h +++ b/src/pulse/message-params.h @@ -60,6 +60,18 @@ int pa_message_param_read_uint64(char *c, uint64_t *result, void **state); /** Read a boolean from the parameter list. */ int pa_message_param_read_bool(char *c, bool *result, void **state); +/** Convert message parameter list to string array */ +int pa_message_param_read_string_array(char *c, char ***parameter_list, bool allocate); + +/** Convert message parameter list to double array */ +int pa_message_param_read_double_array(char *c, double **parameter_list); + +/** Convert message parameter list to int64 array */ +int pa_message_param_read_int64_array(char *c, int64_t **parameter_list); + +/** Convert message parameter list to uint64 array */ +int pa_message_param_read_uint64_array(char *c, uint64_t **parameter_list); + /** Write functions */ /** Create a new pa_message_param structure */ -- 2.14.1