diff --git a/src/map-file b/src/map-file index 172fd441d..7b1ed5206 100644 --- a/src/map-file +++ b/src/map-file @@ -235,10 +235,14 @@ pa_message_params_free; pa_message_params_new; pa_message_params_read_bool; pa_message_params_read_double; +pa_message_params_read_double_array; pa_message_params_read_int64; +pa_message_params_read_int64_array; pa_message_params_read_raw; pa_message_params_read_string; +pa_message_params_read_string_array; pa_message_params_read_uint64; +pa_message_params_read_uint64_array; pa_message_params_to_string_free; pa_message_params_write_bool; pa_message_params_write_double; diff --git a/src/pulse/message-params.c b/src/pulse/message-params.c index 8885f95e8..7d2dd8020 100644 --- a/src/pulse/message-params.c +++ b/src/pulse/message-params.c @@ -39,6 +39,61 @@ struct pa_message_params { pa_strbuf *buffer; }; +/* Helper functions */ + +/* 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_MESSAGE_PARAMS_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) { + 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_MESSAGE_PARAMS_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_MESSAGE_PARAMS_PARSE_ERROR; + + return element_count; +} + /* Split the specified string into elements. An element is defined as * a sub-string between curly braces. The function is needed to parse * the parameters of messages. Each time it is called it returns the @@ -188,7 +243,7 @@ int pa_message_params_read_double(char *c, double *result, void **state) { if (!is_unpacked) return PA_MESSAGE_PARAMS_PARSE_ERROR; - /* Convert to double */ + /* Get decimal separator for current locale */ locale = localeconv(); /* Replace decimal point with the correct character for the @@ -289,6 +344,122 @@ int pa_message_params_read_bool(char *c, bool *result, void **state) { return PA_MESSAGE_PARAMS_OK; } +/* Converts a parameter list to a string array. Escaping is removed from + * the strings. Returns an array of pointers to sub-strings within c in + * *results. The returned array must be freed, but not the strings + * within the array. The function returns the number of strings in the + * array. */ +int pa_message_params_read_string_array(char *c, const char ***results) { + void *state = NULL; + uint32_t element_count, i; + int err; + const char **values; + + pa_assert(results); + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + values = pa_xmalloc0(element_count * sizeof(char *)); + + for (i = 0; (err = pa_message_params_read_string(c, &(values[i]), &state)) > 0; i++) + ; + + if (err < 0) { + pa_xfree(values); + return PA_MESSAGE_PARAMS_PARSE_ERROR; + } + + *results = values; + return element_count; +} + +/* Converts a parameter list to a double array. */ +int pa_message_params_read_double_array(char *c, double **results) { + double *values; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(results); + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + values = pa_xmalloc0(element_count * sizeof(double)); + + for (i = 0; (err = pa_message_params_read_double(c, &(values[i]), &state)) > 0; i++) + ; + + if (err < 0) { + pa_xfree(values); + return PA_MESSAGE_PARAMS_PARSE_ERROR; + } + + *results = values; + return element_count; +} + +/* Converts a parameter list to an int64 array. */ +int pa_message_params_read_int64_array(char *c, int64_t **results) { + int64_t *values; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(results); + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + values = pa_xmalloc0(element_count * sizeof(int64_t)); + + for (i = 0; (err = pa_message_params_read_int64(c, &(values[i]), &state)) > 0; i++) + ; + + if (err < 0) { + pa_xfree(values); + return PA_MESSAGE_PARAMS_PARSE_ERROR; + } + + *results = values; + return element_count; +} + +/* Converts a parameter list to an uint64 array. */ +int pa_message_params_read_uint64_array(char *c, uint64_t **results) { + uint64_t *values; + void *state = NULL; + uint32_t element_count, i; + int err; + + pa_assert(results); + + /* Count elements, return if no element was found or parse error. */ + if ((element_count = count_elements(c)) <= 0) + return element_count; + + /* Allocate array */ + values = pa_xmalloc0(element_count * sizeof(uint64_t)); + + for (i = 0; (err = pa_message_params_read_uint64(c, &(values[i]), &state)) > 0; i++) + ; + + if (err < 0) { + pa_xfree(values); + return PA_MESSAGE_PARAMS_PARSE_ERROR; + } + + *results = values; + 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 a2e0f9e8d..3d90eac3c 100644 --- a/src/pulse/message-params.h +++ b/src/pulse/message-params.h @@ -36,7 +36,12 @@ * the callback, it must be copied using pa_xstrdup(). * When a read function is called, the state pointer is advanced to the * next list element. The variable state points to should be initialized - * to NULL before the first call.\n + * to NULL before the first call. + * All read functions except read_raw() preserve a default value passed + * in result if the call fails. For the array functions, results must be + * initialized prior to the call either to NULL or to an array with default + * values. If the function succeeds, the default array will be freed and + * the number of elements in the result array is returned.\n\n * Write functions operate on a pa_message_params structure which is a * wrapper for pa_strbuf. A parameter list or sub-list is started by a * call to begin_list() and ended by a call to end_list(). @@ -69,9 +74,19 @@ int pa_message_params_read_bool(char *c, bool *result, void **state); /** Read a double from parameter list in c. \since 15.0 */ int pa_message_params_read_double(char *c, double *result, void **state); +/** Converts a parameter list to a double array. Empty elements in the parameter + * list are treated as error. Before the call, results must be initialized, either + * to NULL or to an array with default values. \since 15.0 */ +int pa_message_params_read_double_array(char *c, double **results); + /** Read an integer from parameter list in c. \since 15.0 */ int pa_message_params_read_int64(char *c, int64_t *result, void **state); +/** Converts a parameter list to an int64 array. Empty elements in the parameter + * list are treated as error. Before the call, results must be initialized, either + * to NULL or to an array with default values. \since 15.0 */ +int pa_message_params_read_int64_array(char *c, int64_t **results); + /** Read raw data from parameter list in c. Used to split a message parameter * string into list elements. The string returned in *result must not be freed. \since 15.0 */ int pa_message_params_read_raw(char *c, char **result, void **state); @@ -80,9 +95,21 @@ int pa_message_params_read_raw(char *c, char **result, void **state); * will be unescaped. \since 15.0 */ int pa_message_params_read_string(char *c, const char **result, void **state); +/** Convert a parameter list to a string array. Escaping is removed from + * the strings. Returns an array of pointers to sub-strings within c in + * *results. The returned array must be freed, but not the strings + * within the array. Before the call, results must be initialized, either + * to NULL or to an array with default values. \since 15.0 */ +int pa_message_params_read_string_array(char *c, const char ***results); + /** Read an unsigned integer from parameter list in c. \since 15.0 */ int pa_message_params_read_uint64(char *c, uint64_t *result, void **state); +/** Converts a parameter list to an uint64 array. Empty elements in the parameter + * list are treated as error. Before the call, results must be initialized, either + * to NULL or to an array with default values. \since 15.0 */ +int pa_message_params_read_uint64_array(char *c, uint64_t **results); + /** @} */ /** @{ \name Write functions */