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:
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++)
{