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


      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 slug.
   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_slug (void *cls,
   1490             json_t *root,
   1491             struct GNUNET_JSON_Specification *spec)
   1492 {
   1493   const char *str;
   1494 
   1495   (void) cls;
   1496   str = json_string_value (root);
   1497   if (NULL == str)
   1498   {
   1499     GNUNET_break_op (0);
   1500     return GNUNET_SYSERR;
   1501   }
   1502   if (! TALER_is_slug (str))
   1503   {
   1504     GNUNET_break_op (0);
   1505     return GNUNET_SYSERR;
   1506   }
   1507   *(const char **) spec->ptr = str;
   1508   return GNUNET_OK;
   1509 }
   1510 
   1511 
   1512 struct GNUNET_JSON_Specification
   1513 TALER_JSON_spec_slug (const char *field,
   1514                       const char **slug)
   1515 {
   1516   struct GNUNET_JSON_Specification ret = {
   1517     .parser = &parse_slug,
   1518     .field = field,
   1519     .ptr = slug
   1520   };
   1521 
   1522   *slug = NULL;
   1523   return ret;
   1524 }
   1525 
   1526 
   1527 /**
   1528  * Parse given JSON object to payto:// URI.
   1529  *
   1530  * @param cls closure, NULL
   1531  * @param root the json object representing data
   1532  * @param[out] spec where to write the data
   1533  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1534  */
   1535 static enum GNUNET_GenericReturnValue
   1536 parse_full_payto_uri (void *cls,
   1537                       json_t *root,
   1538                       struct GNUNET_JSON_Specification *spec)
   1539 {
   1540   struct TALER_FullPayto *payto_uri = spec->ptr;
   1541   const char *str;
   1542   char *err;
   1543 
   1544   (void) cls;
   1545   str = json_string_value (root);
   1546   if (NULL == str)
   1547   {
   1548     GNUNET_break_op (0);
   1549     return GNUNET_SYSERR;
   1550   }
   1551   payto_uri->full_payto = (char *) str;
   1552   err = TALER_payto_validate (*payto_uri);
   1553   if (NULL != err)
   1554   {
   1555     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1556                 "payto:// malformed: %s\n",
   1557                 err);
   1558     GNUNET_free (err);
   1559     payto_uri->full_payto = NULL;
   1560     return GNUNET_SYSERR;
   1561   }
   1562   return GNUNET_OK;
   1563 }
   1564 
   1565 
   1566 struct GNUNET_JSON_Specification
   1567 TALER_JSON_spec_full_payto_uri (
   1568   const char *field,
   1569   struct TALER_FullPayto *payto_uri)
   1570 {
   1571   struct GNUNET_JSON_Specification ret = {
   1572     .parser = &parse_full_payto_uri,
   1573     .field = field,
   1574     .ptr = payto_uri
   1575   };
   1576 
   1577   payto_uri->full_payto = NULL;
   1578   return ret;
   1579 }
   1580 
   1581 
   1582 /**
   1583  * Parse given JSON object to payto:// URI.
   1584  *
   1585  * @param cls closure, NULL
   1586  * @param root the json object representing data
   1587  * @param[out] spec where to write the data
   1588  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1589  */
   1590 static enum GNUNET_GenericReturnValue
   1591 parse_normalized_payto_uri (void *cls,
   1592                             json_t *root,
   1593                             struct GNUNET_JSON_Specification *spec)
   1594 {
   1595   struct TALER_NormalizedPayto *payto_uri = spec->ptr;
   1596   const char *str;
   1597 
   1598   (void) cls;
   1599   str = json_string_value (root);
   1600   if (NULL == str)
   1601   {
   1602     GNUNET_break_op (0);
   1603     return GNUNET_SYSERR;
   1604   }
   1605   payto_uri->normalized_payto = (char *) str;
   1606   {
   1607     char *err;
   1608 
   1609     err = TALER_normalized_payto_validate (*payto_uri);
   1610     if (NULL != err)
   1611     {
   1612       GNUNET_break_op (0);
   1613       GNUNET_free (err);
   1614       payto_uri->normalized_payto = NULL;
   1615       return GNUNET_SYSERR;
   1616     }
   1617   }
   1618   return GNUNET_OK;
   1619 }
   1620 
   1621 
   1622 struct GNUNET_JSON_Specification
   1623 TALER_JSON_spec_normalized_payto_uri (
   1624   const char *field,
   1625   struct TALER_NormalizedPayto *payto_uri)
   1626 {
   1627   struct GNUNET_JSON_Specification ret = {
   1628     .parser = &parse_normalized_payto_uri,
   1629     .field = field,
   1630     .ptr = payto_uri
   1631   };
   1632 
   1633   payto_uri->normalized_payto = NULL;
   1634   return ret;
   1635 }
   1636 
   1637 
   1638 /**
   1639  * Parse given JSON object with protocol version.
   1640  *
   1641  * @param cls closure, NULL
   1642  * @param root the json object representing data
   1643  * @param[out] spec where to write the data
   1644  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1645  */
   1646 static enum GNUNET_GenericReturnValue
   1647 parse_protocol_version (void *cls,
   1648                         json_t *root,
   1649                         struct GNUNET_JSON_Specification *spec)
   1650 {
   1651   struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
   1652   const char *ver;
   1653   char dummy;
   1654 
   1655   (void) cls;
   1656   if (! json_is_string (root))
   1657   {
   1658     GNUNET_break_op (0);
   1659     return GNUNET_SYSERR;
   1660   }
   1661   ver = json_string_value (root);
   1662   if (3 != sscanf (ver,
   1663                    "%u:%u:%u%c",
   1664                    &pv->current,
   1665                    &pv->revision,
   1666                    &pv->age,
   1667                    &dummy))
   1668   {
   1669     GNUNET_break_op (0);
   1670     return GNUNET_SYSERR;
   1671   }
   1672   return GNUNET_OK;
   1673 }
   1674 
   1675 
   1676 struct GNUNET_JSON_Specification
   1677 TALER_JSON_spec_version (const char *field,
   1678                          struct TALER_JSON_ProtocolVersion *ver)
   1679 {
   1680   struct GNUNET_JSON_Specification ret = {
   1681     .parser = &parse_protocol_version,
   1682     .field = field,
   1683     .ptr = ver
   1684   };
   1685 
   1686   return ret;
   1687 }
   1688 
   1689 
   1690 /**
   1691  * Parse given JSON object to an OTP key.
   1692  *
   1693  * @param cls closure, NULL
   1694  * @param root the json object representing data
   1695  * @param[out] spec where to write the data
   1696  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1697  */
   1698 static enum GNUNET_GenericReturnValue
   1699 parse_otp_key (void *cls,
   1700                json_t *root,
   1701                struct GNUNET_JSON_Specification *spec)
   1702 {
   1703   const char *pos_key;
   1704 
   1705   (void) cls;
   1706   pos_key = json_string_value (root);
   1707   if (NULL == pos_key)
   1708   {
   1709     GNUNET_break_op (0);
   1710     return GNUNET_SYSERR;
   1711   }
   1712   {
   1713     size_t pos_key_length = strlen (pos_key);
   1714     void *key; /* pos_key in binary */
   1715     size_t key_len; /* length of the key */
   1716     int dret;
   1717 
   1718     key_len = pos_key_length * 5 / 8;
   1719     key = GNUNET_malloc (key_len);
   1720     dret = TALER_rfc3548_base32decode (pos_key,
   1721                                        pos_key_length,
   1722                                        key,
   1723                                        key_len);
   1724     if (-1 == dret)
   1725     {
   1726       GNUNET_free (key);
   1727       GNUNET_break_op (0);
   1728       return GNUNET_SYSERR;
   1729     }
   1730     GNUNET_free (key);
   1731   }
   1732   *(const char **) spec->ptr = pos_key;
   1733   return GNUNET_OK;
   1734 }
   1735 
   1736 
   1737 struct GNUNET_JSON_Specification
   1738 TALER_JSON_spec_otp_key (const char *name,
   1739                          const char **otp_key)
   1740 {
   1741   struct GNUNET_JSON_Specification ret = {
   1742     .parser = &parse_otp_key,
   1743     .field = name,
   1744     .ptr = otp_key
   1745   };
   1746 
   1747   *otp_key = NULL;
   1748   return ret;
   1749 }
   1750 
   1751 
   1752 /**
   1753  * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
   1754  *
   1755  * @param cls closure, NULL
   1756  * @param root the json object representing data
   1757  * @param[out] spec where to write the data
   1758  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1759  */
   1760 static enum GNUNET_GenericReturnValue
   1761 parse_otp_type (void *cls,
   1762                 json_t *root,
   1763                 struct GNUNET_JSON_Specification *spec)
   1764 {
   1765   static const struct Entry
   1766   {
   1767     const char *name;
   1768     enum TALER_MerchantConfirmationAlgorithm val;
   1769   } lt [] = {
   1770     { .name = "NONE",
   1771       .val = TALER_MCA_NONE },
   1772     { .name = "TOTP_WITHOUT_PRICE",
   1773       .val = TALER_MCA_WITHOUT_PRICE },
   1774     { .name = "TOTP_WITH_PRICE",
   1775       .val = TALER_MCA_WITH_PRICE },
   1776     { .name = NULL,
   1777       .val = TALER_MCA_NONE },
   1778   };
   1779   enum TALER_MerchantConfirmationAlgorithm *res
   1780     = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
   1781 
   1782   (void) cls;
   1783   if (json_is_string (root))
   1784   {
   1785     const char *str;
   1786 
   1787     str = json_string_value (root);
   1788     if (NULL == str)
   1789     {
   1790       GNUNET_break_op (0);
   1791       return GNUNET_SYSERR;
   1792     }
   1793     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1794     {
   1795       if (0 == strcasecmp (str,
   1796                            lt[i].name))
   1797       {
   1798         *res = lt[i].val;
   1799         return GNUNET_OK;
   1800       }
   1801     }
   1802     GNUNET_break_op (0);
   1803   }
   1804   if (json_is_integer (root))
   1805   {
   1806     json_int_t val;
   1807 
   1808     val = json_integer_value (root);
   1809     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1810     {
   1811       if (val == lt[i].val)
   1812       {
   1813         *res = lt[i].val;
   1814         return GNUNET_OK;
   1815       }
   1816     }
   1817     GNUNET_break_op (0);
   1818     return GNUNET_SYSERR;
   1819   }
   1820   GNUNET_break_op (0);
   1821   return GNUNET_SYSERR;
   1822 }
   1823 
   1824 
   1825 struct GNUNET_JSON_Specification
   1826 TALER_JSON_spec_otp_type (const char *name,
   1827                           enum TALER_MerchantConfirmationAlgorithm *mca)
   1828 {
   1829   struct GNUNET_JSON_Specification ret = {
   1830     .parser = &parse_otp_type,
   1831     .field = name,
   1832     .ptr = mca
   1833   };
   1834 
   1835   *mca = TALER_MCA_NONE;
   1836   return ret;
   1837 }
   1838 
   1839 
   1840 /**
   1841  * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent`
   1842  *
   1843  * @param cls closure, NULL
   1844  * @param root the json object representing data
   1845  * @param[out] spec where to write the data
   1846  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1847  */
   1848 static enum GNUNET_GenericReturnValue
   1849 parse_kycte (void *cls,
   1850              json_t *root,
   1851              struct GNUNET_JSON_Specification *spec)
   1852 {
   1853   static const struct Entry
   1854   {
   1855     const char *name;
   1856     enum TALER_KYCLOGIC_KycTriggerEvent val;
   1857   } lt [] = {
   1858     { .name = "NONE",
   1859       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1860     { .name = "WITHDRAW",
   1861       .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   1862     { .name = "DEPOSIT",
   1863       .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
   1864     { .name = "MERGE",
   1865       .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   1866     { .name = "BALANCE",
   1867       .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   1868     { .name = "CLOSE",
   1869       .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   1870     { .name = "AGGREGATE",
   1871       .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   1872     { .name = "TRANSACTION",
   1873       .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   1874     { .name = "REFUND",
   1875       .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   1876     { .name = NULL,
   1877       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1878   };
   1879   enum TALER_KYCLOGIC_KycTriggerEvent *res
   1880     = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr;
   1881 
   1882   (void) cls;
   1883   if (json_is_string (root))
   1884   {
   1885     const char *str;
   1886 
   1887     str = json_string_value (root);
   1888     if (NULL == str)
   1889     {
   1890       GNUNET_break_op (0);
   1891       return GNUNET_SYSERR;
   1892     }
   1893     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1894     {
   1895       if (0 == strcasecmp (str,
   1896                            lt[i].name))
   1897       {
   1898         *res = lt[i].val;
   1899         return GNUNET_OK;
   1900       }
   1901     }
   1902     GNUNET_break_op (0);
   1903     return GNUNET_SYSERR;
   1904   }
   1905   if (json_is_integer (root))
   1906   {
   1907     json_int_t val;
   1908 
   1909     val = json_integer_value (root);
   1910     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1911     {
   1912       if (val == lt[i].val)
   1913       {
   1914         *res = lt[i].val;
   1915         return GNUNET_OK;
   1916       }
   1917     }
   1918     GNUNET_break_op (0);
   1919     return GNUNET_SYSERR;
   1920   }
   1921   GNUNET_break_op (0);
   1922   return GNUNET_SYSERR;
   1923 }
   1924 
   1925 
   1926 struct GNUNET_JSON_Specification
   1927 TALER_JSON_spec_kycte (const char *name,
   1928                        enum TALER_KYCLOGIC_KycTriggerEvent *kte)
   1929 {
   1930   struct GNUNET_JSON_Specification ret = {
   1931     .parser = &parse_kycte,
   1932     .field = name,
   1933     .ptr = kte
   1934   };
   1935 
   1936   *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE;
   1937   return ret;
   1938 }
   1939 
   1940 
   1941 /**
   1942  * Parser combinator of a tuple of parsers, for parsing
   1943  * an array of expected size and element types.
   1944  *
   1945  * @param cls closure, array of specs, NULL terminated
   1946  * @param root the json root
   1947  * @param[out] spec where to write the data
   1948  */
   1949 static enum GNUNET_GenericReturnValue
   1950 parse_tuple_of (void *cls,
   1951                 json_t *root,
   1952                 struct GNUNET_JSON_Specification *spec)
   1953 {
   1954   struct GNUNET_JSON_Specification *specs = cls;
   1955   static size_t max_specs = 100;
   1956   bool found_end = false;
   1957 
   1958   enum GNUNET_GenericReturnValue ret;
   1959 
   1960   if (! json_is_array (root))
   1961   {
   1962     return GNUNET_SYSERR;
   1963   }
   1964 
   1965   {
   1966     size_t num;
   1967     for (num = 0; num< max_specs; num++)
   1968     {
   1969       if (NULL == specs[num].parser)
   1970       {
   1971         found_end = true;
   1972         break;
   1973       }
   1974     }
   1975     GNUNET_assert (found_end);
   1976 
   1977     if (num != json_array_size (root))
   1978     {
   1979       GNUNET_break_op (0);
   1980       return GNUNET_SYSERR;
   1981     }
   1982   }
   1983 
   1984   {
   1985     json_t *j_entry;
   1986     size_t idx;
   1987 
   1988     json_array_foreach (root, idx, j_entry) {
   1989       ret = GNUNET_JSON_parse (j_entry,
   1990                                &specs[idx],
   1991                                NULL,
   1992                                NULL);
   1993       if (GNUNET_OK != ret)
   1994       {
   1995         GNUNET_break_op (0);
   1996         return GNUNET_SYSERR;
   1997       }
   1998     }
   1999   }
   2000 
   2001   return GNUNET_OK;
   2002 }
   2003 
   2004 
   2005 struct GNUNET_JSON_Specification
   2006 TALER_JSON_spec_tuple_of (
   2007   const char *field,
   2008   struct GNUNET_JSON_Specification specs[])
   2009 {
   2010   struct GNUNET_JSON_Specification ret = {
   2011     .parser = &parse_tuple_of,
   2012     .field = field,
   2013     .cls = specs
   2014   };
   2015 
   2016   return ret;
   2017 }
   2018 
   2019 
   2020 /**
   2021  * Parser for an array of unknown length but
   2022  * of elements of the same type with the same
   2023  * fixed length.
   2024  *
   2025  * @param cls closure, entry_size
   2026  * @param root the json root
   2027  * @param spec the output spec
   2028  */
   2029 static enum GNUNET_GenericReturnValue
   2030 parse_array_fixed (void *cls,
   2031                    json_t *root,
   2032                    struct GNUNET_JSON_Specification *spec)
   2033 {
   2034   enum GNUNET_GenericReturnValue ret;
   2035   size_t entry_size = (size_t) cls;
   2036   size_t num_entries;
   2037 
   2038   GNUNET_assert (0< entry_size);
   2039   num_entries = spec->ptr_size / entry_size;
   2040   GNUNET_assert (0 < num_entries);
   2041 
   2042 
   2043   if (! json_is_array (root))
   2044   {
   2045     GNUNET_break_op (0);
   2046     return GNUNET_SYSERR;
   2047   }
   2048   if (num_entries != json_array_size (root))
   2049   {
   2050     GNUNET_break_op (0);
   2051     return GNUNET_SYSERR;
   2052   }
   2053 
   2054   {
   2055     json_t *j_entry;
   2056     size_t idx;
   2057     void *ptr = spec->ptr;
   2058     void *end = spec->ptr + spec->ptr_size;
   2059 
   2060     json_array_foreach (root, idx, j_entry) {
   2061       struct GNUNET_JSON_Specification esp[] = {
   2062         GNUNET_JSON_spec_fixed (NULL,
   2063                                 ptr,
   2064                                 entry_size),
   2065         GNUNET_JSON_spec_end ()
   2066       };
   2067       GNUNET_assert (ptr < end);
   2068       ret = GNUNET_JSON_parse (j_entry,
   2069                                esp,
   2070                                NULL,
   2071                                NULL);
   2072       if (GNUNET_OK != ret)
   2073       {
   2074         GNUNET_break_op (0);
   2075         return GNUNET_SYSERR;
   2076       }
   2077       ptr += entry_size;
   2078     }
   2079   }
   2080   return GNUNET_OK;
   2081 }
   2082 
   2083 
   2084 struct GNUNET_JSON_Specification
   2085 TALER_JSON_spec_array_fixed (
   2086   const char *field,
   2087   size_t num_entries,
   2088   void *entries,
   2089   size_t entry_size)
   2090 {
   2091   struct GNUNET_JSON_Specification ret = {
   2092     .parser = &parse_array_fixed,
   2093     .ptr = entries,
   2094     .ptr_size = entry_size * num_entries,
   2095     .field = field,
   2096     .cls = (void *) entry_size,
   2097   };
   2098 
   2099   GNUNET_assert ((num_entries <= 1) ||
   2100                  (entry_size * num_entries > entry_size));
   2101   return ret;
   2102 }
   2103 
   2104 
   2105 /**
   2106  * Closure for the parser of arrays of fixed size data
   2107  * of unknown array length
   2108  */
   2109 struct closure_array_of_data
   2110 {
   2111   /**
   2112    * Fixed (known) size per entry
   2113    */
   2114   size_t entry_size;
   2115 
   2116   /**
   2117    * Pointer where to put the number of elements
   2118    * allocated, i.e. the number of elements in the
   2119    * json array.
   2120    */
   2121   size_t *num_entries;
   2122 };
   2123 
   2124 /**
   2125  * Parser for an array of data of known element size,
   2126  * but unknown array length
   2127  */
   2128 static enum GNUNET_GenericReturnValue
   2129 parse_array_of_data (void *cls,
   2130                      json_t *root,
   2131                      struct GNUNET_JSON_Specification *spec)
   2132 {
   2133   enum GNUNET_GenericReturnValue ret;
   2134   struct closure_array_of_data *info = cls;
   2135   size_t num_entries;
   2136 
   2137   if (! json_is_array (root))
   2138   {
   2139     GNUNET_break_op (0);
   2140     return GNUNET_SYSERR;
   2141   }
   2142   num_entries = json_array_size (root);
   2143   *info->num_entries = num_entries;
   2144   if (0 == num_entries)
   2145   {
   2146     *(char **) spec->ptr = NULL;
   2147     return GNUNET_OK;
   2148   }
   2149 
   2150   spec->ptr_size = num_entries * info->entry_size;
   2151   GNUNET_assert (spec->ptr_size > num_entries);
   2152   *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size);
   2153 
   2154   {
   2155     json_t *j_entry;
   2156     size_t idx;
   2157     char *ptr = *(char **) spec->ptr;
   2158     char *end = ptr + spec->ptr_size;
   2159 
   2160     json_array_foreach (root, idx, j_entry) {
   2161       struct GNUNET_JSON_Specification esp[] = {
   2162         GNUNET_JSON_spec_fixed (NULL,
   2163                                 ptr,
   2164                                 info->entry_size),
   2165         GNUNET_JSON_spec_end ()
   2166       };
   2167       GNUNET_assert (ptr < end);
   2168       ret = GNUNET_JSON_parse (j_entry,
   2169                                esp,
   2170                                NULL,
   2171                                NULL);
   2172       if (GNUNET_OK != ret)
   2173       {
   2174         GNUNET_break_op (0);
   2175         return GNUNET_SYSERR;
   2176       }
   2177       ptr += info->entry_size;
   2178     }
   2179   }
   2180   return GNUNET_OK;
   2181 }
   2182 
   2183 
   2184 /**
   2185  * Cleanup data left from parsing an array of fixed size (but unknown length).
   2186  *
   2187  * @param cls closure_of_array_data
   2188  * @param[out] spec where to free the data
   2189  */
   2190 static void
   2191 cleaner_array_of_data (void *cls,
   2192                        struct GNUNET_JSON_Specification *spec)
   2193 {
   2194   struct closure_array_of_data *info = cls;
   2195 
   2196   GNUNET_free (*(void **) spec->ptr);
   2197   GNUNET_free (info);
   2198 }
   2199 
   2200 
   2201 struct GNUNET_JSON_Specification
   2202 TALER_JSON_spec_array_of_data (
   2203   const char *field,
   2204   size_t entry_size,
   2205   size_t *num_entries,
   2206   void **entries)
   2207 {
   2208   struct closure_array_of_data *cls;
   2209 
   2210   GNUNET_assert (0< entry_size);
   2211   *entries = NULL;
   2212   *num_entries = 0;
   2213   cls = GNUNET_new (struct closure_array_of_data);
   2214   cls->num_entries = num_entries;
   2215   cls->entry_size = entry_size;
   2216   {
   2217     struct GNUNET_JSON_Specification ret = {
   2218       .parser = &parse_array_of_data,
   2219       .ptr = entries,
   2220       .field = field,
   2221       .cleaner = &cleaner_array_of_data,
   2222       .cls = (void *) cls,
   2223     };
   2224 
   2225     return ret;
   2226   }
   2227 }
   2228 
   2229 
   2230 struct GNUNET_JSON_Specification
   2231 TALER_JSON_spec_array_of_denom_pub_h (
   2232   const char *field,
   2233   size_t *num_entries,
   2234   struct TALER_DenominationHashP **entries)
   2235 {
   2236   *num_entries = 0;
   2237   *entries = NULL;
   2238   return TALER_JSON_spec_array_of_data (
   2239     field,
   2240     sizeof (struct TALER_DenominationHashP),
   2241     num_entries,
   2242     (void **) entries);
   2243 }
   2244 
   2245 
   2246 /**
   2247  * Parser for an array of blinded denomination signatures,
   2248  * of unknown array length
   2249  */
   2250 static enum GNUNET_GenericReturnValue
   2251 parse_array_of_blinded_denom_sigs (void *cls,
   2252                                    json_t *root,
   2253                                    struct GNUNET_JSON_Specification *spec)
   2254 {
   2255   enum GNUNET_GenericReturnValue ret;
   2256   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2257   size_t expected_num_entries = (size_t) cls;
   2258   size_t num_entries;
   2259 
   2260   if (! json_is_array (root))
   2261   {
   2262     GNUNET_break_op (0);
   2263     return GNUNET_SYSERR;
   2264   }
   2265   num_entries = json_array_size (root);
   2266   if (num_entries != expected_num_entries)
   2267   {
   2268     GNUNET_break_op (0);
   2269     return GNUNET_SYSERR;
   2270   }
   2271 
   2272   {
   2273     json_t *j_entry;
   2274     size_t idx;
   2275     struct TALER_BlindedDenominationSignature *ptr = sigs;
   2276 
   2277     json_array_foreach (root, idx, j_entry) {
   2278       struct GNUNET_JSON_Specification esp[] = {
   2279         TALER_JSON_spec_blinded_denom_sig (NULL,
   2280                                            ptr),
   2281         GNUNET_JSON_spec_end ()
   2282       };
   2283       ret = GNUNET_JSON_parse (j_entry,
   2284                                esp,
   2285                                NULL,
   2286                                NULL);
   2287       if (GNUNET_OK != ret)
   2288       {
   2289         GNUNET_break_op (0);
   2290         return GNUNET_SYSERR;
   2291       }
   2292       ptr++;
   2293     }
   2294   }
   2295   return GNUNET_OK;
   2296 }
   2297 
   2298 
   2299 struct GNUNET_JSON_Specification
   2300 TALER_JSON_spec_array_of_blinded_denom_sigs (
   2301   const char *field,
   2302   size_t num_entries,
   2303   struct TALER_BlindedDenominationSignature *entries)
   2304 {
   2305   struct GNUNET_JSON_Specification ret = {
   2306     .parser = &parse_array_of_blinded_denom_sigs,
   2307     .ptr = entries,
   2308     .field = field,
   2309     .cls = (void *) num_entries,
   2310   };
   2311 
   2312   for (size_t i = 0; i<num_entries; i++)
   2313     entries[i].blinded_sig = NULL;
   2314   return ret;
   2315 }
   2316 
   2317 
   2318 /* end of json/json_helper.c */