LCOV - code coverage report
Current view: top level - json - json_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 334 687 48.6 %
Date: 2025-07-09 07:38:29 Functions: 41 63 65.1 %

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

Generated by: LCOV version 1.16