exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit d497589c35d3db41c4988ffd1aba83b0d5569b04
parent f434d92a42786bcf4b90600b49d9aef52f9dfeaf
Author: Özgür Kesim <oec@codeblau.de>
Date:   Thu,  1 May 2025 17:08:31 +0200

[json] added helper to parse and pack arrays of unknown length but known element size

Diffstat:
Msrc/include/taler_json_lib.h | 32++++++++++++++++++++++++++++++++
Msrc/json/json_helper.c | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/json/json_pack.c | 9++++++++-
3 files changed, 189 insertions(+), 1 deletion(-)

diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h @@ -781,6 +781,38 @@ TALER_JSON_spec_tuple_of ( * with given number of entries and sizes. * * @param field name of the field for the array, might be NULL + * @param entry_size size of each of the @e num_entries entries in @e entries + * @param[out] num_entries number of entries found in the array + * @param[out] entries pointer to the beginning of @e num_entries continuous entries of size @e entry_size each + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_array_of_data ( + const char *field, + size_t entry_size, + size_t *num_entries, + void **entries); + + +/** + * Generate a parser for an array of unknown length of + * hashes of denomination public keys. + * + * @param field name of the field for the array, might be NULL + * @param[out] num_entries number of entries found in the array + * @param[out] entries pointer to write where the allocated array of @e num_entries entries is + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_array_of_denom_pub_h ( + const char *field, + size_t *num_entries, + struct TALER_DenominationHashP **entries); + + +/** + * Generate a parser for an array of fixed-size elements, + * with an unknown number of entries. + * + * @param field name of the field for the array, might be NULL * @param num_entries number of entries to find in the array * @param entries pointer to the beginning of @e num_entries continuous entries of size @e entry_size each, must be preallocated * @param entry_size size of each of the @e num_entries entries in @e entries diff --git a/src/json/json_helper.c b/src/json/json_helper.c @@ -1735,6 +1735,14 @@ TALER_JSON_spec_kycte (const char *name, } +/** + * Parser combinator of a tuple of parsers, for parsing + * an array of expected size and element types. + * + * @param cls closure, array of specs, NULL terminated + * @param root the json root + * @param[out] spec where to write the data + */ static enum GNUNET_GenericReturnValue parse_tuple_of (void *cls, json_t *root, @@ -1806,6 +1814,15 @@ TALER_JSON_spec_tuple_of ( } +/** + * Parser for an array of unknown length but + * of elements of the same type with the same + * fixed length. + * + * @param cls closure, entry_size + * @param root the json root + * @param spec the output spec + */ static enum GNUNET_GenericReturnValue parse_array_fixed (void *cls, json_t *root, @@ -1883,4 +1900,136 @@ TALER_JSON_spec_array_fixed ( } +/** + * Closure for the parser of arrays of fixed size data + * of unknown array length + */ +struct closure_array_of_data +{ + /* Fixed (known) size per entry */ + size_t entry_size; + + /* Pointer where to put the number of elements + * allocated, i.e. the number of elements in the + * json array. */ + size_t *num_entries; +}; + +/** + * Parser for an array of data of known element size, + * but unknown array length + */ +static enum GNUNET_GenericReturnValue +parse_array_of_data (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + enum GNUNET_GenericReturnValue ret; + struct closure_array_of_data *info = cls; + size_t num_entries; + + if (! json_is_array (root)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num_entries = json_array_size (root); + *info->num_entries = num_entries; + if (0 == num_entries) + { + *(char **) spec->ptr = NULL; + return GNUNET_OK; + } + + spec->ptr_size = num_entries * info->entry_size; + GNUNET_assert (spec->ptr_size > num_entries); + *(char **) spec->ptr = GNUNET_malloc (spec->ptr_size); + + { + json_t *j_entry; + size_t idx; + char *ptr = *(char **) spec->ptr; + char *end = ptr + spec->ptr_size; + + json_array_foreach (root, idx, j_entry) { + struct GNUNET_JSON_Specification esp[] = { + GNUNET_JSON_spec_fixed (NULL, + ptr, + info->entry_size), + GNUNET_JSON_spec_end () + }; + GNUNET_assert (ptr < end); + ret = GNUNET_JSON_parse (j_entry, + esp, + NULL, + NULL); + if (GNUNET_OK != ret) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ptr+=info->entry_size; + } + } + return GNUNET_OK; +} + + +/** + * Cleanup data left from parsing an array of fixed size (but unknown length). + * + * @param cls closure_of_array_data + * @param[out] spec where to free the data + */ +static void +cleaner_array_of_data (void *cls, + struct GNUNET_JSON_Specification *spec) +{ + struct closure_array_of_data *info = cls; + + GNUNET_free (info); +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_array_of_data ( + const char *field, + size_t entry_size, + size_t *num_entries, + void **entries) +{ + struct closure_array_of_data *cls; + + GNUNET_assert (0< entry_size); + GNUNET_assert (NULL != entries); + cls = GNUNET_new (struct closure_array_of_data); + cls->num_entries = num_entries; + cls->entry_size = entry_size; + + struct GNUNET_JSON_Specification ret = { + .parser = &parse_array_of_data, + .ptr = entries, + .field = field, + .cleaner = &cleaner_array_of_data, + .cls = (void *) cls, + }; + + return ret; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_array_of_denom_pub_h ( + const char *field, + size_t *num_entries, + struct TALER_DenominationHashP **entries) +{ + return TALER_JSON_spec_array_of_data ( + field, + sizeof(struct TALER_DenominationHashP), + num_entries, + (void **) entries); +} + + /* end of json/json_helper.c */ diff --git a/src/json/json_pack.c b/src/json/json_pack.c @@ -506,7 +506,14 @@ TALER_JSON_pack_array_of_data ( json_t *j_array = json_array (); GNUNET_assert (NULL!=j_array); - GNUNET_assert (num * size > num); + if (0 == num) + { + ps.object = j_array; + return ps; + } + GNUNET_assert ((0 == size) || + (num == 1) || + (num * size > size)); for (size_t idx = 0; idx < num; idx++) {