LCOV - code coverage report
Current view: top level - json - json_helper.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 82 175 46.9 %
Date: 2021-08-30 06:43:37 Functions: 14 20 70.0 %
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             : json_t *
      30        6037 : TALER_JSON_from_amount (const struct TALER_Amount *amount)
      31             : {
      32        6037 :   char *amount_str = TALER_amount_to_string (amount);
      33             : 
      34        6037 :   GNUNET_assert (NULL != amount_str);
      35             :   {
      36        6037 :     json_t *j = json_string (amount_str);
      37             : 
      38        6037 :     GNUNET_free (amount_str);
      39        6037 :     return j;
      40             :   }
      41             : }
      42             : 
      43             : 
      44             : json_t *
      45           5 : TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount)
      46             : {
      47             :   struct TALER_Amount a;
      48             : 
      49           5 :   TALER_amount_ntoh (&a,
      50             :                      amount);
      51           5 :   return TALER_JSON_from_amount (&a);
      52             : }
      53             : 
      54             : 
      55             : /**
      56             :  * Parse given JSON object to Amount
      57             :  *
      58             :  * @param cls closure, expected currency, or NULL
      59             :  * @param root the json object representing data
      60             :  * @param[out] spec where to write the data
      61             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
      62             :  */
      63             : static int
      64        2483 : parse_amount (void *cls,
      65             :               json_t *root,
      66             :               struct GNUNET_JSON_Specification *spec)
      67             : {
      68        2483 :   const char *currency = cls;
      69        2483 :   struct TALER_Amount *r_amount = spec->ptr;
      70             : 
      71             :   (void) cls;
      72        2483 :   if (! json_is_string (root))
      73             :   {
      74           0 :     GNUNET_break_op (0);
      75           0 :     return GNUNET_SYSERR;
      76             :   }
      77        2483 :   if (GNUNET_OK !=
      78        2483 :       TALER_string_to_amount (json_string_value (root),
      79             :                               r_amount))
      80             :   {
      81           0 :     GNUNET_break_op (0);
      82           0 :     return GNUNET_SYSERR;
      83             :   }
      84        2483 :   if ( (NULL != currency) &&
      85             :        (0 !=
      86         753 :         strcasecmp (currency,
      87         753 :                     r_amount->currency)) )
      88             :   {
      89           1 :     GNUNET_break_op (0);
      90           1 :     return GNUNET_SYSERR;
      91             :   }
      92        2482 :   return GNUNET_OK;
      93             : }
      94             : 
      95             : 
      96             : struct GNUNET_JSON_Specification
      97         755 : TALER_JSON_spec_amount (const char *name,
      98             :                         const char *currency,
      99             :                         struct TALER_Amount *r_amount)
     100             : {
     101         755 :   struct GNUNET_JSON_Specification ret = {
     102             :     .parser = &parse_amount,
     103             :     .cleaner = NULL,
     104             :     .cls = (void *) currency,
     105             :     .field = name,
     106             :     .ptr = r_amount,
     107             :     .ptr_size = 0,
     108             :     .size_ptr = NULL
     109             :   };
     110             : 
     111         755 :   GNUNET_assert (NULL != currency);
     112         755 :   return ret;
     113             : }
     114             : 
     115             : 
     116             : struct GNUNET_JSON_Specification
     117        1730 : TALER_JSON_spec_amount_any (const char *name,
     118             :                             struct TALER_Amount *r_amount)
     119             : {
     120        1730 :   struct GNUNET_JSON_Specification ret = {
     121             :     .parser = &parse_amount,
     122             :     .cleaner = NULL,
     123             :     .cls = NULL,
     124             :     .field = name,
     125             :     .ptr = r_amount,
     126             :     .ptr_size = 0,
     127             :     .size_ptr = NULL
     128             :   };
     129             : 
     130        1730 :   return ret;
     131             : }
     132             : 
     133             : 
     134             : /**
     135             :  * Parse given JSON object to Amount in NBO.
     136             :  *
     137             :  * @param cls closure, NULL
     138             :  * @param root the json object representing data
     139             :  * @param[out] spec where to write the data
     140             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     141             :  */
     142             : static int
     143          30 : parse_amount_nbo (void *cls,
     144             :                   json_t *root,
     145             :                   struct GNUNET_JSON_Specification *spec)
     146             : {
     147          30 :   const char *currency = cls;
     148          30 :   struct TALER_AmountNBO *r_amount = spec->ptr;
     149             :   const char *sv;
     150             : 
     151             :   (void) cls;
     152          30 :   if (! json_is_string (root))
     153             :   {
     154           0 :     GNUNET_break (0);
     155           0 :     return GNUNET_SYSERR;
     156             :   }
     157          30 :   sv = json_string_value (root);
     158          30 :   if (GNUNET_OK !=
     159          30 :       TALER_string_to_amount_nbo (sv,
     160             :                                   r_amount))
     161             :   {
     162           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     163             :                 "`%s' is not a valid amount\n",
     164             :                 sv);
     165           0 :     GNUNET_break_op (0);
     166           0 :     return GNUNET_SYSERR;
     167             :   }
     168          30 :   if ( (NULL != currency) &&
     169             :        (0 !=
     170           0 :         strcasecmp (currency,
     171           0 :                     r_amount->currency)) )
     172             :   {
     173           0 :     GNUNET_break_op (0);
     174           0 :     return GNUNET_SYSERR;
     175             :   }
     176          30 :   return GNUNET_OK;
     177             : }
     178             : 
     179             : 
     180             : struct GNUNET_JSON_Specification
     181           0 : TALER_JSON_spec_amount_nbo (const char *name,
     182             :                             const char *currency,
     183             :                             struct TALER_AmountNBO *r_amount)
     184             : {
     185           0 :   struct GNUNET_JSON_Specification ret = {
     186             :     .parser = &parse_amount_nbo,
     187             :     .cleaner = NULL,
     188             :     .cls = (void *) currency,
     189             :     .field = name,
     190             :     .ptr = r_amount,
     191             :     .ptr_size = 0,
     192             :     .size_ptr = NULL
     193             :   };
     194             : 
     195           0 :   GNUNET_assert (NULL != currency);
     196           0 :   return ret;
     197             : }
     198             : 
     199             : 
     200             : struct GNUNET_JSON_Specification
     201          30 : TALER_JSON_spec_amount_any_nbo (const char *name,
     202             :                                 struct TALER_AmountNBO *r_amount)
     203             : {
     204          30 :   struct GNUNET_JSON_Specification ret = {
     205             :     .parser = &parse_amount_nbo,
     206             :     .cleaner = NULL,
     207             :     .cls = NULL,
     208             :     .field = name,
     209             :     .ptr = r_amount,
     210             :     .ptr_size = 0,
     211             :     .size_ptr = NULL
     212             :   };
     213             : 
     214          30 :   return ret;
     215             : }
     216             : 
     217             : 
     218             : /**
     219             :  * Parse given JSON object to *rounded* absolute time.
     220             :  *
     221             :  * @param cls closure, NULL
     222             :  * @param root the json object representing data
     223             :  * @param[out] spec where to write the data
     224             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     225             :  */
     226             : static int
     227        1818 : parse_abs_time (void *cls,
     228             :                 json_t *root,
     229             :                 struct GNUNET_JSON_Specification *spec)
     230             : {
     231        1818 :   struct GNUNET_TIME_Absolute *abs = spec->ptr;
     232             :   json_t *json_t_ms;
     233             :   unsigned long long int tval;
     234             : 
     235        1818 :   if (! json_is_object (root))
     236             :   {
     237           0 :     GNUNET_break_op (0);
     238           0 :     return GNUNET_SYSERR;
     239             :   }
     240        1818 :   json_t_ms = json_object_get (root,
     241             :                                "t_ms");
     242        1818 :   if (json_is_integer (json_t_ms))
     243             :   {
     244        1818 :     tval = json_integer_value (json_t_ms);
     245             :     /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
     246        1818 :     abs->abs_value_us = tval * 1000LL;
     247        1818 :     if ((abs->abs_value_us) / 1000LL != tval)
     248             :     {
     249             :       /* Integer overflow */
     250           0 :       GNUNET_break_op (0);
     251           0 :       return GNUNET_SYSERR;
     252             :     }
     253        1818 :     if (GNUNET_OK !=
     254        1818 :         GNUNET_TIME_round_abs (abs))
     255             :     {
     256             :       /* time not rounded */
     257           0 :       GNUNET_break_op (0);
     258           0 :       return GNUNET_SYSERR;
     259             :     }
     260        1818 :     return GNUNET_OK;
     261             :   }
     262           0 :   if (json_is_string (json_t_ms))
     263             :   {
     264             :     const char *val;
     265             : 
     266           0 :     val = json_string_value (json_t_ms);
     267           0 :     if ((0 == strcasecmp (val, "never")))
     268             :     {
     269           0 :       *abs = GNUNET_TIME_UNIT_FOREVER_ABS;
     270           0 :       return GNUNET_OK;
     271             :     }
     272           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     273             :                 "`%s' is not a valid absolute time\n",
     274             :                 json_string_value (json_t_ms));
     275           0 :     return GNUNET_SYSERR;
     276             :   }
     277           0 :   return GNUNET_SYSERR;
     278             : }
     279             : 
     280             : 
     281             : struct GNUNET_JSON_Specification
     282        1760 : TALER_JSON_spec_absolute_time (const char *name,
     283             :                                struct GNUNET_TIME_Absolute *r_time)
     284             : {
     285        1760 :   struct GNUNET_JSON_Specification ret = {
     286             :     .parser = &parse_abs_time,
     287             :     .cleaner = NULL,
     288             :     .cls = NULL,
     289             :     .field = name,
     290             :     .ptr = r_time,
     291             :     .ptr_size = sizeof(struct GNUNET_TIME_Absolute),
     292             :     .size_ptr = NULL
     293             :   };
     294             : 
     295        1760 :   return ret;
     296             : }
     297             : 
     298             : 
     299             : /**
     300             :  * Parse given JSON object to absolute time.
     301             :  *
     302             :  * @param cls closure, NULL
     303             :  * @param root the json object representing data
     304             :  * @param[out] spec where to write the data
     305             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     306             :  */
     307             : static int
     308          69 : parse_abs_time_nbo (void *cls,
     309             :                     json_t *root,
     310             :                     struct GNUNET_JSON_Specification *spec)
     311             : {
     312          69 :   struct GNUNET_TIME_AbsoluteNBO *abs = spec->ptr;
     313             :   struct GNUNET_TIME_Absolute a;
     314             :   struct GNUNET_JSON_Specification ispec;
     315             : 
     316          69 :   ispec = *spec;
     317          69 :   ispec.parser = &parse_abs_time;
     318          69 :   ispec.ptr = &a;
     319          69 :   if (GNUNET_OK !=
     320          69 :       parse_abs_time (NULL,
     321             :                       root,
     322             :                       &ispec))
     323             :   {
     324           0 :     GNUNET_break_op (0);
     325           0 :     return GNUNET_SYSERR;
     326             :   }
     327          69 :   *abs = GNUNET_TIME_absolute_hton (a);
     328          69 :   return GNUNET_OK;
     329             : }
     330             : 
     331             : 
     332             : struct GNUNET_JSON_Specification
     333          69 : TALER_JSON_spec_absolute_time_nbo (const char *name,
     334             :                                    struct GNUNET_TIME_AbsoluteNBO *r_time)
     335             : {
     336          69 :   struct GNUNET_JSON_Specification ret = {
     337             :     .parser = &parse_abs_time_nbo,
     338             :     .cleaner = NULL,
     339             :     .cls = NULL,
     340             :     .field = name,
     341             :     .ptr = r_time,
     342             :     .ptr_size = sizeof(struct GNUNET_TIME_AbsoluteNBO),
     343             :     .size_ptr = NULL
     344             :   };
     345             : 
     346          69 :   return ret;
     347             : }
     348             : 
     349             : 
     350             : /**
     351             :  * Parse given JSON object to relative time.
     352             :  *
     353             :  * @param cls closure, NULL
     354             :  * @param root the json object representing data
     355             :  * @param[out] spec where to write the data
     356             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     357             :  */
     358             : static int
     359          16 : parse_rel_time (void *cls,
     360             :                 json_t *root,
     361             :                 struct GNUNET_JSON_Specification *spec)
     362             : {
     363          16 :   struct GNUNET_TIME_Relative *rel = spec->ptr;
     364             :   json_t *json_d_ms;
     365             :   unsigned long long int tval;
     366             : 
     367          16 :   if (! json_is_object (root))
     368             :   {
     369           0 :     GNUNET_break_op (0);
     370           0 :     return GNUNET_SYSERR;
     371             :   }
     372          16 :   json_d_ms = json_object_get (root, "d_ms");
     373          16 :   if (json_is_integer (json_d_ms))
     374             :   {
     375          16 :     tval = json_integer_value (json_d_ms);
     376             :     /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
     377          16 :     rel->rel_value_us = tval * 1000LL;
     378          16 :     if ((rel->rel_value_us) / 1000LL != tval)
     379             :     {
     380             :       /* Integer overflow */
     381           0 :       GNUNET_break_op (0);
     382           0 :       return GNUNET_SYSERR;
     383             :     }
     384          16 :     if (GNUNET_OK !=
     385          16 :         GNUNET_TIME_round_rel (rel))
     386             :     {
     387             :       /* time not rounded */
     388           0 :       GNUNET_break_op (0);
     389           0 :       return GNUNET_SYSERR;
     390             :     }
     391          16 :     return GNUNET_OK;
     392             :   }
     393           0 :   if (json_is_string (json_d_ms))
     394             :   {
     395             :     const char *val;
     396           0 :     val = json_string_value (json_d_ms);
     397           0 :     if ((0 == strcasecmp (val, "forever")))
     398             :     {
     399           0 :       *rel = GNUNET_TIME_UNIT_FOREVER_REL;
     400           0 :       return GNUNET_OK;
     401             :     }
     402           0 :     GNUNET_break_op (0);
     403           0 :     return GNUNET_SYSERR;
     404             :   }
     405           0 :   GNUNET_break_op (0);
     406           0 :   return GNUNET_SYSERR;
     407             : }
     408             : 
     409             : 
     410             : struct GNUNET_JSON_Specification
     411          16 : TALER_JSON_spec_relative_time (const char *name,
     412             :                                struct GNUNET_TIME_Relative *r_time)
     413             : {
     414          16 :   struct GNUNET_JSON_Specification ret = {
     415             :     .parser = &parse_rel_time,
     416             :     .cleaner = NULL,
     417             :     .cls = NULL,
     418             :     .field = name,
     419             :     .ptr = r_time,
     420             :     .ptr_size = sizeof(struct GNUNET_TIME_Relative),
     421             :     .size_ptr = NULL
     422             :   };
     423             : 
     424          16 :   return ret;
     425             : }
     426             : 
     427             : 
     428             : struct GNUNET_JSON_Specification
     429           0 : TALER_JSON_spec_denomination_public_key (const char *field,
     430             :                                          struct TALER_DenominationPublicKey *pk)
     431             : {
     432           0 :   return GNUNET_JSON_spec_rsa_public_key (field,
     433             :                                           &pk->rsa_public_key);
     434             : }
     435             : 
     436             : 
     437             : struct GNUNET_JSON_Specification
     438          80 : TALER_JSON_spec_denomination_signature (const char *field,
     439             :                                         struct TALER_DenominationSignature *sig)
     440             : {
     441          80 :   return GNUNET_JSON_spec_rsa_signature (field,
     442             :                                          &sig->rsa_signature);
     443             : }
     444             : 
     445             : 
     446             : /**
     447             :  * Closure for #parse_i18n_string.
     448             :  */
     449             : struct I18nContext
     450             : {
     451             :   /**
     452             :    * Language pattern to match.
     453             :    */
     454             :   char *lp;
     455             : 
     456             :   /**
     457             :    * Name of the field to match.
     458             :    */
     459             :   const char *field;
     460             : };
     461             : 
     462             : 
     463             : /**
     464             :  * Parse given JSON object to internationalized string.
     465             :  *
     466             :  * @param cls closure, our `struct I18nContext *`
     467             :  * @param root the json object representing data
     468             :  * @param[out] spec where to write the data
     469             :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     470             :  */
     471             : static int
     472           0 : parse_i18n_string (void *cls,
     473             :                    json_t *root,
     474             :                    struct GNUNET_JSON_Specification *spec)
     475             : {
     476           0 :   struct I18nContext *ctx = cls;
     477             :   json_t *i18n;
     478             :   json_t *val;
     479             : 
     480             :   {
     481             :     char *i18nf;
     482             : 
     483           0 :     GNUNET_asprintf (&i18nf,
     484             :                      "%s_i18n",
     485             :                      ctx->field);
     486           0 :     i18n = json_object_get (root,
     487             :                             i18nf);
     488           0 :     GNUNET_free (i18nf);
     489             :   }
     490             : 
     491           0 :   val = json_object_get (root,
     492             :                          ctx->field);
     493           0 :   if ( (NULL != i18n) &&
     494           0 :        (NULL != ctx->lp) )
     495             :   {
     496           0 :     double best = 0.0;
     497             :     json_t *pos;
     498             :     const char *lang;
     499             : 
     500           0 :     json_object_foreach (i18n, lang, pos)
     501             :     {
     502             :       double score;
     503             : 
     504           0 :       score = TALER_language_matches (ctx->lp,
     505             :                                       lang);
     506           0 :       if (score > best)
     507             :       {
     508           0 :         best = score;
     509           0 :         val = pos;
     510             :       }
     511             :     }
     512             :   }
     513             : 
     514             :   {
     515             :     const char *str;
     516             : 
     517           0 :     str = json_string_value (val);
     518           0 :     if (NULL == str)
     519             :     {
     520           0 :       GNUNET_break_op (0);
     521           0 :       return GNUNET_SYSERR;
     522             :     }
     523           0 :     *(const char **) spec->ptr = str;
     524             :   }
     525           0 :   return GNUNET_OK;
     526             : }
     527             : 
     528             : 
     529             : /**
     530             :  * Function called to clean up data from earlier parsing.
     531             :  *
     532             :  * @param cls closure
     533             :  * @param spec our specification entry with data to clean.
     534             :  */
     535             : static void
     536           0 : i18n_cleaner (void *cls,
     537             :               struct GNUNET_JSON_Specification *spec)
     538             : {
     539           0 :   struct I18nContext *ctx = cls;
     540             : 
     541           0 :   GNUNET_free (ctx->lp);
     542           0 :   GNUNET_free (ctx);
     543           0 : }
     544             : 
     545             : 
     546             : struct GNUNET_JSON_Specification
     547           0 : TALER_JSON_spec_i18n_string (const char *name,
     548             :                              const char *language_pattern,
     549             :                              const char **strptr)
     550             : {
     551           0 :   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
     552           0 :   struct GNUNET_JSON_Specification ret = {
     553             :     .parser = &parse_i18n_string,
     554             :     .cleaner = &i18n_cleaner,
     555             :     .cls = ctx,
     556             :     .field = NULL, /* we want the main object */
     557             :     .ptr = strptr,
     558             :     .ptr_size = 0,
     559             :     .size_ptr = NULL
     560             :   };
     561             : 
     562           0 :   ctx->lp = (NULL != language_pattern) ? GNUNET_strdup (language_pattern) :
     563             :             NULL;
     564           0 :   ctx->field = name;
     565           0 :   *strptr = NULL;
     566           0 :   return ret;
     567             : }
     568             : 
     569             : 
     570             : struct GNUNET_JSON_Specification
     571           0 : TALER_JSON_spec_i18n_str (const char *name,
     572             :                           const char **strptr)
     573             : {
     574           0 :   const char *lang = getenv ("LANG");
     575             :   char *dot;
     576             :   char *l;
     577             :   struct GNUNET_JSON_Specification ret;
     578             : 
     579           0 :   if (NULL != lang)
     580             :   {
     581           0 :     dot = strchr (lang,
     582             :                   '.');
     583           0 :     if (NULL == dot)
     584           0 :       l = GNUNET_strdup (lang);
     585             :     else
     586           0 :       l = GNUNET_strndup (lang,
     587             :                           dot - lang);
     588             :   }
     589             :   else
     590             :   {
     591           0 :     l = NULL;
     592             :   }
     593           0 :   ret = TALER_JSON_spec_i18n_string (name,
     594             :                                      l,
     595             :                                      strptr);
     596           0 :   GNUNET_free (l);
     597           0 :   return ret;
     598             : }
     599             : 
     600             : 
     601             : /* end of json/json_helper.c */

Generated by: LCOV version 1.14