LCOV - code coverage report
Current view: top level - pq - pq_result_helper.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 56.1 % 601 337
Test Date: 2026-04-14 15:39:31 Functions: 66.7 % 30 20

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2026 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              :  * @author Özgür Kesim
      21              :  */
      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            1 : 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            1 :   struct TALER_Amount *r_amount = dst;
      51              :   int col;
      52              : 
      53              :   (void) cls;
      54            1 :   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            1 :   memset (r_amount,
      62              :           0,
      63              :           sizeof (struct TALER_Amount));
      64            1 :   col = PQfnumber (result,
      65              :                    fname);
      66            1 :   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            1 :   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            1 :     size = PQgetlength (result,
      87              :                         row,
      88              :                         col);
      89            1 :     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            1 :     in = PQgetvalue (result,
     102              :                      row,
     103              :                      col);
     104            1 :     memset (&ap.c,
     105              :             0,
     106              :             TALER_CURRENCY_LEN);
     107            1 :     memcpy (&ap,
     108              :             in,
     109              :             size);
     110            1 :     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            1 :     r_amount->value = GNUNET_ntohll (ap.v);
     120            1 :     r_amount->fraction = ntohl (ap.f);
     121            1 :     memcpy (r_amount->currency,
     122              :             ap.c,
     123              :             TALER_CURRENCY_LEN);
     124            1 :     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            1 :   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            1 :   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            1 :   return GNUNET_OK;
     152              : }
     153              : 
     154              : 
     155              : struct GNUNET_PQ_ResultSpec
     156            1 : TALER_PQ_result_spec_amount_with_currency (const char *name,
     157              :                                            struct TALER_Amount *amount)
     158              : {
     159            1 :   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            1 :   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         6251 : 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         6251 :   struct TALER_Amount *r_amount = dst;
     193         6251 :   const char *currency = cls;
     194              :   int col;
     195              :   size_t len;
     196              : 
     197         6251 :   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         6251 :   memset (r_amount,
     205              :           0,
     206              :           sizeof (struct TALER_Amount));
     207         6251 :   col = PQfnumber (result,
     208              :                    fname);
     209         6251 :   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         6251 :   if (PQgetisnull (result,
     217              :                    row,
     218              :                    col))
     219              :   {
     220            4 :     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         6247 :     size = PQgetlength (result,
     230              :                         row,
     231              :                         col);
     232         6247 :     in = PQgetvalue (result,
     233              :                      row,
     234              :                      col);
     235         6247 :     if (sizeof(struct TALER_PQ_AmountNullP) == size)
     236              :     {
     237              :       struct TALER_PQ_AmountNullP apn;
     238              : 
     239          173 :       memcpy (&apn,
     240              :               in,
     241              :               size);
     242          173 :       if ( (2 == ntohl (apn.cnt)) &&
     243          173 :            (-1 == (int32_t) ntohl (apn.sz_v)) &&
     244          173 :            (-1 == (int32_t) ntohl (apn.sz_f)) )
     245              :       {
     246              :         /* is NULL! */
     247          173 :         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         6074 :     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         6074 :     memcpy (&ap,
     267              :             in,
     268              :             size);
     269         6074 :     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         6074 :     r_amount->value = GNUNET_ntohll (ap.v);
     279         6074 :     r_amount->fraction = ntohl (ap.f);
     280              :   }
     281              : 
     282         6074 :   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         6074 :   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         6074 :   len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
     298              :                     strlen (currency));
     299              : 
     300         6074 :   GNUNET_memcpy (r_amount->currency,
     301              :                  currency,
     302              :                  len);
     303         6074 :   return GNUNET_OK;
     304              : }
     305              : 
     306              : 
     307              : struct GNUNET_PQ_ResultSpec
     308         8868 : TALER_PQ_result_spec_amount (const char *name,
     309              :                              const char *currency,
     310              :                              struct TALER_Amount *amount)
     311              : {
     312         8868 :   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         8868 :   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          263 : extract_json (void *cls,
     340              :               PGresult *result,
     341              :               int row,
     342              :               const char *fname,
     343              :               size_t *dst_size,
     344              :               void *dst)
     345              : {
     346          263 :   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          263 :   fnum = PQfnumber (result,
     355              :                     fname);
     356          263 :   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          263 :   if (PQgetisnull (result,
     364              :                    row,
     365              :                    fnum))
     366          144 :     return GNUNET_NO;
     367          119 :   slen = PQgetlength (result,
     368              :                       row,
     369              :                       fnum);
     370          119 :   res = (const char *) PQgetvalue (result,
     371              :                                    row,
     372              :                                    fnum);
     373          119 :   *j_dst = json_loadb (res,
     374              :                        slen,
     375              :                        JSON_REJECT_DUPLICATES,
     376              :                        &json_error);
     377          119 :   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          119 :   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           56 : clean_json (void *cls,
     399              :             void *rd)
     400              : {
     401           56 :   json_t **dst = rd;
     402              : 
     403              :   (void) cls;
     404           56 :   if (NULL != *dst)
     405              :   {
     406           51 :     json_decref (*dst);
     407           51 :     *dst = NULL;
     408              :   }
     409           56 : }
     410              : 
     411              : 
     412              : struct GNUNET_PQ_ResultSpec
     413          275 : TALER_PQ_result_spec_json (const char *name,
     414              :                            json_t **jp)
     415              : {
     416          275 :   struct GNUNET_PQ_ResultSpec res = {
     417              :     .conv = &extract_json,
     418              :     .cleaner = &clean_json,
     419              :     .dst = (void *) jp,
     420              :     .fname  = name
     421              :   };
     422              : 
     423          275 :   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          818 : 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          818 :   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          818 :   fnum = PQfnumber (result,
     458              :                     fname);
     459          818 :   if (fnum < 0)
     460              :   {
     461            0 :     GNUNET_break (0);
     462            0 :     return GNUNET_SYSERR;
     463              :   }
     464          818 :   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          818 :   len = PQgetlength (result,
     472              :                      row,
     473              :                      fnum);
     474          818 :   res = PQgetvalue (result,
     475              :                     row,
     476              :                     fnum);
     477          818 :   if (len < sizeof (be))
     478              :   {
     479            0 :     GNUNET_break (0);
     480            0 :     return GNUNET_SYSERR;
     481              :   }
     482          818 :   GNUNET_memcpy (be,
     483              :                  res,
     484              :                  sizeof (be));
     485          818 :   res += sizeof (be);
     486          818 :   len -= sizeof (be);
     487          818 :   bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
     488          818 :   bpk->cipher = ntohl (be[0]);
     489          818 :   bpk->rc = 1;
     490          818 :   pk->age_mask.bits = ntohl (be[1]);
     491          818 :   switch (bpk->cipher)
     492              :   {
     493            0 :   case GNUNET_CRYPTO_BSA_INVALID:
     494            0 :     break;
     495          433 :   case GNUNET_CRYPTO_BSA_RSA:
     496              :     bpk->details.rsa_public_key
     497          433 :       = GNUNET_CRYPTO_rsa_public_key_decode (res,
     498              :                                              len);
     499          433 :     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          433 :     pk->bsign_pub_key = bpk;
     506          433 :     GNUNET_CRYPTO_hash (res,
     507              :                         len,
     508              :                         &bpk->pub_key_hash);
     509          433 :     return GNUNET_OK;
     510          385 :   case GNUNET_CRYPTO_BSA_CS:
     511          385 :     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          385 :     GNUNET_memcpy (&bpk->details.cs_public_key,
     518              :                    res,
     519              :                    len);
     520          385 :     pk->bsign_pub_key = bpk;
     521          385 :     GNUNET_CRYPTO_hash (res,
     522              :                         len,
     523              :                         &bpk->pub_key_hash);
     524          385 :     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          656 : clean_denom_pub (void *cls,
     541              :                  void *rd)
     542              : {
     543          656 :   struct TALER_DenominationPublicKey *denom_pub = rd;
     544              : 
     545              :   (void) cls;
     546          656 :   TALER_denom_pub_free (denom_pub);
     547          656 : }
     548              : 
     549              : 
     550              : struct GNUNET_PQ_ResultSpec
     551          818 : TALER_PQ_result_spec_denom_pub (const char *name,
     552              :                                 struct TALER_DenominationPublicKey *denom_pub)
     553              : {
     554          818 :   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          818 :   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            2 : 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            2 :   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            2 :   fnum = PQfnumber (result,
     596              :                     fname);
     597            2 :   if (fnum < 0)
     598              :   {
     599            0 :     GNUNET_break (0);
     600            0 :     return GNUNET_SYSERR;
     601              :   }
     602            2 :   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            2 :   len = PQgetlength (result,
     610              :                      row,
     611              :                      fnum);
     612            2 :   res = PQgetvalue (result,
     613              :                     row,
     614              :                     fnum);
     615            2 :   if (len < sizeof (be))
     616              :   {
     617            0 :     GNUNET_break (0);
     618            0 :     return GNUNET_SYSERR;
     619              :   }
     620            2 :   GNUNET_memcpy (&be,
     621              :                  res,
     622              :                  sizeof (be));
     623            2 :   if (0x00 != ntohl (be[1]))
     624              :   {
     625            0 :     GNUNET_break (0);
     626            0 :     return GNUNET_SYSERR;
     627              :   }
     628            2 :   res += sizeof (be);
     629            2 :   len -= sizeof (be);
     630            2 :   ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
     631            2 :   ubs->rc = 1;
     632            2 :   ubs->cipher = ntohl (be[0]);
     633            2 :   switch (ubs->cipher)
     634              :   {
     635            0 :   case GNUNET_CRYPTO_BSA_INVALID:
     636            0 :     break;
     637            2 :   case GNUNET_CRYPTO_BSA_RSA:
     638              :     ubs->details.rsa_signature
     639            2 :       = GNUNET_CRYPTO_rsa_signature_decode (res,
     640              :                                             len);
     641            2 :     if (NULL == ubs->details.rsa_signature)
     642              :     {
     643            0 :       GNUNET_break (0);
     644            0 :       GNUNET_free (ubs);
     645            0 :       return GNUNET_SYSERR;
     646              :     }
     647            2 :     sig->unblinded_sig = ubs;
     648            2 :     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            0 : clean_denom_sig (void *cls,
     677              :                  void *rd)
     678              : {
     679            0 :   struct TALER_DenominationSignature *denom_sig = rd;
     680              : 
     681              :   (void) cls;
     682            0 :   TALER_denom_sig_free (denom_sig);
     683            0 : }
     684              : 
     685              : 
     686              : struct GNUNET_PQ_ResultSpec
     687            2 : TALER_PQ_result_spec_denom_sig (const char *name,
     688              :                                 struct TALER_DenominationSignature *denom_sig)
     689              : {
     690            2 :   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            2 :   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           47 : 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           47 :   const struct ArrayResultCls *info = cls;
    1156              :   int data_sz;
    1157              :   char *data;
    1158           47 :   void *out = NULL;
    1159              :   struct GNUNET_PQ_ArrayHeader_P header;
    1160              :   int col_num;
    1161              : 
    1162           47 :   GNUNET_assert (NULL != dst);
    1163           47 :   *((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           47 :   col_num = PQfnumber (result, fname);
    1175           47 :   FAIL_IF (0 > col_num);
    1176              : 
    1177           47 :   if (PQgetisnull (result, row, col_num))
    1178              :   {
    1179            9 :     return GNUNET_NO;
    1180              :   }
    1181              : 
    1182           38 :   data_sz = PQgetlength (result, row, col_num);
    1183           38 :   FAIL_IF (0 > data_sz);
    1184              : 
    1185              :   /* Report if this field is empty */
    1186           38 :   if (0 == (size_t) data_sz)
    1187            0 :     return GNUNET_NO;
    1188              : 
    1189           38 :   data = PQgetvalue (result, row, col_num);
    1190              : 
    1191           38 :   if (sizeof(header) > (size_t) data_sz)
    1192              :   {
    1193              :     uint32_t ndim;
    1194              : 
    1195              :     /* data_sz is shorter than header if the
    1196              :        array length is 0, in which case ndim is 0! */
    1197            2 :     FAIL_IF (sizeof(uint32_t) > (size_t) data_sz);
    1198            2 :     memcpy (&ndim,
    1199              :             data,
    1200              :             sizeof (ndim));
    1201            2 :     FAIL_IF (0 != ndim);
    1202            2 :     *info->num = 0;
    1203            2 :     return GNUNET_OK;
    1204              :   }
    1205           36 :   FAIL_IF (sizeof(header) > (size_t) data_sz);
    1206           36 :   FAIL_IF (NULL == data);
    1207              : 
    1208              :   {
    1209           36 :     struct GNUNET_PQ_ArrayHeader_P *h =
    1210              :       (struct GNUNET_PQ_ArrayHeader_P *) data;
    1211              : 
    1212           36 :     header.ndim = ntohl (h->ndim);
    1213           36 :     header.has_null = ntohl (h->has_null);
    1214           36 :     header.oid = ntohl (h->oid);
    1215           36 :     header.dim = ntohl (h->dim);
    1216           36 :     header.lbound = ntohl (h->lbound);
    1217              : 
    1218           36 :     FAIL_IF (1 != header.ndim);
    1219           36 :     FAIL_IF (INT_MAX <= header.dim);
    1220           36 :     FAIL_IF (0 != header.has_null);
    1221           36 :     FAIL_IF (1 != header.lbound);
    1222           36 :     FAIL_IF (info->oid != header.oid);
    1223              :   }
    1224              : 
    1225           36 :   if (NULL != info->num)
    1226           36 :     *info->num = header.dim;
    1227              : 
    1228              :   {
    1229           36 :     char *in = data + sizeof(header);
    1230              : 
    1231           36 :     switch (info->typ)
    1232              :     {
    1233            1 :     case TALER_PQ_array_of_amount:
    1234              :       {
    1235              :         struct TALER_Amount *amounts;
    1236            1 :         if (NULL != dst_size)
    1237            1 :           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
    1238              : 
    1239            1 :         amounts = GNUNET_new_array (header.dim,
    1240              :                                     struct TALER_Amount);
    1241            1 :         *((void **) dst) = amounts;
    1242              : 
    1243            4 :         for (uint32_t i = 0; i < header.dim; i++)
    1244              :         {
    1245              :           struct TALER_PQ_AmountP ap;
    1246            3 :           struct TALER_Amount *amount = &amounts[i];
    1247              :           uint32_t val;
    1248              :           size_t sz;
    1249              : 
    1250            3 :           GNUNET_memcpy (&val,
    1251              :                          in,
    1252              :                          sizeof(val));
    1253            3 :           sz =  ntohl (val);
    1254            3 :           in += sizeof(val);
    1255              : 
    1256              :           /* total size for this array-entry */
    1257            3 :           FAIL_IF (sizeof(ap) != sz);
    1258              : 
    1259            3 :           GNUNET_memcpy (&ap,
    1260              :                          in,
    1261              :                          sz);
    1262            3 :           FAIL_IF (2 != ntohl (ap.cnt));
    1263              : 
    1264            3 :           amount->value = GNUNET_ntohll (ap.v);
    1265            3 :           amount->fraction = ntohl (ap.f);
    1266            3 :           GNUNET_memcpy (amount->currency,
    1267              :                          info->currency,
    1268              :                          TALER_CURRENCY_LEN);
    1269              : 
    1270            3 :           in += sizeof(struct TALER_PQ_AmountP);
    1271              :         }
    1272            1 :         return GNUNET_OK;
    1273              :       }
    1274            1 :     case TALER_PQ_array_of_amount_currency:
    1275              :       {
    1276              :         struct TALER_Amount *amounts;
    1277            1 :         if (NULL != dst_size)
    1278            1 :           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
    1279              : 
    1280            1 :         amounts = GNUNET_new_array (header.dim,
    1281              :                                     struct TALER_Amount);
    1282            1 :         *((void **) dst) = amounts;
    1283              : 
    1284            3 :         for (uint32_t i = 0; i < header.dim; i++)
    1285              :         {
    1286              :           struct TALER_PQ_AmountCurrencyP ap;
    1287            2 :           struct TALER_Amount *amount = &amounts[i];
    1288              :           uint32_t val;
    1289              :           size_t sz;
    1290              : 
    1291            2 :           GNUNET_memcpy (&val,
    1292              :                          in,
    1293              :                          sizeof(val));
    1294            2 :           sz =  ntohl (val);
    1295            2 :           in += sizeof(val);
    1296              : 
    1297            2 :           FAIL_IF ( (sz >= sizeof(ap)) ||
    1298              :                     (sz <= sizeof(ap) - TALER_CURRENCY_LEN) );
    1299              : 
    1300            2 :           memset (&ap,
    1301              :                   0,
    1302              :                   sizeof(ap));
    1303            2 :           GNUNET_memcpy (&ap,
    1304              :                          in,
    1305              :                          sz);
    1306            2 :           FAIL_IF (3 != ntohl (ap.cnt));
    1307              : 
    1308            2 :           amount->value = GNUNET_ntohll (ap.v);
    1309            2 :           amount->fraction = ntohl (ap.f);
    1310            2 :           GNUNET_memcpy (amount->currency,
    1311              :                          ap.c,
    1312              :                          TALER_CURRENCY_LEN);
    1313              : 
    1314            2 :           FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]);
    1315            2 :           FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
    1316            2 :           FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
    1317              : 
    1318            2 :           in += sz;
    1319              :         }
    1320            1 :         return GNUNET_OK;
    1321              :       }
    1322            7 :     case TALER_PQ_array_of_denom_hash:
    1323            7 :       if (NULL != dst_size)
    1324            7 :         *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
    1325            7 :       out = GNUNET_new_array (header.dim,
    1326              :                               struct TALER_DenominationHashP);
    1327            7 :       *((void **) dst) = out;
    1328           16 :       for (uint32_t i = 0; i < header.dim; i++)
    1329              :       {
    1330              :         uint32_t val;
    1331              :         size_t sz;
    1332              : 
    1333            9 :         GNUNET_memcpy (&val,
    1334              :                        in,
    1335              :                        sizeof(val));
    1336            9 :         sz =  ntohl (val);
    1337            9 :         FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
    1338            9 :         in += sizeof(uint32_t);
    1339            9 :         *(struct TALER_DenominationHashP *) out =
    1340              :           *(struct TALER_DenominationHashP *) in;
    1341            9 :         in += sz;
    1342            9 :         out += sz;
    1343              :       }
    1344            7 :       return GNUNET_OK;
    1345              : 
    1346            1 :     case TALER_PQ_array_of_hash_code:
    1347            1 :       if (NULL != dst_size)
    1348            1 :         *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
    1349            1 :       out = GNUNET_new_array (header.dim,
    1350              :                               struct GNUNET_HashCode);
    1351            1 :       *((void **) dst) = out;
    1352            3 :       for (uint32_t i = 0; i < header.dim; i++)
    1353              :       {
    1354              :         uint32_t val;
    1355              :         size_t sz;
    1356              : 
    1357            2 :         GNUNET_memcpy (&val,
    1358              :                        in,
    1359              :                        sizeof(val));
    1360            2 :         sz =  ntohl (val);
    1361            2 :         FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
    1362            2 :         in += sizeof(uint32_t);
    1363            2 :         *(struct GNUNET_HashCode *) out =
    1364              :           *(struct GNUNET_HashCode *) in;
    1365            2 :         in += sz;
    1366            2 :         out += sz;
    1367              :       }
    1368            1 :       return GNUNET_OK;
    1369              : 
    1370            0 :     case TALER_PQ_array_of_blinded_coin_hash:
    1371            0 :       if (NULL != dst_size)
    1372            0 :         *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
    1373            0 :       out = GNUNET_new_array (header.dim,
    1374              :                               struct TALER_BlindedCoinHashP);
    1375            0 :       *((void **) dst) = out;
    1376            0 :       for (uint32_t i = 0; i < header.dim; i++)
    1377              :       {
    1378              :         uint32_t val;
    1379              :         size_t sz;
    1380              : 
    1381            0 :         GNUNET_memcpy (&val,
    1382              :                        in,
    1383              :                        sizeof(val));
    1384            0 :         sz =  ntohl (val);
    1385            0 :         FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
    1386            0 :         in += sizeof(uint32_t);
    1387            0 :         *(struct TALER_BlindedCoinHashP *) out =
    1388              :           *(struct TALER_BlindedCoinHashP *) in;
    1389            0 :         in += sz;
    1390            0 :         out += sz;
    1391              :       }
    1392            0 :       return GNUNET_OK;
    1393              : 
    1394            9 :     case TALER_PQ_array_of_cs_r_pub:
    1395            9 :       if (NULL != dst_size)
    1396            9 :         *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
    1397            9 :       out = GNUNET_new_array (header.dim,
    1398              :                               struct GNUNET_CRYPTO_CSPublicRPairP);
    1399            9 :       *((void **) dst) = out;
    1400           45 :       for (uint32_t i = 0; i < header.dim; i++)
    1401              :       {
    1402              :         uint32_t val;
    1403              :         size_t sz;
    1404              : 
    1405           36 :         GNUNET_memcpy (&val,
    1406              :                        in,
    1407              :                        sizeof(val));
    1408           36 :         sz =  ntohl (val);
    1409           36 :         FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
    1410           36 :         in += sizeof(uint32_t);
    1411           36 :         *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
    1412              :           *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
    1413           36 :         in += sz;
    1414           36 :         out += sz;
    1415              :       }
    1416            9 :       return GNUNET_OK;
    1417              : 
    1418           17 :     case TALER_PQ_array_of_blinded_denom_sig:
    1419              :       {
    1420              :         struct TALER_BlindedDenominationSignature *denom_sigs;
    1421           17 :         if (0 == header.dim)
    1422              :         {
    1423            0 :           if (NULL != dst_size)
    1424            0 :             *dst_size = 0;
    1425            0 :           break;
    1426              :         }
    1427              : 
    1428           17 :         denom_sigs = GNUNET_new_array (header.dim,
    1429              :                                        struct TALER_BlindedDenominationSignature);
    1430           17 :         *((void **) dst) = denom_sigs;
    1431              : 
    1432              :         /* copy data */
    1433           80 :         for (uint32_t i = 0; i < header.dim; i++)
    1434              :         {
    1435           63 :           struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
    1436              :           struct GNUNET_CRYPTO_BlindedSignature *bs;
    1437              :           uint32_t be[2];
    1438              :           uint32_t val;
    1439              :           size_t sz;
    1440              : 
    1441           63 :           GNUNET_memcpy (&val,
    1442              :                          in,
    1443              :                          sizeof(val));
    1444           63 :           sz = ntohl (val);
    1445           63 :           FAIL_IF (sizeof(be) > sz);
    1446              : 
    1447           63 :           in += sizeof(val);
    1448           63 :           GNUNET_memcpy (&be,
    1449              :                          in,
    1450              :                          sizeof(be));
    1451           63 :           FAIL_IF (0x01 != ntohl (be[1]));  /* magic marker: blinded */
    1452              : 
    1453           63 :           in += sizeof(be);
    1454           63 :           sz -= sizeof(be);
    1455           63 :           bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    1456           63 :           bs->cipher = ntohl (be[0]);
    1457           63 :           bs->rc = 1;
    1458           63 :           switch (bs->cipher)
    1459              :           {
    1460           32 :           case GNUNET_CRYPTO_BSA_RSA:
    1461              :             bs->details.blinded_rsa_signature
    1462           32 :               = GNUNET_CRYPTO_rsa_signature_decode (in,
    1463              :                                                     sz);
    1464           32 :             if (NULL == bs->details.blinded_rsa_signature)
    1465              :             {
    1466            0 :               GNUNET_free (bs);
    1467            0 :               FAIL_IF (true);
    1468              :             }
    1469           32 :             break;
    1470           31 :           case GNUNET_CRYPTO_BSA_CS:
    1471           31 :             if (sizeof(bs->details.blinded_cs_answer) != sz)
    1472              :             {
    1473            0 :               GNUNET_free (bs);
    1474            0 :               FAIL_IF (true);
    1475              :             }
    1476           31 :             GNUNET_memcpy (&bs->details.blinded_cs_answer,
    1477              :                            in,
    1478              :                            sz);
    1479           31 :             break;
    1480            0 :           default:
    1481            0 :             GNUNET_free (bs);
    1482            0 :             FAIL_IF (true);
    1483              :           }
    1484           63 :           denom_sig->blinded_sig = bs;
    1485           63 :           in += sz;
    1486              :         }
    1487           17 :         return GNUNET_OK;
    1488              :       }
    1489            0 :     default:
    1490            0 :       FAIL_IF (true);
    1491              :     }
    1492              :   }
    1493            0 : FAIL:
    1494            0 :   GNUNET_free (*(void **) dst);
    1495            0 :   return GNUNET_SYSERR;
    1496              : #undef FAIL_IF
    1497              : }
    1498              : 
    1499              : 
    1500              : /**
    1501              :  * Cleanup of the data and closure of an array spec.
    1502              :  */
    1503              : static void
    1504           87 : array_cleanup (void *cls,
    1505              :                void *rd)
    1506              : {
    1507           87 :   struct ArrayResultCls *info = cls;
    1508           87 :   void **dst = rd;
    1509              : 
    1510           87 :   if ( (0 == info->same_size) &&
    1511           87 :        (NULL != info->sizes) )
    1512            0 :     GNUNET_free (*(info->sizes));
    1513              : 
    1514              :   /* Clean up signatures, if applicable */
    1515           87 :   if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
    1516           37 :       (NULL != *dst))
    1517              :   {
    1518            0 :     struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
    1519              : 
    1520            0 :     GNUNET_assert (NULL != info->num);
    1521            0 :     for (size_t i = 0; i < *info->num; i++)
    1522            0 :       GNUNET_free (denom_sigs[i].blinded_sig);
    1523              :   }
    1524           87 :   GNUNET_free (info);
    1525           87 :   GNUNET_free (*dst);
    1526           87 :   *dst = NULL;
    1527           87 : }
    1528              : 
    1529              : 
    1530              : struct GNUNET_PQ_ResultSpec
    1531           37 : TALER_PQ_result_spec_array_blinded_denom_sig (
    1532              :   struct GNUNET_PQ_Context *db,
    1533              :   const char *name,
    1534              :   size_t *num,
    1535              :   struct TALER_BlindedDenominationSignature **denom_sigs)
    1536              : {
    1537           37 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1538              : 
    1539           37 :   info->num = num;
    1540           37 :   info->typ = TALER_PQ_array_of_blinded_denom_sig;
    1541           37 :   GNUNET_assert (GNUNET_OK ==
    1542              :                  GNUNET_PQ_get_oid_by_name (db,
    1543              :                                             "bytea",
    1544              :                                             &info->oid));
    1545              :   {
    1546           37 :     struct GNUNET_PQ_ResultSpec res = {
    1547              :       .conv = extract_array_generic,
    1548              :       .cleaner = &array_cleanup,
    1549              :       .dst = (void *) denom_sigs,
    1550              :       .fname = name,
    1551              :       .cls = info
    1552              :     };
    1553              : 
    1554           37 :     return res;
    1555              :   }
    1556              : }
    1557              : 
    1558              : 
    1559              : struct GNUNET_PQ_ResultSpec
    1560            0 : TALER_PQ_result_spec_array_blinded_coin_hash (
    1561              :   struct GNUNET_PQ_Context *db,
    1562              :   const char *name,
    1563              :   size_t *num,
    1564              :   struct TALER_BlindedCoinHashP **h_coin_evs)
    1565              : {
    1566            0 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1567              : 
    1568            0 :   info->num = num;
    1569            0 :   info->typ = TALER_PQ_array_of_blinded_coin_hash;
    1570            0 :   GNUNET_assert (GNUNET_OK ==
    1571              :                  GNUNET_PQ_get_oid_by_name (db,
    1572              :                                             "bytea",
    1573              :                                             &info->oid));
    1574              :   {
    1575            0 :     struct GNUNET_PQ_ResultSpec res = {
    1576              :       .conv = extract_array_generic,
    1577              :       .cleaner = &array_cleanup,
    1578              :       .dst = (void *) h_coin_evs,
    1579              :       .fname = name,
    1580              :       .cls = info
    1581              :     };
    1582              : 
    1583            0 :     return res;
    1584              :   }
    1585              : }
    1586              : 
    1587              : 
    1588              : struct GNUNET_PQ_ResultSpec
    1589            7 : TALER_PQ_result_spec_array_denom_hash (
    1590              :   struct GNUNET_PQ_Context *db,
    1591              :   const char *name,
    1592              :   size_t *num,
    1593              :   struct TALER_DenominationHashP **denom_hs)
    1594              : {
    1595            7 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1596              : 
    1597            7 :   info->num = num;
    1598            7 :   info->typ = TALER_PQ_array_of_denom_hash;
    1599            7 :   GNUNET_assert (GNUNET_OK ==
    1600              :                  GNUNET_PQ_get_oid_by_name (db,
    1601              :                                             "bytea",
    1602              :                                             &info->oid));
    1603              :   {
    1604            7 :     struct GNUNET_PQ_ResultSpec res = {
    1605              :       .conv = extract_array_generic,
    1606              :       .cleaner = &array_cleanup,
    1607              :       .dst = (void *) denom_hs,
    1608              :       .fname = name,
    1609              :       .cls = info
    1610              :     };
    1611              : 
    1612            7 :     return res;
    1613              :   }
    1614              : }
    1615              : 
    1616              : 
    1617              : struct GNUNET_PQ_ResultSpec
    1618            2 : TALER_PQ_result_spec_array_amount (
    1619              :   struct GNUNET_PQ_Context *db,
    1620              :   const char *name,
    1621              :   const char *currency,
    1622              :   size_t *num,
    1623              :   struct TALER_Amount **amounts)
    1624              : {
    1625            2 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1626              : 
    1627            2 :   info->num = num;
    1628            2 :   info->typ = TALER_PQ_array_of_amount;
    1629            2 :   info->db = db;
    1630            2 :   GNUNET_assert (GNUNET_OK ==
    1631              :                  GNUNET_PQ_get_oid_by_name (db,
    1632              :                                             "taler_amount",
    1633              :                                             &info->oid));
    1634              : 
    1635              :   {
    1636            2 :     size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
    1637              :                               strlen (currency));
    1638            2 :     GNUNET_memcpy (&info->currency,
    1639              :                    currency,
    1640              :                    clen);
    1641              :   }
    1642              :   {
    1643            2 :     struct GNUNET_PQ_ResultSpec res = {
    1644              :       .conv = extract_array_generic,
    1645              :       .cleaner = &array_cleanup,
    1646              :       .dst = (void *) amounts,
    1647              :       .fname = name,
    1648              :       .cls = info,
    1649              :     };
    1650              : 
    1651            2 :     return res;
    1652              :   }
    1653              : }
    1654              : 
    1655              : 
    1656              : struct GNUNET_PQ_ResultSpec
    1657            2 : TALER_PQ_result_spec_array_amount_with_currency (
    1658              :   struct GNUNET_PQ_Context *db,
    1659              :   const char *name,
    1660              :   size_t *num,
    1661              :   struct TALER_Amount **amounts)
    1662              : {
    1663            2 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1664              : 
    1665            2 :   info->num = num;
    1666            2 :   info->typ = TALER_PQ_array_of_amount_currency;
    1667            2 :   info->db = db;
    1668            2 :   GNUNET_assert (GNUNET_OK ==
    1669              :                  GNUNET_PQ_get_oid_by_name (db,
    1670              :                                             "taler_amount_currency",
    1671              :                                             &info->oid));
    1672              : 
    1673              :   {
    1674            2 :     struct GNUNET_PQ_ResultSpec res = {
    1675              :       .conv = extract_array_generic,
    1676              :       .cleaner = &array_cleanup,
    1677              :       .dst = (void *) amounts,
    1678              :       .fname = name,
    1679              :       .cls = info,
    1680              :     };
    1681              : 
    1682            2 :     return res;
    1683              :   }
    1684              : }
    1685              : 
    1686              : 
    1687              : struct GNUNET_PQ_ResultSpec
    1688            1 : TALER_PQ_result_spec_array_hash_code (
    1689              :   struct GNUNET_PQ_Context *db,
    1690              :   const char *name,
    1691              :   size_t *num,
    1692              :   struct GNUNET_HashCode **hashes)
    1693              : {
    1694            1 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1695              : 
    1696            1 :   info->num = num;
    1697            1 :   info->typ = TALER_PQ_array_of_hash_code;
    1698            1 :   info->db = db;
    1699            1 :   GNUNET_assert (GNUNET_OK ==
    1700              :                  GNUNET_PQ_get_oid_by_name (db,
    1701              :                                             "gnunet_hashcode",
    1702              :                                             &info->oid));
    1703              :   {
    1704            1 :     struct GNUNET_PQ_ResultSpec res = {
    1705              :       .conv = extract_array_generic,
    1706              :       .cleaner = &array_cleanup,
    1707              :       .dst = (void *) hashes,
    1708              :       .fname = name,
    1709              :       .cls = info,
    1710              :     };
    1711              : 
    1712            1 :     return res;
    1713              :   }
    1714              : }
    1715              : 
    1716              : 
    1717              : struct GNUNET_PQ_ResultSpec
    1718           38 : TALER_PQ_result_spec_array_cs_r_pub (
    1719              :   struct GNUNET_PQ_Context *db,
    1720              :   const char *name,
    1721              :   size_t *num,
    1722              :   struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
    1723              : {
    1724           38 :   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    1725              : 
    1726           38 :   info->num = num;
    1727           38 :   info->typ = TALER_PQ_array_of_cs_r_pub;
    1728           38 :   GNUNET_assert (GNUNET_OK ==
    1729              :                  GNUNET_PQ_get_oid_by_name (db,
    1730              :                                             "bytea",
    1731              :                                             &info->oid));
    1732              :   {
    1733           38 :     struct GNUNET_PQ_ResultSpec res = {
    1734              :       .conv = extract_array_generic,
    1735              :       .cleaner = &array_cleanup,
    1736              :       .dst = (void *) cs_r_pubs,
    1737              :       .fname = name,
    1738              :       .cls = info
    1739              :     };
    1740              : 
    1741           38 :     return res;
    1742              :   }
    1743              : }
    1744              : 
    1745              : 
    1746              : /* end of pq_result_helper.c */
        

Generated by: LCOV version 2.0-1