LCOV - code coverage report
Current view: top level - pq - pq_result_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 307 563 54.5 %
Date: 2025-08-30 09:28:00 Functions: 20 29 69.0 %

          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 pq/pq_result_helper.c
      18             :  * @brief functions to initialize parameter arrays
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "taler/platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include "pq_common.h"
      24             : #include "taler/taler_pq_lib.h"
      25             : 
      26             : 
      27             : /**
      28             :  * Extract an amount from a tuple including the currency from a Postgres
      29             :  * database @a result at row @a row.
      30             :  *
      31             :  * @param cls closure; not used
      32             :  * @param result where to extract data from
      33             :  * @param row row to extract data from
      34             :  * @param fname name (or prefix) of the fields to extract from
      35             :  * @param[in,out] dst_size where to store size of result, may be NULL
      36             :  * @param[out] dst where to store the result
      37             :  * @return
      38             :  *   #GNUNET_YES if all results could be extracted
      39             :  *   #GNUNET_NO if at least one result was NULL
      40             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
      41             :  */
      42             : static enum GNUNET_GenericReturnValue
      43          39 : extract_amount_currency_tuple (void *cls,
      44             :                                PGresult *result,
      45             :                                int row,
      46             :                                const char *fname,
      47             :                                size_t *dst_size,
      48             :                                void *dst)
      49             : {
      50          39 :   struct TALER_Amount *r_amount = dst;
      51             :   int col;
      52             : 
      53             :   (void) cls;
      54          39 :   if (sizeof (struct TALER_Amount) != *dst_size)
      55             :   {
      56           0 :     GNUNET_break (0);
      57           0 :     return GNUNET_SYSERR;
      58             :   }
      59             : 
      60             :   /* Set return value to invalid in case we don't finish */
      61          39 :   memset (r_amount,
      62             :           0,
      63             :           sizeof (struct TALER_Amount));
      64          39 :   col = PQfnumber (result,
      65             :                    fname);
      66          39 :   if (col < 0)
      67             :   {
      68           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      69             :                 "Field `%s' does not exist in result\n",
      70             :                 fname);
      71           0 :     return GNUNET_SYSERR;
      72             :   }
      73          39 :   if (PQgetisnull (result,
      74             :                    row,
      75             :                    col))
      76             :   {
      77           0 :     return GNUNET_NO;
      78             :   }
      79             : 
      80             :   /* Parse the tuple */
      81             :   {
      82             :     struct TALER_PQ_AmountCurrencyP ap;
      83             :     const char *in;
      84             :     size_t size;
      85             : 
      86          39 :     size = PQgetlength (result,
      87             :                         row,
      88             :                         col);
      89          39 :     if ( (size >= sizeof (ap)) ||
      90             :          (size <= sizeof (ap) - TALER_CURRENCY_LEN) )
      91             :     {
      92           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      93             :                   "Incorrect size of binary field `%s' (got %zu, expected (%zu-%zu))\n",
      94             :                   fname,
      95             :                   size,
      96             :                   sizeof (ap) - TALER_CURRENCY_LEN,
      97             :                   sizeof (ap));
      98           0 :       return GNUNET_SYSERR;
      99             :     }
     100             : 
     101          39 :     in = PQgetvalue (result,
     102             :                      row,
     103             :                      col);
     104          39 :     memset (&ap.c,
     105             :             0,
     106             :             TALER_CURRENCY_LEN);
     107          39 :     memcpy (&ap,
     108             :             in,
     109             :             size);
     110          39 :     if (3 != ntohl (ap.cnt))
     111             :     {
     112           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     113             :                   "Incorrect number of elements in tuple-field `%s'\n",
     114             :                   fname);
     115           0 :       return GNUNET_SYSERR;
     116             :     }
     117             :     /* FIXME[oec]: OID-checks? */
     118             : 
     119          39 :     r_amount->value = GNUNET_ntohll (ap.v);
     120          39 :     r_amount->fraction = ntohl (ap.f);
     121          39 :     memcpy (r_amount->currency,
     122             :             ap.c,
     123             :             TALER_CURRENCY_LEN);
     124          39 :     if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1])
     125             :     {
     126           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     127             :                   "Invalid currency (not 0-terminated) in tuple field `%s'\n",
     128             :                   fname);
     129             :       /* be sure nobody uses this by accident */
     130           0 :       memset (r_amount,
     131             :               0,
     132             :               sizeof (struct TALER_Amount));
     133           0 :       return GNUNET_SYSERR;
     134             :     }
     135             :   }
     136             : 
     137          39 :   if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
     138             :   {
     139           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     140             :                 "Value in field `%s' exceeds legal range\n",
     141             :                 fname);
     142           0 :     return GNUNET_SYSERR;
     143             :   }
     144          39 :   if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
     145             :   {
     146           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     147             :                 "Fraction in field `%s' exceeds legal range\n",
     148             :                 fname);
     149           0 :     return GNUNET_SYSERR;
     150             :   }
     151          39 :   return GNUNET_OK;
     152             : }
     153             : 
     154             : 
     155             : struct GNUNET_PQ_ResultSpec
     156          39 : TALER_PQ_result_spec_amount_with_currency (const char *name,
     157             :                                            struct TALER_Amount *amount)
     158             : {
     159          39 :   struct GNUNET_PQ_ResultSpec res = {
     160             :     .conv = &extract_amount_currency_tuple,
     161             :     .dst = (void *) amount,
     162             :     .dst_size = sizeof (*amount),
     163             :     .fname = name
     164             :   };
     165             : 
     166          39 :   return res;
     167             : }
     168             : 
     169             : 
     170             : /**
     171             :  * Extract an amount from a tuple from a Postgres database @a result at row @a row.
     172             :  *
     173             :  * @param cls closure, a `const char *` giving the currency
     174             :  * @param result where to extract data from
     175             :  * @param row row to extract data from
     176             :  * @param fname name (or prefix) of the fields to extract from
     177             :  * @param[in,out] dst_size where to store size of result, may be NULL
     178             :  * @param[out] dst where to store the result
     179             :  * @return
     180             :  *   #GNUNET_YES if all results could be extracted
     181             :  *   #GNUNET_NO if at least one result was NULL
     182             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     183             :  */
     184             : static enum GNUNET_GenericReturnValue
     185      415080 : extract_amount_tuple (void *cls,
     186             :                       PGresult *result,
     187             :                       int row,
     188             :                       const char *fname,
     189             :                       size_t *dst_size,
     190             :                       void *dst)
     191             : {
     192      415080 :   struct TALER_Amount *r_amount = dst;
     193      415080 :   const char *currency = cls;
     194             :   int col;
     195             :   size_t len;
     196             : 
     197      415080 :   if (sizeof (struct TALER_Amount) != *dst_size)
     198             :   {
     199           0 :     GNUNET_break (0);
     200           0 :     return GNUNET_SYSERR;
     201             :   }
     202             : 
     203             :   /* Set return value to invalid in case we don't finish */
     204      415080 :   memset (r_amount,
     205             :           0,
     206             :           sizeof (struct TALER_Amount));
     207      415080 :   col = PQfnumber (result,
     208             :                    fname);
     209      415080 :   if (col < 0)
     210             :   {
     211           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     212             :                 "Field `%s' does not exist in result\n",
     213             :                 fname);
     214           0 :     return GNUNET_SYSERR;
     215             :   }
     216      415080 :   if (PQgetisnull (result,
     217             :                    row,
     218             :                    col))
     219             :   {
     220           0 :     return GNUNET_NO;
     221             :   }
     222             : 
     223             :   /* Parse the tuple */
     224             :   {
     225             :     struct TALER_PQ_AmountP ap;
     226             :     const char *in;
     227             :     size_t size;
     228             : 
     229      415080 :     size = PQgetlength (result,
     230             :                         row,
     231             :                         col);
     232      415080 :     in = PQgetvalue (result,
     233             :                      row,
     234             :                      col);
     235      415080 :     if (sizeof(struct TALER_PQ_AmountNullP) == size)
     236             :     {
     237             :       struct TALER_PQ_AmountNullP apn;
     238             : 
     239        2425 :       memcpy (&apn,
     240             :               in,
     241             :               size);
     242        2425 :       if ( (2 == ntohl (apn.cnt)) &&
     243        2425 :            (-1 == (int32_t) ntohl (apn.sz_v)) &&
     244        2425 :            (-1 == (int32_t) ntohl (apn.sz_f)) )
     245             :       {
     246             :         /* is NULL! */
     247        2425 :         return GNUNET_NO;
     248             :       }
     249           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     250             :                   "Incorrect size of binary field `%s' and not NULL (got %zu, expected %zu)\n",
     251             :                   fname,
     252             :                   size,
     253             :                   sizeof(ap));
     254           0 :       return GNUNET_SYSERR;
     255             :     }
     256      412655 :     if (sizeof(ap) != size)
     257             :     {
     258           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     259             :                   "Incorrect size of binary field `%s' (got %zu, expected %zu)\n",
     260             :                   fname,
     261             :                   size,
     262             :                   sizeof(ap));
     263           0 :       return GNUNET_SYSERR;
     264             :     }
     265             : 
     266      412655 :     memcpy (&ap,
     267             :             in,
     268             :             size);
     269      412655 :     if (2 != ntohl (ap.cnt))
     270             :     {
     271           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     272             :                   "Incorrect number of elements in tuple-field `%s'\n",
     273             :                   fname);
     274           0 :       return GNUNET_SYSERR;
     275             :     }
     276             :     /* FIXME[oec]: OID-checks? */
     277             : 
     278      412655 :     r_amount->value = GNUNET_ntohll (ap.v);
     279      412655 :     r_amount->fraction = ntohl (ap.f);
     280             :   }
     281             : 
     282      412655 :   if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
     283             :   {
     284           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     285             :                 "Value in field `%s' exceeds legal range\n",
     286             :                 fname);
     287           0 :     return GNUNET_SYSERR;
     288             :   }
     289      412655 :   if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
     290             :   {
     291           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     292             :                 "Fraction in field `%s' exceeds legal range\n",
     293             :                 fname);
     294           0 :     return GNUNET_SYSERR;
     295             :   }
     296             : 
     297      412655 :   len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
     298             :                     strlen (currency));
     299             : 
     300      412655 :   GNUNET_memcpy (r_amount->currency,
     301             :                  currency,
     302             :                  len);
     303      412655 :   return GNUNET_OK;
     304             : }
     305             : 
     306             : 
     307             : struct GNUNET_PQ_ResultSpec
     308      447971 : TALER_PQ_result_spec_amount (const char *name,
     309             :                              const char *currency,
     310             :                              struct TALER_Amount *amount)
     311             : {
     312      447971 :   struct GNUNET_PQ_ResultSpec res = {
     313             :     .conv = &extract_amount_tuple,
     314             :     .cls = (void *) currency,
     315             :     .dst = (void *) amount,
     316             :     .dst_size = sizeof (*amount),
     317             :     .fname = name
     318             :   };
     319             : 
     320      447971 :   return res;
     321             : }
     322             : 
     323             : 
     324             : /**
     325             :  * Extract data from a Postgres database @a result at row @a row.
     326             :  *
     327             :  * @param cls closure
     328             :  * @param result where to extract data from
     329             :  * @param row row to extract data from
     330             :  * @param fname name (or prefix) of the fields to extract from
     331             :  * @param[in,out] dst_size where to store size of result, may be NULL
     332             :  * @param[out] dst where to store the result
     333             :  * @return
     334             :  *   #GNUNET_YES if all results could be extracted
     335             :  *   #GNUNET_NO if at least one result was NULL
     336             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     337             :  */
     338             : static enum GNUNET_GenericReturnValue
     339         317 : extract_json (void *cls,
     340             :               PGresult *result,
     341             :               int row,
     342             :               const char *fname,
     343             :               size_t *dst_size,
     344             :               void *dst)
     345             : {
     346         317 :   json_t **j_dst = dst;
     347             :   const char *res;
     348             :   int fnum;
     349             :   json_error_t json_error;
     350             :   size_t slen;
     351             : 
     352             :   (void) cls;
     353             :   (void) dst_size;
     354         317 :   fnum = PQfnumber (result,
     355             :                     fname);
     356         317 :   if (fnum < 0)
     357             :   {
     358           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     359             :                 "Field `%s' does not exist in result\n",
     360             :                 fname);
     361           0 :     return GNUNET_SYSERR;
     362             :   }
     363         317 :   if (PQgetisnull (result,
     364             :                    row,
     365             :                    fnum))
     366         144 :     return GNUNET_NO;
     367         173 :   slen = PQgetlength (result,
     368             :                       row,
     369             :                       fnum);
     370         173 :   res = (const char *) PQgetvalue (result,
     371             :                                    row,
     372             :                                    fnum);
     373         173 :   *j_dst = json_loadb (res,
     374             :                        slen,
     375             :                        JSON_REJECT_DUPLICATES,
     376             :                        &json_error);
     377         173 :   if (NULL == *j_dst)
     378             :   {
     379           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     380             :                 "Failed to parse JSON result for field `%s': %s (%s)\n",
     381             :                 fname,
     382             :                 json_error.text,
     383             :                 json_error.source);
     384           0 :     return GNUNET_SYSERR;
     385             :   }
     386         173 :   return GNUNET_OK;
     387             : }
     388             : 
     389             : 
     390             : /**
     391             :  * Function called to clean up memory allocated
     392             :  * by a #GNUNET_PQ_ResultConverter.
     393             :  *
     394             :  * @param cls closure
     395             :  * @param rd result data to clean up
     396             :  */
     397             : static void
     398          68 : clean_json (void *cls,
     399             :             void *rd)
     400             : {
     401          68 :   json_t **dst = rd;
     402             : 
     403             :   (void) cls;
     404          68 :   if (NULL != *dst)
     405             :   {
     406          63 :     json_decref (*dst);
     407          63 :     *dst = NULL;
     408             :   }
     409          68 : }
     410             : 
     411             : 
     412             : struct GNUNET_PQ_ResultSpec
     413         367 : TALER_PQ_result_spec_json (const char *name,
     414             :                            json_t **jp)
     415             : {
     416         367 :   struct GNUNET_PQ_ResultSpec res = {
     417             :     .conv = &extract_json,
     418             :     .cleaner = &clean_json,
     419             :     .dst = (void *) jp,
     420             :     .fname  = name
     421             :   };
     422             : 
     423         367 :   return res;
     424             : }
     425             : 
     426             : 
     427             : /**
     428             :  * Extract data from a Postgres database @a result at row @a row.
     429             :  *
     430             :  * @param cls closure
     431             :  * @param result where to extract data from
     432             :  * @param row the row to extract data from
     433             :  * @param fname name (or prefix) of the fields to extract from
     434             :  * @param[in,out] dst_size where to store size of result, may be NULL
     435             :  * @param[out] dst where to store the result
     436             :  * @return
     437             :  *   #GNUNET_YES if all results could be extracted
     438             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
     439             :  */
     440             : static enum GNUNET_GenericReturnValue
     441       77792 : extract_denom_pub (void *cls,
     442             :                    PGresult *result,
     443             :                    int row,
     444             :                    const char *fname,
     445             :                    size_t *dst_size,
     446             :                    void *dst)
     447             : {
     448       77792 :   struct TALER_DenominationPublicKey *pk = dst;
     449             :   struct GNUNET_CRYPTO_BlindSignPublicKey *bpk;
     450             :   size_t len;
     451             :   const char *res;
     452             :   int fnum;
     453             :   uint32_t be[2];
     454             : 
     455             :   (void) cls;
     456             :   (void) dst_size;
     457       77792 :   fnum = PQfnumber (result,
     458             :                     fname);
     459       77792 :   if (fnum < 0)
     460             :   {
     461           0 :     GNUNET_break (0);
     462           0 :     return GNUNET_SYSERR;
     463             :   }
     464       77792 :   if (PQgetisnull (result,
     465             :                    row,
     466             :                    fnum))
     467           0 :     return GNUNET_NO;
     468             : 
     469             :   /* if a field is null, continue but
     470             :    * remember that we now return a different result */
     471       77792 :   len = PQgetlength (result,
     472             :                      row,
     473             :                      fnum);
     474       77792 :   res = PQgetvalue (result,
     475             :                     row,
     476             :                     fnum);
     477       77792 :   if (len < sizeof (be))
     478             :   {
     479           0 :     GNUNET_break (0);
     480           0 :     return GNUNET_SYSERR;
     481             :   }
     482       77792 :   GNUNET_memcpy (be,
     483             :                  res,
     484             :                  sizeof (be));
     485       77792 :   res += sizeof (be);
     486       77792 :   len -= sizeof (be);
     487       77792 :   bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
     488       77792 :   bpk->cipher = ntohl (be[0]);
     489       77792 :   bpk->rc = 1;
     490       77792 :   pk->age_mask.bits = ntohl (be[1]);
     491       77792 :   switch (bpk->cipher)
     492             :   {
     493           0 :   case GNUNET_CRYPTO_BSA_INVALID:
     494           0 :     break;
     495       72995 :   case GNUNET_CRYPTO_BSA_RSA:
     496             :     bpk->details.rsa_public_key
     497       72995 :       = GNUNET_CRYPTO_rsa_public_key_decode (res,
     498             :                                              len);
     499       72995 :     if (NULL == bpk->details.rsa_public_key)
     500             :     {
     501           0 :       GNUNET_break (0);
     502           0 :       GNUNET_free (bpk);
     503           0 :       return GNUNET_SYSERR;
     504             :     }
     505       72995 :     pk->bsign_pub_key = bpk;
     506       72995 :     GNUNET_CRYPTO_hash (res,
     507             :                         len,
     508             :                         &bpk->pub_key_hash);
     509       72995 :     return GNUNET_OK;
     510        4797 :   case GNUNET_CRYPTO_BSA_CS:
     511        4797 :     if (sizeof (bpk->details.cs_public_key) != len)
     512             :     {
     513           0 :       GNUNET_break (0);
     514           0 :       GNUNET_free (bpk);
     515           0 :       return GNUNET_SYSERR;
     516             :     }
     517        4797 :     GNUNET_memcpy (&bpk->details.cs_public_key,
     518             :                    res,
     519             :                    len);
     520        4797 :     pk->bsign_pub_key = bpk;
     521        4797 :     GNUNET_CRYPTO_hash (res,
     522             :                         len,
     523             :                         &bpk->pub_key_hash);
     524        4797 :     return GNUNET_OK;
     525             :   }
     526           0 :   GNUNET_break (0);
     527           0 :   GNUNET_free (bpk);
     528           0 :   return GNUNET_SYSERR;
     529             : }
     530             : 
     531             : 
     532             : /**
     533             :  * Function called to clean up memory allocated
     534             :  * by a #GNUNET_PQ_ResultConverter.
     535             :  *
     536             :  * @param cls closure
     537             :  * @param rd result data to clean up
     538             :  */
     539             : static void
     540       11646 : clean_denom_pub (void *cls,
     541             :                  void *rd)
     542             : {
     543       11646 :   struct TALER_DenominationPublicKey *denom_pub = rd;
     544             : 
     545             :   (void) cls;
     546       11646 :   TALER_denom_pub_free (denom_pub);
     547       11646 : }
     548             : 
     549             : 
     550             : struct GNUNET_PQ_ResultSpec
     551       77792 : TALER_PQ_result_spec_denom_pub (const char *name,
     552             :                                 struct TALER_DenominationPublicKey *denom_pub)
     553             : {
     554       77792 :   struct GNUNET_PQ_ResultSpec res = {
     555             :     .conv = &extract_denom_pub,
     556             :     .cleaner = &clean_denom_pub,
     557             :     .dst = (void *) denom_pub,
     558             :     .fname = name
     559             :   };
     560             : 
     561       77792 :   return res;
     562             : }
     563             : 
     564             : 
     565             : /**
     566             :  * Extract data from a Postgres database @a result at row @a row.
     567             :  *
     568             :  * @param cls closure
     569             :  * @param result where to extract data from
     570             :  * @param row the row to extract data from
     571             :  * @param fname name (or prefix) of the fields to extract from
     572             :  * @param[in,out] dst_size where to store size of result, may be NULL
     573             :  * @param[out] dst where to store the result
     574             :  * @return
     575             :  *   #GNUNET_YES if all results could be extracted
     576             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
     577             :  */
     578             : static enum GNUNET_GenericReturnValue
     579         282 : extract_denom_sig (void *cls,
     580             :                    PGresult *result,
     581             :                    int row,
     582             :                    const char *fname,
     583             :                    size_t *dst_size,
     584             :                    void *dst)
     585             : {
     586         282 :   struct TALER_DenominationSignature *sig = dst;
     587             :   struct GNUNET_CRYPTO_UnblindedSignature *ubs;
     588             :   size_t len;
     589             :   const char *res;
     590             :   int fnum;
     591             :   uint32_t be[2];
     592             : 
     593             :   (void) cls;
     594             :   (void) dst_size;
     595         282 :   fnum = PQfnumber (result,
     596             :                     fname);
     597         282 :   if (fnum < 0)
     598             :   {
     599           0 :     GNUNET_break (0);
     600           0 :     return GNUNET_SYSERR;
     601             :   }
     602         282 :   if (PQgetisnull (result,
     603             :                    row,
     604             :                    fnum))
     605           0 :     return GNUNET_NO;
     606             : 
     607             :   /* if a field is null, continue but
     608             :    * remember that we now return a different result */
     609         282 :   len = PQgetlength (result,
     610             :                      row,
     611             :                      fnum);
     612         282 :   res = PQgetvalue (result,
     613             :                     row,
     614             :                     fnum);
     615         282 :   if (len < sizeof (be))
     616             :   {
     617           0 :     GNUNET_break (0);
     618           0 :     return GNUNET_SYSERR;
     619             :   }
     620         282 :   GNUNET_memcpy (&be,
     621             :                  res,
     622             :                  sizeof (be));
     623         282 :   if (0x00 != ntohl (be[1]))
     624             :   {
     625           0 :     GNUNET_break (0);
     626           0 :     return GNUNET_SYSERR;
     627             :   }
     628         282 :   res += sizeof (be);
     629         282 :   len -= sizeof (be);
     630         282 :   ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
     631         282 :   ubs->rc = 1;
     632         282 :   ubs->cipher = ntohl (be[0]);
     633         282 :   switch (ubs->cipher)
     634             :   {
     635           0 :   case GNUNET_CRYPTO_BSA_INVALID:
     636           0 :     break;
     637         282 :   case GNUNET_CRYPTO_BSA_RSA:
     638             :     ubs->details.rsa_signature
     639         282 :       = GNUNET_CRYPTO_rsa_signature_decode (res,
     640             :                                             len);
     641         282 :     if (NULL == ubs->details.rsa_signature)
     642             :     {
     643           0 :       GNUNET_break (0);
     644           0 :       GNUNET_free (ubs);
     645           0 :       return GNUNET_SYSERR;
     646             :     }
     647         282 :     sig->unblinded_sig = ubs;
     648         282 :     return GNUNET_OK;
     649           0 :   case GNUNET_CRYPTO_BSA_CS:
     650           0 :     if (sizeof (ubs->details.cs_signature) != len)
     651             :     {
     652           0 :       GNUNET_break (0);
     653           0 :       GNUNET_free (ubs);
     654           0 :       return GNUNET_SYSERR;
     655             :     }
     656           0 :     GNUNET_memcpy (&ubs->details.cs_signature,
     657             :                    res,
     658             :                    len);
     659           0 :     sig->unblinded_sig = ubs;
     660           0 :     return GNUNET_OK;
     661             :   }
     662           0 :   GNUNET_break (0);
     663           0 :   GNUNET_free (ubs);
     664           0 :   return GNUNET_SYSERR;
     665             : }
     666             : 
     667             : 
     668             : /**
     669             :  * Function called to clean up memory allocated
     670             :  * by a #GNUNET_PQ_ResultConverter.
     671             :  *
     672             :  * @param cls closure
     673             :  * @param rd result data to clean up
     674             :  */
     675             : static void
     676           3 : clean_denom_sig (void *cls,
     677             :                  void *rd)
     678             : {
     679           3 :   struct TALER_DenominationSignature *denom_sig = rd;
     680             : 
     681             :   (void) cls;
     682           3 :   TALER_denom_sig_free (denom_sig);
     683           3 : }
     684             : 
     685             : 
     686             : struct GNUNET_PQ_ResultSpec
     687         282 : TALER_PQ_result_spec_denom_sig (const char *name,
     688             :                                 struct TALER_DenominationSignature *denom_sig)
     689             : {
     690         282 :   struct GNUNET_PQ_ResultSpec res = {
     691             :     .conv = &extract_denom_sig,
     692             :     .cleaner = &clean_denom_sig,
     693             :     .dst = (void *) denom_sig,
     694             :     .fname = name
     695             :   };
     696             : 
     697         282 :   return res;
     698             : }
     699             : 
     700             : 
     701             : /**
     702             :  * Extract data from a Postgres database @a result at row @a row.
     703             :  *
     704             :  * @param cls closure
     705             :  * @param result where to extract data from
     706             :  * @param row the row to extract data from
     707             :  * @param fname name (or prefix) of the fields to extract from
     708             :  * @param[in,out] dst_size where to store size of result, may be NULL
     709             :  * @param[out] dst where to store the result
     710             :  * @return
     711             :  *   #GNUNET_YES if all results could be extracted
     712             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
     713             :  */
     714             : static enum GNUNET_GenericReturnValue
     715           0 : extract_blinded_denom_sig (void *cls,
     716             :                            PGresult *result,
     717             :                            int row,
     718             :                            const char *fname,
     719             :                            size_t *dst_size,
     720             :                            void *dst)
     721             : {
     722           0 :   struct TALER_BlindedDenominationSignature *sig = dst;
     723             :   struct GNUNET_CRYPTO_BlindedSignature *bs;
     724             :   size_t len;
     725             :   const char *res;
     726             :   int fnum;
     727             :   uint32_t be[2];
     728             : 
     729             :   (void) cls;
     730             :   (void) dst_size;
     731           0 :   fnum = PQfnumber (result,
     732             :                     fname);
     733           0 :   if (fnum < 0)
     734             :   {
     735           0 :     GNUNET_break (0);
     736           0 :     return GNUNET_SYSERR;
     737             :   }
     738           0 :   if (PQgetisnull (result,
     739             :                    row,
     740             :                    fnum))
     741           0 :     return GNUNET_NO;
     742             : 
     743             :   /* if a field is null, continue but
     744             :    * remember that we now return a different result */
     745           0 :   len = PQgetlength (result,
     746             :                      row,
     747             :                      fnum);
     748           0 :   res = PQgetvalue (result,
     749             :                     row,
     750             :                     fnum);
     751           0 :   if (len < sizeof (be))
     752             :   {
     753           0 :     GNUNET_break (0);
     754           0 :     return GNUNET_SYSERR;
     755             :   }
     756           0 :   GNUNET_memcpy (&be,
     757             :                  res,
     758             :                  sizeof (be));
     759           0 :   if (0x01 != ntohl (be[1])) /* magic marker: blinded */
     760             :   {
     761           0 :     GNUNET_break (0);
     762           0 :     return GNUNET_SYSERR;
     763             :   }
     764           0 :   res += sizeof (be);
     765           0 :   len -= sizeof (be);
     766           0 :   bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
     767           0 :   bs->rc = 1;
     768           0 :   bs->cipher = ntohl (be[0]);
     769           0 :   switch (bs->cipher)
     770             :   {
     771           0 :   case GNUNET_CRYPTO_BSA_INVALID:
     772           0 :     break;
     773           0 :   case GNUNET_CRYPTO_BSA_RSA:
     774             :     bs->details.blinded_rsa_signature
     775           0 :       = GNUNET_CRYPTO_rsa_signature_decode (res,
     776             :                                             len);
     777           0 :     if (NULL == bs->details.blinded_rsa_signature)
     778             :     {
     779           0 :       GNUNET_break (0);
     780           0 :       GNUNET_free (bs);
     781           0 :       return GNUNET_SYSERR;
     782             :     }
     783           0 :     sig->blinded_sig = bs;
     784           0 :     return GNUNET_OK;
     785           0 :   case GNUNET_CRYPTO_BSA_CS:
     786           0 :     if (sizeof (bs->details.blinded_cs_answer) != len)
     787             :     {
     788           0 :       GNUNET_break (0);
     789           0 :       GNUNET_free (bs);
     790           0 :       return GNUNET_SYSERR;
     791             :     }
     792           0 :     GNUNET_memcpy (&bs->details.blinded_cs_answer,
     793             :                    res,
     794             :                    len);
     795           0 :     sig->blinded_sig = bs;
     796           0 :     return GNUNET_OK;
     797             :   }
     798           0 :   GNUNET_break (0);
     799           0 :   GNUNET_free (bs);
     800           0 :   return GNUNET_SYSERR;
     801             : }
     802             : 
     803             : 
     804             : /**
     805             :  * Function called to clean up memory allocated
     806             :  * by a #GNUNET_PQ_ResultConverter.
     807             :  *
     808             :  * @param cls closure
     809             :  * @param rd result data to clean up
     810             :  */
     811             : static void
     812           0 : clean_blinded_denom_sig (void *cls,
     813             :                          void *rd)
     814             : {
     815           0 :   struct TALER_BlindedDenominationSignature *denom_sig = rd;
     816             : 
     817             :   (void) cls;
     818           0 :   TALER_blinded_denom_sig_free (denom_sig);
     819           0 : }
     820             : 
     821             : 
     822             : struct GNUNET_PQ_ResultSpec
     823           0 : TALER_PQ_result_spec_blinded_denom_sig (
     824             :   const char *name,
     825             :   struct TALER_BlindedDenominationSignature *denom_sig)
     826             : {
     827             :   // FIXME: use GNUNET_PQ_result_spec_blinded_sig()
     828           0 :   struct GNUNET_PQ_ResultSpec res = {
     829             :     .conv = &extract_blinded_denom_sig,
     830             :     .cleaner = &clean_blinded_denom_sig,
     831             :     .dst = (void *) denom_sig,
     832             :     .fname = name
     833             :   };
     834             : 
     835           0 :   return res;
     836             : }
     837             : 
     838             : 
     839             : /**
     840             :  * Extract data from a Postgres database @a result at row @a row.
     841             :  *
     842             :  * @param cls closure
     843             :  * @param result where to extract data from
     844             :  * @param row the row to extract data from
     845             :  * @param fname name (or prefix) of the fields to extract from
     846             :  * @param[in,out] dst_size where to store size of result, may be NULL
     847             :  * @param[out] dst where to store the result
     848             :  * @return
     849             :  *   #GNUNET_YES if all results could be extracted
     850             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
     851             :  */
     852             : static enum GNUNET_GenericReturnValue
     853           0 : extract_blinded_planchet (void *cls,
     854             :                           PGresult *result,
     855             :                           int row,
     856             :                           const char *fname,
     857             :                           size_t *dst_size,
     858             :                           void *dst)
     859             : {
     860           0 :   struct TALER_BlindedPlanchet *bp = dst;
     861             :   struct GNUNET_CRYPTO_BlindedMessage *bm;
     862             :   size_t len;
     863             :   const char *res;
     864             :   int fnum;
     865             :   uint32_t be[2];
     866             : 
     867             :   (void) cls;
     868             :   (void) dst_size;
     869           0 :   fnum = PQfnumber (result,
     870             :                     fname);
     871           0 :   if (fnum < 0)
     872             :   {
     873           0 :     GNUNET_break (0);
     874           0 :     return GNUNET_SYSERR;
     875             :   }
     876           0 :   if (PQgetisnull (result,
     877             :                    row,
     878             :                    fnum))
     879           0 :     return GNUNET_NO;
     880             : 
     881             :   /* if a field is null, continue but
     882             :    * remember that we now return a different result */
     883           0 :   len = PQgetlength (result,
     884             :                      row,
     885             :                      fnum);
     886           0 :   res = PQgetvalue (result,
     887             :                     row,
     888             :                     fnum);
     889           0 :   if (len < sizeof (be))
     890             :   {
     891           0 :     GNUNET_break (0);
     892           0 :     return GNUNET_SYSERR;
     893             :   }
     894           0 :   GNUNET_memcpy (&be,
     895             :                  res,
     896             :                  sizeof (be));
     897           0 :   if (0x0100 != ntohl (be[1])) /* magic marker: blinded */
     898             :   {
     899           0 :     GNUNET_break (0);
     900           0 :     return GNUNET_SYSERR;
     901             :   }
     902           0 :   res += sizeof (be);
     903           0 :   len -= sizeof (be);
     904           0 :   bm = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
     905           0 :   bm->rc = 1;
     906           0 :   bm->cipher = ntohl (be[0]);
     907           0 :   switch (bm->cipher)
     908             :   {
     909           0 :   case GNUNET_CRYPTO_BSA_INVALID:
     910           0 :     break;
     911           0 :   case GNUNET_CRYPTO_BSA_RSA:
     912             :     bm->details.rsa_blinded_message.blinded_msg_size
     913           0 :       = len;
     914             :     bm->details.rsa_blinded_message.blinded_msg
     915           0 :       = GNUNET_memdup (res,
     916             :                        len);
     917           0 :     bp->blinded_message = bm;
     918           0 :     return GNUNET_OK;
     919           0 :   case GNUNET_CRYPTO_BSA_CS:
     920           0 :     if (sizeof (bm->details.cs_blinded_message) != len)
     921             :     {
     922           0 :       GNUNET_break (0);
     923           0 :       GNUNET_free (bm);
     924           0 :       return GNUNET_SYSERR;
     925             :     }
     926           0 :     GNUNET_memcpy (&bm->details.cs_blinded_message,
     927             :                    res,
     928             :                    len);
     929           0 :     bp->blinded_message = bm;
     930           0 :     return GNUNET_OK;
     931             :   }
     932           0 :   GNUNET_break (0);
     933           0 :   GNUNET_free (bm);
     934           0 :   return GNUNET_SYSERR;
     935             : }
     936             : 
     937             : 
     938             : /**
     939             :  * Function called to clean up memory allocated
     940             :  * by a #GNUNET_PQ_ResultConverter.
     941             :  *
     942             :  * @param cls closure
     943             :  * @param rd result data to clean up
     944             :  */
     945             : static void
     946           0 : clean_blinded_planchet (void *cls,
     947             :                         void *rd)
     948             : {
     949           0 :   struct TALER_BlindedPlanchet *bp = rd;
     950             : 
     951             :   (void) cls;
     952           0 :   TALER_blinded_planchet_free (bp);
     953           0 : }
     954             : 
     955             : 
     956             : struct GNUNET_PQ_ResultSpec
     957           0 : TALER_PQ_result_spec_blinded_planchet (
     958             :   const char *name,
     959             :   struct TALER_BlindedPlanchet *bp)
     960             : {
     961           0 :   struct GNUNET_PQ_ResultSpec res = {
     962             :     .conv = &extract_blinded_planchet,
     963             :     .cleaner = &clean_blinded_planchet,
     964             :     .dst = (void *) bp,
     965             :     .fname = name
     966             :   };
     967             : 
     968           0 :   return res;
     969             : }
     970             : 
     971             : 
     972             : /**
     973             :  * Extract data from a Postgres database @a result at row @a row.
     974             :  *
     975             :  * @param cls closure
     976             :  * @param result where to extract data from
     977             :  * @param row row to extract data from
     978             :  * @param fname name (or prefix) of the fields to extract from
     979             :  * @param[in,out] dst_size where to store size of result, may be NULL
     980             :  * @param[out] dst where to store the result
     981             :  * @return
     982             :  *   #GNUNET_YES if all results could be extracted
     983             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
     984             :  */
     985             : static enum GNUNET_GenericReturnValue
     986           0 : extract_exchange_withdraw_values (void *cls,
     987             :                                   PGresult *result,
     988             :                                   int row,
     989             :                                   const char *fname,
     990             :                                   size_t *dst_size,
     991             :                                   void *dst)
     992             : {
     993           0 :   struct TALER_ExchangeBlindingValues *alg_values = dst;
     994             :   struct GNUNET_CRYPTO_BlindingInputValues *bi;
     995             :   size_t len;
     996             :   const char *res;
     997             :   int fnum;
     998             :   uint32_t be[2];
     999             : 
    1000             :   (void) cls;
    1001             :   (void) dst_size;
    1002           0 :   fnum = PQfnumber (result,
    1003             :                     fname);
    1004           0 :   if (fnum < 0)
    1005             :   {
    1006           0 :     GNUNET_break (0);
    1007           0 :     return GNUNET_SYSERR;
    1008             :   }
    1009           0 :   if (PQgetisnull (result,
    1010             :                    row,
    1011             :                    fnum))
    1012           0 :     return GNUNET_NO;
    1013             : 
    1014             :   /* if a field is null, continue but
    1015             :    * remember that we now return a different result */
    1016           0 :   len = PQgetlength (result,
    1017             :                      row,
    1018             :                      fnum);
    1019           0 :   res = PQgetvalue (result,
    1020             :                     row,
    1021             :                     fnum);
    1022           0 :   if (len < sizeof (be))
    1023             :   {
    1024           0 :     GNUNET_break (0);
    1025           0 :     return GNUNET_SYSERR;
    1026             :   }
    1027           0 :   GNUNET_memcpy (&be,
    1028             :                  res,
    1029             :                  sizeof (be));
    1030           0 :   if (0x010000 != ntohl (be[1])) /* magic marker: EWV */
    1031             :   {
    1032           0 :     GNUNET_break (0);
    1033           0 :     return GNUNET_SYSERR;
    1034             :   }
    1035           0 :   res += sizeof (be);
    1036           0 :   len -= sizeof (be);
    1037           0 :   bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
    1038           0 :   bi->rc = 1;
    1039           0 :   bi->cipher = ntohl (be[0]);
    1040           0 :   switch (bi->cipher)
    1041             :   {
    1042           0 :   case GNUNET_CRYPTO_BSA_INVALID:
    1043           0 :     break;
    1044           0 :   case GNUNET_CRYPTO_BSA_RSA:
    1045           0 :     if (0 != len)
    1046             :     {
    1047           0 :       GNUNET_break (0);
    1048           0 :       GNUNET_free (bi);
    1049           0 :       return GNUNET_SYSERR;
    1050             :     }
    1051           0 :     alg_values->blinding_inputs = bi;
    1052           0 :     return GNUNET_OK;
    1053           0 :   case GNUNET_CRYPTO_BSA_CS:
    1054           0 :     if (sizeof (bi->details.cs_values) != len)
    1055             :     {
    1056           0 :       GNUNET_break (0);
    1057           0 :       GNUNET_free (bi);
    1058           0 :       return GNUNET_SYSERR;
    1059             :     }
    1060           0 :     GNUNET_memcpy (&bi->details.cs_values,
    1061             :                    res,
    1062             :                    len);
    1063           0 :     alg_values->blinding_inputs = bi;
    1064           0 :     return GNUNET_OK;
    1065             :   }
    1066           0 :   GNUNET_break (0);
    1067           0 :   GNUNET_free (bi);
    1068           0 :   return GNUNET_SYSERR;
    1069             : }
    1070             : 
    1071             : 
    1072             : struct GNUNET_PQ_ResultSpec
    1073           0 : TALER_PQ_result_spec_exchange_withdraw_values (
    1074             :   const char *name,
    1075             :   struct TALER_ExchangeBlindingValues *ewv)
    1076             : {
    1077           0 :   struct GNUNET_PQ_ResultSpec res = {
    1078             :     .conv = &extract_exchange_withdraw_values,
    1079             :     .dst = (void *) ewv,
    1080             :     .fname = name
    1081             :   };
    1082             : 
    1083           0 :   return res;
    1084             : }
    1085             : 
    1086             : 
    1087             : /**
    1088             :  * Closure for the array result specifications.  Contains type information
    1089             :  * for the generic parser extract_array_generic and out-pointers for the results.
    1090             :  */
    1091             : struct ArrayResultCls
    1092             : {
    1093             :   /**
    1094             :    * Oid of the expected type, must match the oid in the header of the PQResult struct
    1095             :    */
    1096             :   Oid oid;
    1097             : 
    1098             :   /**
    1099             :    * Target type
    1100             :    */
    1101             :   enum TALER_PQ_ArrayType typ;
    1102             : 
    1103             :   /**
    1104             :    * If not 0, defines the expected size of each entry
    1105             :    */
    1106             :   size_t same_size;
    1107             : 
    1108             :   /**
    1109             :    * Out-pointer to write the number of elements in the array
    1110             :    */
    1111             :   size_t *num;
    1112             : 
    1113             :   /**
    1114             :    * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0,
    1115             :    * allocate and put the array of @a num sizes here. NULL otherwise
    1116             :    */
    1117             :   size_t **sizes;
    1118             : 
    1119             :   /**
    1120             :    * DB_connection, needed for OID-lookup for composite types
    1121             :    */
    1122             :   const struct GNUNET_PQ_Context *db;
    1123             : 
    1124             :   /**
    1125             :    * Currency information for amount composites
    1126             :    */
    1127             :   char currency[TALER_CURRENCY_LEN];
    1128             : };
    1129             : 
    1130             : 
    1131             : /**
    1132             :  * Extract data from a Postgres database @a result as array of a specific type
    1133             :  * from row @a row.  The type information and optionally additional
    1134             :  * out-parameters are given in @a cls which is of type array_result_cls.
    1135             :  *
    1136             :  * @param cls closure of type array_result_cls
    1137             :  * @param result where to extract data from
    1138             :  * @param row row to extract data from
    1139             :  * @param fname name (or prefix) of the fields to extract from
    1140             :  * @param[in,out] dst_size where to store size of result, may be NULL
    1141             :  * @param[out] dst where to store the result
    1142             :  * @return
    1143             :  *   #GNUNET_YES if all results could be extracted
    1144             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    1145             :  */
    1146             : static enum GNUNET_GenericReturnValue
    1147          72 : extract_array_generic (
    1148             :   void *cls,
    1149             :   PGresult *result,
    1150             :   int row,
    1151             :   const char *fname,
    1152             :   size_t *dst_size,
    1153             :   void *dst)
    1154             : {
    1155          72 :   const struct ArrayResultCls *info = cls;
    1156             :   int data_sz;
    1157             :   char *data;
    1158          72 :   void *out = NULL;
    1159             :   struct GNUNET_PQ_ArrayHeader_P header;
    1160             :   int col_num;
    1161             : 
    1162          72 :   GNUNET_assert (NULL != dst);
    1163          72 :   *((void **) dst) = NULL;
    1164             : 
    1165             :   #define FAIL_IF(cond) \
    1166             :           do { \
    1167             :             if ((cond)) \
    1168             :             { \
    1169             :               GNUNET_break (! (cond)); \
    1170             :               goto FAIL; \
    1171             :             } \
    1172             :           } while (0)
    1173             : 
    1174          72 :   col_num = PQfnumber (result, fname);
    1175          72 :   FAIL_IF (0 > col_num);
    1176             : 
    1177          72 :   if (PQgetisnull (result, row, col_num))
    1178             :   {
    1179          23 :     return GNUNET_NO;
    1180             :   }
    1181             : 
    1182          49 :   data_sz = PQgetlength (result, row, col_num);
    1183          49 :   FAIL_IF (0 > data_sz);
    1184          49 :   FAIL_IF (sizeof(header) > (size_t) data_sz);
    1185             : 
    1186          49 :   data = PQgetvalue (result, row, col_num);
    1187          49 :   FAIL_IF (NULL == data);
    1188             : 
    1189             :   {
    1190          49 :     struct GNUNET_PQ_ArrayHeader_P *h =
    1191             :       (struct GNUNET_PQ_ArrayHeader_P *) data;
    1192             : 
    1193          49 :     header.ndim = ntohl (h->ndim);
    1194          49 :     header.has_null = ntohl (h->has_null);
    1195          49 :     header.oid = ntohl (h->oid);
    1196          49 :     header.dim = ntohl (h->dim);
    1197          49 :     header.lbound = ntohl (h->lbound);
    1198             : 
    1199          49 :     FAIL_IF (1 != header.ndim);
    1200          49 :     FAIL_IF (INT_MAX <= header.dim);
    1201          49 :     FAIL_IF (0 != header.has_null);
    1202          49 :     FAIL_IF (1 != header.lbound);
    1203          49 :     FAIL_IF (info->oid != header.oid);
    1204             :   }
    1205             : 
    1206          49 :   if (NULL != info->num)
    1207          49 :     *info->num = header.dim;
    1208             : 
    1209             :   {
    1210          49 :     char *in = data + sizeof(header);
    1211             : 
    1212          49 :     switch (info->typ)
    1213             :     {
    1214           1 :     case TALER_PQ_array_of_amount:
    1215             :       {
    1216             :         struct TALER_Amount *amounts;
    1217           1 :         if (NULL != dst_size)
    1218           1 :           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
    1219             : 
    1220           1 :         amounts = GNUNET_new_array (header.dim,
    1221             :                                     struct TALER_Amount);
    1222           1 :         *((void **) dst) = amounts;
    1223             : 
    1224           4 :         for (uint32_t i = 0; i < header.dim; i++)
    1225             :         {
    1226             :           struct TALER_PQ_AmountP ap;
    1227           3 :           struct TALER_Amount *amount = &amounts[i];
    1228             :           uint32_t val;
    1229             :           size_t sz;
    1230             : 
    1231           3 :           GNUNET_memcpy (&val,
    1232             :                          in,
    1233             :                          sizeof(val));
    1234           3 :           sz =  ntohl (val);
    1235           3 :           in += sizeof(val);
    1236             : 
    1237             :           /* total size for this array-entry */
    1238           3 :           FAIL_IF (sizeof(ap) != sz);
    1239             : 
    1240           3 :           GNUNET_memcpy (&ap,
    1241             :                          in,
    1242             :                          sz);
    1243           3 :           FAIL_IF (2 != ntohl (ap.cnt));
    1244             : 
    1245           3 :           amount->value = GNUNET_ntohll (ap.v);
    1246           3 :           amount->fraction = ntohl (ap.f);
    1247           3 :           GNUNET_memcpy (amount->currency,
    1248             :                          info->currency,
    1249             :                          TALER_CURRENCY_LEN);
    1250             : 
    1251           3 :           in += sizeof(struct TALER_PQ_AmountP);
    1252             :         }
    1253           1 :         return GNUNET_OK;
    1254             :       }
    1255           7 :     case TALER_PQ_array_of_denom_hash:
    1256           7 :       if (NULL != dst_size)
    1257           7 :         *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
    1258           7 :       out = GNUNET_new_array (header.dim,
    1259             :                               struct TALER_DenominationHashP);
    1260           7 :       *((void **) dst) = out;
    1261          16 :       for (uint32_t i = 0; i < header.dim; i++)
    1262             :       {
    1263             :         uint32_t val;
    1264             :         size_t sz;
    1265             : 
    1266           9 :         GNUNET_memcpy (&val,
    1267             :                        in,
    1268             :                        sizeof(val));
    1269           9 :         sz =  ntohl (val);
    1270           9 :         FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
    1271           9 :         in += sizeof(uint32_t);
    1272           9 :         *(struct TALER_DenominationHashP *) out =
    1273             :           *(struct TALER_DenominationHashP *) in;
    1274           9 :         in += sz;
    1275           9 :         out += sz;
    1276             :       }
    1277           7 :       return GNUNET_OK;
    1278             : 
    1279           1 :     case TALER_PQ_array_of_hash_code:
    1280           1 :       if (NULL != dst_size)
    1281           1 :         *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
    1282           1 :       out = GNUNET_new_array (header.dim,
    1283             :                               struct GNUNET_HashCode);
    1284           1 :       *((void **) dst) = out;
    1285           3 :       for (uint32_t i = 0; i < header.dim; i++)
    1286             :       {
    1287             :         uint32_t val;
    1288             :         size_t sz;
    1289             : 
    1290           2 :         GNUNET_memcpy (&val,
    1291             :                        in,
    1292             :                        sizeof(val));
    1293           2 :         sz =  ntohl (val);
    1294           2 :         FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
    1295           2 :         in += sizeof(uint32_t);
    1296           2 :         *(struct GNUNET_HashCode *) out =
    1297             :           *(struct GNUNET_HashCode *) in;
    1298           2 :         in += sz;
    1299           2 :         out += sz;
    1300             :       }
    1301           1 :       return GNUNET_OK;
    1302             : 
    1303           0 :     case TALER_PQ_array_of_blinded_coin_hash:
    1304           0 :       if (NULL != dst_size)
    1305           0 :         *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
    1306           0 :       out = GNUNET_new_array (header.dim,
    1307             :                               struct TALER_BlindedCoinHashP);
    1308           0 :       *((void **) dst) = out;
    1309           0 :       for (uint32_t i = 0; i < header.dim; i++)
    1310             :       {
    1311             :         uint32_t val;
    1312             :         size_t sz;
    1313             : 
    1314           0 :         GNUNET_memcpy (&val,
    1315             :                        in,
    1316             :                        sizeof(val));
    1317           0 :         sz =  ntohl (val);
    1318           0 :         FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
    1319           0 :         in += sizeof(uint32_t);
    1320           0 :         *(struct TALER_BlindedCoinHashP *) out =
    1321             :           *(struct TALER_BlindedCoinHashP *) in;
    1322           0 :         in += sz;
    1323           0 :         out += sz;
    1324             :       }
    1325           0 :       return GNUNET_OK;
    1326             : 
    1327           9 :     case TALER_PQ_array_of_cs_r_pub:
    1328           9 :       if (NULL != dst_size)
    1329           9 :         *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
    1330           9 :       out = GNUNET_new_array (header.dim,
    1331             :                               struct GNUNET_CRYPTO_CSPublicRPairP);
    1332           9 :       *((void **) dst) = out;
    1333          45 :       for (uint32_t i = 0; i < header.dim; i++)
    1334             :       {
    1335             :         uint32_t val;
    1336             :         size_t sz;
    1337             : 
    1338          36 :         GNUNET_memcpy (&val,
    1339             :                        in,
    1340             :                        sizeof(val));
    1341          36 :         sz =  ntohl (val);
    1342          36 :         FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
    1343          36 :         in += sizeof(uint32_t);
    1344          36 :         *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
    1345             :           *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
    1346          36 :         in += sz;
    1347          36 :         out += sz;
    1348             :       }
    1349           9 :       return GNUNET_OK;
    1350             : 
    1351          31 :     case TALER_PQ_array_of_blinded_denom_sig:
    1352             :       {
    1353             :         struct TALER_BlindedDenominationSignature *denom_sigs;
    1354          31 :         if (0 == header.dim)
    1355             :         {
    1356           0 :           if (NULL != dst_size)
    1357           0 :             *dst_size = 0;
    1358           0 :           break;
    1359             :         }
    1360             : 
    1361          31 :         denom_sigs = GNUNET_new_array (header.dim,
    1362             :                                        struct TALER_BlindedDenominationSignature);
    1363          31 :         *((void **) dst) = denom_sigs;
    1364             : 
    1365             :         /* copy data */
    1366         252 :         for (uint32_t i = 0; i < header.dim; i++)
    1367             :         {
    1368         221 :           struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
    1369             :           struct GNUNET_CRYPTO_BlindedSignature *bs;
    1370             :           uint32_t be[2];
    1371             :           uint32_t val;
    1372             :           size_t sz;
    1373             : 
    1374         221 :           GNUNET_memcpy (&val,
    1375             :                          in,
    1376             :                          sizeof(val));
    1377         221 :           sz = ntohl (val);
    1378         221 :           FAIL_IF (sizeof(be) > sz);
    1379             : 
    1380         221 :           in += sizeof(val);
    1381         221 :           GNUNET_memcpy (&be,
    1382             :                          in,
    1383             :                          sizeof(be));
    1384         221 :           FAIL_IF (0x01 != ntohl (be[1]));  /* magic marker: blinded */
    1385             : 
    1386         221 :           in += sizeof(be);
    1387         221 :           sz -= sizeof(be);
    1388         221 :           bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    1389         221 :           bs->cipher = ntohl (be[0]);
    1390         221 :           bs->rc = 1;
    1391         221 :           switch (bs->cipher)
    1392             :           {
    1393         190 :           case GNUNET_CRYPTO_BSA_RSA:
    1394             :             bs->details.blinded_rsa_signature
    1395         190 :               = GNUNET_CRYPTO_rsa_signature_decode (in,
    1396             :                                                     sz);
    1397         190 :             if (NULL == bs->details.blinded_rsa_signature)
    1398             :             {
    1399           0 :               GNUNET_free (bs);
    1400           0 :               FAIL_IF (true);
    1401             :             }
    1402         190 :             break;
    1403          31 :           case GNUNET_CRYPTO_BSA_CS:
    1404          31 :             if (sizeof(bs->details.blinded_cs_answer) != sz)
    1405             :             {
    1406           0 :               GNUNET_free (bs);
    1407           0 :               FAIL_IF (true);
    1408             :             }
    1409          31 :             GNUNET_memcpy (&bs->details.blinded_cs_answer,
    1410             :                            in,
    1411             :                            sz);
    1412          31 :             break;
    1413           0 :           default:
    1414           0 :             GNUNET_free (bs);
    1415           0 :             FAIL_IF (true);
    1416             :           }
    1417         221 :           denom_sig->blinded_sig = bs;
    1418         221 :           in += sz;
    1419             :         }
    1420          31 :         return GNUNET_OK;
    1421             :       }
    1422           0 :     default:
    1423           0 :       FAIL_IF (true);
    1424             :     }
    1425             :   }
    1426           0 : FAIL:
    1427           0 :   GNUNET_free (*(void **) dst);
    1428           0 :   return GNUNET_SYSERR;
    1429             : #undef FAIL_IF
    1430             : }
    1431             : 
    1432             : 
    1433             : /**
    1434             :  * Cleanup of the data and closure of an array spec.
    1435             :  */
    1436             : static void
    1437         112 : array_cleanup (void *cls,
    1438             :                void *rd)
    1439             : {
    1440         112 :   struct ArrayResultCls *info = cls;
    1441         112 :   void **dst = rd;
    1442             : 
    1443         112 :   if ( (0 == info->same_size) &&
    1444         112 :        (NULL != info->sizes) )
    1445           0 :     GNUNET_free (*(info->sizes));
    1446             : 
    1447             :   /* Clean up signatures, if applicable */
    1448         112 :   if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
    1449          51 :       (NULL != *dst))
    1450             :   {
    1451           6 :     struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
    1452             : 
    1453           6 :     GNUNET_assert (NULL != info->num);
    1454          76 :     for (size_t i = 0; i < *info->num; i++)
    1455          70 :       GNUNET_free (denom_sigs[i].blinded_sig);
    1456             :   }
    1457         112 :   GNUNET_free (info);
    1458         112 :   GNUNET_free (*dst);
    1459         112 :   *dst = NULL;
    1460         112 : }
    1461             : 
    1462             : 
    1463             : struct GNUNET_PQ_ResultSpec
    1464          51 : TALER_PQ_result_spec_array_blinded_denom_sig (
    1465             :   struct GNUNET_PQ_Context *db,
    1466             :   const char *name,
    1467             :   size_t *num,
    1468             :   struct TALER_BlindedDenominationSignature **denom_sigs)
    1469             : {
    1470          51 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1471             : 
    1472          51 :   info->num = num;
    1473          51 :   info->typ = TALER_PQ_array_of_blinded_denom_sig;
    1474          51 :   GNUNET_assert (GNUNET_OK ==
    1475             :                  GNUNET_PQ_get_oid_by_name (db,
    1476             :                                             "bytea",
    1477             :                                             &info->oid));
    1478             :   {
    1479          51 :     struct GNUNET_PQ_ResultSpec res = {
    1480             :       .conv = extract_array_generic,
    1481             :       .cleaner = &array_cleanup,
    1482             :       .dst = (void *) denom_sigs,
    1483             :       .fname = name,
    1484             :       .cls = info
    1485             :     };
    1486             : 
    1487          51 :     return res;
    1488             :   }
    1489             : }
    1490             : 
    1491             : 
    1492             : struct GNUNET_PQ_ResultSpec
    1493           0 : TALER_PQ_result_spec_array_blinded_coin_hash (
    1494             :   struct GNUNET_PQ_Context *db,
    1495             :   const char *name,
    1496             :   size_t *num,
    1497             :   struct TALER_BlindedCoinHashP **h_coin_evs)
    1498             : {
    1499           0 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1500             : 
    1501           0 :   info->num = num;
    1502           0 :   info->typ = TALER_PQ_array_of_blinded_coin_hash;
    1503           0 :   GNUNET_assert (GNUNET_OK ==
    1504             :                  GNUNET_PQ_get_oid_by_name (db,
    1505             :                                             "bytea",
    1506             :                                             &info->oid));
    1507             :   {
    1508           0 :     struct GNUNET_PQ_ResultSpec res = {
    1509             :       .conv = extract_array_generic,
    1510             :       .cleaner = &array_cleanup,
    1511             :       .dst = (void *) h_coin_evs,
    1512             :       .fname = name,
    1513             :       .cls = info
    1514             :     };
    1515             : 
    1516           0 :     return res;
    1517             :   }
    1518             : }
    1519             : 
    1520             : 
    1521             : struct GNUNET_PQ_ResultSpec
    1522           7 : TALER_PQ_result_spec_array_denom_hash (
    1523             :   struct GNUNET_PQ_Context *db,
    1524             :   const char *name,
    1525             :   size_t *num,
    1526             :   struct TALER_DenominationHashP **denom_hs)
    1527             : {
    1528           7 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1529             : 
    1530           7 :   info->num = num;
    1531           7 :   info->typ = TALER_PQ_array_of_denom_hash;
    1532           7 :   GNUNET_assert (GNUNET_OK ==
    1533             :                  GNUNET_PQ_get_oid_by_name (db,
    1534             :                                             "bytea",
    1535             :                                             &info->oid));
    1536             :   {
    1537           7 :     struct GNUNET_PQ_ResultSpec res = {
    1538             :       .conv = extract_array_generic,
    1539             :       .cleaner = &array_cleanup,
    1540             :       .dst = (void *) denom_hs,
    1541             :       .fname = name,
    1542             :       .cls = info
    1543             :     };
    1544             : 
    1545           7 :     return res;
    1546             :   }
    1547             : }
    1548             : 
    1549             : 
    1550             : struct GNUNET_PQ_ResultSpec
    1551           1 : TALER_PQ_result_spec_array_amount (
    1552             :   struct GNUNET_PQ_Context *db,
    1553             :   const char *name,
    1554             :   const char *currency,
    1555             :   size_t *num,
    1556             :   struct TALER_Amount **amounts)
    1557             : {
    1558           1 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1559             : 
    1560           1 :   info->num = num;
    1561           1 :   info->typ = TALER_PQ_array_of_amount;
    1562           1 :   info->db = db;
    1563           1 :   GNUNET_assert (GNUNET_OK ==
    1564             :                  GNUNET_PQ_get_oid_by_name (db,
    1565             :                                             "taler_amount",
    1566             :                                             &info->oid));
    1567             : 
    1568             :   {
    1569           1 :     size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
    1570             :                               strlen (currency));
    1571           1 :     GNUNET_memcpy (&info->currency,
    1572             :                    currency,
    1573             :                    clen);
    1574             :   }
    1575             :   {
    1576           1 :     struct GNUNET_PQ_ResultSpec res = {
    1577             :       .conv = extract_array_generic,
    1578             :       .cleaner = &array_cleanup,
    1579             :       .dst = (void *) amounts,
    1580             :       .fname = name,
    1581             :       .cls = info,
    1582             :     };
    1583             : 
    1584           1 :     return res;
    1585             :   }
    1586             : }
    1587             : 
    1588             : 
    1589             : struct GNUNET_PQ_ResultSpec
    1590           1 : TALER_PQ_result_spec_array_hash_code (
    1591             :   struct GNUNET_PQ_Context *db,
    1592             :   const char *name,
    1593             :   size_t *num,
    1594             :   struct GNUNET_HashCode **hashes)
    1595             : {
    1596           1 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1597             : 
    1598           1 :   info->num = num;
    1599           1 :   info->typ = TALER_PQ_array_of_hash_code;
    1600           1 :   info->db = db;
    1601           1 :   GNUNET_assert (GNUNET_OK ==
    1602             :                  GNUNET_PQ_get_oid_by_name (db,
    1603             :                                             "gnunet_hashcode",
    1604             :                                             &info->oid));
    1605             :   {
    1606           1 :     struct GNUNET_PQ_ResultSpec res = {
    1607             :       .conv = extract_array_generic,
    1608             :       .cleaner = &array_cleanup,
    1609             :       .dst = (void *) hashes,
    1610             :       .fname = name,
    1611             :       .cls = info,
    1612             :     };
    1613             : 
    1614           1 :     return res;
    1615             :   }
    1616             : }
    1617             : 
    1618             : 
    1619             : struct GNUNET_PQ_ResultSpec
    1620          52 : TALER_PQ_result_spec_array_cs_r_pub (
    1621             :   struct GNUNET_PQ_Context *db,
    1622             :   const char *name,
    1623             :   size_t *num,
    1624             :   struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
    1625             : {
    1626          52 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1627             : 
    1628          52 :   info->num = num;
    1629          52 :   info->typ = TALER_PQ_array_of_cs_r_pub;
    1630          52 :   GNUNET_assert (GNUNET_OK ==
    1631             :                  GNUNET_PQ_get_oid_by_name (db,
    1632             :                                             "bytea",
    1633             :                                             &info->oid));
    1634             :   {
    1635          52 :     struct GNUNET_PQ_ResultSpec res = {
    1636             :       .conv = extract_array_generic,
    1637             :       .cleaner = &array_cleanup,
    1638             :       .dst = (void *) cs_r_pubs,
    1639             :       .fname = name,
    1640             :       .cls = info
    1641             :     };
    1642             : 
    1643          52 :     return res;
    1644             :   }
    1645             : }
    1646             : 
    1647             : 
    1648             : /* end of pq_result_helper.c */

Generated by: LCOV version 1.16