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


      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                 gspec[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                 gspec[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_free (age_commitment->pubs);
    643       age_commitment->num = 0;
    644       return GNUNET_SYSERR;
    645     }
    646   };
    647 
    648   return GNUNET_OK;
    649 }
    650 
    651 
    652 /**
    653  * Cleanup data left from parsing age commitment
    654  *
    655  * @param cls closure, NULL
    656  * @param[out] spec where to free the data
    657  */
    658 static void
    659 clean_age_commitment (void *cls,
    660                       struct GNUNET_JSON_Specification *spec)
    661 {
    662   struct TALER_AgeCommitment *age_commitment = spec->ptr;
    663 
    664   (void) cls;
    665   if ( (NULL == age_commitment) ||
    666        (NULL == age_commitment->pubs) )
    667     return;
    668   age_commitment->num = 0;
    669   GNUNET_free (age_commitment->pubs);
    670 }
    671 
    672 
    673 struct GNUNET_JSON_Specification
    674 TALER_JSON_spec_age_commitment (const char *name,
    675                                 struct TALER_AgeCommitment *age_commitment)
    676 {
    677   struct GNUNET_JSON_Specification ret = {
    678     .parser = &parse_age_commitment,
    679     .cleaner = &clean_age_commitment,
    680     .field = name,
    681     .ptr = age_commitment
    682   };
    683 
    684   return ret;
    685 }
    686 
    687 
    688 struct GNUNET_JSON_Specification
    689 TALER_JSON_spec_token_issue_sig (const char *field,
    690                                  struct TALER_TokenIssueSignature *sig)
    691 {
    692   sig->signature = NULL;
    693   return GNUNET_JSON_spec_unblinded_signature (field,
    694                                                &sig->signature);
    695 }
    696 
    697 
    698 struct GNUNET_JSON_Specification
    699 TALER_JSON_spec_blinded_token_issue_sig (
    700   const char *field,
    701   struct TALER_BlindedTokenIssueSignature *sig)
    702 {
    703   sig->signature = NULL;
    704   return GNUNET_JSON_spec_blinded_signature (field,
    705                                              &sig->signature);
    706 }
    707 
    708 
    709 struct GNUNET_JSON_Specification
    710 TALER_JSON_spec_token_envelope (const char *field,
    711                                 struct TALER_TokenEnvelope *env)
    712 {
    713   env->blinded_pub = NULL;
    714   return GNUNET_JSON_spec_blinded_message (field,
    715                                            &env->blinded_pub);
    716 }
    717 
    718 
    719 /**
    720  * Parse given JSON object to denomination public key.
    721  *
    722  * @param cls closure, NULL
    723  * @param root the json object representing data
    724  * @param[out] spec where to write the data
    725  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    726  */
    727 static enum GNUNET_GenericReturnValue
    728 parse_denom_pub (void *cls,
    729                  json_t *root,
    730                  struct GNUNET_JSON_Specification *spec)
    731 {
    732   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    733   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    734   const char *cipher;
    735   bool age_mask_missing = false;
    736   struct GNUNET_JSON_Specification dspec[] = {
    737     GNUNET_JSON_spec_string ("cipher",
    738                              &cipher),
    739     GNUNET_JSON_spec_mark_optional (
    740       GNUNET_JSON_spec_uint32 ("age_mask",
    741                                &denom_pub->age_mask.bits),
    742       &age_mask_missing),
    743     GNUNET_JSON_spec_end ()
    744   };
    745   const char *emsg;
    746   unsigned int eline;
    747 
    748   (void) cls;
    749   if (GNUNET_OK !=
    750       GNUNET_JSON_parse (root,
    751                          dspec,
    752                          &emsg,
    753                          &eline))
    754   {
    755     GNUNET_break_op (0);
    756     return GNUNET_SYSERR;
    757   }
    758 
    759   if (age_mask_missing)
    760     denom_pub->age_mask.bits = 0;
    761   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    762   bsign_pub->rc = 1;
    763   bsign_pub->cipher = string_to_cipher (cipher);
    764   switch (bsign_pub->cipher)
    765   {
    766   case GNUNET_CRYPTO_BSA_INVALID:
    767     break;
    768   case GNUNET_CRYPTO_BSA_RSA:
    769     {
    770       struct GNUNET_JSON_Specification ispec[] = {
    771         GNUNET_JSON_spec_rsa_public_key (
    772           "rsa_pub",
    773           &bsign_pub->details.rsa_public_key),
    774         GNUNET_JSON_spec_end ()
    775       };
    776 
    777       if (GNUNET_OK !=
    778           GNUNET_JSON_parse (root,
    779                              ispec,
    780                              &emsg,
    781                              &eline))
    782       {
    783         GNUNET_break_op (0);
    784         GNUNET_free (bsign_pub);
    785         return GNUNET_SYSERR;
    786       }
    787       denom_pub->bsign_pub_key = bsign_pub;
    788       return GNUNET_OK;
    789     }
    790   case GNUNET_CRYPTO_BSA_CS:
    791     {
    792       struct GNUNET_JSON_Specification ispec[] = {
    793         GNUNET_JSON_spec_fixed ("cs_pub",
    794                                 &bsign_pub->details.cs_public_key,
    795                                 sizeof (bsign_pub->details.cs_public_key)),
    796         GNUNET_JSON_spec_end ()
    797       };
    798 
    799       if (GNUNET_OK !=
    800           GNUNET_JSON_parse (root,
    801                              ispec,
    802                              &emsg,
    803                              &eline))
    804       {
    805         GNUNET_break_op (0);
    806         GNUNET_free (bsign_pub);
    807         return GNUNET_SYSERR;
    808       }
    809       denom_pub->bsign_pub_key = bsign_pub;
    810       return GNUNET_OK;
    811     }
    812   }
    813   GNUNET_break_op (0);
    814   GNUNET_free (bsign_pub);
    815   return GNUNET_SYSERR;
    816 }
    817 
    818 
    819 /**
    820  * Cleanup data left from parsing denomination public key.
    821  *
    822  * @param cls closure, NULL
    823  * @param[out] spec where to free the data
    824  */
    825 static void
    826 clean_denom_pub (void *cls,
    827                  struct GNUNET_JSON_Specification *spec)
    828 {
    829   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    830 
    831   (void) cls;
    832   TALER_denom_pub_free (denom_pub);
    833 }
    834 
    835 
    836 struct GNUNET_JSON_Specification
    837 TALER_JSON_spec_denom_pub (const char *field,
    838                            struct TALER_DenominationPublicKey *pk)
    839 {
    840   struct GNUNET_JSON_Specification ret = {
    841     .parser = &parse_denom_pub,
    842     .cleaner = &clean_denom_pub,
    843     .field = field,
    844     .ptr = pk
    845   };
    846 
    847   pk->bsign_pub_key = NULL;
    848   return ret;
    849 }
    850 
    851 
    852 /**
    853  * Parse given JSON object to token issue public key.
    854  *
    855  * @param cls closure, NULL
    856  * @param root the json object representing data
    857  * @param[out] spec where to write the data
    858  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    859  */
    860 static enum GNUNET_GenericReturnValue
    861 parse_token_pub (void *cls,
    862                  json_t *root,
    863                  struct GNUNET_JSON_Specification *spec)
    864 {
    865   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    866   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    867   const char *cipher;
    868   struct GNUNET_JSON_Specification dspec[] = {
    869     GNUNET_JSON_spec_string ("cipher",
    870                              &cipher),
    871     GNUNET_JSON_spec_end ()
    872   };
    873   const char *emsg;
    874   unsigned int eline;
    875 
    876   (void) cls;
    877   if (GNUNET_OK !=
    878       GNUNET_JSON_parse (root,
    879                          dspec,
    880                          &emsg,
    881                          &eline))
    882   {
    883     GNUNET_break_op (0);
    884     return GNUNET_SYSERR;
    885   }
    886 
    887   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    888   bsign_pub->rc = 1;
    889   bsign_pub->cipher = string_to_cipher (cipher);
    890   switch (bsign_pub->cipher)
    891   {
    892   case GNUNET_CRYPTO_BSA_INVALID:
    893     break;
    894   case GNUNET_CRYPTO_BSA_RSA:
    895     {
    896       struct GNUNET_JSON_Specification ispec[] = {
    897         GNUNET_JSON_spec_rsa_public_key (
    898           "rsa_pub",
    899           &bsign_pub->details.rsa_public_key),
    900         GNUNET_JSON_spec_end ()
    901       };
    902 
    903       if (GNUNET_OK !=
    904           GNUNET_JSON_parse (root,
    905                              ispec,
    906                              &emsg,
    907                              &eline))
    908       {
    909         GNUNET_break_op (0);
    910         GNUNET_free (bsign_pub);
    911         return GNUNET_SYSERR;
    912       }
    913       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
    914                                          &bsign_pub->pub_key_hash);
    915       token_pub->public_key = bsign_pub;
    916       return GNUNET_OK;
    917     }
    918   case GNUNET_CRYPTO_BSA_CS:
    919     {
    920       struct GNUNET_JSON_Specification ispec[] = {
    921         GNUNET_JSON_spec_fixed ("cs_pub",
    922                                 &bsign_pub->details.cs_public_key,
    923                                 sizeof (bsign_pub->details.cs_public_key)),
    924         GNUNET_JSON_spec_end ()
    925       };
    926 
    927       if (GNUNET_OK !=
    928           GNUNET_JSON_parse (root,
    929                              ispec,
    930                              &emsg,
    931                              &eline))
    932       {
    933         GNUNET_break_op (0);
    934         GNUNET_free (bsign_pub);
    935         return GNUNET_SYSERR;
    936       }
    937       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
    938                           sizeof(bsign_pub->details.cs_public_key),
    939                           &bsign_pub->pub_key_hash);
    940       token_pub->public_key = bsign_pub;
    941       return GNUNET_OK;
    942     }
    943   }
    944   GNUNET_break_op (0);
    945   GNUNET_free (bsign_pub);
    946   return GNUNET_SYSERR;
    947 }
    948 
    949 
    950 /**
    951  * Cleanup data left from parsing token issue public key.
    952  *
    953  * @param cls closure, NULL
    954  * @param[out] spec where to free the data
    955  */
    956 static void
    957 clean_token_pub (void *cls,
    958                  struct GNUNET_JSON_Specification *spec)
    959 {
    960   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    961 
    962   (void) cls;
    963   TALER_token_issue_pub_free (token_pub);
    964 }
    965 
    966 
    967 struct GNUNET_JSON_Specification
    968 TALER_JSON_spec_token_pub (const char *field,
    969                            struct TALER_TokenIssuePublicKey *pk)
    970 {
    971   struct GNUNET_JSON_Specification ret = {
    972     .field = field,
    973     .parser = &parse_token_pub,
    974     .cleaner = &clean_token_pub,
    975     .ptr = pk
    976   };
    977 
    978   pk->public_key = NULL;
    979   return ret;
    980 }
    981 
    982 
    983 /**
    984  * Parse given JSON object partially into a denomination public key.
    985  *
    986  * Depending on the cipher in cls, it parses the corresponding public key type.
    987  *
    988  * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
    989  * @param root the json object representing data
    990  * @param[out] spec where to write the data
    991  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    992  */
    993 static enum GNUNET_GenericReturnValue
    994 parse_denom_pub_cipher (void *cls,
    995                         json_t *root,
    996                         struct GNUNET_JSON_Specification *spec)
    997 {
    998   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    999   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
   1000     (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
   1001   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
   1002   const char *emsg;
   1003   unsigned int eline;
   1004 
   1005   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
   1006   bsign_pub->cipher = cipher;
   1007   bsign_pub->rc = 1;
   1008   switch (cipher)
   1009   {
   1010   case GNUNET_CRYPTO_BSA_INVALID:
   1011     break;
   1012   case GNUNET_CRYPTO_BSA_RSA:
   1013     {
   1014       struct GNUNET_JSON_Specification ispec[] = {
   1015         GNUNET_JSON_spec_rsa_public_key (
   1016           "rsa_pub",
   1017           &bsign_pub->details.rsa_public_key),
   1018         GNUNET_JSON_spec_end ()
   1019       };
   1020 
   1021       if (GNUNET_OK !=
   1022           GNUNET_JSON_parse (root,
   1023                              ispec,
   1024                              &emsg,
   1025                              &eline))
   1026       {
   1027         GNUNET_break_op (0);
   1028         GNUNET_free (bsign_pub);
   1029         return GNUNET_SYSERR;
   1030       }
   1031       denom_pub->bsign_pub_key = bsign_pub;
   1032       return GNUNET_OK;
   1033     }
   1034   case GNUNET_CRYPTO_BSA_CS:
   1035     {
   1036       struct GNUNET_JSON_Specification ispec[] = {
   1037         GNUNET_JSON_spec_fixed ("cs_pub",
   1038                                 &bsign_pub->details.cs_public_key,
   1039                                 sizeof (bsign_pub->details.cs_public_key)),
   1040         GNUNET_JSON_spec_end ()
   1041       };
   1042 
   1043       if (GNUNET_OK !=
   1044           GNUNET_JSON_parse (root,
   1045                              ispec,
   1046                              &emsg,
   1047                              &eline))
   1048       {
   1049         GNUNET_break_op (0);
   1050         GNUNET_free (bsign_pub);
   1051         return GNUNET_SYSERR;
   1052       }
   1053       denom_pub->bsign_pub_key = bsign_pub;
   1054       return GNUNET_OK;
   1055     }
   1056   }
   1057   GNUNET_break_op (0);
   1058   GNUNET_free (bsign_pub);
   1059   return GNUNET_SYSERR;
   1060 }
   1061 
   1062 
   1063 struct GNUNET_JSON_Specification
   1064 TALER_JSON_spec_denom_pub_cipher (
   1065   const char *field,
   1066   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
   1067   struct TALER_DenominationPublicKey *pk)
   1068 {
   1069   struct GNUNET_JSON_Specification ret = {
   1070     .parser = &parse_denom_pub_cipher,
   1071     .cleaner = &clean_denom_pub,
   1072     .field = field,
   1073     .cls = (void *) cipher,
   1074     .ptr = pk
   1075   };
   1076 
   1077   pk->bsign_pub_key = NULL;
   1078   return ret;
   1079 }
   1080 
   1081 
   1082 struct GNUNET_JSON_Specification
   1083 TALER_JSON_spec_denom_sig (const char *field,
   1084                            struct TALER_DenominationSignature *sig)
   1085 {
   1086   sig->unblinded_sig = NULL;
   1087   return GNUNET_JSON_spec_unblinded_signature (field,
   1088                                                &sig->unblinded_sig);
   1089 }
   1090 
   1091 
   1092 struct GNUNET_JSON_Specification
   1093 TALER_JSON_spec_blinded_denom_sig (
   1094   const char *field,
   1095   struct TALER_BlindedDenominationSignature *sig)
   1096 {
   1097   sig->blinded_sig = NULL;
   1098   return GNUNET_JSON_spec_blinded_signature (field,
   1099                                              &sig->blinded_sig);
   1100 }
   1101 
   1102 
   1103 struct GNUNET_JSON_Specification
   1104 TALER_JSON_spec_blinded_planchet (
   1105   const char *field,
   1106   struct TALER_BlindedPlanchet *blinded_planchet)
   1107 {
   1108   blinded_planchet->blinded_message = NULL;
   1109   return GNUNET_JSON_spec_blinded_message (field,
   1110                                            &blinded_planchet->blinded_message);
   1111 }
   1112 
   1113 
   1114 /**
   1115  * Parse given JSON object to exchange withdraw values (/csr).
   1116  *
   1117  * @param cls closure, NULL
   1118  * @param root the json object representing data
   1119  * @param[out] spec where to write the data
   1120  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1121  */
   1122 static enum GNUNET_GenericReturnValue
   1123 parse_exchange_blinding_values (void *cls,
   1124                                 json_t *root,
   1125                                 struct GNUNET_JSON_Specification *spec)
   1126 {
   1127   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1128   struct GNUNET_CRYPTO_BlindingInputValues *bi;
   1129   const char *cipher;
   1130   struct GNUNET_JSON_Specification dspec[] = {
   1131     GNUNET_JSON_spec_string ("cipher",
   1132                              &cipher),
   1133     GNUNET_JSON_spec_end ()
   1134   };
   1135   const char *emsg;
   1136   unsigned int eline;
   1137   enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
   1138 
   1139   (void) cls;
   1140   if (GNUNET_OK !=
   1141       GNUNET_JSON_parse (root,
   1142                          dspec,
   1143                          &emsg,
   1144                          &eline))
   1145   {
   1146     GNUNET_break_op (0);
   1147     return GNUNET_SYSERR;
   1148   }
   1149   ci = string_to_cipher (cipher);
   1150   switch (ci)
   1151   {
   1152   case GNUNET_CRYPTO_BSA_INVALID:
   1153     break;
   1154   case GNUNET_CRYPTO_BSA_RSA:
   1155     ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
   1156     return GNUNET_OK;
   1157   case GNUNET_CRYPTO_BSA_CS:
   1158     bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
   1159     bi->cipher = GNUNET_CRYPTO_BSA_CS;
   1160     bi->rc = 1;
   1161     {
   1162       struct GNUNET_JSON_Specification ispec[] = {
   1163         GNUNET_JSON_spec_fixed (
   1164           "r_pub_0",
   1165           &bi->details.cs_values.r_pub[0],
   1166           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1167         GNUNET_JSON_spec_fixed (
   1168           "r_pub_1",
   1169           &bi->details.cs_values.r_pub[1],
   1170           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1171         GNUNET_JSON_spec_end ()
   1172       };
   1173 
   1174       if (GNUNET_OK !=
   1175           GNUNET_JSON_parse (root,
   1176                              ispec,
   1177                              &emsg,
   1178                              &eline))
   1179       {
   1180         GNUNET_break_op (0);
   1181         GNUNET_free (bi);
   1182         return GNUNET_SYSERR;
   1183       }
   1184       ewv->blinding_inputs = bi;
   1185       return GNUNET_OK;
   1186     }
   1187   }
   1188   GNUNET_break_op (0);
   1189   return GNUNET_SYSERR;
   1190 }
   1191 
   1192 
   1193 /**
   1194  * Cleanup data left from parsing withdraw values
   1195  *
   1196  * @param cls closure, NULL
   1197  * @param[out] spec where to free the data
   1198  */
   1199 static void
   1200 clean_exchange_blinding_values (
   1201   void *cls,
   1202   struct GNUNET_JSON_Specification *spec)
   1203 {
   1204   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1205 
   1206   (void) cls;
   1207   TALER_denom_ewv_free (ewv);
   1208 }
   1209 
   1210 
   1211 struct GNUNET_JSON_Specification
   1212 TALER_JSON_spec_exchange_blinding_values (
   1213   const char *field,
   1214   struct TALER_ExchangeBlindingValues *ewv)
   1215 {
   1216   struct GNUNET_JSON_Specification ret = {
   1217     .parser = &parse_exchange_blinding_values,
   1218     .cleaner = &clean_exchange_blinding_values,
   1219     .field = field,
   1220     .ptr = ewv
   1221   };
   1222 
   1223   ewv->blinding_inputs = NULL;
   1224   return ret;
   1225 }
   1226 
   1227 
   1228 /**
   1229  * Closure for #parse_i18n_string.
   1230  */
   1231 struct I18nContext
   1232 {
   1233   /**
   1234    * Language pattern to match.
   1235    */
   1236   char *lp;
   1237 
   1238   /**
   1239    * Name of the field to match.
   1240    */
   1241   const char *field;
   1242 };
   1243 
   1244 
   1245 /**
   1246  * Parse given JSON object to internationalized string.
   1247  *
   1248  * @param cls closure, our `struct I18nContext *`
   1249  * @param root the json object representing data
   1250  * @param[out] spec where to write the data
   1251  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1252  */
   1253 static enum GNUNET_GenericReturnValue
   1254 parse_i18n_string (void *cls,
   1255                    json_t *root,
   1256                    struct GNUNET_JSON_Specification *spec)
   1257 {
   1258   struct I18nContext *ctx = cls;
   1259   json_t *i18n;
   1260   json_t *val;
   1261 
   1262   {
   1263     char *i18nf;
   1264 
   1265     GNUNET_asprintf (&i18nf,
   1266                      "%s_i18n",
   1267                      ctx->field);
   1268     i18n = json_object_get (root,
   1269                             i18nf);
   1270     GNUNET_free (i18nf);
   1271   }
   1272 
   1273   val = json_object_get (root,
   1274                          ctx->field);
   1275   if ( (NULL != i18n) &&
   1276        (NULL != ctx->lp) )
   1277   {
   1278     double best = 0.0;
   1279     json_t *pos;
   1280     const char *lang;
   1281 
   1282     json_object_foreach (i18n, lang, pos)
   1283     {
   1284       double score;
   1285 
   1286       score = TALER_pattern_matches (ctx->lp,
   1287                                      lang);
   1288       if (score > best)
   1289       {
   1290         best = score;
   1291         val = pos;
   1292       }
   1293     }
   1294   }
   1295 
   1296   {
   1297     const char *str;
   1298 
   1299     str = json_string_value (val);
   1300     *(const char **) spec->ptr = str;
   1301   }
   1302   return GNUNET_OK;
   1303 }
   1304 
   1305 
   1306 /**
   1307  * Function called to clean up data from earlier parsing.
   1308  *
   1309  * @param cls closure
   1310  * @param spec our specification entry with data to clean.
   1311  */
   1312 static void
   1313 i18n_cleaner (void *cls,
   1314               struct GNUNET_JSON_Specification *spec)
   1315 {
   1316   struct I18nContext *ctx = cls;
   1317 
   1318   (void) spec;
   1319   if (NULL != ctx)
   1320   {
   1321     GNUNET_free (ctx->lp);
   1322     GNUNET_free (ctx);
   1323   }
   1324 }
   1325 
   1326 
   1327 struct GNUNET_JSON_Specification
   1328 TALER_JSON_spec_i18n_string (const char *name,
   1329                              const char *language_pattern,
   1330                              const char **strptr)
   1331 {
   1332   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
   1333   struct GNUNET_JSON_Specification ret = {
   1334     .parser = &parse_i18n_string,
   1335     .cleaner = &i18n_cleaner,
   1336     .cls = ctx,
   1337     .field = NULL, /* we want the main object */
   1338     .ptr = strptr,
   1339     .ptr_size = 0,
   1340     .size_ptr = NULL
   1341   };
   1342 
   1343   ctx->lp = (NULL != language_pattern)
   1344     ? GNUNET_strdup (language_pattern)
   1345     : NULL;
   1346   ctx->field = name;
   1347   *strptr = NULL;
   1348   return ret;
   1349 }
   1350 
   1351 
   1352 struct GNUNET_JSON_Specification
   1353 TALER_JSON_spec_i18n_str (const char *name,
   1354                           const char **strptr)
   1355 {
   1356   const char *lang = getenv ("LANG");
   1357   char *dot;
   1358   char *l;
   1359   struct GNUNET_JSON_Specification ret;
   1360 
   1361   if (NULL != lang)
   1362   {
   1363     dot = strchr (lang,
   1364                   '.');
   1365     if (NULL == dot)
   1366       l = GNUNET_strdup (lang);
   1367     else
   1368       l = GNUNET_strndup (lang,
   1369                           dot - lang);
   1370   }
   1371   else
   1372   {
   1373     l = NULL;
   1374   }
   1375   ret = TALER_JSON_spec_i18n_string (name,
   1376                                      l,
   1377                                      strptr);
   1378   GNUNET_free (l);
   1379   return ret;
   1380 }
   1381 
   1382 
   1383 /**
   1384  * Parse given JSON object with Taler error code.
   1385  *
   1386  * @param cls closure, NULL
   1387  * @param root the json object representing data
   1388  * @param[out] spec where to write the data
   1389  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1390  */
   1391 static enum GNUNET_GenericReturnValue
   1392 parse_ec (void *cls,
   1393           json_t *root,
   1394           struct GNUNET_JSON_Specification *spec)
   1395 {
   1396   enum TALER_ErrorCode *ec = spec->ptr;
   1397   json_int_t num;
   1398 
   1399   (void) cls;
   1400   if (! json_is_integer (root))
   1401   {
   1402     GNUNET_break_op (0);
   1403     return GNUNET_SYSERR;
   1404   }
   1405   num = json_integer_value (root);
   1406   if (num < 0)
   1407   {
   1408     GNUNET_break_op (0);
   1409     *ec = TALER_EC_INVALID;
   1410     return GNUNET_SYSERR;
   1411   }
   1412   *ec = (enum TALER_ErrorCode) num;
   1413   return GNUNET_OK;
   1414 }
   1415 
   1416 
   1417 struct GNUNET_JSON_Specification
   1418 TALER_JSON_spec_ec (const char *field,
   1419                     enum TALER_ErrorCode *ec)
   1420 {
   1421   struct GNUNET_JSON_Specification ret = {
   1422     .parser = &parse_ec,
   1423     .field = field,
   1424     .ptr = ec
   1425   };
   1426 
   1427   *ec = TALER_EC_NONE;
   1428   return ret;
   1429 }
   1430 
   1431 
   1432 /**
   1433  * Parse given JSON object to web URL.
   1434  *
   1435  * @param cls closure, NULL
   1436  * @param root the json object representing data
   1437  * @param[out] spec where to write the data
   1438  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1439  */
   1440 static enum GNUNET_GenericReturnValue
   1441 parse_web_url (void *cls,
   1442                json_t *root,
   1443                struct GNUNET_JSON_Specification *spec)
   1444 {
   1445   const char *str;
   1446 
   1447   (void) cls;
   1448   str = json_string_value (root);
   1449   if (NULL == str)
   1450   {
   1451     GNUNET_break_op (0);
   1452     return GNUNET_SYSERR;
   1453   }
   1454   if (! TALER_is_web_url (str))
   1455   {
   1456     GNUNET_break_op (0);
   1457     return GNUNET_SYSERR;
   1458   }
   1459   *(const char **) spec->ptr = str;
   1460   return GNUNET_OK;
   1461 }
   1462 
   1463 
   1464 struct GNUNET_JSON_Specification
   1465 TALER_JSON_spec_web_url (const char *field,
   1466                          const char **url)
   1467 {
   1468   struct GNUNET_JSON_Specification ret = {
   1469     .parser = &parse_web_url,
   1470     .field = field,
   1471     .ptr = url
   1472   };
   1473 
   1474   *url = NULL;
   1475   return ret;
   1476 }
   1477 
   1478 
   1479 /**
   1480  * Parse given JSON object to slug.
   1481  *
   1482  * @param cls closure, NULL
   1483  * @param root the json object representing data
   1484  * @param[out] spec where to write the data
   1485  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1486  */
   1487 static enum GNUNET_GenericReturnValue
   1488 parse_slug (void *cls,
   1489             json_t *root,
   1490             struct GNUNET_JSON_Specification *spec)
   1491 {
   1492   const char *str;
   1493 
   1494   (void) cls;
   1495   str = json_string_value (root);
   1496   if (NULL == str)
   1497   {
   1498     GNUNET_break_op (0);
   1499     return GNUNET_SYSERR;
   1500   }
   1501   if (! TALER_is_slug (str))
   1502   {
   1503     GNUNET_break_op (0);
   1504     return GNUNET_SYSERR;
   1505   }
   1506   *(const char **) spec->ptr = str;
   1507   return GNUNET_OK;
   1508 }
   1509 
   1510 
   1511 struct GNUNET_JSON_Specification
   1512 TALER_JSON_spec_slug (const char *field,
   1513                       const char **slug)
   1514 {
   1515   struct GNUNET_JSON_Specification ret = {
   1516     .parser = &parse_slug,
   1517     .field = field,
   1518     .ptr = slug
   1519   };
   1520 
   1521   *slug = NULL;
   1522   return ret;
   1523 }
   1524 
   1525 
   1526 /**
   1527  * Parse given JSON object to payto:// URI.
   1528  *
   1529  * @param cls closure, NULL
   1530  * @param root the json object representing data
   1531  * @param[out] spec where to write the data
   1532  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1533  */
   1534 static enum GNUNET_GenericReturnValue
   1535 parse_full_payto_uri (void *cls,
   1536                       json_t *root,
   1537                       struct GNUNET_JSON_Specification *spec)
   1538 {
   1539   struct TALER_FullPayto *payto_uri = spec->ptr;
   1540   const char *str;
   1541   char *err;
   1542 
   1543   (void) cls;
   1544   str = json_string_value (root);
   1545   if (NULL == str)
   1546   {
   1547     GNUNET_break_op (0);
   1548     return GNUNET_SYSERR;
   1549   }
   1550   payto_uri->full_payto = (char *) str;
   1551   err = TALER_payto_validate (*payto_uri);
   1552   if (NULL != err)
   1553   {
   1554     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1555                 "payto:// malformed: %s\n",
   1556                 err);
   1557     GNUNET_free (err);
   1558     payto_uri->full_payto = NULL;
   1559     return GNUNET_SYSERR;
   1560   }
   1561   return GNUNET_OK;
   1562 }
   1563 
   1564 
   1565 struct GNUNET_JSON_Specification
   1566 TALER_JSON_spec_full_payto_uri (
   1567   const char *field,
   1568   struct TALER_FullPayto *payto_uri)
   1569 {
   1570   struct GNUNET_JSON_Specification ret = {
   1571     .parser = &parse_full_payto_uri,
   1572     .field = field,
   1573     .ptr = payto_uri
   1574   };
   1575 
   1576   payto_uri->full_payto = NULL;
   1577   return ret;
   1578 }
   1579 
   1580 
   1581 /**
   1582  * Parse given JSON object to payto:// URI.
   1583  *
   1584  * @param cls closure, NULL
   1585  * @param root the json object representing data
   1586  * @param[out] spec where to write the data
   1587  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1588  */
   1589 static enum GNUNET_GenericReturnValue
   1590 parse_normalized_payto_uri (void *cls,
   1591                             json_t *root,
   1592                             struct GNUNET_JSON_Specification *spec)
   1593 {
   1594   struct TALER_NormalizedPayto *payto_uri = spec->ptr;
   1595   const char *str;
   1596 
   1597   (void) cls;
   1598   str = json_string_value (root);
   1599   if (NULL == str)
   1600   {
   1601     GNUNET_break_op (0);
   1602     return GNUNET_SYSERR;
   1603   }
   1604   payto_uri->normalized_payto = (char *) str;
   1605   {
   1606     char *err;
   1607 
   1608     err = TALER_normalized_payto_validate (*payto_uri);
   1609     if (NULL != err)
   1610     {
   1611       GNUNET_break_op (0);
   1612       GNUNET_free (err);
   1613       payto_uri->normalized_payto = NULL;
   1614       return GNUNET_SYSERR;
   1615     }
   1616   }
   1617   return GNUNET_OK;
   1618 }
   1619 
   1620 
   1621 struct GNUNET_JSON_Specification
   1622 TALER_JSON_spec_normalized_payto_uri (
   1623   const char *field,
   1624   struct TALER_NormalizedPayto *payto_uri)
   1625 {
   1626   struct GNUNET_JSON_Specification ret = {
   1627     .parser = &parse_normalized_payto_uri,
   1628     .field = field,
   1629     .ptr = payto_uri
   1630   };
   1631 
   1632   payto_uri->normalized_payto = NULL;
   1633   return ret;
   1634 }
   1635 
   1636 
   1637 /**
   1638  * Parse given JSON object with protocol version.
   1639  *
   1640  * @param cls closure, NULL
   1641  * @param root the json object representing data
   1642  * @param[out] spec where to write the data
   1643  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1644  */
   1645 static enum GNUNET_GenericReturnValue
   1646 parse_protocol_version (void *cls,
   1647                         json_t *root,
   1648                         struct GNUNET_JSON_Specification *spec)
   1649 {
   1650   struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
   1651   const char *ver;
   1652   char dummy;
   1653 
   1654   (void) cls;
   1655   if (! json_is_string (root))
   1656   {
   1657     GNUNET_break_op (0);
   1658     return GNUNET_SYSERR;
   1659   }
   1660   ver = json_string_value (root);
   1661   if (3 != sscanf (ver,
   1662                    "%u:%u:%u%c",
   1663                    &pv->current,
   1664                    &pv->revision,
   1665                    &pv->age,
   1666                    &dummy))
   1667   {
   1668     GNUNET_break_op (0);
   1669     return GNUNET_SYSERR;
   1670   }
   1671   return GNUNET_OK;
   1672 }
   1673 
   1674 
   1675 struct GNUNET_JSON_Specification
   1676 TALER_JSON_spec_version (const char *field,
   1677                          struct TALER_JSON_ProtocolVersion *ver)
   1678 {
   1679   struct GNUNET_JSON_Specification ret = {
   1680     .parser = &parse_protocol_version,
   1681     .field = field,
   1682     .ptr = ver
   1683   };
   1684 
   1685   return ret;
   1686 }
   1687 
   1688 
   1689 /**
   1690  * Parse given JSON object to an OTP key.
   1691  *
   1692  * @param cls closure, NULL
   1693  * @param root the json object representing data
   1694  * @param[out] spec where to write the data
   1695  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1696  */
   1697 static enum GNUNET_GenericReturnValue
   1698 parse_otp_key (void *cls,
   1699                json_t *root,
   1700                struct GNUNET_JSON_Specification *spec)
   1701 {
   1702   const char *pos_key;
   1703 
   1704   (void) cls;
   1705   pos_key = json_string_value (root);
   1706   if (NULL == pos_key)
   1707   {
   1708     GNUNET_break_op (0);
   1709     return GNUNET_SYSERR;
   1710   }
   1711   {
   1712     size_t pos_key_length = strlen (pos_key);
   1713     void *key; /* pos_key in binary */
   1714     size_t key_len; /* length of the key */
   1715     int dret;
   1716 
   1717     key_len = pos_key_length * 5 / 8;
   1718     key = GNUNET_malloc (key_len);
   1719     dret = TALER_rfc3548_base32decode (pos_key,
   1720                                        pos_key_length,
   1721                                        key,
   1722                                        key_len);
   1723     if (-1 == dret)
   1724     {
   1725       GNUNET_free (key);
   1726       GNUNET_break_op (0);
   1727       return GNUNET_SYSERR;
   1728     }
   1729     GNUNET_free (key);
   1730   }
   1731   *(const char **) spec->ptr = pos_key;
   1732   return GNUNET_OK;
   1733 }
   1734 
   1735 
   1736 struct GNUNET_JSON_Specification
   1737 TALER_JSON_spec_otp_key (const char *name,
   1738                          const char **otp_key)
   1739 {
   1740   struct GNUNET_JSON_Specification ret = {
   1741     .parser = &parse_otp_key,
   1742     .field = name,
   1743     .ptr = otp_key
   1744   };
   1745 
   1746   *otp_key = NULL;
   1747   return ret;
   1748 }
   1749 
   1750 
   1751 /**
   1752  * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
   1753  *
   1754  * @param cls closure, NULL
   1755  * @param root the json object representing data
   1756  * @param[out] spec where to write the data
   1757  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1758  */
   1759 static enum GNUNET_GenericReturnValue
   1760 parse_otp_type (void *cls,
   1761                 json_t *root,
   1762                 struct GNUNET_JSON_Specification *spec)
   1763 {
   1764   static const struct Entry
   1765   {
   1766     const char *name;
   1767     enum TALER_MerchantConfirmationAlgorithm val;
   1768   } lt [] = {
   1769     { .name = "NONE",
   1770       .val = TALER_MCA_NONE },
   1771     { .name = "TOTP_WITHOUT_PRICE",
   1772       .val = TALER_MCA_WITHOUT_PRICE },
   1773     { .name = "TOTP_WITH_PRICE",
   1774       .val = TALER_MCA_WITH_PRICE },
   1775     { .name = NULL,
   1776       .val = TALER_MCA_NONE },
   1777   };
   1778   enum TALER_MerchantConfirmationAlgorithm *res
   1779     = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
   1780 
   1781   (void) cls;
   1782   if (json_is_string (root))
   1783   {
   1784     const char *str;
   1785 
   1786     str = json_string_value (root);
   1787     if (NULL == str)
   1788     {
   1789       GNUNET_break_op (0);
   1790       return GNUNET_SYSERR;
   1791     }
   1792     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1793     {
   1794       if (0 == strcasecmp (str,
   1795                            lt[i].name))
   1796       {
   1797         *res = lt[i].val;
   1798         return GNUNET_OK;
   1799       }
   1800     }
   1801     GNUNET_break_op (0);
   1802   }
   1803   if (json_is_integer (root))
   1804   {
   1805     json_int_t val;
   1806 
   1807     val = json_integer_value (root);
   1808     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1809     {
   1810       if (val == lt[i].val)
   1811       {
   1812         *res = lt[i].val;
   1813         return GNUNET_OK;
   1814       }
   1815     }
   1816     GNUNET_break_op (0);
   1817     return GNUNET_SYSERR;
   1818   }
   1819   GNUNET_break_op (0);
   1820   return GNUNET_SYSERR;
   1821 }
   1822 
   1823 
   1824 struct GNUNET_JSON_Specification
   1825 TALER_JSON_spec_otp_type (const char *name,
   1826                           enum TALER_MerchantConfirmationAlgorithm *mca)
   1827 {
   1828   struct GNUNET_JSON_Specification ret = {
   1829     .parser = &parse_otp_type,
   1830     .field = name,
   1831     .ptr = mca
   1832   };
   1833 
   1834   *mca = TALER_MCA_NONE;
   1835   return ret;
   1836 }
   1837 
   1838 
   1839 /**
   1840  * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent`
   1841  *
   1842  * @param cls closure, NULL
   1843  * @param root the json object representing data
   1844  * @param[out] spec where to write the data
   1845  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1846  */
   1847 static enum GNUNET_GenericReturnValue
   1848 parse_kycte (void *cls,
   1849              json_t *root,
   1850              struct GNUNET_JSON_Specification *spec)
   1851 {
   1852   static const struct Entry
   1853   {
   1854     const char *name;
   1855     enum TALER_KYCLOGIC_KycTriggerEvent val;
   1856   } lt [] = {
   1857     { .name = "NONE",
   1858       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1859     { .name = "WITHDRAW",
   1860       .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   1861     { .name = "DEPOSIT",
   1862       .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
   1863     { .name = "MERGE",
   1864       .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   1865     { .name = "BALANCE",
   1866       .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   1867     { .name = "CLOSE",
   1868       .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   1869     { .name = "AGGREGATE",
   1870       .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   1871     { .name = "TRANSACTION",
   1872       .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   1873     { .name = "REFUND",
   1874       .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   1875     { .name = NULL,
   1876       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   1877   };
   1878   enum TALER_KYCLOGIC_KycTriggerEvent *res
   1879     = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr;
   1880 
   1881   (void) cls;
   1882   if (json_is_string (root))
   1883   {
   1884     const char *str;
   1885 
   1886     str = json_string_value (root);
   1887     if (NULL == str)
   1888     {
   1889       GNUNET_break_op (0);
   1890       return GNUNET_SYSERR;
   1891     }
   1892     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1893     {
   1894       if (0 == strcasecmp (str,
   1895                            lt[i].name))
   1896       {
   1897         *res = lt[i].val;
   1898         return GNUNET_OK;
   1899       }
   1900     }
   1901     GNUNET_break_op (0);
   1902     return GNUNET_SYSERR;
   1903   }
   1904   if (json_is_integer (root))
   1905   {
   1906     json_int_t val;
   1907 
   1908     val = json_integer_value (root);
   1909     for (unsigned int i = 0; NULL != lt[i].name; i++)
   1910     {
   1911       if (val == lt[i].val)
   1912       {
   1913         *res = lt[i].val;
   1914         return GNUNET_OK;
   1915       }
   1916     }
   1917     GNUNET_break_op (0);
   1918     return GNUNET_SYSERR;
   1919   }
   1920   GNUNET_break_op (0);
   1921   return GNUNET_SYSERR;
   1922 }
   1923 
   1924 
   1925 struct GNUNET_JSON_Specification
   1926 TALER_JSON_spec_kycte (const char *name,
   1927                        enum TALER_KYCLOGIC_KycTriggerEvent *kte)
   1928 {
   1929   struct GNUNET_JSON_Specification ret = {
   1930     .parser = &parse_kycte,
   1931     .field = name,
   1932     .ptr = kte
   1933   };
   1934 
   1935   *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE;
   1936   return ret;
   1937 }
   1938 
   1939 
   1940 /**
   1941  * Parser combinator of a tuple of parsers, for parsing
   1942  * an array of expected size and element types.
   1943  *
   1944  * @param cls closure, array of specs, NULL terminated
   1945  * @param root the json root
   1946  * @param[out] spec where to write the data
   1947  */
   1948 static enum GNUNET_GenericReturnValue
   1949 parse_tuple_of (void *cls,
   1950                 json_t *root,
   1951                 struct GNUNET_JSON_Specification *spec)
   1952 {
   1953   struct GNUNET_JSON_Specification *specs = cls;
   1954   static size_t max_specs = 100;
   1955   bool found_end = false;
   1956 
   1957   enum GNUNET_GenericReturnValue ret;
   1958 
   1959   if (! json_is_array (root))
   1960   {
   1961     return GNUNET_SYSERR;
   1962   }
   1963 
   1964   {
   1965     size_t num;
   1966     for (num = 0; num< max_specs; num++)
   1967     {
   1968       if (NULL == specs[num].parser)
   1969       {
   1970         found_end = true;
   1971         break;
   1972       }
   1973     }
   1974     GNUNET_assert (found_end);
   1975 
   1976     if (num != json_array_size (root))
   1977     {
   1978       GNUNET_break_op (0);
   1979       return GNUNET_SYSERR;
   1980     }
   1981   }
   1982 
   1983   {
   1984     json_t *j_entry;
   1985     size_t idx;
   1986 
   1987     json_array_foreach (root, idx, j_entry) {
   1988       ret = GNUNET_JSON_parse (j_entry,
   1989                                &specs[idx],
   1990                                NULL,
   1991                                NULL);
   1992       if (GNUNET_OK != ret)
   1993       {
   1994         GNUNET_break_op (0);
   1995         return GNUNET_SYSERR;
   1996       }
   1997     }
   1998   }
   1999 
   2000   return GNUNET_OK;
   2001 }
   2002 
   2003 
   2004 struct GNUNET_JSON_Specification
   2005 TALER_JSON_spec_tuple_of (
   2006   const char *field,
   2007   struct GNUNET_JSON_Specification specs[])
   2008 {
   2009   struct GNUNET_JSON_Specification ret = {
   2010     .parser = &parse_tuple_of,
   2011     .field = field,
   2012     .cls = specs
   2013   };
   2014 
   2015   return ret;
   2016 }
   2017 
   2018 
   2019 /**
   2020  * Parser for an array of unknown length but
   2021  * of elements of the same type with the same
   2022  * fixed length.
   2023  *
   2024  * @param cls closure, entry_size
   2025  * @param root the json root
   2026  * @param spec the output spec
   2027  */
   2028 static enum GNUNET_GenericReturnValue
   2029 parse_array_fixed (void *cls,
   2030                    json_t *root,
   2031                    struct GNUNET_JSON_Specification *spec)
   2032 {
   2033   enum GNUNET_GenericReturnValue ret;
   2034   size_t entry_size = (size_t) cls;
   2035   size_t num_entries;
   2036 
   2037   GNUNET_assert (0< entry_size);
   2038   num_entries = spec->ptr_size / entry_size;
   2039   GNUNET_assert (0 < num_entries);
   2040 
   2041 
   2042   if (! json_is_array (root))
   2043   {
   2044     GNUNET_break_op (0);
   2045     return GNUNET_SYSERR;
   2046   }
   2047   if (num_entries != json_array_size (root))
   2048   {
   2049     GNUNET_break_op (0);
   2050     return GNUNET_SYSERR;
   2051   }
   2052 
   2053   {
   2054     json_t *j_entry;
   2055     size_t idx;
   2056     void *ptr = spec->ptr;
   2057     void *end = spec->ptr + spec->ptr_size;
   2058 
   2059     json_array_foreach (root, idx, j_entry) {
   2060       struct GNUNET_JSON_Specification esp[] = {
   2061         GNUNET_JSON_spec_fixed (NULL,
   2062                                 ptr,
   2063                                 entry_size),
   2064         GNUNET_JSON_spec_end ()
   2065       };
   2066       GNUNET_assert (ptr < end);
   2067       ret = GNUNET_JSON_parse (j_entry,
   2068                                esp,
   2069                                NULL,
   2070                                NULL);
   2071       if (GNUNET_OK != ret)
   2072       {
   2073         GNUNET_break_op (0);
   2074         return GNUNET_SYSERR;
   2075       }
   2076       ptr += entry_size;
   2077     }
   2078   }
   2079   return GNUNET_OK;
   2080 }
   2081 
   2082 
   2083 struct GNUNET_JSON_Specification
   2084 TALER_JSON_spec_array_fixed (
   2085   const char *field,
   2086   size_t num_entries,
   2087   void *entries,
   2088   size_t entry_size)
   2089 {
   2090   struct GNUNET_JSON_Specification ret = {
   2091     .parser = &parse_array_fixed,
   2092     .ptr = entries,
   2093     .ptr_size = entry_size * num_entries,
   2094     .field = field,
   2095     .cls = (void *) entry_size,
   2096   };
   2097 
   2098   GNUNET_assert ((num_entries <= 1) ||
   2099                  (entry_size * num_entries > entry_size));
   2100   return ret;
   2101 }
   2102 
   2103 
   2104 /**
   2105  * Closure for the parser of arrays of fixed size data
   2106  * of unknown array length
   2107  */
   2108 struct closure_array_of_data
   2109 {
   2110   /**
   2111    * Fixed (known) size per entry
   2112    */
   2113   size_t entry_size;
   2114 
   2115   /**
   2116    * Pointer where to put the number of elements
   2117    * allocated, i.e. the number of elements in the
   2118    * json array.
   2119    */
   2120   size_t *num_entries;
   2121 };
   2122 
   2123 /**
   2124  * Parser for an array of data of known element size,
   2125  * but unknown array length
   2126  */
   2127 static enum GNUNET_GenericReturnValue
   2128 parse_array_of_data (void *cls,
   2129                      json_t *root,
   2130                      struct GNUNET_JSON_Specification *spec)
   2131 {
   2132   enum GNUNET_GenericReturnValue ret;
   2133   struct closure_array_of_data *info = cls;
   2134   size_t num_entries;
   2135 
   2136   if (! json_is_array (root))
   2137   {
   2138     GNUNET_break_op (0);
   2139     return GNUNET_SYSERR;
   2140   }
   2141   num_entries = json_array_size (root);
   2142   *info->num_entries = num_entries;
   2143   if (0 == num_entries)
   2144   {
   2145     *(char **) spec->ptr = NULL;
   2146     return GNUNET_OK;
   2147   }
   2148 
   2149   spec->ptr_size = num_entries * info->entry_size;
   2150   GNUNET_assert (spec->ptr_size > num_entries);
   2151   *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size);
   2152 
   2153   {
   2154     json_t *j_entry;
   2155     size_t idx;
   2156     char *ptr = *(char **) spec->ptr;
   2157     char *end = ptr + spec->ptr_size;
   2158 
   2159     json_array_foreach (root, idx, j_entry) {
   2160       struct GNUNET_JSON_Specification esp[] = {
   2161         GNUNET_JSON_spec_fixed (NULL,
   2162                                 ptr,
   2163                                 info->entry_size),
   2164         GNUNET_JSON_spec_end ()
   2165       };
   2166       GNUNET_assert (ptr < end);
   2167       ret = GNUNET_JSON_parse (j_entry,
   2168                                esp,
   2169                                NULL,
   2170                                NULL);
   2171       if (GNUNET_OK != ret)
   2172       {
   2173         GNUNET_break_op (0);
   2174         return GNUNET_SYSERR;
   2175       }
   2176       ptr += info->entry_size;
   2177     }
   2178   }
   2179   return GNUNET_OK;
   2180 }
   2181 
   2182 
   2183 /**
   2184  * Cleanup data left from parsing an array of fixed size (but unknown length).
   2185  *
   2186  * @param cls closure_of_array_data
   2187  * @param[out] spec where to free the data
   2188  */
   2189 static void
   2190 cleaner_array_of_data (void *cls,
   2191                        struct GNUNET_JSON_Specification *spec)
   2192 {
   2193   struct closure_array_of_data *info = cls;
   2194 
   2195   GNUNET_free (*(void **) spec->ptr);
   2196   GNUNET_free (info);
   2197 }
   2198 
   2199 
   2200 struct GNUNET_JSON_Specification
   2201 TALER_JSON_spec_array_of_data (
   2202   const char *field,
   2203   size_t entry_size,
   2204   size_t *num_entries,
   2205   void **entries)
   2206 {
   2207   struct closure_array_of_data *cls;
   2208 
   2209   GNUNET_assert (0< entry_size);
   2210   *entries = NULL;
   2211   *num_entries = 0;
   2212   cls = GNUNET_new (struct closure_array_of_data);
   2213   cls->num_entries = num_entries;
   2214   cls->entry_size = entry_size;
   2215   {
   2216     struct GNUNET_JSON_Specification ret = {
   2217       .parser = &parse_array_of_data,
   2218       .ptr = entries,
   2219       .field = field,
   2220       .cleaner = &cleaner_array_of_data,
   2221       .cls = (void *) cls,
   2222     };
   2223 
   2224     return ret;
   2225   }
   2226 }
   2227 
   2228 
   2229 struct GNUNET_JSON_Specification
   2230 TALER_JSON_spec_array_of_denom_pub_h (
   2231   const char *field,
   2232   size_t *num_entries,
   2233   struct TALER_DenominationHashP **entries)
   2234 {
   2235   *num_entries = 0;
   2236   *entries = NULL;
   2237   return TALER_JSON_spec_array_of_data (
   2238     field,
   2239     sizeof (struct TALER_DenominationHashP),
   2240     num_entries,
   2241     (void **) entries);
   2242 }
   2243 
   2244 
   2245 /**
   2246  * Parser for an array of blinded denomination signatures,
   2247  * of unknown array length
   2248  */
   2249 static enum GNUNET_GenericReturnValue
   2250 parse_array_of_blinded_denom_sigs (void *cls,
   2251                                    json_t *root,
   2252                                    struct GNUNET_JSON_Specification *spec)
   2253 {
   2254   enum GNUNET_GenericReturnValue ret;
   2255   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2256   size_t expected_num_entries = (size_t) cls;
   2257   size_t num_entries;
   2258 
   2259   if (! json_is_array (root))
   2260   {
   2261     GNUNET_break_op (0);
   2262     return GNUNET_SYSERR;
   2263   }
   2264   num_entries = json_array_size (root);
   2265   if (num_entries != expected_num_entries)
   2266   {
   2267     GNUNET_break_op (0);
   2268     return GNUNET_SYSERR;
   2269   }
   2270 
   2271   {
   2272     json_t *j_entry;
   2273     size_t idx;
   2274     struct TALER_BlindedDenominationSignature *ptr = sigs;
   2275 
   2276     json_array_foreach (root, idx, j_entry) {
   2277       struct GNUNET_JSON_Specification esp[] = {
   2278         TALER_JSON_spec_blinded_denom_sig (NULL,
   2279                                            ptr),
   2280         GNUNET_JSON_spec_end ()
   2281       };
   2282       ret = GNUNET_JSON_parse (j_entry,
   2283                                esp,
   2284                                NULL,
   2285                                NULL);
   2286       if (GNUNET_OK != ret)
   2287       {
   2288         GNUNET_break_op (0);
   2289         for (size_t i = 0; i < idx; i++)
   2290         {
   2291           TALER_blinded_denom_sig_free (&sigs[i]);
   2292           sigs[i].blinded_sig = NULL;
   2293         }
   2294         return GNUNET_SYSERR;
   2295       }
   2296       ptr++;
   2297     }
   2298   }
   2299   return GNUNET_OK;
   2300 }
   2301 
   2302 
   2303 /**
   2304  * Cleanup data left from parsing an array of blinded signatures.
   2305  *
   2306  * @param cls pointer to a size_t with the length of the array
   2307  * @param[out] spec where to free the data
   2308  */
   2309 static void
   2310 cleaner_array_of_blinded_denom_sigs (
   2311   void *cls,
   2312   struct GNUNET_JSON_Specification *spec)
   2313 {
   2314   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2315   size_t num_entries = (size_t) cls;
   2316 
   2317   for (size_t i = 0; i < num_entries; i++)
   2318   {
   2319     if (NULL != sigs[i].blinded_sig)
   2320     {
   2321       TALER_blinded_denom_sig_free (&sigs[i]);
   2322       sigs[i].blinded_sig = NULL;
   2323     }
   2324   }
   2325 }
   2326 
   2327 
   2328 struct GNUNET_JSON_Specification
   2329 TALER_JSON_spec_array_of_blinded_denom_sigs (
   2330   const char *field,
   2331   size_t num_entries,
   2332   struct TALER_BlindedDenominationSignature *entries)
   2333 {
   2334   struct GNUNET_JSON_Specification ret = {
   2335     .parser = &parse_array_of_blinded_denom_sigs,
   2336     .ptr = entries,
   2337     .field = field,
   2338     .cleaner = &cleaner_array_of_blinded_denom_sigs,
   2339     .cls = (void *) num_entries,
   2340   };
   2341 
   2342   for (size_t i = 0; i<num_entries; i++)
   2343     entries[i].blinded_sig = NULL;
   2344   return ret;
   2345 }
   2346 
   2347 
   2348 /* end of json/json_helper.c */