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 (54868B)


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