exchange

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

json_helper.c (54811B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file json/json_helper.c
     18  * @brief helper functions to generate specifications to parse
     19  *        Taler-specific JSON objects with libgnunetjson
     20  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     21  * @author Christian Grothoff
     22  */
     23 #include "taler/platform.h"
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include "taler/taler_util.h"
     26 #include "taler/taler_json_lib.h"
     27 
     28 
     29 /**
     30  * Convert string value to numeric cipher value.
     31  *
     32  * @param cipher_s input string
     33  * @return numeric cipher value
     34  */
     35 static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
     36 string_to_cipher (const char *cipher_s)
     37 {
     38   if ((0 == strcasecmp (cipher_s,
     39                         "RSA")) ||
     40       (0 == strcasecmp (cipher_s,
     41                         "RSA+age_restricted")))
     42     return GNUNET_CRYPTO_BSA_RSA;
     43   if ((0 == strcasecmp (cipher_s,
     44                         "CS")) ||
     45       (0 == strcasecmp (cipher_s,
     46                         "CS+age_restricted")))
     47     return GNUNET_CRYPTO_BSA_CS;
     48   return GNUNET_CRYPTO_BSA_INVALID;
     49 }
     50 
     51 
     52 json_t *
     53 TALER_JSON_from_amount (const struct TALER_Amount *amount)
     54 {
     55   char *amount_str = TALER_amount_to_string (amount);
     56 
     57   GNUNET_assert (NULL != amount_str);
     58   {
     59     json_t *j = json_string (amount_str);
     60 
     61     GNUNET_free (amount_str);
     62     return j;
     63   }
     64 }
     65 
     66 
     67 /**
     68  * Parse given JSON object to Amount
     69  *
     70  * @param cls closure, expected currency, or NULL
     71  * @param root the json object representing data
     72  * @param[out] spec where to write the data
     73  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     74  */
     75 static enum GNUNET_GenericReturnValue
     76 parse_amount (void *cls,
     77               json_t *root,
     78               struct GNUNET_JSON_Specification *spec)
     79 {
     80   const char *currency = cls;
     81   struct TALER_Amount *r_amount = spec->ptr;
     82 
     83   (void) cls;
     84   if (! json_is_string (root))
     85   {
     86     GNUNET_break_op (0);
     87     return GNUNET_SYSERR;
     88   }
     89   if (GNUNET_OK !=
     90       TALER_string_to_amount (json_string_value (root),
     91                               r_amount))
     92   {
     93     GNUNET_break_op (0);
     94     return GNUNET_SYSERR;
     95   }
     96   if ( (NULL != currency) &&
     97        (0 !=
     98         strcasecmp (currency,
     99                     r_amount->currency)) )
    100   {
    101     GNUNET_break_op (0);
    102     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    103                 "Expected currency `%s', but amount used currency `%s' in field `%s'\n",
    104                 currency,
    105                 r_amount->currency,
    106                 spec->field);
    107     return GNUNET_SYSERR;
    108   }
    109   return GNUNET_OK;
    110 }
    111 
    112 
    113 struct GNUNET_JSON_Specification
    114 TALER_JSON_spec_amount (const char *name,
    115                         const char *currency,
    116                         struct TALER_Amount *r_amount)
    117 {
    118   struct GNUNET_JSON_Specification ret = {
    119     .parser = &parse_amount,
    120     .cleaner = NULL,
    121     .cls = (void *) currency,
    122     .field = name,
    123     .ptr = r_amount,
    124     .ptr_size = 0,
    125     .size_ptr = NULL
    126   };
    127 
    128   GNUNET_assert (NULL != currency);
    129   return ret;
    130 }
    131 
    132 
    133 struct GNUNET_JSON_Specification
    134 TALER_JSON_spec_amount_any (const char *name,
    135                             struct TALER_Amount *r_amount)
    136 {
    137   struct GNUNET_JSON_Specification ret = {
    138     .parser = &parse_amount,
    139     .cleaner = NULL,
    140     .cls = NULL,
    141     .field = name,
    142     .ptr = r_amount,
    143     .ptr_size = 0,
    144     .size_ptr = NULL
    145   };
    146 
    147   return ret;
    148 }
    149 
    150 
    151 /**
    152  * Closure for parsing amount arrays.
    153  */
    154 struct AmountArrayCtx
    155 {
    156   /**
    157    * Pointer where to store the resulting array length.
    158    */
    159   size_t *len;
    160 };
    161 
    162 
    163 /**
    164  * Parse a JSON array of arbitrary amounts.
    165  */
    166 static enum GNUNET_GenericReturnValue
    167 parse_amount_any_array (void *cls,
    168                         json_t *root,
    169                         struct GNUNET_JSON_Specification *spec)
    170 {
    171   struct AmountArrayCtx *ctx = cls;
    172   struct TALER_Amount **out = spec->ptr;
    173 
    174   GNUNET_assert (NULL != ctx);
    175   GNUNET_assert (NULL != out);
    176   *out = NULL;
    177   if (NULL != ctx->len)
    178     *ctx->len = 0;
    179 
    180   if (! json_is_array (root))
    181   {
    182     GNUNET_break_op (0);
    183     return GNUNET_SYSERR;
    184   }
    185 
    186   {
    187     size_t len = json_array_size (root);
    188     json_t *entry;
    189     size_t idx;
    190 
    191     if (NULL != ctx->len)
    192       *ctx->len = len;
    193     if (0 == len)
    194     {
    195       GNUNET_break_op (0);
    196       return GNUNET_SYSERR;
    197     }
    198     *out = GNUNET_new_array (len,
    199                              struct TALER_Amount);
    200     json_array_foreach (root, idx, entry) {
    201       const char *amount_str;
    202 
    203       if (! json_is_string (entry))
    204       {
    205         GNUNET_break_op (0);
    206         return GNUNET_SYSERR;
    207       }
    208       amount_str = json_string_value (entry);
    209       if (GNUNET_OK !=
    210           TALER_string_to_amount (amount_str,
    211                                   &(*out)[idx]))
    212       {
    213         GNUNET_break_op (0);
    214         return GNUNET_SYSERR;
    215       }
    216     }
    217   }
    218   return GNUNET_OK;
    219 }
    220 
    221 
    222 /**
    223  * Cleanup helper for the amount array parser.
    224  */
    225 static void
    226 clean_amount_any_array (void *cls,
    227                         struct GNUNET_JSON_Specification *spec)
    228 {
    229   struct AmountArrayCtx *ctx = cls;
    230 
    231   if (NULL != spec->ptr)
    232   {
    233     GNUNET_free (*(void **) spec->ptr);
    234     *(void **) spec->ptr = NULL;
    235   }
    236   if ( (NULL != ctx) &&
    237        (NULL != ctx->len) )
    238     *ctx->len = 0;
    239   GNUNET_free (ctx);
    240 }
    241 
    242 
    243 struct GNUNET_JSON_Specification
    244 TALER_JSON_spec_amount_any_array (const char *field,
    245                                   size_t *amounts_len,
    246                                   struct TALER_Amount **amounts)
    247 {
    248   struct AmountArrayCtx *ctx;
    249 
    250   GNUNET_assert (NULL != amounts_len);
    251   GNUNET_assert (NULL != amounts);
    252   ctx = GNUNET_new (struct AmountArrayCtx);
    253   ctx->len = amounts_len;
    254   {
    255     struct GNUNET_JSON_Specification ret = {
    256       .parser = &parse_amount_any_array,
    257       .cleaner = &clean_amount_any_array,
    258       .cls = ctx,
    259       .field = field,
    260       .ptr = amounts
    261     };
    262 
    263     return ret;
    264   }
    265 }
    266 
    267 
    268 /**
    269  * Parse given JSON object to currency spec.
    270  *
    271  * @param cls closure, NULL
    272  * @param root the json object representing data
    273  * @param[out] spec where to write the data
    274  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    275  */
    276 static enum GNUNET_GenericReturnValue
    277 parse_cspec (void *cls,
    278              json_t *root,
    279              struct GNUNET_JSON_Specification *spec)
    280 {
    281   struct TALER_CurrencySpecification *r_cspec = spec->ptr;
    282   const char *currency = spec->cls;
    283   const char *name;
    284   uint32_t fid;
    285   uint32_t fnd;
    286   uint32_t ftzd;
    287   const json_t *map;
    288   const json_t *ca = NULL;
    289   struct GNUNET_JSON_Specification gspec[] = {
    290     GNUNET_JSON_spec_string ("name",
    291                              &name),
    292     GNUNET_JSON_spec_uint32 ("num_fractional_input_digits",
    293                              &fid),
    294     GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits",
    295                              &fnd),
    296     GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits",
    297                              &ftzd),
    298     GNUNET_JSON_spec_object_const ("alt_unit_names",
    299                                    &map),
    300     GNUNET_JSON_spec_mark_optional (
    301       GNUNET_JSON_spec_array_const ("common_amounts",
    302                                     &ca),
    303       NULL),
    304     GNUNET_JSON_spec_end ()
    305   };
    306   const char *emsg;
    307   unsigned int eline;
    308 
    309   memset (r_cspec->currency,
    310           0,
    311           sizeof (r_cspec->currency));
    312   if (GNUNET_OK !=
    313       GNUNET_JSON_parse (root,
    314                          gspec,
    315                          &emsg,
    316                          &eline))
    317   {
    318     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    319                 "Failed to parse %s at %u: %s\n",
    320                 spec[eline].field,
    321                 eline,
    322                 emsg);
    323     GNUNET_break_op (0);
    324     return GNUNET_SYSERR;
    325   }
    326   if (strlen (currency) >= TALER_CURRENCY_LEN)
    327   {
    328     GNUNET_break_op (0);
    329     return GNUNET_SYSERR;
    330   }
    331   if ( (fid > TALER_AMOUNT_FRAC_LEN) ||
    332        (fnd > TALER_AMOUNT_FRAC_LEN) ||
    333        (ftzd > TALER_AMOUNT_FRAC_LEN) )
    334   {
    335     GNUNET_break_op (0);
    336     return GNUNET_SYSERR;
    337   }
    338   if (GNUNET_OK !=
    339       TALER_check_currency (currency))
    340   {
    341     GNUNET_break_op (0);
    342     return GNUNET_SYSERR;
    343   }
    344   strcpy (r_cspec->currency,
    345           currency);
    346   if (GNUNET_OK !=
    347       TALER_check_currency_scale_map (map))
    348   {
    349     GNUNET_break_op (0);
    350     return GNUNET_SYSERR;
    351   }
    352   r_cspec->name = GNUNET_strdup (name);
    353   r_cspec->map_alt_unit_names = json_incref ((json_t *) map);
    354   if (NULL != ca)
    355   {
    356     size_t i;
    357     json_t *v;
    358 
    359     json_array_foreach ((json_t *) ca, i, v)
    360     {
    361       struct TALER_Amount val;
    362       const char *vstr;
    363 
    364       vstr = json_string_value (v);
    365       if ( (NULL == vstr) ||
    366            (GNUNET_OK !=
    367             TALER_string_to_amount (vstr,
    368                                     &val)) )
    369       {
    370         GNUNET_break_op (0);
    371         return GNUNET_SYSERR;
    372       }
    373       if (0 != strcasecmp (val.currency,
    374                            r_cspec->currency))
    375       {
    376         GNUNET_break_op (0);
    377         return GNUNET_SYSERR;
    378       }
    379       GNUNET_array_append (r_cspec->common_amounts,
    380                            r_cspec->num_common_amounts,
    381                            val);
    382     }
    383   }
    384   return GNUNET_OK;
    385 }
    386 
    387 
    388 /**
    389  * Cleanup data left from parsing encrypted contract.
    390  *
    391  * @param cls closure, NULL
    392  * @param[out] spec where to free the data
    393  */
    394 static void
    395 clean_cspec (void *cls,
    396              struct GNUNET_JSON_Specification *spec)
    397 {
    398   struct TALER_CurrencySpecification *cspec = spec->ptr;
    399 
    400   (void) cls;
    401   GNUNET_array_grow (cspec->common_amounts,
    402                      cspec->num_common_amounts,
    403                      0);
    404   GNUNET_free (cspec->name);
    405   json_decref (cspec->map_alt_unit_names);
    406 }
    407 
    408 
    409 struct GNUNET_JSON_Specification
    410 TALER_JSON_spec_currency_specification (
    411   const char *name,
    412   const char *currency,
    413   struct TALER_CurrencySpecification *r_cspec)
    414 {
    415   struct GNUNET_JSON_Specification ret = {
    416     .parser = &parse_cspec,
    417     .cleaner = &clean_cspec,
    418     .cls = (void *) currency,
    419     .field = name,
    420     .ptr = r_cspec,
    421     .ptr_size = sizeof (*r_cspec),
    422     .size_ptr = NULL
    423   };
    424 
    425   memset (r_cspec,
    426           0,
    427           sizeof (*r_cspec));
    428   return ret;
    429 }
    430 
    431 
    432 static enum GNUNET_GenericReturnValue
    433 parse_denomination_group (void *cls,
    434                           json_t *root,
    435                           struct GNUNET_JSON_Specification *spec)
    436 {
    437   struct TALER_DenominationGroup *group = spec->ptr;
    438   const char *cipher;
    439   const char *currency = cls;
    440   bool age_mask_missing = false;
    441   bool has_age_restricted_suffix = false;
    442   struct GNUNET_JSON_Specification gspec[] = {
    443     GNUNET_JSON_spec_string ("cipher",
    444                              &cipher),
    445     TALER_JSON_spec_amount ("value",
    446                             currency,
    447                             &group->value),
    448     TALER_JSON_SPEC_DENOM_FEES ("fee",
    449                                 currency,
    450                                 &group->fees),
    451     GNUNET_JSON_spec_mark_optional (
    452       GNUNET_JSON_spec_uint32 ("age_mask",
    453                                &group->age_mask.bits),
    454       &age_mask_missing),
    455     GNUNET_JSON_spec_end ()
    456   };
    457   const char *emsg;
    458   unsigned int eline;
    459 
    460   if (GNUNET_OK !=
    461       GNUNET_JSON_parse (root,
    462                          gspec,
    463                          &emsg,
    464                          &eline))
    465   {
    466     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    467                 "Failed to parse %s at %u: %s\n",
    468                 spec[eline].field,
    469                 eline,
    470                 emsg);
    471     GNUNET_break_op (0);
    472     return GNUNET_SYSERR;
    473   }
    474 
    475   group->cipher = string_to_cipher (cipher);
    476   if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
    477   {
    478     GNUNET_break_op (0);
    479     return GNUNET_SYSERR;
    480   }
    481 
    482   /* age_mask and suffix must be consistent */
    483   has_age_restricted_suffix =
    484     (NULL != strstr (cipher, "+age_restricted"));
    485   if (has_age_restricted_suffix && age_mask_missing)
    486   {
    487     GNUNET_break_op (0);
    488     return GNUNET_SYSERR;
    489   }
    490 
    491   if (age_mask_missing)
    492     group->age_mask.bits = 0;
    493 
    494   return GNUNET_OK;
    495 }
    496 
    497 
    498 struct GNUNET_JSON_Specification
    499 TALER_JSON_spec_denomination_group (const char *name,
    500                                     const char *currency,
    501                                     struct TALER_DenominationGroup *group)
    502 {
    503   struct GNUNET_JSON_Specification ret = {
    504     .cls = (void *) currency,
    505     .parser = &parse_denomination_group,
    506     .field = name,
    507     .ptr = group,
    508     .ptr_size = sizeof(*group)
    509   };
    510 
    511   return ret;
    512 }
    513 
    514 
    515 /**
    516  * Parse given JSON object to an encrypted contract.
    517  *
    518  * @param cls closure, NULL
    519  * @param root the json object representing data
    520  * @param[out] spec where to write the data
    521  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    522  */
    523 static enum GNUNET_GenericReturnValue
    524 parse_econtract (void *cls,
    525                  json_t *root,
    526                  struct GNUNET_JSON_Specification *spec)
    527 {
    528   struct TALER_EncryptedContract *econtract = spec->ptr;
    529   struct GNUNET_JSON_Specification ispec[] = {
    530     GNUNET_JSON_spec_varsize ("econtract",
    531                               &econtract->econtract,
    532                               &econtract->econtract_size),
    533     GNUNET_JSON_spec_fixed_auto ("econtract_sig",
    534                                  &econtract->econtract_sig),
    535     GNUNET_JSON_spec_fixed_auto ("contract_pub",
    536                                  &econtract->contract_pub),
    537     GNUNET_JSON_spec_end ()
    538   };
    539   const char *emsg;
    540   unsigned int eline;
    541 
    542   (void) cls;
    543   if (GNUNET_OK !=
    544       GNUNET_JSON_parse (root,
    545                          ispec,
    546                          &emsg,
    547                          &eline))
    548   {
    549     GNUNET_break_op (0);
    550     return GNUNET_SYSERR;
    551   }
    552   return GNUNET_OK;
    553 }
    554 
    555 
    556 /**
    557  * Cleanup data left from parsing encrypted contract.
    558  *
    559  * @param cls closure, NULL
    560  * @param[out] spec where to free the data
    561  */
    562 static void
    563 clean_econtract (void *cls,
    564                  struct GNUNET_JSON_Specification *spec)
    565 {
    566   struct TALER_EncryptedContract *econtract = spec->ptr;
    567 
    568   (void) cls;
    569   GNUNET_free (econtract->econtract);
    570 }
    571 
    572 
    573 struct GNUNET_JSON_Specification
    574 TALER_JSON_spec_econtract (const char *name,
    575                            struct TALER_EncryptedContract *econtract)
    576 {
    577   struct GNUNET_JSON_Specification ret = {
    578     .parser = &parse_econtract,
    579     .cleaner = &clean_econtract,
    580     .field = name,
    581     .ptr = econtract
    582   };
    583 
    584   return ret;
    585 }
    586 
    587 
    588 /**
    589  * Parse given JSON object to an age commitmnet
    590  *
    591  * @param cls closure, NULL
    592  * @param root the json object representing data
    593  * @param[out] spec where to write the data
    594  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    595  */
    596 static enum GNUNET_GenericReturnValue
    597 parse_age_commitment (void *cls,
    598                       json_t *root,
    599                       struct GNUNET_JSON_Specification *spec)
    600 {
    601   struct TALER_AgeCommitment *age_commitment = spec->ptr;
    602   json_t *pk;
    603   unsigned int idx;
    604   size_t num;
    605 
    606   (void) cls;
    607   if ( (NULL == root) ||
    608        (! json_is_array (root)))
    609   {
    610     GNUNET_break_op (0);
    611     return GNUNET_SYSERR;
    612   }
    613 
    614   num = json_array_size (root);
    615   if (32 <= num || 0 == num)
    616   {
    617     GNUNET_break_op (0);
    618     return GNUNET_SYSERR;
    619   }
    620 
    621   age_commitment->num = num;
    622   age_commitment->pubs =
    623     GNUNET_new_array (num,
    624                       struct TALER_AgeCommitmentPublicKeyP);
    625 
    626   json_array_foreach (root, idx, pk) {
    627     const char *emsg;
    628     unsigned int eline;
    629     struct GNUNET_JSON_Specification pkspec[] = {
    630       GNUNET_JSON_spec_fixed_auto (
    631         NULL,
    632         &age_commitment->pubs[idx].pub),
    633       GNUNET_JSON_spec_end ()
    634     };
    635 
    636     if (GNUNET_OK !=
    637         GNUNET_JSON_parse (pk,
    638                            pkspec,
    639                            &emsg,
    640                            &eline))
    641     {
    642       GNUNET_break_op (0);
    643       GNUNET_JSON_parse_free (spec);
    644       return GNUNET_SYSERR;
    645     }
    646   };
    647 
    648   return GNUNET_OK;
    649 }
    650 
    651 
    652 /**
    653  * Cleanup data left from parsing age commitment
    654  *
    655  * @param cls closure, NULL
    656  * @param[out] spec where to free the data
    657  */
    658 static void
    659 clean_age_commitment (void *cls,
    660                       struct GNUNET_JSON_Specification *spec)
    661 {
    662   struct TALER_AgeCommitment *age_commitment = spec->ptr;
    663 
    664   (void) cls;
    665 
    666   if (NULL == age_commitment ||
    667       NULL == age_commitment->pubs)
    668     return;
    669 
    670   age_commitment->num = 0;
    671   GNUNET_free (age_commitment->pubs);
    672   age_commitment->pubs = NULL;
    673 }
    674 
    675 
    676 struct GNUNET_JSON_Specification
    677 TALER_JSON_spec_age_commitment (const char *name,
    678                                 struct TALER_AgeCommitment *age_commitment)
    679 {
    680   struct GNUNET_JSON_Specification ret = {
    681     .parser = &parse_age_commitment,
    682     .cleaner = &clean_age_commitment,
    683     .field = name,
    684     .ptr = age_commitment
    685   };
    686 
    687   return ret;
    688 }
    689 
    690 
    691 struct GNUNET_JSON_Specification
    692 TALER_JSON_spec_token_issue_sig (const char *field,
    693                                  struct TALER_TokenIssueSignature *sig)
    694 {
    695   sig->signature = NULL;
    696   return GNUNET_JSON_spec_unblinded_signature (field,
    697                                                &sig->signature);
    698 }
    699 
    700 
    701 struct GNUNET_JSON_Specification
    702 TALER_JSON_spec_blinded_token_issue_sig (
    703   const char *field,
    704   struct TALER_BlindedTokenIssueSignature *sig)
    705 {
    706   sig->signature = NULL;
    707   return GNUNET_JSON_spec_blinded_signature (field,
    708                                              &sig->signature);
    709 }
    710 
    711 
    712 struct GNUNET_JSON_Specification
    713 TALER_JSON_spec_token_envelope (const char *field,
    714                                 struct TALER_TokenEnvelope *env)
    715 {
    716   env->blinded_pub = NULL;
    717   return GNUNET_JSON_spec_blinded_message (field,
    718                                            &env->blinded_pub);
    719 }
    720 
    721 
    722 /**
    723  * Parse given JSON object to denomination public key.
    724  *
    725  * @param cls closure, NULL
    726  * @param root the json object representing data
    727  * @param[out] spec where to write the data
    728  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    729  */
    730 static enum GNUNET_GenericReturnValue
    731 parse_denom_pub (void *cls,
    732                  json_t *root,
    733                  struct GNUNET_JSON_Specification *spec)
    734 {
    735   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    736   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    737   const char *cipher;
    738   bool age_mask_missing = false;
    739   struct GNUNET_JSON_Specification dspec[] = {
    740     GNUNET_JSON_spec_string ("cipher",
    741                              &cipher),
    742     GNUNET_JSON_spec_mark_optional (
    743       GNUNET_JSON_spec_uint32 ("age_mask",
    744                                &denom_pub->age_mask.bits),
    745       &age_mask_missing),
    746     GNUNET_JSON_spec_end ()
    747   };
    748   const char *emsg;
    749   unsigned int eline;
    750 
    751   (void) cls;
    752   if (GNUNET_OK !=
    753       GNUNET_JSON_parse (root,
    754                          dspec,
    755                          &emsg,
    756                          &eline))
    757   {
    758     GNUNET_break_op (0);
    759     return GNUNET_SYSERR;
    760   }
    761 
    762   if (age_mask_missing)
    763     denom_pub->age_mask.bits = 0;
    764   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    765   bsign_pub->rc = 1;
    766   bsign_pub->cipher = string_to_cipher (cipher);
    767   switch (bsign_pub->cipher)
    768   {
    769   case GNUNET_CRYPTO_BSA_INVALID:
    770     break;
    771   case GNUNET_CRYPTO_BSA_RSA:
    772     {
    773       struct GNUNET_JSON_Specification ispec[] = {
    774         GNUNET_JSON_spec_rsa_public_key (
    775           "rsa_pub",
    776           &bsign_pub->details.rsa_public_key),
    777         GNUNET_JSON_spec_end ()
    778       };
    779 
    780       if (GNUNET_OK !=
    781           GNUNET_JSON_parse (root,
    782                              ispec,
    783                              &emsg,
    784                              &eline))
    785       {
    786         GNUNET_break_op (0);
    787         GNUNET_free (bsign_pub);
    788         return GNUNET_SYSERR;
    789       }
    790       denom_pub->bsign_pub_key = bsign_pub;
    791       return GNUNET_OK;
    792     }
    793   case GNUNET_CRYPTO_BSA_CS:
    794     {
    795       struct GNUNET_JSON_Specification ispec[] = {
    796         GNUNET_JSON_spec_fixed ("cs_pub",
    797                                 &bsign_pub->details.cs_public_key,
    798                                 sizeof (bsign_pub->details.cs_public_key)),
    799         GNUNET_JSON_spec_end ()
    800       };
    801 
    802       if (GNUNET_OK !=
    803           GNUNET_JSON_parse (root,
    804                              ispec,
    805                              &emsg,
    806                              &eline))
    807       {
    808         GNUNET_break_op (0);
    809         GNUNET_free (bsign_pub);
    810         return GNUNET_SYSERR;
    811       }
    812       denom_pub->bsign_pub_key = bsign_pub;
    813       return GNUNET_OK;
    814     }
    815   }
    816   GNUNET_break_op (0);
    817   GNUNET_free (bsign_pub);
    818   return GNUNET_SYSERR;
    819 }
    820 
    821 
    822 /**
    823  * Cleanup data left from parsing denomination public key.
    824  *
    825  * @param cls closure, NULL
    826  * @param[out] spec where to free the data
    827  */
    828 static void
    829 clean_denom_pub (void *cls,
    830                  struct GNUNET_JSON_Specification *spec)
    831 {
    832   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    833 
    834   (void) cls;
    835   TALER_denom_pub_free (denom_pub);
    836 }
    837 
    838 
    839 struct GNUNET_JSON_Specification
    840 TALER_JSON_spec_denom_pub (const char *field,
    841                            struct TALER_DenominationPublicKey *pk)
    842 {
    843   struct GNUNET_JSON_Specification ret = {
    844     .parser = &parse_denom_pub,
    845     .cleaner = &clean_denom_pub,
    846     .field = field,
    847     .ptr = pk
    848   };
    849 
    850   pk->bsign_pub_key = NULL;
    851   return ret;
    852 }
    853 
    854 
    855 /**
    856  * Parse given JSON object to token issue public key.
    857  *
    858  * @param cls closure, NULL
    859  * @param root the json object representing data
    860  * @param[out] spec where to write the data
    861  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    862  */
    863 static enum GNUNET_GenericReturnValue
    864 parse_token_pub (void *cls,
    865                  json_t *root,
    866                  struct GNUNET_JSON_Specification *spec)
    867 {
    868   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    869   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    870   const char *cipher;
    871   struct GNUNET_JSON_Specification dspec[] = {
    872     GNUNET_JSON_spec_string ("cipher",
    873                              &cipher),
    874     GNUNET_JSON_spec_end ()
    875   };
    876   const char *emsg;
    877   unsigned int eline;
    878 
    879   (void) cls;
    880   if (GNUNET_OK !=
    881       GNUNET_JSON_parse (root,
    882                          dspec,
    883                          &emsg,
    884                          &eline))
    885   {
    886     GNUNET_break_op (0);
    887     return GNUNET_SYSERR;
    888   }
    889 
    890   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    891   bsign_pub->rc = 1;
    892   bsign_pub->cipher = string_to_cipher (cipher);
    893   switch (bsign_pub->cipher)
    894   {
    895   case GNUNET_CRYPTO_BSA_INVALID:
    896     break;
    897   case GNUNET_CRYPTO_BSA_RSA:
    898     {
    899       struct GNUNET_JSON_Specification ispec[] = {
    900         GNUNET_JSON_spec_rsa_public_key (
    901           "rsa_pub",
    902           &bsign_pub->details.rsa_public_key),
    903         GNUNET_JSON_spec_end ()
    904       };
    905 
    906       if (GNUNET_OK !=
    907           GNUNET_JSON_parse (root,
    908                              ispec,
    909                              &emsg,
    910                              &eline))
    911       {
    912         GNUNET_break_op (0);
    913         GNUNET_free (bsign_pub);
    914         return GNUNET_SYSERR;
    915       }
    916       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
    917                                          &bsign_pub->pub_key_hash);
    918       token_pub->public_key = bsign_pub;
    919       return GNUNET_OK;
    920     }
    921   case GNUNET_CRYPTO_BSA_CS:
    922     {
    923       struct GNUNET_JSON_Specification ispec[] = {
    924         GNUNET_JSON_spec_fixed ("cs_pub",
    925                                 &bsign_pub->details.cs_public_key,
    926                                 sizeof (bsign_pub->details.cs_public_key)),
    927         GNUNET_JSON_spec_end ()
    928       };
    929 
    930       if (GNUNET_OK !=
    931           GNUNET_JSON_parse (root,
    932                              ispec,
    933                              &emsg,
    934                              &eline))
    935       {
    936         GNUNET_break_op (0);
    937         GNUNET_free (bsign_pub);
    938         return GNUNET_SYSERR;
    939       }
    940       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
    941                           sizeof(bsign_pub->details.cs_public_key),
    942                           &bsign_pub->pub_key_hash);
    943       token_pub->public_key = bsign_pub;
    944       return GNUNET_OK;
    945     }
    946   }
    947   GNUNET_break_op (0);
    948   GNUNET_free (bsign_pub);
    949   return GNUNET_SYSERR;
    950 }
    951 
    952 
    953 /**
    954  * Cleanup data left from parsing token issue public key.
    955  *
    956  * @param cls closure, NULL
    957  * @param[out] spec where to free the data
    958  */
    959 static void
    960 clean_token_pub (void *cls,
    961                  struct GNUNET_JSON_Specification *spec)
    962 {
    963   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    964 
    965   (void) cls;
    966   TALER_token_issue_pub_free (token_pub);
    967 }
    968 
    969 
    970 struct GNUNET_JSON_Specification
    971 TALER_JSON_spec_token_pub (const char *field,
    972                            struct TALER_TokenIssuePublicKey *pk)
    973 {
    974   struct GNUNET_JSON_Specification ret = {
    975     .field = field,
    976     .parser = &parse_token_pub,
    977     .cleaner = &clean_token_pub,
    978     .ptr = pk
    979   };
    980 
    981   pk->public_key = NULL;
    982   return ret;
    983 }
    984 
    985 
    986 /**
    987  * Parse given JSON object partially into a denomination public key.
    988  *
    989  * Depending on the cipher in cls, it parses the corresponding public key type.
    990  *
    991  * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
    992  * @param root the json object representing data
    993  * @param[out] spec where to write the data
    994  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    995  */
    996 static enum GNUNET_GenericReturnValue
    997 parse_denom_pub_cipher (void *cls,
    998                         json_t *root,
    999                         struct GNUNET_JSON_Specification *spec)
   1000 {
   1001   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
   1002   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
   1003     (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
   1004   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
   1005   const char *emsg;
   1006   unsigned int eline;
   1007 
   1008   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
   1009   bsign_pub->cipher = cipher;
   1010   bsign_pub->rc = 1;
   1011   switch (cipher)
   1012   {
   1013   case GNUNET_CRYPTO_BSA_INVALID:
   1014     break;
   1015   case GNUNET_CRYPTO_BSA_RSA:
   1016     {
   1017       struct GNUNET_JSON_Specification ispec[] = {
   1018         GNUNET_JSON_spec_rsa_public_key (
   1019           "rsa_pub",
   1020           &bsign_pub->details.rsa_public_key),
   1021         GNUNET_JSON_spec_end ()
   1022       };
   1023 
   1024       if (GNUNET_OK !=
   1025           GNUNET_JSON_parse (root,
   1026                              ispec,
   1027                              &emsg,
   1028                              &eline))
   1029       {
   1030         GNUNET_break_op (0);
   1031         GNUNET_free (bsign_pub);
   1032         return GNUNET_SYSERR;
   1033       }
   1034       denom_pub->bsign_pub_key = bsign_pub;
   1035       return GNUNET_OK;
   1036     }
   1037   case GNUNET_CRYPTO_BSA_CS:
   1038     {
   1039       struct GNUNET_JSON_Specification ispec[] = {
   1040         GNUNET_JSON_spec_fixed ("cs_pub",
   1041                                 &bsign_pub->details.cs_public_key,
   1042                                 sizeof (bsign_pub->details.cs_public_key)),
   1043         GNUNET_JSON_spec_end ()
   1044       };
   1045 
   1046       if (GNUNET_OK !=
   1047           GNUNET_JSON_parse (root,
   1048                              ispec,
   1049                              &emsg,
   1050                              &eline))
   1051       {
   1052         GNUNET_break_op (0);
   1053         GNUNET_free (bsign_pub);
   1054         return GNUNET_SYSERR;
   1055       }
   1056       denom_pub->bsign_pub_key = bsign_pub;
   1057       return GNUNET_OK;
   1058     }
   1059   }
   1060   GNUNET_break_op (0);
   1061   GNUNET_free (bsign_pub);
   1062   return GNUNET_SYSERR;
   1063 }
   1064 
   1065 
   1066 struct GNUNET_JSON_Specification
   1067 TALER_JSON_spec_denom_pub_cipher (
   1068   const char *field,
   1069   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
   1070   struct TALER_DenominationPublicKey *pk)
   1071 {
   1072   struct GNUNET_JSON_Specification ret = {
   1073     .parser = &parse_denom_pub_cipher,
   1074     .cleaner = &clean_denom_pub,
   1075     .field = field,
   1076     .cls = (void *) cipher,
   1077     .ptr = pk
   1078   };
   1079 
   1080   return ret;
   1081 }
   1082 
   1083 
   1084 struct GNUNET_JSON_Specification
   1085 TALER_JSON_spec_denom_sig (const char *field,
   1086                            struct TALER_DenominationSignature *sig)
   1087 {
   1088   sig->unblinded_sig = NULL;
   1089   return GNUNET_JSON_spec_unblinded_signature (field,
   1090                                                &sig->unblinded_sig);
   1091 }
   1092 
   1093 
   1094 struct GNUNET_JSON_Specification
   1095 TALER_JSON_spec_blinded_denom_sig (
   1096   const char *field,
   1097   struct TALER_BlindedDenominationSignature *sig)
   1098 {
   1099   sig->blinded_sig = NULL;
   1100   return GNUNET_JSON_spec_blinded_signature (field,
   1101                                              &sig->blinded_sig);
   1102 }
   1103 
   1104 
   1105 struct GNUNET_JSON_Specification
   1106 TALER_JSON_spec_blinded_planchet (
   1107   const char *field,
   1108   struct TALER_BlindedPlanchet *blinded_planchet)
   1109 {
   1110   blinded_planchet->blinded_message = NULL;
   1111   return GNUNET_JSON_spec_blinded_message (field,
   1112                                            &blinded_planchet->blinded_message);
   1113 }
   1114 
   1115 
   1116 /**
   1117  * Parse given JSON object to exchange withdraw values (/csr).
   1118  *
   1119  * @param cls closure, NULL
   1120  * @param root the json object representing data
   1121  * @param[out] spec where to write the data
   1122  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1123  */
   1124 static enum GNUNET_GenericReturnValue
   1125 parse_exchange_blinding_values (void *cls,
   1126                                 json_t *root,
   1127                                 struct GNUNET_JSON_Specification *spec)
   1128 {
   1129   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1130   struct GNUNET_CRYPTO_BlindingInputValues *bi;
   1131   const char *cipher;
   1132   struct GNUNET_JSON_Specification dspec[] = {
   1133     GNUNET_JSON_spec_string ("cipher",
   1134                              &cipher),
   1135     GNUNET_JSON_spec_end ()
   1136   };
   1137   const char *emsg;
   1138   unsigned int eline;
   1139   enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
   1140 
   1141   (void) cls;
   1142   if (GNUNET_OK !=
   1143       GNUNET_JSON_parse (root,
   1144                          dspec,
   1145                          &emsg,
   1146                          &eline))
   1147   {
   1148     GNUNET_break_op (0);
   1149     return GNUNET_SYSERR;
   1150   }
   1151   ci = string_to_cipher (cipher);
   1152   switch (ci)
   1153   {
   1154   case GNUNET_CRYPTO_BSA_INVALID:
   1155     break;
   1156   case GNUNET_CRYPTO_BSA_RSA:
   1157     ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
   1158     return GNUNET_OK;
   1159   case GNUNET_CRYPTO_BSA_CS:
   1160     bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
   1161     bi->cipher = GNUNET_CRYPTO_BSA_CS;
   1162     bi->rc = 1;
   1163     {
   1164       struct GNUNET_JSON_Specification ispec[] = {
   1165         GNUNET_JSON_spec_fixed (
   1166           "r_pub_0",
   1167           &bi->details.cs_values.r_pub[0],
   1168           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1169         GNUNET_JSON_spec_fixed (
   1170           "r_pub_1",
   1171           &bi->details.cs_values.r_pub[1],
   1172           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1173         GNUNET_JSON_spec_end ()
   1174       };
   1175 
   1176       if (GNUNET_OK !=
   1177           GNUNET_JSON_parse (root,
   1178                              ispec,
   1179                              &emsg,
   1180                              &eline))
   1181       {
   1182         GNUNET_break_op (0);
   1183         GNUNET_free (bi);
   1184         return GNUNET_SYSERR;
   1185       }
   1186       ewv->blinding_inputs = bi;
   1187       return GNUNET_OK;
   1188     }
   1189   }
   1190   GNUNET_break_op (0);
   1191   return GNUNET_SYSERR;
   1192 }
   1193 
   1194 
   1195 /**
   1196  * Cleanup data left from parsing withdraw values
   1197  *
   1198  * @param cls closure, NULL
   1199  * @param[out] spec where to free the data
   1200  */
   1201 static void
   1202 clean_exchange_blinding_values (
   1203   void *cls,
   1204   struct GNUNET_JSON_Specification *spec)
   1205 {
   1206   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1207 
   1208   (void) cls;
   1209   TALER_denom_ewv_free (ewv);
   1210 }
   1211 
   1212 
   1213 struct GNUNET_JSON_Specification
   1214 TALER_JSON_spec_exchange_blinding_values (
   1215   const char *field,
   1216   struct TALER_ExchangeBlindingValues *ewv)
   1217 {
   1218   struct GNUNET_JSON_Specification ret = {
   1219     .parser = &parse_exchange_blinding_values,
   1220     .cleaner = &clean_exchange_blinding_values,
   1221     .field = field,
   1222     .ptr = ewv
   1223   };
   1224 
   1225   ewv->blinding_inputs = NULL;
   1226   return ret;
   1227 }
   1228 
   1229 
   1230 /**
   1231  * Closure for #parse_i18n_string.
   1232  */
   1233 struct I18nContext
   1234 {
   1235   /**
   1236    * Language pattern to match.
   1237    */
   1238   char *lp;
   1239 
   1240   /**
   1241    * Name of the field to match.
   1242    */
   1243   const char *field;
   1244 };
   1245 
   1246 
   1247 /**
   1248  * Parse given JSON object to internationalized string.
   1249  *
   1250  * @param cls closure, our `struct I18nContext *`
   1251  * @param root the json object representing data
   1252  * @param[out] spec where to write the data
   1253  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1254  */
   1255 static enum GNUNET_GenericReturnValue
   1256 parse_i18n_string (void *cls,
   1257                    json_t *root,
   1258                    struct GNUNET_JSON_Specification *spec)
   1259 {
   1260   struct I18nContext *ctx = cls;
   1261   json_t *i18n;
   1262   json_t *val;
   1263 
   1264   {
   1265     char *i18nf;
   1266 
   1267     GNUNET_asprintf (&i18nf,
   1268                      "%s_i18n",
   1269                      ctx->field);
   1270     i18n = json_object_get (root,
   1271                             i18nf);
   1272     GNUNET_free (i18nf);
   1273   }
   1274 
   1275   val = json_object_get (root,
   1276                          ctx->field);
   1277   if ( (NULL != i18n) &&
   1278        (NULL != ctx->lp) )
   1279   {
   1280     double best = 0.0;
   1281     json_t *pos;
   1282     const char *lang;
   1283 
   1284     json_object_foreach (i18n, lang, pos)
   1285     {
   1286       double score;
   1287 
   1288       score = TALER_pattern_matches (ctx->lp,
   1289                                      lang);
   1290       if (score > best)
   1291       {
   1292         best = score;
   1293         val = pos;
   1294       }
   1295     }
   1296   }
   1297 
   1298   {
   1299     const char *str;
   1300 
   1301     str = json_string_value (val);
   1302     *(const char **) spec->ptr = str;
   1303   }
   1304   return GNUNET_OK;
   1305 }
   1306 
   1307 
   1308 /**
   1309  * Function called to clean up data from earlier parsing.
   1310  *
   1311  * @param cls closure
   1312  * @param spec our specification entry with data to clean.
   1313  */
   1314 static void
   1315 i18n_cleaner (void *cls,
   1316               struct GNUNET_JSON_Specification *spec)
   1317 {
   1318   struct I18nContext *ctx = cls;
   1319 
   1320   (void) spec;
   1321   if (NULL != ctx)
   1322   {
   1323     GNUNET_free (ctx->lp);
   1324     GNUNET_free (ctx);
   1325   }
   1326 }
   1327 
   1328 
   1329 struct GNUNET_JSON_Specification
   1330 TALER_JSON_spec_i18n_string (const char *name,
   1331                              const char *language_pattern,
   1332                              const char **strptr)
   1333 {
   1334   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
   1335   struct GNUNET_JSON_Specification ret = {
   1336     .parser = &parse_i18n_string,
   1337     .cleaner = &i18n_cleaner,
   1338     .cls = ctx,
   1339     .field = NULL, /* we want the main object */
   1340     .ptr = strptr,
   1341     .ptr_size = 0,
   1342     .size_ptr = NULL
   1343   };
   1344 
   1345   ctx->lp = (NULL != language_pattern)
   1346     ? GNUNET_strdup (language_pattern)
   1347     : NULL;
   1348   ctx->field = name;
   1349   *strptr = NULL;
   1350   return ret;
   1351 }
   1352 
   1353 
   1354 struct GNUNET_JSON_Specification
   1355 TALER_JSON_spec_i18n_str (const char *name,
   1356                           const char **strptr)
   1357 {
   1358   const char *lang = getenv ("LANG");
   1359   char *dot;
   1360   char *l;
   1361   struct GNUNET_JSON_Specification ret;
   1362 
   1363   if (NULL != lang)
   1364   {
   1365     dot = strchr (lang,
   1366                   '.');
   1367     if (NULL == dot)
   1368       l = GNUNET_strdup (lang);
   1369     else
   1370       l = GNUNET_strndup (lang,
   1371                           dot - lang);
   1372   }
   1373   else
   1374   {
   1375     l = NULL;
   1376   }
   1377   ret = TALER_JSON_spec_i18n_string (name,
   1378                                      l,
   1379                                      strptr);
   1380   GNUNET_free (l);
   1381   return ret;
   1382 }
   1383 
   1384 
   1385 /**
   1386  * Parse given JSON object with Taler error code.
   1387  *
   1388  * @param cls closure, NULL
   1389  * @param root the json object representing data
   1390  * @param[out] spec where to write the data
   1391  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1392  */
   1393 static enum GNUNET_GenericReturnValue
   1394 parse_ec (void *cls,
   1395           json_t *root,
   1396           struct GNUNET_JSON_Specification *spec)
   1397 {
   1398   enum TALER_ErrorCode *ec = spec->ptr;
   1399   json_int_t num;
   1400 
   1401   (void) cls;
   1402   if (! json_is_integer (root))
   1403   {
   1404     GNUNET_break_op (0);
   1405     return GNUNET_SYSERR;
   1406   }
   1407   num = json_integer_value (root);
   1408   if (num < 0)
   1409   {
   1410     GNUNET_break_op (0);
   1411     *ec = TALER_EC_INVALID;
   1412     return GNUNET_SYSERR;
   1413   }
   1414   *ec = (enum TALER_ErrorCode) num;
   1415   return GNUNET_OK;
   1416 }
   1417 
   1418 
   1419 struct GNUNET_JSON_Specification
   1420 TALER_JSON_spec_ec (const char *field,
   1421                     enum TALER_ErrorCode *ec)
   1422 {
   1423   struct GNUNET_JSON_Specification ret = {
   1424     .parser = &parse_ec,
   1425     .field = field,
   1426     .ptr = ec
   1427   };
   1428 
   1429   *ec = TALER_EC_NONE;
   1430   return ret;
   1431 }
   1432 
   1433 
   1434 /**
   1435  * Parse given JSON object to web URL.
   1436  *
   1437  * @param cls closure, NULL
   1438  * @param root the json object representing data
   1439  * @param[out] spec where to write the data
   1440  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1441  */
   1442 static enum GNUNET_GenericReturnValue
   1443 parse_web_url (void *cls,
   1444                json_t *root,
   1445                struct GNUNET_JSON_Specification *spec)
   1446 {
   1447   const char *str;
   1448 
   1449   (void) cls;
   1450   str = json_string_value (root);
   1451   if (NULL == str)
   1452   {
   1453     GNUNET_break_op (0);
   1454     return GNUNET_SYSERR;
   1455   }
   1456   if (! TALER_is_web_url (str))
   1457   {
   1458     GNUNET_break_op (0);
   1459     return GNUNET_SYSERR;
   1460   }
   1461   *(const char **) spec->ptr = str;
   1462   return GNUNET_OK;
   1463 }
   1464 
   1465 
   1466 struct GNUNET_JSON_Specification
   1467 TALER_JSON_spec_web_url (const char *field,
   1468                          const char **url)
   1469 {
   1470   struct GNUNET_JSON_Specification ret = {
   1471     .parser = &parse_web_url,
   1472     .field = field,
   1473     .ptr = url
   1474   };
   1475 
   1476   *url = NULL;
   1477   return ret;
   1478 }
   1479 
   1480 
   1481 /**
   1482  * Parse given JSON object to payto:// URI.
   1483  *
   1484  * @param cls closure, NULL
   1485  * @param root the json object representing data
   1486  * @param[out] spec where to write the data
   1487  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1488  */
   1489 static enum GNUNET_GenericReturnValue
   1490 parse_full_payto_uri (void *cls,
   1491                       json_t *root,
   1492                       struct GNUNET_JSON_Specification *spec)
   1493 {
   1494   struct TALER_FullPayto *payto_uri = spec->ptr;
   1495   const char *str;
   1496   char *err;
   1497 
   1498   (void) cls;
   1499   str = json_string_value (root);
   1500   if (NULL == str)
   1501   {
   1502     GNUNET_break_op (0);
   1503     return GNUNET_SYSERR;
   1504   }
   1505   payto_uri->full_payto = (char *) str;
   1506   err = TALER_payto_validate (*payto_uri);
   1507   if (NULL != err)
   1508   {
   1509     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1510                 "payto:// malformed: %s\n",
   1511                 err);
   1512     GNUNET_free (err);
   1513     payto_uri->full_payto = NULL;
   1514     return GNUNET_SYSERR;
   1515   }
   1516   return GNUNET_OK;
   1517 }
   1518 
   1519 
   1520 struct GNUNET_JSON_Specification
   1521 TALER_JSON_spec_full_payto_uri (
   1522   const char *field,
   1523   struct TALER_FullPayto *payto_uri)
   1524 {
   1525   struct GNUNET_JSON_Specification ret = {
   1526     .parser = &parse_full_payto_uri,
   1527     .field = field,
   1528     .ptr = payto_uri
   1529   };
   1530 
   1531   payto_uri->full_payto = NULL;
   1532   return ret;
   1533 }
   1534 
   1535 
   1536 /**
   1537  * Parse given JSON object to payto:// URI.
   1538  *
   1539  * @param cls closure, NULL
   1540  * @param root the json object representing data
   1541  * @param[out] spec where to write the data
   1542  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1543  */
   1544 static enum GNUNET_GenericReturnValue
   1545 parse_normalized_payto_uri (void *cls,
   1546                             json_t *root,
   1547                             struct GNUNET_JSON_Specification *spec)
   1548 {
   1549   struct TALER_NormalizedPayto *payto_uri = spec->ptr;
   1550   const char *str;
   1551 
   1552   (void) cls;
   1553   str = json_string_value (root);
   1554   if (NULL == str)
   1555   {
   1556     GNUNET_break_op (0);
   1557     return GNUNET_SYSERR;
   1558   }
   1559   payto_uri->normalized_payto = (char *) str;
   1560   {
   1561     char *err;
   1562 
   1563     err = TALER_normalized_payto_validate (*payto_uri);
   1564     if (NULL != err)
   1565     {
   1566       GNUNET_break_op (0);
   1567       GNUNET_free (err);
   1568       payto_uri->normalized_payto = NULL;
   1569       return GNUNET_SYSERR;
   1570     }
   1571   }
   1572   return GNUNET_OK;
   1573 }
   1574 
   1575 
   1576 struct GNUNET_JSON_Specification
   1577 TALER_JSON_spec_normalized_payto_uri (
   1578   const char *field,
   1579   struct TALER_NormalizedPayto *payto_uri)
   1580 {
   1581   struct GNUNET_JSON_Specification ret = {
   1582     .parser = &parse_normalized_payto_uri,
   1583     .field = field,
   1584     .ptr = payto_uri
   1585   };
   1586 
   1587   payto_uri->normalized_payto = NULL;
   1588   return ret;
   1589 }
   1590 
   1591 
   1592 /**
   1593  * Parse given JSON object with protocol version.
   1594  *
   1595  * @param cls closure, NULL
   1596  * @param root the json object representing data
   1597  * @param[out] spec where to write the data
   1598  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1599  */
   1600 static enum GNUNET_GenericReturnValue
   1601 parse_protocol_version (void *cls,
   1602                         json_t *root,
   1603                         struct GNUNET_JSON_Specification *spec)
   1604 {
   1605   struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
   1606   const char *ver;
   1607   char dummy;
   1608 
   1609   (void) cls;
   1610   if (! json_is_string (root))
   1611   {
   1612     GNUNET_break_op (0);
   1613     return GNUNET_SYSERR;
   1614   }
   1615   ver = json_string_value (root);
   1616   if (3 != sscanf (ver,
   1617                    "%u:%u:%u%c",
   1618                    &pv->current,
   1619                    &pv->revision,
   1620                    &pv->age,
   1621                    &dummy))
   1622   {
   1623     GNUNET_break_op (0);
   1624     return GNUNET_SYSERR;
   1625   }
   1626   return GNUNET_OK;
   1627 }
   1628 
   1629 
   1630 struct GNUNET_JSON_Specification
   1631 TALER_JSON_spec_version (const char *field,
   1632                          struct TALER_JSON_ProtocolVersion *ver)
   1633 {
   1634   struct GNUNET_JSON_Specification ret = {
   1635     .parser = &parse_protocol_version,
   1636     .field = field,
   1637     .ptr = ver
   1638   };
   1639 
   1640   return ret;
   1641 }
   1642 
   1643 
   1644 /**
   1645  * Parse given JSON object to an OTP key.
   1646  *
   1647  * @param cls closure, NULL
   1648  * @param root the json object representing data
   1649  * @param[out] spec where to write the data
   1650  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1651  */
   1652 static enum GNUNET_GenericReturnValue
   1653 parse_otp_key (void *cls,
   1654                json_t *root,
   1655                struct GNUNET_JSON_Specification *spec)
   1656 {
   1657   const char *pos_key;
   1658 
   1659   (void) cls;
   1660   pos_key = json_string_value (root);
   1661   if (NULL == pos_key)
   1662   {
   1663     GNUNET_break_op (0);
   1664     return GNUNET_SYSERR;
   1665   }
   1666   {
   1667     size_t pos_key_length = strlen (pos_key);
   1668     void *key; /* pos_key in binary */
   1669     size_t key_len; /* length of the key */
   1670     int dret;
   1671 
   1672     key_len = pos_key_length * 5 / 8;
   1673     key = GNUNET_malloc (key_len);
   1674     dret = TALER_rfc3548_base32decode (pos_key,
   1675                                        pos_key_length,
   1676                                        key,
   1677                                        key_len);
   1678     if (-1 == dret)
   1679     {
   1680       GNUNET_free (key);
   1681       GNUNET_break_op (0);
   1682       return GNUNET_SYSERR;
   1683     }
   1684     GNUNET_free (key);
   1685   }
   1686   *(const char **) spec->ptr = pos_key;
   1687   return GNUNET_OK;
   1688 }
   1689 
   1690 
   1691 struct GNUNET_JSON_Specification
   1692 TALER_JSON_spec_otp_key (const char *name,
   1693                          const char **otp_key)
   1694 {
   1695   struct GNUNET_JSON_Specification ret = {
   1696     .parser = &parse_otp_key,
   1697     .field = name,
   1698     .ptr = otp_key
   1699   };
   1700 
   1701   *otp_key = NULL;
   1702   return ret;
   1703 }
   1704 
   1705 
   1706 /**
   1707  * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
   1708  *
   1709  * @param cls closure, NULL
   1710  * @param root the json object representing data
   1711  * @param[out] spec where to write the data
   1712  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1713  */
   1714 static enum GNUNET_GenericReturnValue
   1715 parse_otp_type (void *cls,
   1716                 json_t *root,
   1717                 struct GNUNET_JSON_Specification *spec)
   1718 {
   1719   static const struct Entry
   1720   {
   1721     const char *name;
   1722     enum TALER_MerchantConfirmationAlgorithm val;
   1723   } lt [] = {
   1724     { .name = "NONE",
   1725       .val = TALER_MCA_NONE },
   1726     { .name = "TOTP_WITHOUT_PRICE",
   1727       .val = TALER_MCA_WITHOUT_PRICE },
   1728     { .name = "TOTP_WITH_PRICE",
   1729       .val = TALER_MCA_WITH_PRICE },
   1730     { .name = NULL,
   1731       .val = TALER_MCA_NONE },
   1732   };
   1733   enum TALER_MerchantConfirmationAlgorithm *res
   1734     = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
   1735 
   1736   (void) cls;
   1737   if (json_is_string (root))
   1738   {
   1739     const char *str;
   1740 
   1741     str = json_string_value (root);
   1742     if (NULL == str)
   1743     {
   1744       GNUNET_break_op (0);
   1745       return GNUNET_SYSERR;
   1746     }
   1747     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1748     {
   1749       if (0 == strcasecmp (str,
   1750                            lt[i].name))
   1751       {
   1752         *res = lt[i].val;
   1753         return GNUNET_OK;
   1754       }
   1755     }
   1756     GNUNET_break_op (0);
   1757   }
   1758   if (json_is_integer (root))
   1759   {
   1760     json_int_t val;
   1761 
   1762     val = json_integer_value (root);
   1763     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1764     {
   1765       if (val == lt[i].val)
   1766       {
   1767         *res = lt[i].val;
   1768         return GNUNET_OK;
   1769       }
   1770     }
   1771     GNUNET_break_op (0);
   1772     return GNUNET_SYSERR;
   1773   }
   1774   GNUNET_break_op (0);
   1775   return GNUNET_SYSERR;
   1776 }
   1777 
   1778 
   1779 struct GNUNET_JSON_Specification
   1780 TALER_JSON_spec_otp_type (const char *name,
   1781                           enum TALER_MerchantConfirmationAlgorithm *mca)
   1782 {
   1783   struct GNUNET_JSON_Specification ret = {
   1784     .parser = &parse_otp_type,
   1785     .field = name,
   1786     .ptr = mca
   1787   };
   1788 
   1789   *mca = TALER_MCA_NONE;
   1790   return ret;
   1791 }
   1792 
   1793 
   1794 /**
   1795  * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent`
   1796  *
   1797  * @param cls closure, NULL
   1798  * @param root the json object representing data
   1799  * @param[out] spec where to write the data
   1800  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1801  */
   1802 static enum GNUNET_GenericReturnValue
   1803 parse_kycte (void *cls,
   1804              json_t *root,
   1805              struct GNUNET_JSON_Specification *spec)
   1806 {
   1807   static const struct Entry
   1808   {
   1809     const char *name;
   1810     enum TALER_KYCLOGIC_KycTriggerEvent val;
   1811   } lt [] = {
   1812     { .name = "NONE",
   1813       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1814     { .name = "WITHDRAW",
   1815       .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   1816     { .name = "DEPOSIT",
   1817       .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
   1818     { .name = "MERGE",
   1819       .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   1820     { .name = "BALANCE",
   1821       .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   1822     { .name = "CLOSE",
   1823       .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   1824     { .name = "AGGREGATE",
   1825       .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   1826     { .name = "TRANSACTION",
   1827       .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   1828     { .name = "REFUND",
   1829       .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   1830     { .name = NULL,
   1831       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1832   };
   1833   enum TALER_KYCLOGIC_KycTriggerEvent *res
   1834     = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr;
   1835 
   1836   (void) cls;
   1837   if (json_is_string (root))
   1838   {
   1839     const char *str;
   1840 
   1841     str = json_string_value (root);
   1842     if (NULL == str)
   1843     {
   1844       GNUNET_break_op (0);
   1845       return GNUNET_SYSERR;
   1846     }
   1847     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1848     {
   1849       if (0 == strcasecmp (str,
   1850                            lt[i].name))
   1851       {
   1852         *res = lt[i].val;
   1853         return GNUNET_OK;
   1854       }
   1855     }
   1856     GNUNET_break_op (0);
   1857     return GNUNET_SYSERR;
   1858   }
   1859   if (json_is_integer (root))
   1860   {
   1861     json_int_t val;
   1862 
   1863     val = json_integer_value (root);
   1864     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1865     {
   1866       if (val == lt[i].val)
   1867       {
   1868         *res = lt[i].val;
   1869         return GNUNET_OK;
   1870       }
   1871     }
   1872     GNUNET_break_op (0);
   1873     return GNUNET_SYSERR;
   1874   }
   1875   GNUNET_break_op (0);
   1876   return GNUNET_SYSERR;
   1877 }
   1878 
   1879 
   1880 struct GNUNET_JSON_Specification
   1881 TALER_JSON_spec_kycte (const char *name,
   1882                        enum TALER_KYCLOGIC_KycTriggerEvent *kte)
   1883 {
   1884   struct GNUNET_JSON_Specification ret = {
   1885     .parser = &parse_kycte,
   1886     .field = name,
   1887     .ptr = kte
   1888   };
   1889 
   1890   *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE;
   1891   return ret;
   1892 }
   1893 
   1894 
   1895 /**
   1896  * Parser combinator of a tuple of parsers, for parsing
   1897  * an array of expected size and element types.
   1898  *
   1899  * @param cls closure, array of specs, NULL terminated
   1900  * @param root the json root
   1901  * @param[out] spec where to write the data
   1902  */
   1903 static enum GNUNET_GenericReturnValue
   1904 parse_tuple_of (void *cls,
   1905                 json_t *root,
   1906                 struct GNUNET_JSON_Specification *spec)
   1907 {
   1908   struct GNUNET_JSON_Specification *specs = cls;
   1909   static size_t max_specs = 100;
   1910   bool found_end = false;
   1911 
   1912   enum GNUNET_GenericReturnValue ret;
   1913 
   1914   if (! json_is_array (root))
   1915   {
   1916     return GNUNET_SYSERR;
   1917   }
   1918 
   1919   {
   1920     size_t num;
   1921     for (num = 0; num< max_specs; num++)
   1922     {
   1923       if (NULL == specs[num].parser)
   1924       {
   1925         found_end = true;
   1926         break;
   1927       }
   1928     }
   1929     GNUNET_assert (found_end);
   1930 
   1931     if (num != json_array_size (root))
   1932     {
   1933       GNUNET_break_op (0);
   1934       return GNUNET_SYSERR;
   1935     }
   1936   }
   1937 
   1938   {
   1939     json_t *j_entry;
   1940     size_t idx;
   1941 
   1942     json_array_foreach (root, idx, j_entry) {
   1943       ret = GNUNET_JSON_parse (j_entry,
   1944                                &specs[idx],
   1945                                NULL,
   1946                                NULL);
   1947       if (GNUNET_OK != ret)
   1948       {
   1949         GNUNET_break_op (0);
   1950         return GNUNET_SYSERR;
   1951       }
   1952     }
   1953   }
   1954 
   1955   return GNUNET_OK;
   1956 }
   1957 
   1958 
   1959 struct GNUNET_JSON_Specification
   1960 TALER_JSON_spec_tuple_of (
   1961   const char *field,
   1962   struct GNUNET_JSON_Specification specs[])
   1963 {
   1964   struct GNUNET_JSON_Specification ret = {
   1965     .parser = &parse_tuple_of,
   1966     .field = field,
   1967     .cls = specs
   1968   };
   1969 
   1970   return ret;
   1971 }
   1972 
   1973 
   1974 /**
   1975  * Parser for an array of unknown length but
   1976  * of elements of the same type with the same
   1977  * fixed length.
   1978  *
   1979  * @param cls closure, entry_size
   1980  * @param root the json root
   1981  * @param spec the output spec
   1982  */
   1983 static enum GNUNET_GenericReturnValue
   1984 parse_array_fixed (void *cls,
   1985                    json_t *root,
   1986                    struct GNUNET_JSON_Specification *spec)
   1987 {
   1988   enum GNUNET_GenericReturnValue ret;
   1989   size_t entry_size = (size_t) cls;
   1990   size_t num_entries;
   1991 
   1992   GNUNET_assert (0< entry_size);
   1993   num_entries = spec->ptr_size / entry_size;
   1994   GNUNET_assert (0 < num_entries);
   1995 
   1996 
   1997   if (! json_is_array (root))
   1998   {
   1999     GNUNET_break_op (0);
   2000     return GNUNET_SYSERR;
   2001   }
   2002   if (num_entries != json_array_size (root))
   2003   {
   2004     GNUNET_break_op (0);
   2005     return GNUNET_SYSERR;
   2006   }
   2007 
   2008   {
   2009     json_t *j_entry;
   2010     size_t idx;
   2011     void *ptr = spec->ptr;
   2012     void *end = spec->ptr + spec->ptr_size;
   2013 
   2014     json_array_foreach (root, idx, j_entry) {
   2015       struct GNUNET_JSON_Specification esp[] = {
   2016         GNUNET_JSON_spec_fixed (NULL,
   2017                                 ptr,
   2018                                 entry_size),
   2019         GNUNET_JSON_spec_end ()
   2020       };
   2021       GNUNET_assert (ptr < end);
   2022       ret = GNUNET_JSON_parse (j_entry,
   2023                                esp,
   2024                                NULL,
   2025                                NULL);
   2026       if (GNUNET_OK != ret)
   2027       {
   2028         GNUNET_break_op (0);
   2029         return GNUNET_SYSERR;
   2030       }
   2031       ptr += entry_size;
   2032     }
   2033   }
   2034   return GNUNET_OK;
   2035 }
   2036 
   2037 
   2038 struct GNUNET_JSON_Specification
   2039 TALER_JSON_spec_array_fixed (
   2040   const char *field,
   2041   size_t num_entries,
   2042   void *entries,
   2043   size_t entry_size)
   2044 {
   2045   struct GNUNET_JSON_Specification ret = {
   2046     .parser = &parse_array_fixed,
   2047     .ptr = entries,
   2048     .ptr_size = entry_size * num_entries,
   2049     .field = field,
   2050     .cls = (void *) entry_size,
   2051   };
   2052 
   2053   GNUNET_assert ((num_entries <= 1) ||
   2054                  (entry_size * num_entries > entry_size));
   2055   return ret;
   2056 }
   2057 
   2058 
   2059 /**
   2060  * Closure for the parser of arrays of fixed size data
   2061  * of unknown array length
   2062  */
   2063 struct closure_array_of_data
   2064 {
   2065   /**
   2066    * Fixed (known) size per entry
   2067    */
   2068   size_t entry_size;
   2069 
   2070   /**
   2071    * Pointer where to put the number of elements
   2072    * allocated, i.e. the number of elements in the
   2073    * json array.
   2074    */
   2075   size_t *num_entries;
   2076 };
   2077 
   2078 /**
   2079  * Parser for an array of data of known element size,
   2080  * but unknown array length
   2081  */
   2082 static enum GNUNET_GenericReturnValue
   2083 parse_array_of_data (void *cls,
   2084                      json_t *root,
   2085                      struct GNUNET_JSON_Specification *spec)
   2086 {
   2087   enum GNUNET_GenericReturnValue ret;
   2088   struct closure_array_of_data *info = cls;
   2089   size_t num_entries;
   2090 
   2091   if (! json_is_array (root))
   2092   {
   2093     GNUNET_break_op (0);
   2094     return GNUNET_SYSERR;
   2095   }
   2096   num_entries = json_array_size (root);
   2097   *info->num_entries = num_entries;
   2098   if (0 == num_entries)
   2099   {
   2100     *(char **) spec->ptr = NULL;
   2101     return GNUNET_OK;
   2102   }
   2103 
   2104   spec->ptr_size = num_entries * info->entry_size;
   2105   GNUNET_assert (spec->ptr_size > num_entries);
   2106   *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size);
   2107 
   2108   {
   2109     json_t *j_entry;
   2110     size_t idx;
   2111     char *ptr = *(char **) spec->ptr;
   2112     char *end = ptr + spec->ptr_size;
   2113 
   2114     json_array_foreach (root, idx, j_entry) {
   2115       struct GNUNET_JSON_Specification esp[] = {
   2116         GNUNET_JSON_spec_fixed (NULL,
   2117                                 ptr,
   2118                                 info->entry_size),
   2119         GNUNET_JSON_spec_end ()
   2120       };
   2121       GNUNET_assert (ptr < end);
   2122       ret = GNUNET_JSON_parse (j_entry,
   2123                                esp,
   2124                                NULL,
   2125                                NULL);
   2126       if (GNUNET_OK != ret)
   2127       {
   2128         GNUNET_break_op (0);
   2129         return GNUNET_SYSERR;
   2130       }
   2131       ptr += info->entry_size;
   2132     }
   2133   }
   2134   return GNUNET_OK;
   2135 }
   2136 
   2137 
   2138 /**
   2139  * Cleanup data left from parsing an array of fixed size (but unknown length).
   2140  *
   2141  * @param cls closure_of_array_data
   2142  * @param[out] spec where to free the data
   2143  */
   2144 static void
   2145 cleaner_array_of_data (void *cls,
   2146                        struct GNUNET_JSON_Specification *spec)
   2147 {
   2148   struct closure_array_of_data *info = cls;
   2149 
   2150   GNUNET_free (*(void **) spec->ptr);
   2151   GNUNET_free (info);
   2152 }
   2153 
   2154 
   2155 struct GNUNET_JSON_Specification
   2156 TALER_JSON_spec_array_of_data (
   2157   const char *field,
   2158   size_t entry_size,
   2159   size_t *num_entries,
   2160   void **entries)
   2161 {
   2162   struct closure_array_of_data *cls;
   2163 
   2164   GNUNET_assert (0< entry_size);
   2165   GNUNET_assert (NULL != entries);
   2166   cls = GNUNET_new (struct closure_array_of_data);
   2167   cls->num_entries = num_entries;
   2168   cls->entry_size = entry_size;
   2169   {
   2170     struct GNUNET_JSON_Specification ret = {
   2171       .parser = &parse_array_of_data,
   2172       .ptr = entries,
   2173       .field = field,
   2174       .cleaner = &cleaner_array_of_data,
   2175       .cls = (void *) cls,
   2176     };
   2177 
   2178     return ret;
   2179   }
   2180 }
   2181 
   2182 
   2183 struct GNUNET_JSON_Specification
   2184 TALER_JSON_spec_array_of_denom_pub_h (
   2185   const char *field,
   2186   size_t *num_entries,
   2187   struct TALER_DenominationHashP **entries)
   2188 {
   2189   return TALER_JSON_spec_array_of_data (
   2190     field,
   2191     sizeof (struct TALER_DenominationHashP),
   2192     num_entries,
   2193     (void **) entries);
   2194 }
   2195 
   2196 
   2197 /**
   2198  * Parser for an array of blinded denomination signatures,
   2199  * of unknown array length
   2200  */
   2201 static enum GNUNET_GenericReturnValue
   2202 parse_array_of_blinded_denom_sigs (void *cls,
   2203                                    json_t *root,
   2204                                    struct GNUNET_JSON_Specification *spec)
   2205 {
   2206   enum GNUNET_GenericReturnValue ret;
   2207   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2208   size_t expected_num_entries = (size_t) cls;
   2209   size_t num_entries;
   2210 
   2211   if (! json_is_array (root))
   2212   {
   2213     GNUNET_break_op (0);
   2214     return GNUNET_SYSERR;
   2215   }
   2216   num_entries = json_array_size (root);
   2217   if (num_entries != expected_num_entries)
   2218   {
   2219     GNUNET_break_op (0);
   2220     return GNUNET_SYSERR;
   2221   }
   2222 
   2223   {
   2224     json_t *j_entry;
   2225     size_t idx;
   2226     struct TALER_BlindedDenominationSignature *ptr = sigs;
   2227 
   2228     json_array_foreach (root, idx, j_entry) {
   2229       struct GNUNET_JSON_Specification esp[] = {
   2230         TALER_JSON_spec_blinded_denom_sig (NULL,
   2231                                            ptr),
   2232         GNUNET_JSON_spec_end ()
   2233       };
   2234       ret = GNUNET_JSON_parse (j_entry,
   2235                                esp,
   2236                                NULL,
   2237                                NULL);
   2238       if (GNUNET_OK != ret)
   2239       {
   2240         GNUNET_break_op (0);
   2241         return GNUNET_SYSERR;
   2242       }
   2243       ptr++;
   2244     }
   2245   }
   2246   return GNUNET_OK;
   2247 }
   2248 
   2249 
   2250 struct GNUNET_JSON_Specification
   2251 TALER_JSON_spec_array_of_blinded_denom_sigs (
   2252   const char *field,
   2253   size_t num_entries,
   2254   struct TALER_BlindedDenominationSignature *entries)
   2255 {
   2256   struct GNUNET_JSON_Specification ret = {
   2257     .parser = &parse_array_of_blinded_denom_sigs,
   2258     .ptr = entries,
   2259     .field = field,
   2260     .cls = (void *) num_entries,
   2261   };
   2262   return ret;
   2263 }
   2264 
   2265 
   2266 /* end of json/json_helper.c */