LCOV - code coverage report
Current view: top level - json - json_helper.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 23 406 5.7 %
Date: 2022-08-09 06:13:43 Functions: 4 37 10.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2021 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 "platform.h"
      24             : #include <gnunet/gnunet_util_lib.h>
      25             : #include "taler_util.h"
      26             : #include "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 TALER_DenominationCipher
      36           0 : string_to_cipher (const char *cipher_s)
      37             : {
      38           0 :   if ((0 == strcasecmp (cipher_s,
      39           0 :                         "RSA")) ||
      40           0 :       (0 == strcasecmp (cipher_s,
      41             :                         "RSA+age_restricted")))
      42           0 :     return TALER_DENOMINATION_RSA;
      43           0 :   if ((0 == strcasecmp (cipher_s,
      44           0 :                         "CS")) ||
      45           0 :       (0 == strcasecmp (cipher_s,
      46             :                         "CS+age_restricted")))
      47           0 :     return TALER_DENOMINATION_CS;
      48           0 :   return TALER_DENOMINATION_INVALID;
      49             : }
      50             : 
      51             : 
      52             : json_t *
      53          17 : TALER_JSON_from_amount (const struct TALER_Amount *amount)
      54             : {
      55          17 :   char *amount_str = TALER_amount_to_string (amount);
      56             : 
      57          17 :   GNUNET_assert (NULL != amount_str);
      58             :   {
      59          17 :     json_t *j = json_string (amount_str);
      60             : 
      61          17 :     GNUNET_free (amount_str);
      62          17 :     return j;
      63             :   }
      64             : }
      65             : 
      66             : 
      67             : json_t *
      68           0 : TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount)
      69             : {
      70             :   struct TALER_Amount a;
      71             : 
      72           0 :   TALER_amount_ntoh (&a,
      73             :                      amount);
      74           0 :   return TALER_JSON_from_amount (&a);
      75             : }
      76             : 
      77             : 
      78             : /**
      79             :  * Parse given JSON object to Amount
      80             :  *
      81             :  * @param cls closure, expected currency, or NULL
      82             :  * @param root the json object representing data
      83             :  * @param[out] spec where to write the data
      84             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
      85             :  */
      86             : static enum GNUNET_GenericReturnValue
      87          15 : parse_amount (void *cls,
      88             :               json_t *root,
      89             :               struct GNUNET_JSON_Specification *spec)
      90             : {
      91          15 :   const char *currency = cls;
      92          15 :   struct TALER_Amount *r_amount = spec->ptr;
      93             : 
      94             :   (void) cls;
      95          15 :   if (! json_is_string (root))
      96             :   {
      97           0 :     GNUNET_break_op (0);
      98           0 :     return GNUNET_SYSERR;
      99             :   }
     100          15 :   if (GNUNET_OK !=
     101          15 :       TALER_string_to_amount (json_string_value (root),
     102             :                               r_amount))
     103             :   {
     104           0 :     GNUNET_break_op (0);
     105           0 :     return GNUNET_SYSERR;
     106             :   }
     107          15 :   if ( (NULL != currency) &&
     108             :        (0 !=
     109           9 :         strcasecmp (currency,
     110           9 :                     r_amount->currency)) )
     111             :   {
     112           0 :     GNUNET_break_op (0);
     113           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     114             :                 "Expected currency `%s', but amount used currency `%s' in field `%s'\n",
     115             :                 currency,
     116             :                 r_amount->currency,
     117             :                 spec->field);
     118           0 :     return GNUNET_SYSERR;
     119             :   }
     120          15 :   return GNUNET_OK;
     121             : }
     122             : 
     123             : 
     124             : struct GNUNET_JSON_Specification
     125           9 : TALER_JSON_spec_amount (const char *name,
     126             :                         const char *currency,
     127             :                         struct TALER_Amount *r_amount)
     128             : {
     129           9 :   struct GNUNET_JSON_Specification ret = {
     130             :     .parser = &parse_amount,
     131             :     .cleaner = NULL,
     132             :     .cls = (void *) currency,
     133             :     .field = name,
     134             :     .ptr = r_amount,
     135             :     .ptr_size = 0,
     136             :     .size_ptr = NULL
     137             :   };
     138             : 
     139           9 :   GNUNET_assert (NULL != currency);
     140           9 :   return ret;
     141             : }
     142             : 
     143             : 
     144             : struct GNUNET_JSON_Specification
     145           6 : TALER_JSON_spec_amount_any (const char *name,
     146             :                             struct TALER_Amount *r_amount)
     147             : {
     148           6 :   struct GNUNET_JSON_Specification ret = {
     149             :     .parser = &parse_amount,
     150             :     .cleaner = NULL,
     151             :     .cls = NULL,
     152             :     .field = name,
     153             :     .ptr = r_amount,
     154             :     .ptr_size = 0,
     155             :     .size_ptr = NULL
     156             :   };
     157             : 
     158           6 :   return ret;
     159             : }
     160             : 
     161             : 
     162             : /**
     163             :  * Parse given JSON object to Amount in NBO.
     164             :  *
     165             :  * @param cls closure, NULL
     166             :  * @param root the json object representing data
     167             :  * @param[out] spec where to write the data
     168             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     169             :  */
     170             : static enum GNUNET_GenericReturnValue
     171           0 : parse_amount_nbo (void *cls,
     172             :                   json_t *root,
     173             :                   struct GNUNET_JSON_Specification *spec)
     174             : {
     175           0 :   const char *currency = cls;
     176           0 :   struct TALER_AmountNBO *r_amount = spec->ptr;
     177             :   const char *sv;
     178             : 
     179             :   (void) cls;
     180           0 :   if (! json_is_string (root))
     181             :   {
     182           0 :     GNUNET_break (0);
     183           0 :     return GNUNET_SYSERR;
     184             :   }
     185           0 :   sv = json_string_value (root);
     186           0 :   if (GNUNET_OK !=
     187           0 :       TALER_string_to_amount_nbo (sv,
     188             :                                   r_amount))
     189             :   {
     190           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     191             :                 "`%s' is not a valid amount\n",
     192             :                 sv);
     193           0 :     GNUNET_break_op (0);
     194           0 :     return GNUNET_SYSERR;
     195             :   }
     196           0 :   if ( (NULL != currency) &&
     197             :        (0 !=
     198           0 :         strcasecmp (currency,
     199           0 :                     r_amount->currency)) )
     200             :   {
     201           0 :     GNUNET_break_op (0);
     202           0 :     return GNUNET_SYSERR;
     203             :   }
     204           0 :   return GNUNET_OK;
     205             : }
     206             : 
     207             : 
     208             : struct GNUNET_JSON_Specification
     209           0 : TALER_JSON_spec_amount_nbo (const char *name,
     210             :                             const char *currency,
     211             :                             struct TALER_AmountNBO *r_amount)
     212             : {
     213           0 :   struct GNUNET_JSON_Specification ret = {
     214             :     .parser = &parse_amount_nbo,
     215             :     .cleaner = NULL,
     216             :     .cls = (void *) currency,
     217             :     .field = name,
     218             :     .ptr = r_amount,
     219             :     .ptr_size = 0,
     220             :     .size_ptr = NULL
     221             :   };
     222             : 
     223           0 :   GNUNET_assert (NULL != currency);
     224           0 :   return ret;
     225             : }
     226             : 
     227             : 
     228             : struct GNUNET_JSON_Specification
     229           0 : TALER_JSON_spec_amount_any_nbo (const char *name,
     230             :                                 struct TALER_AmountNBO *r_amount)
     231             : {
     232           0 :   struct GNUNET_JSON_Specification ret = {
     233             :     .parser = &parse_amount_nbo,
     234             :     .cleaner = NULL,
     235             :     .cls = NULL,
     236             :     .field = name,
     237             :     .ptr = r_amount,
     238             :     .ptr_size = 0,
     239             :     .size_ptr = NULL
     240             :   };
     241             : 
     242           0 :   return ret;
     243             : }
     244             : 
     245             : 
     246             : static enum GNUNET_GenericReturnValue
     247           0 : parse_denomination_group (void *cls,
     248             :                           json_t *root,
     249             :                           struct GNUNET_JSON_Specification *spec)
     250             : {
     251           0 :   struct TALER_DenominationGroup *group = spec->ptr;
     252             :   const char *cipher;
     253           0 :   const char *currency = cls;
     254           0 :   bool age_mask_missing = false;
     255           0 :   bool has_age_restricted_suffix = false;
     256             :   struct GNUNET_JSON_Specification gspec[] = {
     257           0 :     GNUNET_JSON_spec_string ("cipher",
     258             :                              &cipher),
     259           0 :     TALER_JSON_spec_amount ("value",
     260             :                             currency,
     261             :                             &group->value),
     262           0 :     TALER_JSON_SPEC_DENOM_FEES ("fee",
     263             :                                 currency,
     264             :                                 &group->fees),
     265           0 :     GNUNET_JSON_spec_mark_optional (
     266             :       GNUNET_JSON_spec_uint32 ("age_mask",
     267             :                                &group->age_mask.bits),
     268             :       &age_mask_missing),
     269           0 :     GNUNET_JSON_spec_fixed_auto ("hash",
     270             :                                  &group->hash),
     271           0 :     GNUNET_JSON_spec_end ()
     272             :   };
     273             :   const char *emsg;
     274             :   unsigned int eline;
     275             : 
     276           0 :   if (GNUNET_OK !=
     277           0 :       GNUNET_JSON_parse (root,
     278             :                          gspec,
     279             :                          &emsg,
     280             :                          &eline))
     281             :   {
     282           0 :     GNUNET_break_op (0);
     283           0 :     return GNUNET_SYSERR;
     284             :   }
     285             : 
     286           0 :   group->cipher = string_to_cipher (cipher);
     287           0 :   if (TALER_DENOMINATION_INVALID == group->cipher)
     288             :   {
     289           0 :     GNUNET_break_op (0);
     290           0 :     return GNUNET_SYSERR;
     291             :   }
     292             : 
     293             :   /* age_mask and suffix must be consistent */
     294           0 :   has_age_restricted_suffix =
     295           0 :     (NULL != strstr (cipher, "+age_restricted"));
     296           0 :   if (has_age_restricted_suffix && age_mask_missing)
     297             :   {
     298           0 :     GNUNET_break_op (0);
     299           0 :     return GNUNET_SYSERR;
     300             :   }
     301             : 
     302           0 :   if (age_mask_missing)
     303           0 :     group->age_mask.bits = 0;
     304             : 
     305           0 :   return GNUNET_OK;
     306             : }
     307             : 
     308             : 
     309             : struct GNUNET_JSON_Specification
     310           0 : TALER_JSON_spec_denomination_group (const char *name,
     311             :                                     const char *currency,
     312             :                                     struct TALER_DenominationGroup *group)
     313             : {
     314           0 :   struct GNUNET_JSON_Specification ret = {
     315             :     .cls = (void *) currency,
     316             :     .parser = &parse_denomination_group,
     317             :     .cleaner = NULL,
     318             :     .field = name,
     319             :     .ptr = group,
     320             :     .ptr_size = sizeof(*group),
     321             :     .size_ptr = NULL,
     322             :   };
     323             : 
     324           0 :   return ret;
     325             : }
     326             : 
     327             : 
     328             : /**
     329             :  * Parse given JSON object to an encrypted contract.
     330             :  *
     331             :  * @param cls closure, NULL
     332             :  * @param root the json object representing data
     333             :  * @param[out] spec where to write the data
     334             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     335             :  */
     336             : static enum GNUNET_GenericReturnValue
     337           0 : parse_econtract (void *cls,
     338             :                  json_t *root,
     339             :                  struct GNUNET_JSON_Specification *spec)
     340             : {
     341           0 :   struct TALER_EncryptedContract *econtract = spec->ptr;
     342             :   struct GNUNET_JSON_Specification ispec[] = {
     343           0 :     GNUNET_JSON_spec_varsize ("econtract",
     344             :                               &econtract->econtract,
     345             :                               &econtract->econtract_size),
     346           0 :     GNUNET_JSON_spec_fixed_auto ("econtract_sig",
     347             :                                  &econtract->econtract_sig),
     348           0 :     GNUNET_JSON_spec_fixed_auto ("contract_pub",
     349             :                                  &econtract->contract_pub),
     350           0 :     GNUNET_JSON_spec_end ()
     351             :   };
     352             :   const char *emsg;
     353             :   unsigned int eline;
     354             : 
     355             :   (void) cls;
     356           0 :   if (GNUNET_OK !=
     357           0 :       GNUNET_JSON_parse (root,
     358             :                          ispec,
     359             :                          &emsg,
     360             :                          &eline))
     361             :   {
     362           0 :     GNUNET_break_op (0);
     363           0 :     return GNUNET_SYSERR;
     364             :   }
     365           0 :   return GNUNET_OK;
     366             : }
     367             : 
     368             : 
     369             : /**
     370             :  * Cleanup data left from parsing encrypted contract.
     371             :  *
     372             :  * @param cls closure, NULL
     373             :  * @param[out] spec where to free the data
     374             :  */
     375             : static void
     376           0 : clean_econtract (void *cls,
     377             :                  struct GNUNET_JSON_Specification *spec)
     378             : {
     379           0 :   struct TALER_EncryptedContract *econtract = spec->ptr;
     380             : 
     381             :   (void) cls;
     382           0 :   GNUNET_free (econtract->econtract);
     383           0 : }
     384             : 
     385             : 
     386             : struct GNUNET_JSON_Specification
     387           0 : TALER_JSON_spec_econtract (const char *name,
     388             :                            struct TALER_EncryptedContract *econtract)
     389             : {
     390           0 :   struct GNUNET_JSON_Specification ret = {
     391             :     .parser = &parse_econtract,
     392             :     .cleaner = &clean_econtract,
     393             :     .cls = NULL,
     394             :     .field = name,
     395             :     .ptr = econtract,
     396             :     .ptr_size = 0,
     397             :     .size_ptr = NULL
     398             :   };
     399             : 
     400           0 :   return ret;
     401             : }
     402             : 
     403             : 
     404             : /**
     405             :  * Parse given JSON object to an age commitmnet
     406             :  *
     407             :  * @param cls closure, NULL
     408             :  * @param root the json object representing data
     409             :  * @param[out] spec where to write the data
     410             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     411             :  */
     412             : static enum GNUNET_GenericReturnValue
     413           0 : parse_age_commitment (void *cls,
     414             :                       json_t *root,
     415             :                       struct GNUNET_JSON_Specification *spec)
     416             : {
     417           0 :   struct TALER_AgeCommitment *age_commitment = spec->ptr;
     418             :   json_t *pk;
     419             :   unsigned int idx;
     420             :   size_t num;
     421             : 
     422           0 :   if (NULL == root || ! json_is_array (root))
     423             :   {
     424           0 :     GNUNET_break_op (0);
     425           0 :     return GNUNET_SYSERR;
     426             :   }
     427             : 
     428           0 :   num = json_array_size (root);
     429           0 :   if (32 <= num || 0 == num)
     430             :   {
     431           0 :     GNUNET_break_op (0);
     432           0 :     return GNUNET_SYSERR;
     433             :   }
     434             : 
     435           0 :   age_commitment->num = num;
     436           0 :   age_commitment->keys =
     437           0 :     GNUNET_new_array (num,
     438             :                       struct TALER_AgeCommitmentPublicKeyP);
     439             : 
     440           0 :   json_array_foreach (root, idx, pk) {
     441             :     const char *emsg;
     442             :     unsigned int eline;
     443             :     struct GNUNET_JSON_Specification pkspec[] = {
     444           0 :       GNUNET_JSON_spec_fixed_auto (
     445             :         NULL,
     446             :         &age_commitment->keys[idx].pub),
     447           0 :       GNUNET_JSON_spec_end ()
     448             :     };
     449             : 
     450           0 :     if (GNUNET_OK !=
     451           0 :         GNUNET_JSON_parse (pk,
     452             :                            pkspec,
     453             :                            &emsg,
     454             :                            &eline))
     455             :     {
     456           0 :       GNUNET_break_op (0);
     457           0 :       GNUNET_JSON_parse_free (spec);
     458           0 :       return GNUNET_SYSERR;
     459             :     }
     460             :   };
     461             : 
     462           0 :   return GNUNET_OK;
     463             : }
     464             : 
     465             : 
     466             : /**
     467             :  * Cleanup data left fom parsing age commitment
     468             :  *
     469             :  * @param cls closure, NULL
     470             :  * @param[out] spec where to free the data
     471             :  */
     472             : static void
     473           0 : clean_age_commitment (void *cls,
     474             :                       struct GNUNET_JSON_Specification *spec)
     475             : {
     476           0 :   struct TALER_AgeCommitment *age_commitment = spec->ptr;
     477             : 
     478             :   (void) cls;
     479             : 
     480           0 :   if (NULL == age_commitment ||
     481           0 :       NULL == age_commitment->keys)
     482           0 :     return;
     483             : 
     484           0 :   age_commitment->num = 0;
     485           0 :   GNUNET_free (age_commitment->keys);
     486             : }
     487             : 
     488             : 
     489             : struct GNUNET_JSON_Specification
     490           0 : TALER_JSON_spec_age_commitment (const char *name,
     491             :                                 struct TALER_AgeCommitment *age_commitment)
     492             : {
     493           0 :   struct GNUNET_JSON_Specification ret = {
     494             :     .parser = &parse_age_commitment,
     495             :     .cleaner = &clean_age_commitment,
     496             :     .cls = NULL,
     497             :     .field = name,
     498             :     .ptr = age_commitment,
     499             :     .ptr_size = 0,
     500             :     .size_ptr = NULL
     501             :   };
     502             : 
     503           0 :   return ret;
     504             : }
     505             : 
     506             : 
     507             : /**
     508             :  * Parse given JSON object to denomination public key.
     509             :  *
     510             :  * @param cls closure, NULL
     511             :  * @param root the json object representing data
     512             :  * @param[out] spec where to write the data
     513             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     514             :  */
     515             : static enum GNUNET_GenericReturnValue
     516           0 : parse_denom_pub (void *cls,
     517             :                  json_t *root,
     518             :                  struct GNUNET_JSON_Specification *spec)
     519             : {
     520           0 :   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
     521             :   const char *cipher;
     522           0 :   bool age_mask_missing = false;
     523             :   struct GNUNET_JSON_Specification dspec[] = {
     524           0 :     GNUNET_JSON_spec_string ("cipher",
     525             :                              &cipher),
     526           0 :     GNUNET_JSON_spec_mark_optional (
     527             :       GNUNET_JSON_spec_uint32 ("age_mask",
     528             :                                &denom_pub->age_mask.bits),
     529             :       &age_mask_missing),
     530           0 :     GNUNET_JSON_spec_end ()
     531             :   };
     532             :   const char *emsg;
     533             :   unsigned int eline;
     534             : 
     535             :   (void) cls;
     536           0 :   if (GNUNET_OK !=
     537           0 :       GNUNET_JSON_parse (root,
     538             :                          dspec,
     539             :                          &emsg,
     540             :                          &eline))
     541             :   {
     542           0 :     GNUNET_break_op (0);
     543           0 :     return GNUNET_SYSERR;
     544             :   }
     545             : 
     546           0 :   if (age_mask_missing)
     547           0 :     denom_pub->age_mask.bits = 0;
     548             : 
     549           0 :   denom_pub->cipher = string_to_cipher (cipher);
     550           0 :   switch (denom_pub->cipher)
     551             :   {
     552           0 :   case TALER_DENOMINATION_RSA:
     553             :     {
     554             :       struct GNUNET_JSON_Specification ispec[] = {
     555           0 :         GNUNET_JSON_spec_rsa_public_key (
     556             :           "rsa_public_key",
     557             :           &denom_pub->details.rsa_public_key),
     558           0 :         GNUNET_JSON_spec_end ()
     559             :       };
     560             : 
     561           0 :       if (GNUNET_OK !=
     562           0 :           GNUNET_JSON_parse (root,
     563             :                              ispec,
     564             :                              &emsg,
     565             :                              &eline))
     566             :       {
     567           0 :         GNUNET_break_op (0);
     568           0 :         return GNUNET_SYSERR;
     569             :       }
     570           0 :       return GNUNET_OK;
     571             :     }
     572           0 :   case TALER_DENOMINATION_CS:
     573             :     {
     574             :       struct GNUNET_JSON_Specification ispec[] = {
     575           0 :         GNUNET_JSON_spec_fixed ("cs_public_key",
     576           0 :                                 &denom_pub->details.cs_public_key,
     577             :                                 sizeof (denom_pub->details.cs_public_key)),
     578           0 :         GNUNET_JSON_spec_end ()
     579             :       };
     580             : 
     581           0 :       if (GNUNET_OK !=
     582           0 :           GNUNET_JSON_parse (root,
     583             :                              ispec,
     584             :                              &emsg,
     585             :                              &eline))
     586             :       {
     587           0 :         GNUNET_break_op (0);
     588           0 :         return GNUNET_SYSERR;
     589             :       }
     590           0 :       return GNUNET_OK;
     591             :     }
     592           0 :   default:
     593           0 :     GNUNET_break_op (0);
     594           0 :     return GNUNET_SYSERR;
     595             :   }
     596             : }
     597             : 
     598             : 
     599             : /**
     600             :  * Cleanup data left from parsing denomination public key.
     601             :  *
     602             :  * @param cls closure, NULL
     603             :  * @param[out] spec where to free the data
     604             :  */
     605             : static void
     606           0 : clean_denom_pub (void *cls,
     607             :                  struct GNUNET_JSON_Specification *spec)
     608             : {
     609           0 :   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
     610             : 
     611             :   (void) cls;
     612           0 :   TALER_denom_pub_free (denom_pub);
     613           0 : }
     614             : 
     615             : 
     616             : struct GNUNET_JSON_Specification
     617           0 : TALER_JSON_spec_denom_pub (const char *field,
     618             :                            struct TALER_DenominationPublicKey *pk)
     619             : {
     620           0 :   struct GNUNET_JSON_Specification ret = {
     621             :     .parser = &parse_denom_pub,
     622             :     .cleaner = &clean_denom_pub,
     623             :     .field = field,
     624             :     .ptr = pk
     625             :   };
     626             : 
     627           0 :   pk->cipher = TALER_DENOMINATION_INVALID;
     628           0 :   return ret;
     629             : }
     630             : 
     631             : 
     632             : /**
     633             :  * Parse given JSON object partially into a denomination public key.
     634             :  *
     635             :  * Depending on the cipher in cls, it parses the corresponding public key type.
     636             :  *
     637             :  * @param cls closure, enum TALER_DenominationCipher
     638             :  * @param root the json object representing data
     639             :  * @param[out] spec where to write the data
     640             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     641             :  */
     642             : static enum GNUNET_GenericReturnValue
     643           0 : parse_denom_pub_cipher (void *cls,
     644             :                         json_t *root,
     645             :                         struct GNUNET_JSON_Specification *spec)
     646             : {
     647           0 :   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
     648           0 :   enum TALER_DenominationCipher cipher = (enum TALER_DenominationCipher) cls;
     649             :   const char *emsg;
     650             :   unsigned int eline;
     651             : 
     652           0 :   switch (cipher)
     653             :   {
     654           0 :   case TALER_DENOMINATION_RSA:
     655             :     {
     656             :       struct GNUNET_JSON_Specification ispec[] = {
     657           0 :         GNUNET_JSON_spec_rsa_public_key (
     658             :           "rsa_pub",
     659             :           &denom_pub->details.rsa_public_key),
     660           0 :         GNUNET_JSON_spec_end ()
     661             :       };
     662             : 
     663           0 :       if (GNUNET_OK !=
     664           0 :           GNUNET_JSON_parse (root,
     665             :                              ispec,
     666             :                              &emsg,
     667             :                              &eline))
     668             :       {
     669           0 :         GNUNET_break_op (0);
     670           0 :         return GNUNET_SYSERR;
     671             :       }
     672           0 :       return GNUNET_OK;
     673             :     }
     674           0 :   case TALER_DENOMINATION_CS:
     675             :     {
     676             :       struct GNUNET_JSON_Specification ispec[] = {
     677           0 :         GNUNET_JSON_spec_fixed ("cs_pub",
     678           0 :                                 &denom_pub->details.cs_public_key,
     679             :                                 sizeof (denom_pub->details.cs_public_key)),
     680           0 :         GNUNET_JSON_spec_end ()
     681             :       };
     682             : 
     683           0 :       if (GNUNET_OK !=
     684           0 :           GNUNET_JSON_parse (root,
     685             :                              ispec,
     686             :                              &emsg,
     687             :                              &eline))
     688             :       {
     689           0 :         GNUNET_break_op (0);
     690           0 :         return GNUNET_SYSERR;
     691             :       }
     692           0 :       return GNUNET_OK;
     693             :     }
     694           0 :   default:
     695           0 :     GNUNET_break_op (0);
     696           0 :     return GNUNET_SYSERR;
     697             :   }
     698             : }
     699             : 
     700             : 
     701             : struct GNUNET_JSON_Specification
     702           0 : TALER_JSON_spec_denom_pub_cipher (const char *field,
     703             :                                   enum TALER_DenominationCipher cipher,
     704             :                                   struct TALER_DenominationPublicKey *pk)
     705             : {
     706           0 :   struct GNUNET_JSON_Specification ret = {
     707             :     .parser = &parse_denom_pub_cipher,
     708             :     .cleaner = &clean_denom_pub,
     709             :     .field = field,
     710           0 :     .cls = (void *) cipher,
     711             :     .ptr = pk
     712             :   };
     713             : 
     714           0 :   return ret;
     715             : }
     716             : 
     717             : 
     718             : /**
     719             :  * Parse given JSON object to denomination signature.
     720             :  *
     721             :  * @param cls closure, NULL
     722             :  * @param root the json object representing data
     723             :  * @param[out] spec where to write the data
     724             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     725             :  */
     726             : static enum GNUNET_GenericReturnValue
     727           0 : parse_denom_sig (void *cls,
     728             :                  json_t *root,
     729             :                  struct GNUNET_JSON_Specification *spec)
     730             : {
     731           0 :   struct TALER_DenominationSignature *denom_sig = spec->ptr;
     732             :   const char *cipher;
     733             :   struct GNUNET_JSON_Specification dspec[] = {
     734           0 :     GNUNET_JSON_spec_string ("cipher",
     735             :                              &cipher),
     736           0 :     GNUNET_JSON_spec_end ()
     737             :   };
     738             :   const char *emsg;
     739             :   unsigned int eline;
     740             : 
     741             :   (void) cls;
     742           0 :   if (GNUNET_OK !=
     743           0 :       GNUNET_JSON_parse (root,
     744             :                          dspec,
     745             :                          &emsg,
     746             :                          &eline))
     747             :   {
     748           0 :     GNUNET_break_op (0);
     749           0 :     return GNUNET_SYSERR;
     750             :   }
     751           0 :   denom_sig->cipher = string_to_cipher (cipher);
     752           0 :   switch (denom_sig->cipher)
     753             :   {
     754           0 :   case TALER_DENOMINATION_RSA:
     755             :     {
     756             :       struct GNUNET_JSON_Specification ispec[] = {
     757           0 :         GNUNET_JSON_spec_rsa_signature (
     758             :           "rsa_signature",
     759             :           &denom_sig->details.rsa_signature),
     760           0 :         GNUNET_JSON_spec_end ()
     761             :       };
     762             : 
     763           0 :       if (GNUNET_OK !=
     764           0 :           GNUNET_JSON_parse (root,
     765             :                              ispec,
     766             :                              &emsg,
     767             :                              &eline))
     768             :       {
     769           0 :         GNUNET_break_op (0);
     770           0 :         return GNUNET_SYSERR;
     771             :       }
     772           0 :       return GNUNET_OK;
     773             :     }
     774           0 :   case TALER_DENOMINATION_CS:
     775             :     {
     776             :       struct GNUNET_JSON_Specification ispec[] = {
     777           0 :         GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
     778             :                                      &denom_sig->details.cs_signature.r_point),
     779           0 :         GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
     780             :                                      &denom_sig->details.cs_signature.s_scalar),
     781           0 :         GNUNET_JSON_spec_end ()
     782             :       };
     783             : 
     784           0 :       if (GNUNET_OK !=
     785           0 :           GNUNET_JSON_parse (root,
     786             :                              ispec,
     787             :                              &emsg,
     788             :                              &eline))
     789             :       {
     790           0 :         GNUNET_break_op (0);
     791           0 :         return GNUNET_SYSERR;
     792             :       }
     793           0 :       return GNUNET_OK;
     794             :     }
     795           0 :   default:
     796           0 :     GNUNET_break_op (0);
     797           0 :     return GNUNET_SYSERR;
     798             :   }
     799             : }
     800             : 
     801             : 
     802             : /**
     803             :  * Cleanup data left from parsing denomination public key.
     804             :  *
     805             :  * @param cls closure, NULL
     806             :  * @param[out] spec where to free the data
     807             :  */
     808             : static void
     809           0 : clean_denom_sig (void *cls,
     810             :                  struct GNUNET_JSON_Specification *spec)
     811             : {
     812           0 :   struct TALER_DenominationSignature *denom_sig = spec->ptr;
     813             : 
     814             :   (void) cls;
     815           0 :   TALER_denom_sig_free (denom_sig);
     816           0 : }
     817             : 
     818             : 
     819             : struct GNUNET_JSON_Specification
     820           0 : TALER_JSON_spec_denom_sig (const char *field,
     821             :                            struct TALER_DenominationSignature *sig)
     822             : {
     823           0 :   struct GNUNET_JSON_Specification ret = {
     824             :     .parser = &parse_denom_sig,
     825             :     .cleaner = &clean_denom_sig,
     826             :     .field = field,
     827             :     .ptr = sig
     828             :   };
     829             : 
     830           0 :   sig->cipher = TALER_DENOMINATION_INVALID;
     831           0 :   return ret;
     832             : }
     833             : 
     834             : 
     835             : /**
     836             :  * Parse given JSON object to blinded denomination signature.
     837             :  *
     838             :  * @param cls closure, NULL
     839             :  * @param root the json object representing data
     840             :  * @param[out] spec where to write the data
     841             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     842             :  */
     843             : static enum GNUNET_GenericReturnValue
     844           0 : parse_blinded_denom_sig (void *cls,
     845             :                          json_t *root,
     846             :                          struct GNUNET_JSON_Specification *spec)
     847             : {
     848           0 :   struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
     849             :   const char *cipher;
     850             :   struct GNUNET_JSON_Specification dspec[] = {
     851           0 :     GNUNET_JSON_spec_string ("cipher",
     852             :                              &cipher),
     853           0 :     GNUNET_JSON_spec_end ()
     854             :   };
     855             :   const char *emsg;
     856             :   unsigned int eline;
     857             : 
     858             :   (void) cls;
     859           0 :   if (GNUNET_OK !=
     860           0 :       GNUNET_JSON_parse (root,
     861             :                          dspec,
     862             :                          &emsg,
     863             :                          &eline))
     864             :   {
     865           0 :     GNUNET_break_op (0);
     866           0 :     return GNUNET_SYSERR;
     867             :   }
     868           0 :   denom_sig->cipher = string_to_cipher (cipher);
     869           0 :   switch (denom_sig->cipher)
     870             :   {
     871           0 :   case TALER_DENOMINATION_RSA:
     872             :     {
     873             :       struct GNUNET_JSON_Specification ispec[] = {
     874           0 :         GNUNET_JSON_spec_rsa_signature (
     875             :           "blinded_rsa_signature",
     876             :           &denom_sig->details.blinded_rsa_signature),
     877           0 :         GNUNET_JSON_spec_end ()
     878             :       };
     879             : 
     880           0 :       if (GNUNET_OK !=
     881           0 :           GNUNET_JSON_parse (root,
     882             :                              ispec,
     883             :                              &emsg,
     884             :                              &eline))
     885             :       {
     886           0 :         GNUNET_break_op (0);
     887           0 :         return GNUNET_SYSERR;
     888             :       }
     889           0 :       return GNUNET_OK;
     890             :     }
     891           0 :   case TALER_DENOMINATION_CS:
     892             :     {
     893             :       struct GNUNET_JSON_Specification ispec[] = {
     894           0 :         GNUNET_JSON_spec_uint32 ("b",
     895           0 :                                  &denom_sig->details.blinded_cs_answer.b),
     896           0 :         GNUNET_JSON_spec_fixed_auto ("s",
     897             :                                      &denom_sig->details.blinded_cs_answer.
     898             :                                      s_scalar),
     899           0 :         GNUNET_JSON_spec_end ()
     900             :       };
     901             : 
     902           0 :       if (GNUNET_OK !=
     903           0 :           GNUNET_JSON_parse (root,
     904             :                              ispec,
     905             :                              &emsg,
     906             :                              &eline))
     907             :       {
     908           0 :         GNUNET_break_op (0);
     909           0 :         return GNUNET_SYSERR;
     910             :       }
     911           0 :       return GNUNET_OK;
     912             :     }
     913             :     break;
     914           0 :   default:
     915           0 :     GNUNET_break_op (0);
     916           0 :     return GNUNET_SYSERR;
     917             :   }
     918             : }
     919             : 
     920             : 
     921             : /**
     922             :  * Cleanup data left from parsing denomination public key.
     923             :  *
     924             :  * @param cls closure, NULL
     925             :  * @param[out] spec where to free the data
     926             :  */
     927             : static void
     928           0 : clean_blinded_denom_sig (void *cls,
     929             :                          struct GNUNET_JSON_Specification *spec)
     930             : {
     931           0 :   struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
     932             : 
     933             :   (void) cls;
     934           0 :   TALER_blinded_denom_sig_free (denom_sig);
     935           0 : }
     936             : 
     937             : 
     938             : struct GNUNET_JSON_Specification
     939           0 : TALER_JSON_spec_blinded_denom_sig (
     940             :   const char *field,
     941             :   struct TALER_BlindedDenominationSignature *sig)
     942             : {
     943           0 :   struct GNUNET_JSON_Specification ret = {
     944             :     .parser = &parse_blinded_denom_sig,
     945             :     .cleaner = &clean_blinded_denom_sig,
     946             :     .field = field,
     947             :     .ptr = sig
     948             :   };
     949             : 
     950           0 :   sig->cipher = TALER_DENOMINATION_INVALID;
     951           0 :   return ret;
     952             : }
     953             : 
     954             : 
     955             : /**
     956             :  * Parse given JSON object to blinded planchet.
     957             :  *
     958             :  * @param cls closure, NULL
     959             :  * @param root the json object representing data
     960             :  * @param[out] spec where to write the data
     961             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     962             :  */
     963             : static enum GNUNET_GenericReturnValue
     964           0 : parse_blinded_planchet (void *cls,
     965             :                         json_t *root,
     966             :                         struct GNUNET_JSON_Specification *spec)
     967             : {
     968           0 :   struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
     969             :   const char *cipher;
     970             :   struct GNUNET_JSON_Specification dspec[] = {
     971           0 :     GNUNET_JSON_spec_string ("cipher",
     972             :                              &cipher),
     973           0 :     GNUNET_JSON_spec_end ()
     974             :   };
     975             :   const char *emsg;
     976             :   unsigned int eline;
     977             : 
     978             :   (void) cls;
     979           0 :   if (GNUNET_OK !=
     980           0 :       GNUNET_JSON_parse (root,
     981             :                          dspec,
     982             :                          &emsg,
     983             :                          &eline))
     984             :   {
     985           0 :     GNUNET_break_op (0);
     986           0 :     return GNUNET_SYSERR;
     987             :   }
     988           0 :   blinded_planchet->cipher = string_to_cipher (cipher);
     989           0 :   switch (blinded_planchet->cipher)
     990             :   {
     991           0 :   case TALER_DENOMINATION_RSA:
     992             :     {
     993             :       struct GNUNET_JSON_Specification ispec[] = {
     994           0 :         GNUNET_JSON_spec_varsize (
     995             :           "rsa_blinded_planchet",
     996             :           &blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
     997             :           &blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size),
     998           0 :         GNUNET_JSON_spec_end ()
     999             :       };
    1000             : 
    1001           0 :       if (GNUNET_OK !=
    1002           0 :           GNUNET_JSON_parse (root,
    1003             :                              ispec,
    1004             :                              &emsg,
    1005             :                              &eline))
    1006             :       {
    1007           0 :         GNUNET_break_op (0);
    1008           0 :         return GNUNET_SYSERR;
    1009             :       }
    1010           0 :       return GNUNET_OK;
    1011             :     }
    1012           0 :   case TALER_DENOMINATION_CS:
    1013             :     {
    1014             :       struct GNUNET_JSON_Specification ispec[] = {
    1015           0 :         GNUNET_JSON_spec_fixed_auto (
    1016             :           "cs_nonce",
    1017             :           &blinded_planchet->details.cs_blinded_planchet.nonce),
    1018           0 :         GNUNET_JSON_spec_fixed_auto (
    1019             :           "cs_blinded_c0",
    1020             :           &blinded_planchet->details.cs_blinded_planchet.c[0]),
    1021           0 :         GNUNET_JSON_spec_fixed_auto (
    1022             :           "cs_blinded_c1",
    1023             :           &blinded_planchet->details.cs_blinded_planchet.c[1]),
    1024           0 :         GNUNET_JSON_spec_end ()
    1025             :       };
    1026             : 
    1027           0 :       if (GNUNET_OK !=
    1028           0 :           GNUNET_JSON_parse (root,
    1029             :                              ispec,
    1030             :                              &emsg,
    1031             :                              &eline))
    1032             :       {
    1033           0 :         GNUNET_break_op (0);
    1034           0 :         return GNUNET_SYSERR;
    1035             :       }
    1036           0 :       return GNUNET_OK;
    1037             :     }
    1038             :     break;
    1039           0 :   default:
    1040           0 :     GNUNET_break_op (0);
    1041           0 :     return GNUNET_SYSERR;
    1042             :   }
    1043             : }
    1044             : 
    1045             : 
    1046             : /**
    1047             :  * Cleanup data left from parsing blinded planchet.
    1048             :  *
    1049             :  * @param cls closure, NULL
    1050             :  * @param[out] spec where to free the data
    1051             :  */
    1052             : static void
    1053           0 : clean_blinded_planchet (void *cls,
    1054             :                         struct GNUNET_JSON_Specification *spec)
    1055             : {
    1056           0 :   struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
    1057             : 
    1058             :   (void) cls;
    1059           0 :   TALER_blinded_planchet_free (blinded_planchet);
    1060           0 : }
    1061             : 
    1062             : 
    1063             : struct GNUNET_JSON_Specification
    1064           0 : TALER_JSON_spec_blinded_planchet (const char *field,
    1065             :                                   struct TALER_BlindedPlanchet *blinded_planchet)
    1066             : {
    1067           0 :   struct GNUNET_JSON_Specification ret = {
    1068             :     .parser = &parse_blinded_planchet,
    1069             :     .cleaner = &clean_blinded_planchet,
    1070             :     .field = field,
    1071             :     .ptr = blinded_planchet
    1072             :   };
    1073             : 
    1074           0 :   blinded_planchet->cipher = TALER_DENOMINATION_INVALID;
    1075           0 :   return ret;
    1076             : }
    1077             : 
    1078             : 
    1079             : /**
    1080             :  * Parse given JSON object to exchange withdraw values (/csr).
    1081             :  *
    1082             :  * @param cls closure, NULL
    1083             :  * @param root the json object representing data
    1084             :  * @param[out] spec where to write the data
    1085             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    1086             :  */
    1087             : static enum GNUNET_GenericReturnValue
    1088           0 : parse_exchange_withdraw_values (void *cls,
    1089             :                                 json_t *root,
    1090             :                                 struct GNUNET_JSON_Specification *spec)
    1091             : {
    1092           0 :   struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
    1093             :   const char *cipher;
    1094             :   struct GNUNET_JSON_Specification dspec[] = {
    1095           0 :     GNUNET_JSON_spec_string ("cipher",
    1096             :                              &cipher),
    1097           0 :     GNUNET_JSON_spec_end ()
    1098             :   };
    1099             :   const char *emsg;
    1100             :   unsigned int eline;
    1101             : 
    1102             :   (void) cls;
    1103           0 :   if (GNUNET_OK !=
    1104           0 :       GNUNET_JSON_parse (root,
    1105             :                          dspec,
    1106             :                          &emsg,
    1107             :                          &eline))
    1108             :   {
    1109           0 :     GNUNET_break_op (0);
    1110           0 :     return GNUNET_SYSERR;
    1111             :   }
    1112           0 :   ewv->cipher = string_to_cipher (cipher);
    1113           0 :   switch (ewv->cipher)
    1114             :   {
    1115           0 :   case TALER_DENOMINATION_RSA:
    1116           0 :     return GNUNET_OK;
    1117           0 :   case TALER_DENOMINATION_CS:
    1118             :     {
    1119             :       struct GNUNET_JSON_Specification ispec[] = {
    1120           0 :         GNUNET_JSON_spec_fixed (
    1121             :           "r_pub_0",
    1122           0 :           &ewv->details.cs_values.r_pub[0],
    1123             :           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
    1124           0 :         GNUNET_JSON_spec_fixed (
    1125             :           "r_pub_1",
    1126           0 :           &ewv->details.cs_values.r_pub[1],
    1127             :           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
    1128           0 :         GNUNET_JSON_spec_end ()
    1129             :       };
    1130             : 
    1131           0 :       if (GNUNET_OK !=
    1132           0 :           GNUNET_JSON_parse (root,
    1133             :                              ispec,
    1134             :                              &emsg,
    1135             :                              &eline))
    1136             :       {
    1137           0 :         GNUNET_break_op (0);
    1138           0 :         return GNUNET_SYSERR;
    1139             :       }
    1140           0 :       return GNUNET_OK;
    1141             :     }
    1142           0 :   default:
    1143           0 :     GNUNET_break_op (0);
    1144           0 :     return GNUNET_SYSERR;
    1145             :   }
    1146             : }
    1147             : 
    1148             : 
    1149             : struct GNUNET_JSON_Specification
    1150           0 : TALER_JSON_spec_exchange_withdraw_values (
    1151             :   const char *field,
    1152             :   struct TALER_ExchangeWithdrawValues *ewv)
    1153             : {
    1154           0 :   struct GNUNET_JSON_Specification ret = {
    1155             :     .parser = &parse_exchange_withdraw_values,
    1156             :     .field = field,
    1157             :     .ptr = ewv
    1158             :   };
    1159             : 
    1160           0 :   ewv->cipher = TALER_DENOMINATION_INVALID;
    1161           0 :   return ret;
    1162             : }
    1163             : 
    1164             : 
    1165             : /**
    1166             :  * Closure for #parse_i18n_string.
    1167             :  */
    1168             : struct I18nContext
    1169             : {
    1170             :   /**
    1171             :    * Language pattern to match.
    1172             :    */
    1173             :   char *lp;
    1174             : 
    1175             :   /**
    1176             :    * Name of the field to match.
    1177             :    */
    1178             :   const char *field;
    1179             : };
    1180             : 
    1181             : 
    1182             : /**
    1183             :  * Parse given JSON object to internationalized string.
    1184             :  *
    1185             :  * @param cls closure, our `struct I18nContext *`
    1186             :  * @param root the json object representing data
    1187             :  * @param[out] spec where to write the data
    1188             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    1189             :  */
    1190             : static enum GNUNET_GenericReturnValue
    1191           0 : parse_i18n_string (void *cls,
    1192             :                    json_t *root,
    1193             :                    struct GNUNET_JSON_Specification *spec)
    1194             : {
    1195           0 :   struct I18nContext *ctx = cls;
    1196             :   json_t *i18n;
    1197             :   json_t *val;
    1198             : 
    1199             :   {
    1200             :     char *i18nf;
    1201             : 
    1202           0 :     GNUNET_asprintf (&i18nf,
    1203             :                      "%s_i18n",
    1204             :                      ctx->field);
    1205           0 :     i18n = json_object_get (root,
    1206             :                             i18nf);
    1207           0 :     GNUNET_free (i18nf);
    1208             :   }
    1209             : 
    1210           0 :   val = json_object_get (root,
    1211             :                          ctx->field);
    1212           0 :   if ( (NULL != i18n) &&
    1213           0 :        (NULL != ctx->lp) )
    1214             :   {
    1215           0 :     double best = 0.0;
    1216             :     json_t *pos;
    1217             :     const char *lang;
    1218             : 
    1219           0 :     json_object_foreach (i18n, lang, pos)
    1220             :     {
    1221             :       double score;
    1222             : 
    1223           0 :       score = TALER_language_matches (ctx->lp,
    1224             :                                       lang);
    1225           0 :       if (score > best)
    1226             :       {
    1227           0 :         best = score;
    1228           0 :         val = pos;
    1229             :       }
    1230             :     }
    1231             :   }
    1232             : 
    1233             :   {
    1234             :     const char *str;
    1235             : 
    1236           0 :     str = json_string_value (val);
    1237           0 :     if (NULL == str)
    1238             :     {
    1239           0 :       GNUNET_break_op (0);
    1240           0 :       return GNUNET_SYSERR;
    1241             :     }
    1242           0 :     *(const char **) spec->ptr = str;
    1243             :   }
    1244           0 :   return GNUNET_OK;
    1245             : }
    1246             : 
    1247             : 
    1248             : /**
    1249             :  * Function called to clean up data from earlier parsing.
    1250             :  *
    1251             :  * @param cls closure
    1252             :  * @param spec our specification entry with data to clean.
    1253             :  */
    1254             : static void
    1255           0 : i18n_cleaner (void *cls,
    1256             :               struct GNUNET_JSON_Specification *spec)
    1257             : {
    1258           0 :   struct I18nContext *ctx = cls;
    1259             : 
    1260             :   (void) spec;
    1261           0 :   GNUNET_free (ctx->lp);
    1262           0 :   GNUNET_free (ctx);
    1263           0 : }
    1264             : 
    1265             : 
    1266             : struct GNUNET_JSON_Specification
    1267           0 : TALER_JSON_spec_i18n_string (const char *name,
    1268             :                              const char *language_pattern,
    1269             :                              const char **strptr)
    1270             : {
    1271           0 :   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
    1272           0 :   struct GNUNET_JSON_Specification ret = {
    1273             :     .parser = &parse_i18n_string,
    1274             :     .cleaner = &i18n_cleaner,
    1275             :     .cls = ctx,
    1276             :     .field = NULL, /* we want the main object */
    1277             :     .ptr = strptr,
    1278             :     .ptr_size = 0,
    1279             :     .size_ptr = NULL
    1280             :   };
    1281             : 
    1282           0 :   ctx->lp = (NULL != language_pattern) ? GNUNET_strdup (language_pattern) :
    1283             :             NULL;
    1284           0 :   ctx->field = name;
    1285           0 :   *strptr = NULL;
    1286           0 :   return ret;
    1287             : }
    1288             : 
    1289             : 
    1290             : struct GNUNET_JSON_Specification
    1291           0 : TALER_JSON_spec_i18n_str (const char *name,
    1292             :                           const char **strptr)
    1293             : {
    1294           0 :   const char *lang = getenv ("LANG");
    1295             :   char *dot;
    1296             :   char *l;
    1297             :   struct GNUNET_JSON_Specification ret;
    1298             : 
    1299           0 :   if (NULL != lang)
    1300             :   {
    1301           0 :     dot = strchr (lang,
    1302             :                   '.');
    1303           0 :     if (NULL == dot)
    1304           0 :       l = GNUNET_strdup (lang);
    1305             :     else
    1306           0 :       l = GNUNET_strndup (lang,
    1307             :                           dot - lang);
    1308             :   }
    1309             :   else
    1310             :   {
    1311           0 :     l = NULL;
    1312             :   }
    1313           0 :   ret = TALER_JSON_spec_i18n_string (name,
    1314             :                                      l,
    1315             :                                      strptr);
    1316           0 :   GNUNET_free (l);
    1317           0 :   return ret;
    1318             : }
    1319             : 
    1320             : 
    1321             : /* end of json/json_helper.c */

Generated by: LCOV version 1.14