LCOV - code coverage report
Current view: top level - src - writer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 167 28.1 %
Date: 2016-09-12 12:51:24 Functions: 6 15 40.0 %

          Line data    Source code
       1             : /* writer.c - provides the Writer object
       2             :  * Copyright (C) 2001, 2010, 2012 g10 Code GmbH
       3             :  *
       4             :  * This file is part of KSBA.
       5             :  *
       6             :  * KSBA is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * KSBA is distributed in the hope that it will be useful, but WITHOUT
      22             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      23             :  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      24             :  * License for more details.
      25             :  *
      26             :  * You should have received a copies of the GNU General Public License
      27             :  * and the GNU Lesser General Public License along with this program;
      28             :  * if not, see <http://www.gnu.org/licenses/>.
      29             :  */
      30             : 
      31             : #include <config.h>
      32             : #include <stdio.h>
      33             : #include <stdlib.h>
      34             : #include <string.h>
      35             : #include <assert.h>
      36             : #include <errno.h>
      37             : #include "util.h"
      38             : 
      39             : #include "ksba.h"
      40             : #include "writer.h"
      41             : #include "asn1-func.h"
      42             : #include "ber-help.h"
      43             : 
      44             : /**
      45             :  * ksba_writer_new:
      46             :  *
      47             :  * Create a new but uninitialized ksba_writer_t Object.  Using this
      48             :  * write object in unitialized state does always return an error.
      49             :  *
      50             :  * Return value: ksba_writer_t object or an error code.
      51             :  **/
      52             : gpg_error_t
      53          21 : ksba_writer_new (ksba_writer_t *r_w)
      54             : {
      55          21 :   *r_w = xtrycalloc (1, sizeof **r_w);
      56          21 :   if (!*r_w)
      57           0 :     return gpg_error_from_errno (errno);
      58             : 
      59          21 :   return 0;
      60             : }
      61             : 
      62             : 
      63             : /**
      64             :  * ksba_writer_release:
      65             :  * @w: Writer Object (or NULL)
      66             :  *
      67             :  * Release this object
      68             :  **/
      69             : void
      70          21 : ksba_writer_release (ksba_writer_t w)
      71             : {
      72          21 :   if (!w)
      73          21 :     return;
      74          21 :   if (w->notify_cb)
      75             :     {
      76           0 :       void (*notify_fnc)(void*,ksba_writer_t) = w->notify_cb;
      77             : 
      78           0 :       w->notify_cb = NULL;
      79           0 :       notify_fnc (w->notify_cb_value, w);
      80             :     }
      81          21 :   if (w->type == WRITER_TYPE_MEM)
      82          10 :     xfree (w->u.mem.buffer);
      83          21 :   xfree (w);
      84             : }
      85             : 
      86             : 
      87             : /* Set NOTIFY as function to be called by ksba_reader_release before
      88             :    resources are actually deallocated.  NOTIFY_VALUE is passed to the
      89             :    called function as its first argument.  Note that only the last
      90             :    registered function will be called; passing NULL for NOTIFY removes
      91             :    the notification.  */
      92             : gpg_error_t
      93           0 : ksba_writer_set_release_notify (ksba_writer_t w,
      94             :                                 void (*notify)(void*,ksba_writer_t),
      95             :                                 void *notify_value)
      96             : {
      97           0 :   if (!w)
      98           0 :     return gpg_error (GPG_ERR_INV_VALUE);
      99           0 :   w->notify_cb = notify;
     100           0 :   w->notify_cb_value = notify_value;
     101           0 :   return 0;
     102             : }
     103             : 
     104             : 
     105             : int
     106           0 : ksba_writer_error (ksba_writer_t w)
     107             : {
     108           0 :   return w? gpg_error_from_errno (w->error) : gpg_error (GPG_ERR_INV_VALUE);
     109             : }
     110             : 
     111             : unsigned long
     112           0 : ksba_writer_tell (ksba_writer_t w)
     113             : {
     114           0 :   return w? w->nwritten : 0;
     115             : }
     116             : 
     117             : 
     118             : /**
     119             :  * ksba_writer_set_fd:
     120             :  * @w: Writer object
     121             :  * @fd: file descriptor
     122             :  *
     123             :  * Initialize the Writer object with a file descriptor, so that write
     124             :  * operations on this object are excuted on this file descriptor.
     125             :  *
     126             :  * Return value:
     127             :  **/
     128             : gpg_error_t
     129           0 : ksba_writer_set_fd (ksba_writer_t w, int fd)
     130             : {
     131           0 :   if (!w || fd == -1)
     132           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     133           0 :   if (w->type)
     134           0 :     return gpg_error (GPG_ERR_CONFLICT);
     135             : 
     136           0 :   w->error = 0;
     137           0 :   w->type = WRITER_TYPE_FD;
     138           0 :   w->u.fd = fd;
     139             : 
     140           0 :   return 0;
     141             : }
     142             : 
     143             : /**
     144             :  * ksba_writer_set_file:
     145             :  * @w: Writer object
     146             :  * @fp: file pointer
     147             :  *
     148             :  * Initialize the Writer object with a stdio file pointer, so that write
     149             :  * operations on this object are excuted on this stream
     150             :  *
     151             :  * Return value:
     152             :  **/
     153             : gpg_error_t
     154           0 : ksba_writer_set_file (ksba_writer_t w, FILE *fp)
     155             : {
     156           0 :   if (!w || !fp)
     157           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     158           0 :   if (w->type)
     159           0 :     return gpg_error (GPG_ERR_CONFLICT);
     160             : 
     161           0 :   w->error = 0;
     162           0 :   w->type = WRITER_TYPE_FILE;
     163           0 :   w->u.file = fp;
     164           0 :   return 0;
     165             : }
     166             : 
     167             : 
     168             : 
     169             : /**
     170             :  * ksba_writer_set_cb:
     171             :  * @w: Writer object
     172             :  * @cb: Callback function
     173             :  * @cb_value: Value passed to the callback function
     174             :  *
     175             :  * Initialize the writer object with a callback function.
     176             :  * This callback function is defined as:
     177             :  * <literal>
     178             :  * typedef int (*cb) (void *cb_value,
     179             :  *                    const void *buffer, size_t count);
     180             :  * </literal>
     181             :  *
     182             :  * The callback is expected to process all @count bytes from @buffer
     183             :  * @count should not be 0 and @buffer should not be %NULL
     184             :  * The callback should return 0 on success or an %KSBA_xxx error code.
     185             :  *
     186             :  * Return value: 0 on success or an error code
     187             :  **/
     188             : gpg_error_t
     189           0 : ksba_writer_set_cb (ksba_writer_t w,
     190             :                     int (*cb)(void*,const void *,size_t), void *cb_value )
     191             : {
     192           0 :   if (!w || !cb)
     193           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     194           0 :   if (w->type)
     195           0 :     return gpg_error (GPG_ERR_CONFLICT);
     196             : 
     197           0 :   w->error = 0;
     198           0 :   w->type = WRITER_TYPE_CB;
     199           0 :   w->u.cb.fnc = cb;
     200           0 :   w->u.cb.value = cb_value;
     201             : 
     202           0 :   return 0;
     203             : }
     204             : 
     205             : 
     206             : gpg_error_t
     207          32 : ksba_writer_set_mem (ksba_writer_t w, size_t initial_size)
     208             : {
     209          32 :   if (!w)
     210           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     211          32 :   if (w->type == WRITER_TYPE_MEM)
     212             :     ; /* Reuse the buffer (we ignore the initial size)*/
     213             :   else
     214             :     {
     215          32 :       if (w->type)
     216           0 :         return gpg_error (GPG_ERR_CONFLICT);
     217             : 
     218          32 :       if (!initial_size)
     219           0 :         initial_size = 1024;
     220             : 
     221          32 :       w->u.mem.buffer = xtrymalloc (initial_size);
     222          32 :       if (!w->u.mem.buffer)
     223           0 :         return gpg_error (GPG_ERR_ENOMEM);
     224          32 :       w->u.mem.size = initial_size;
     225          32 :       w->type = WRITER_TYPE_MEM;
     226             :     }
     227          32 :   w->error = 0;
     228          32 :   w->nwritten = 0;
     229             : 
     230          32 :   return 0;
     231             : }
     232             : 
     233             : /* Return the pointer to the memory and the size of it.  This pointer
     234             :    is valid as long as the writer object is valid and no write
     235             :    operations takes place (because they might reallocate the buffer).
     236             :    if NBYTES is not NULL, it will receive the number of bytes in this
     237             :    buffer which is the same value ksba_writer_tell() returns.
     238             : 
     239             :    In case of an error NULL is returned.
     240             :   */
     241             : const void *
     242           0 : ksba_writer_get_mem (ksba_writer_t w, size_t *nbytes)
     243             : {
     244           0 :   if (!w || w->type != WRITER_TYPE_MEM || w->error)
     245           0 :     return NULL;
     246           0 :   if (nbytes)
     247           0 :     *nbytes = w->nwritten;
     248           0 :   return w->u.mem.buffer;
     249             : }
     250             : 
     251             : /* Return the the memory and the size of it.  The writer object is set
     252             :    back into the uninitalized state; i.e. one of the
     253             :    ksab_writer_set_xxx () must be used before all other operations.
     254             :    if NBYTES is not NULL, it will receive the number of bytes in this
     255             :    buffer which is the same value ksba_writer_tell() returns.
     256             : 
     257             :    In case of an error NULL is returned.  */
     258             : void *
     259          22 : ksba_writer_snatch_mem (ksba_writer_t w, size_t *nbytes)
     260             : {
     261             :   void *p;
     262             : 
     263          22 :   if (!w || w->type != WRITER_TYPE_MEM || w->error)
     264           0 :     return NULL;
     265          22 :   if (nbytes)
     266          22 :     *nbytes = w->nwritten;
     267          22 :   p = w->u.mem.buffer;
     268          22 :   w->u.mem.buffer = NULL;
     269          22 :   w->type = 0;
     270          22 :   w->nwritten = 0;
     271          22 :   return p;
     272             : }
     273             : 
     274             : 
     275             : 
     276             : gpg_error_t
     277           0 : ksba_writer_set_filter (ksba_writer_t w,
     278             :                         gpg_error_t (*filter)(void*,
     279             :                                             const void *,size_t, size_t *,
     280             :                                             void *, size_t, size_t *),
     281             :                         void *filter_arg)
     282             : {
     283           0 :   if (!w)
     284           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     285             : 
     286           0 :   w->filter = filter;
     287           0 :   w->filter_arg = filter_arg;
     288           0 :   return 0;
     289             : }
     290             : 
     291             : 
     292             : 
     293             : 
     294             : static gpg_error_t
     295         281 : do_writer_write (ksba_writer_t w, const void *buffer, size_t length)
     296             : {
     297         281 :   if (!w->type)
     298             :     {
     299           0 :       w->error = EINVAL;
     300           0 :       return gpg_error_from_errno (w->error);
     301             :     }
     302         281 :   else if (w->type == WRITER_TYPE_MEM)
     303             :     {
     304         281 :       if (w->error == ENOMEM)
     305           0 :         return gpg_error (GPG_ERR_ENOMEM); /* it does not make sense to proceed then */
     306             : 
     307         281 :       if (w->nwritten + length > w->u.mem.size)
     308             :         {
     309           0 :           size_t newsize = w->nwritten + length;
     310             :           char *p;
     311             : 
     312           0 :           newsize = ((newsize + 4095)/4096)*4096;
     313           0 :           if (newsize < 16384)
     314           0 :             newsize += 4096;
     315             :           else
     316           0 :             newsize += 16384;
     317             : 
     318           0 :           p = xtryrealloc (w->u.mem.buffer, newsize);
     319           0 :           if (!p)
     320             :             {
     321             :               /* Keep an error flag so that the user does not need to
     322             :                  check the return code of a write but instead use
     323             :                  ksba_writer_error() to check for it or even figure
     324             :                  this state out when using ksba_writer_get_mem() */
     325           0 :               w->error = ENOMEM;
     326           0 :               return gpg_error (GPG_ERR_ENOMEM);
     327             :             }
     328           0 :           w->u.mem.buffer = p;
     329           0 :           w->u.mem.size = newsize;
     330             :           /* Better check again in case of an overwrap. */
     331           0 :           if (w->nwritten + length > w->u.mem.size)
     332           0 :             return gpg_error (GPG_ERR_ENOMEM);
     333             :         }
     334         281 :       memcpy (w->u.mem.buffer + w->nwritten, buffer, length);
     335         281 :       w->nwritten += length;
     336             :     }
     337           0 :   else if (w->type == WRITER_TYPE_FILE)
     338             :     {
     339           0 :       if (!length)
     340           0 :         return 0;
     341             : 
     342           0 :       if ( fwrite (buffer, length, 1, w->u.file) == 1)
     343             :         {
     344           0 :           w->nwritten += length;
     345             :         }
     346             :       else
     347             :         {
     348           0 :           w->error = errno;
     349           0 :           return gpg_error_from_errno (errno);
     350             :         }
     351             :     }
     352           0 :   else if (w->type == WRITER_TYPE_CB)
     353             :     {
     354           0 :       int err = w->u.cb.fnc (w->u.cb.value, buffer, length);
     355           0 :       if (err)
     356           0 :         return err;
     357           0 :       w->nwritten += length;
     358             :     }
     359             :   else
     360           0 :     return gpg_error (GPG_ERR_BUG);
     361             : 
     362         281 :   return 0;
     363             : }
     364             : 
     365             : /**
     366             :  * ksba_writer_write:
     367             :  * @w: Writer object
     368             :  * @buffer: A buffer with the data to be written
     369             :  * @length: The length of this buffer
     370             :  *
     371             :  * Write @length bytes from @buffer.
     372             :  *
     373             :  * Return value: 0 on success or an error code
     374             :  **/
     375             : gpg_error_t
     376         281 : ksba_writer_write (ksba_writer_t w, const void *buffer, size_t length)
     377             : {
     378         281 :   gpg_error_t err=0;
     379             : 
     380         281 :   if (!w)
     381           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     382             : 
     383         281 :   if (!buffer)
     384           0 :       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     385             : 
     386         281 :   if (w->filter)
     387             :     {
     388             :       char outbuf[4096];
     389             :       size_t nin, nout;
     390           0 :       const char *p = buffer;
     391             : 
     392           0 :       while (length)
     393             :         {
     394           0 :           err = w->filter (w->filter_arg, p, length, &nin,
     395             :                            outbuf, sizeof (outbuf), &nout);
     396           0 :           if (err)
     397           0 :             break;
     398           0 :           if (nin > length || nout > sizeof (outbuf))
     399           0 :             return gpg_error (GPG_ERR_BUG); /* tsss, someone else made an error */
     400           0 :           err = do_writer_write (w, outbuf, nout);
     401           0 :           if (err)
     402           0 :             break;
     403           0 :           length -= nin;
     404           0 :           p += nin;
     405             :         }
     406             :     }
     407             :   else
     408             :     {
     409         281 :       err = do_writer_write (w, buffer, length);
     410             :     }
     411             : 
     412         281 :   return err;
     413             : }
     414             : 
     415             : /* Write LENGTH bytes of BUFFER to W while encoding it as an BER
     416             :    encoded octet string.  With FLUSH set to 1 the octet stream will be
     417             :    terminated.  If the entire octet string is available in BUFFER it
     418             :    is a good idea to set FLUSH to 1 so that the function does not need
     419             :    to encode the string partially. */
     420             : gpg_error_t
     421           0 : ksba_writer_write_octet_string (ksba_writer_t w,
     422             :                                 const void *buffer, size_t length, int flush)
     423             : {
     424           0 :   gpg_error_t err = 0;
     425             : 
     426           0 :   if (!w)
     427           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     428             : 
     429           0 :   if (buffer && length)
     430             :     {
     431           0 :       if (!w->ndef_is_open && !flush)
     432             :         {
     433           0 :           err = _ksba_ber_write_tl (w, TYPE_OCTET_STRING,
     434             :                                     CLASS_UNIVERSAL, 1, 0);
     435           0 :           if (err)
     436           0 :             return err;
     437           0 :           w->ndef_is_open = 1;
     438             :         }
     439             : 
     440           0 :       err = _ksba_ber_write_tl (w, TYPE_OCTET_STRING,
     441             :                                 CLASS_UNIVERSAL, 0, length);
     442           0 :       if (!err)
     443           0 :         err = ksba_writer_write (w, buffer, length);
     444             :     }
     445             : 
     446           0 :   if (!err && flush && w->ndef_is_open) /* write an end tag */
     447           0 :       err = _ksba_ber_write_tl (w, 0, 0, 0, 0);
     448             : 
     449           0 :   if (flush) /* Reset it even in case of an error. */
     450           0 :     w->ndef_is_open = 1;
     451             : 
     452           0 :   return err;
     453             : }

Generated by: LCOV version 1.11