[git] GPG-ERROR - branch, master, updated. gpgrt-1.28-14-g30621ee

by Werner Koch cvs at cvs.gnupg.org
Thu Mar 22 17:49:40 CET 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Error codes used by GnuPG et al.".

The branch, master has been updated
       via  30621ee4c13006d08881994c32c89f60604c0188 (commit)
       via  72b70167ea433d6bb46226b1008e2d8e911146a7 (commit)
       via  ffc8f805165a13d16ed227051c59d732117ec9d4 (commit)
       via  b3df10d6620894bc4047af1e14239b258e440803 (commit)
      from  4dc6d4d2067c726cdb13593bf151637319ff65e6 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 30621ee4c13006d08881994c32c89f60604c0188
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Mar 22 17:42:20 2018 +0100

    yat2m: Avoid compiler warnings
    
    * doc/yat2m.c (evaluate_conditions): Mark args unused
    (proc_texi_cmd): Avoid shadowing warning.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/yat2m.c b/doc/yat2m.c
index 8c6319c..a509d1b 100644
--- a/doc/yat2m.c
+++ b/doc/yat2m.c
@@ -486,6 +486,9 @@ evaluate_conditions (const char *fname, int lnr)
 {
   int i;
 
+  (void)fname;
+  (void)lnr;
+
   /* for (i=0; i < condition_stack_idx; i++) */
   /*   inf ("%s:%d:   stack[%d] %s %s %c", */
   /*        fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
@@ -857,18 +860,20 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
                 }
               else
                 {
-                  size_t len = s - (rest + 1);
+                  size_t rlen = s - (rest + 1);
                   macro_t m;
 
                   for (m = variablelist; m; m = m->next)
-                    if (strlen (m->name) == len
-                        &&!strncmp (m->name, rest+1, len))
-                      break;
+                    {
+                      if (strlen (m->name) == rlen
+                          && !strncmp (m->name, rest+1, rlen))
+                        break;
+                    }
                   if (m)
                     fputs (m->value, fp);
                   else
                     inf ("texinfo variable '%.*s' is not set",
-                         (int)len, rest+1);
+                         (int)rlen, rest+1);
                 }
             }
           break;

commit 72b70167ea433d6bb46226b1008e2d8e911146a7
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Mar 22 17:21:32 2018 +0100

    core: Remove outdated comments.
    
    --

diff --git a/src/argparse.c b/src/argparse.c
index c5a942f..00ba68c 100644
--- a/src/argparse.c
+++ b/src/argparse.c
@@ -144,48 +144,6 @@ map_fixed_string (const char *string)
 }
 
 
-
-/*********************************
- * @Summary arg_parse
- *  #include "argparse.h"
- *
- *  You do not need to process the options 'h', '--help' or '--version'
- *  because this function includes standard help processing; but if you
- *  specify '-h', '--help' or '--version' you have to do it yourself.
- *  The option '--' stops argument processing; if bit 1 is set the function
- *  continues to return normal arguments.
- *  To process float args or unsigned args you must use a string args and do
- *  the conversion yourself.
- * @Example
- *
- *     gpgrt_opt_t opts[] = {
- *     { 'v', "verbose",   0 },
- *     { 'd', "debug",     0 },
- *     { 'o', "output",    2 },
- *     { 'c', "cross-ref", 2|8 },
- *     { 'm', "my-option", 1|8 },
- *     { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
- *     { 500, "have-no-short-option-for-this-long-option", 0 },
- *     {0} };
- *     gpgrt_argparse_t pargs = { &argc, &argv, 0 }
- *
- *     while( ArgParse( &pargs, &opts) ) {
- *	   switch( pargs.r_opt ) {
- *	     case 'v': opt.verbose++; break;
- *	     case 'd': opt.debug++; break;
- *	     case 'o': opt.outfile = pargs.r.ret_str; break;
- *	     case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
- *	     case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
- *	     case 500: opt.a_long_one++;  break
- *	     default : pargs.err = 1; break; -- force warning output --
- *	   }
- *     }
- *     if( argc > 1 )
- *	   log_fatal( "Too many args");
- *
- */
-
-
 /* Write STRING and all following const char * arguments either to
    stdout or, if IS_ERROR is set, to stderr.  The list of strings must
    be terminated by a NULL.  */
diff --git a/tests/t-argparse.c b/tests/t-argparse.c
index 177992a..277d860 100644
--- a/tests/t-argparse.c
+++ b/tests/t-argparse.c
@@ -103,7 +103,8 @@ main (int argc, char **argv)
     }
   for (i=0; i < argc; i++ )
     printf ("%3d -> (%s)\n", i, argv[i] );
-  puts ("Options:");
+  if (opt.verbose)
+    puts ("Options:");
   if (opt.verbose)
     printf ("  verbose=%d\n", opt.verbose );
   if (opt.debug)

commit ffc8f805165a13d16ed227051c59d732117ec9d4
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Mar 22 17:20:52 2018 +0100

    core: Add Base-64 encoder.
    
    * src/b64enc.c: Change to fit into libgpg-error.
    * src/Makefile.am: Add b64enc.c
    * src/b64dec.c: Use xtrymalloc etc.  Always use gpg_err_code_t.
    (_gpgrt_b64dec_start): Set decoder flag
    (_gpgrt_b64dec_finish): Check for conflict.
    (_gpgrt_b64state): Move to ...
    * src/gpgrt-int.h: here.  Add new fields.
    * src/visibility.c (gpgrt_b64enc_start): New.
    (gpgrt_b64enc_write): New.
    (gpgrt_b64enc_finish): New.
    * src/gpg-error.vers, src/gpg-error.def.in: Add new functions.
    * src/gpg-error.h.in: Ditto.
    * src/visibility.h: Ditto.
    
    * tests/t-b64dec.c: Remove.
    * tests/t-b64.c: New.
    * tests/Makefile.am (TESTS): Replace t-b64dec by t-b64.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index e21f534..de551f4 100644
--- a/NEWS
+++ b/NEWS
@@ -4,13 +4,16 @@ Noteworthy changes in version 1.29 (unreleased) [C23/A23/R_]
 
  * Interface changes relative to the 1.28 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- gpgrt_argparse                  New API.
- gpgrt_usage                     New API.
- gpgrt_strusage                  New API.
- gpgrt_set_strusage              New API.
- gpgrt_set_usage_outfnc          New API.
- gpgrt_set_fixed_string_mapper   New API.
+ gpgrt_argparse                  New.
+ gpgrt_usage                     New.
+ gpgrt_strusage                  New.
+ gpgrt_set_strusage              New.
+ gpgrt_set_usage_outfnc          New.
+ gpgrt_set_fixed_string_mapper   New.
  GPGRT_ENABLE_ARGPARSE_MACROS    New macro.
+ gpgrt_b64enc_start              New.
+ gpgrt_b64enc_write              New.
+ gpgrt_b64enc_finish             New.
 
 
 Noteworthy changes in version 1.28 (2018-03-13) [C23/A23/R0]
diff --git a/src/Makefile.am b/src/Makefile.am
index 66c4414..42998e4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -190,7 +190,7 @@ libgpg_error_la_SOURCES = gettext.h $(arch_sources) \
 	sysutils.c \
 	syscall-clamp.c \
 	logging.c \
-	b64dec.c \
+	b64dec.c b64enc.c \
 	argparse.c
 
 
diff --git a/src/b64dec.c b/src/b64dec.c
index a8a8351..1235406 100644
--- a/src/b64dec.c
+++ b/src/b64dec.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
  * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
  *
- * This file is part of GnuPG.
+ * This file is part of Libgpg-error.
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -16,26 +16,18 @@
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This file was originally a part of GnuPG.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpgrt-int.h"
 
-struct _gpgrt_b64state
-{
-  int idx;
-  int quad_count;
-  char *title;
-  unsigned char radbuf[4];
-  int stop_seen:1;
-  int invalid_encoding:1;
-  gpg_error_t lasterr;
-};
 
 /* The reverse base-64 list used for base-64 decoding. */
 static unsigned char const asctobin[128] =
@@ -79,15 +71,15 @@ _gpgrt_b64dec_start (const char *title)
 
   if (title)
     {
-      t = strdup (title);
+      t = xtrystrdup (title);
       if (!t)
         return NULL;
     }
 
-  state = calloc (1, sizeof (struct _gpgrt_b64state));
+  state = xtrycalloc (1, sizeof (struct _gpgrt_b64state));
   if (!state)
     {
-      free (t);
+      xfree (t);
       return NULL;
     }
 
@@ -99,13 +91,15 @@ _gpgrt_b64dec_start (const char *title)
   else
     state->idx = s_b64_0;
 
+  state->using_decoder = 1;
+
   return state;
 }
 
 
 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Stores the
    new length of the buffer at R_NBYTES. */
-gpg_error_t
+gpg_err_code_t
 _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
                     size_t *r_nbytes)
 {
@@ -120,8 +114,8 @@ _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
   if (state->stop_seen)
     {
       *r_nbytes = 0;
-      state->lasterr = gpg_error (GPG_ERR_EOF);
-      free (state->title);
+      state->lasterr = GPG_ERR_EOF;
+      xfree (state->title);
       state->title = NULL;
       return state->lasterr;
     }
@@ -247,7 +241,7 @@ _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
             state->stop_seen = 1;
           break;
         default:
-          assert (!"invalid state");
+          gpgrt_assert (!"invalid state");
         }
     }
 
@@ -262,17 +256,22 @@ _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
 
 /* Return an error code in case an encoding error has been found
    during decoding. */
-gpg_error_t
+gpg_err_code_t
 _gpgrt_b64dec_finish (gpgrt_b64state_t state)
 {
   gpg_error_t err;
 
-  if (state->lasterr)
+  if (!state)
+    return 0;  /* Already released.  */
+
+  if (!state->using_decoder)
+    err = GPG_ERR_CONFLICT;  /* State was allocated for the encoder.  */
+  else if (state->lasterr)
     err = state->lasterr;
   else
     {
       free (state->title);
-      err = state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
+      err = state->invalid_encoding? GPG_ERR_BAD_DATA : 0;
     }
   free (state);
 
diff --git a/src/b64enc.c b/src/b64enc.c
index 91960c7..571f4ec 100644
--- a/src/b64enc.c
+++ b/src/b64enc.c
@@ -2,9 +2,9 @@
  * Copyright (C) 2001, 2003, 2004, 2008, 2010,
  *               2011 Free Software Foundation, Inc.
  * Copyright (C) 2001, 2003, 2004, 2008, 2010,
- *               2011 g10 Code GmbH
+ *               2011, 2018 g10 Code GmbH
  *
- * This file is part of GnuPG.
+ * This file is part of Libgpg-error.
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -18,17 +18,20 @@
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This file was originally a part of GnuPG.
  */
 
 #include <config.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
-#include "i18n.h"
-#include "util.h"
+#include "gpgrt-int.h"
+
 
 #define B64ENC_DID_HEADER   1
 #define B64ENC_DID_TRAILER  2
@@ -36,9 +39,9 @@
 #define B64ENC_USE_PGPCRC   32
 
 /* The base-64 character list */
-static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                    "abcdefghijklmnopqrstuvwxyz"
-                                    "0123456789+/";
+static unsigned char const bintoasc[64] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                           "abcdefghijklmnopqrstuvwxyz"
+                                           "0123456789+/");
 
 /* Stuff required to create the OpenPGP CRC.  This crc_table has been
    created using this code:
@@ -92,7 +95,7 @@ static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    }
 */
 #define CRCINIT 0xB704CE
-static const u32 crc_table[256] = {
+static const uint32_t crc_table[256] = {
   0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
   0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
   0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
@@ -139,14 +142,28 @@ static const u32 crc_table[256] = {
 };
 
 
-static gpg_error_t
-enc_start (struct b64state *state, FILE *fp, estream_t stream,
-           const char *title)
+/* Prepare for Base-64 writing to STREAM.  If TITLE is not NULL and
+ * not an empty string, that string will be used as the title for the
+ * armor lines, with TITLE being an empty string, we don't write the
+ * header lines and furthermore even don't write any linefeeds.  If
+ * TITLE starts with "PGP " the OpenPGP CRC checksum will be written
+ * as well.  With TITLE being NULL, we merely don't write header but
+ * make sure that lines are not too long.  Note, that we don't write
+ * anything unless at least one byte is written using b64enc_write.
+ * On success an enoder object is returned which needs to be released
+ * using _gpgrt_b64dec_finish.  On error NULL is returned an ERRNO is
+ * set.
+ */
+gpgrt_b64state_t
+_gpgrt_b64enc_start (estream_t stream, const char *title)
 {
-  memset (state, 0, sizeof *state);
-  state->fp = fp;
+  gpgrt_b64state_t state;
+
+  state = xtrycalloc (1, sizeof *state);
+  if (!state)
+    return NULL;
+
   state->stream = stream;
-  state->lasterr = 0;
   if (title && !*title)
     state->flags |= B64ENC_NO_LINEFEEDS;
   else if (title)
@@ -158,50 +175,21 @@ enc_start (struct b64state *state, FILE *fp, estream_t stream,
         }
       state->title = xtrystrdup (title);
       if (!state->title)
-        state->lasterr = gpg_error_from_syserror ();
+        {
+          xfree (state);
+          return NULL;
+        }
     }
-  return state->lasterr;
-}
-
-
-/* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
-   and not an empty string, this string will be used as the title for
-   the armor lines, with TITLE being an empty string, we don't write
-   the header lines and furthermore even don't write any linefeeds.
-   If TITLE starts with "PGP " the OpenPGP CRC checksum will be
-   written as well.  With TITLE being NULL, we merely don't write
-   header but make sure that lines are not too long. Note, that we
-   don't write any output unless at least one byte get written using
-   b64enc_write. */
-gpg_error_t
-b64enc_start (struct b64state *state, FILE *fp, const char *title)
-{
-  return enc_start (state, fp, NULL, title);
-}
-
-/* Same as b64enc_start but takes an estream.  */
-gpg_error_t
-b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
-{
-  return enc_start (state, NULL, fp, title);
-}
-
 
-static int
-my_fputs (const char *string, struct b64state *state)
-{
-  if (state->stream)
-    return es_fputs (string, state->stream);
-  else
-    return fputs (string, state->fp);
+  return state;
 }
 
 
-/* Write NBYTES from BUFFER to the Base 64 stream identified by
-   STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
-   stream. */
-gpg_error_t
-b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
+/* Write NBYTES from BUFFER to the Base 64 stream identified by STATE.
+ * With BUFFER and NBYTES being 0, merely do a fflush on the stream.
+ */
+gpg_err_code_t
+_gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes)
 {
   unsigned char radbuf[4];
   int idx, quad_count;
@@ -213,7 +201,7 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
   if (!nbytes)
     {
       if (buffer)
-        if (state->stream? es_fflush (state->stream) : fflush (state->fp))
+        if (_gpgrt_fflush (state->stream))
           goto write_error;
       return 0;
     }
@@ -222,12 +210,12 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
     {
       if (state->title)
         {
-          if ( my_fputs ("-----BEGIN ", state) == EOF
-               || my_fputs (state->title, state) == EOF
-               || my_fputs ("-----\n", state) == EOF)
+          if ( _gpgrt_fputs ("-----BEGIN ", state->stream) == EOF
+               || _gpgrt_fputs (state->title, state->stream) == EOF
+               || _gpgrt_fputs ("-----\n", state->stream) == EOF)
             goto write_error;
           if ( (state->flags & B64ENC_USE_PGPCRC)
-               && my_fputs ("\n", state) == EOF)
+               && _gpgrt_fputs ("\n", state->stream) == EOF)
             goto write_error;
         }
 
@@ -236,16 +224,16 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
 
   idx = state->idx;
   quad_count = state->quad_count;
-  assert (idx < 4);
+  gpgrt_assert (idx < 4);
   memcpy (radbuf, state->radbuf, idx);
 
   if ( (state->flags & B64ENC_USE_PGPCRC) )
     {
       size_t n;
-      u32 crc = state->crc;
+      uint32_t crc = state->crc;
 
       for (p=buffer, n=nbytes; n; p++, n-- )
-        crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
+        crc = ((uint32_t)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
       state->crc = (crc & 0x00ffffff);
     }
 
@@ -260,27 +248,17 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
           tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
           tmp[3] = bintoasc[radbuf[2]&077];
-          if (state->stream)
-            {
-              for (idx=0; idx < 4; idx++)
-                es_putc (tmp[idx], state->stream);
-              idx = 0;
-              if (es_ferror (state->stream))
-                goto write_error;
-            }
-          else
-            {
-              for (idx=0; idx < 4; idx++)
-                putc (tmp[idx], state->fp);
-              idx = 0;
-              if (ferror (state->fp))
-                goto write_error;
-            }
+          for (idx=0; idx < 4; idx++)
+            _gpgrt_fputc (tmp[idx], state->stream);
+          idx = 0;
+          if (_gpgrt_ferror (state->stream))
+            goto write_error;
+
           if (++quad_count >= (64/4))
             {
               quad_count = 0;
               if (!(state->flags & B64ENC_NO_LINEFEEDS)
-                  && my_fputs ("\n", state) == EOF)
+                  && _gpgrt_fputs ("\n", state->stream) == EOF)
                 goto write_error;
             }
         }
@@ -291,7 +269,7 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
   return 0;
 
  write_error:
-  state->lasterr = gpg_error_from_syserror ();
+  state->lasterr = _gpg_err_code_from_syserror ();
   if (state->title)
     {
       xfree (state->title);
@@ -301,16 +279,28 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
 }
 
 
-gpg_error_t
-b64enc_finish (struct b64state *state)
+gpg_err_code_t
+_gpgrt_b64enc_finish (gpgrt_b64state_t state)
 {
-  gpg_error_t err = 0;
+  gpg_err_code_t err = 0;
   unsigned char radbuf[4];
   int idx, quad_count;
   char tmp[4];
 
+  if (!state)
+    return 0;  /* Already released.  */
+
+  if (state->using_decoder)
+    {
+      err = GPG_ERR_CONFLICT;  /* State was created for the decoder.  */
+      goto cleanup;
+    }
+
   if (state->lasterr)
-    return state->lasterr;
+    {
+      err = state->lasterr;
+      goto cleanup;
+    }
 
   if (!(state->flags & B64ENC_DID_HEADER))
     goto cleanup;
@@ -318,7 +308,7 @@ b64enc_finish (struct b64state *state)
   /* Flush the base64 encoding */
   idx = state->idx;
   quad_count = state->quad_count;
-  assert (idx < 4);
+  gpgrt_assert (idx < 4);
   memcpy (radbuf, state->radbuf, idx);
 
   if (idx)
@@ -336,26 +326,16 @@ b64enc_finish (struct b64state *state)
           tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
           tmp[3] = '=';
         }
-      if (state->stream)
-        {
-          for (idx=0; idx < 4; idx++)
-            es_putc (tmp[idx], state->stream);
-          if (es_ferror (state->stream))
-            goto write_error;
-        }
-      else
-        {
-          for (idx=0; idx < 4; idx++)
-            putc (tmp[idx], state->fp);
-          if (ferror (state->fp))
-            goto write_error;
-        }
+      for (idx=0; idx < 4; idx++)
+        _gpgrt_fputc (tmp[idx], state->stream);
+      if (_gpgrt_ferror (state->stream))
+        goto write_error;
 
       if (++quad_count >= (64/4))
         {
           quad_count = 0;
           if (!(state->flags & B64ENC_NO_LINEFEEDS)
-              && my_fputs ("\n", state) == EOF)
+              && _gpgrt_fputs ("\n", state->stream) == EOF)
             goto write_error;
         }
     }
@@ -363,13 +343,13 @@ b64enc_finish (struct b64state *state)
   /* Finish the last line and write the trailer. */
   if (quad_count
       && !(state->flags & B64ENC_NO_LINEFEEDS)
-      && my_fputs ("\n", state) == EOF)
+      && _gpgrt_fputs ("\n", state->stream) == EOF)
     goto write_error;
 
   if ( (state->flags & B64ENC_USE_PGPCRC) )
     {
       /* Write the CRC.  */
-      my_fputs ("=", state);
+      _gpgrt_fputs ("=", state->stream);
       radbuf[0] = state->crc >>16;
       radbuf[1] = state->crc >> 8;
       radbuf[2] = state->crc;
@@ -377,46 +357,30 @@ b64enc_finish (struct b64state *state)
       tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
       tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
       tmp[3] = bintoasc[radbuf[2]&077];
-      if (state->stream)
-        {
-          for (idx=0; idx < 4; idx++)
-            es_putc (tmp[idx], state->stream);
-          if (es_ferror (state->stream))
-            goto write_error;
-        }
-      else
-        {
-          for (idx=0; idx < 4; idx++)
-            putc (tmp[idx], state->fp);
-          if (ferror (state->fp))
-            goto write_error;
-        }
+      for (idx=0; idx < 4; idx++)
+        _gpgrt_fputc (tmp[idx], state->stream);
+      if (_gpgrt_ferror (state->stream))
+        goto write_error;
+
       if (!(state->flags & B64ENC_NO_LINEFEEDS)
-          && my_fputs ("\n", state) == EOF)
+          && _gpgrt_fputs ("\n", state->stream) == EOF)
         goto write_error;
     }
 
   if (state->title)
     {
-      if ( my_fputs ("-----END ", state) == EOF
-           || my_fputs (state->title, state) == EOF
-           || my_fputs ("-----\n", state) == EOF)
+      if ( _gpgrt_fputs ("-----END ", state->stream) == EOF
+           || _gpgrt_fputs (state->title, state->stream) == EOF
+           || _gpgrt_fputs ("-----\n", state->stream) == EOF)
         goto write_error;
     }
 
-  goto cleanup;
+ cleanup:
+  xfree (state->title);
+  xfree (state);
+  return err;
 
  write_error:
   err = gpg_error_from_syserror ();
-
- cleanup:
-  if (state->title)
-    {
-      xfree (state->title);
-      state->title = NULL;
-    }
-  state->fp = NULL;
-  state->stream = NULL;
-  state->lasterr = err;
-  return err;
+  goto cleanup;
 }
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 33ef794..67bb12e 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -214,5 +214,9 @@ EXPORTS
  gpgrt_set_usage_outfnc       @164
  gpgrt_set_fixed_string_mapper  @165
 
+ gpgrt_b64enc_start           @166
+ gpgrt_b64enc_write           @167
+ gpgrt_b64enc_finish          @168
+
 
 ;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index c0656e2..a36e8b1 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -908,16 +908,22 @@ int gpgrt_vsnprintf (char *buf,size_t bufsize,
 
 

 /*
- * Base64 decode functions.
+ * Base64 encode and decode functions.
  */
 
 struct _gpgrt_b64state;
 typedef struct _gpgrt_b64state *gpgrt_b64state_t;
 
+gpgrt_b64state_t gpgrt_b64enc_start (gpgrt_stream_t stream, const char *title);
+gpg_err_code_t   gpgrt_b64enc_write (gpgrt_b64state_t state,
+                                     const void *buffer, size_t nbytes);
+gpg_err_code_t   gpgrt_b64enc_finish (gpgrt_b64state_t state);
+
 gpgrt_b64state_t gpgrt_b64dec_start (const char *title);
-gpg_error_t gpgrt_b64dec_proc (gpgrt_b64state_t state,
-                               void *buffer, size_t length, size_t *r_nbytes);
-gpg_error_t gpgrt_b64dec_finish (gpgrt_b64state_t state);
+gpg_error_t      gpgrt_b64dec_proc (gpgrt_b64state_t state,
+                                    void *buffer, size_t length,
+                                    size_t *r_nbytes);
+gpg_error_t      gpgrt_b64dec_finish (gpgrt_b64state_t state);
 
 
 

diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index c7de3c4..201b784 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -186,6 +186,11 @@ GPG_ERROR_1.0 {
     gpgrt_set_usage_outfnc;
     gpgrt_set_fixed_string_mapper;
 
+    gpgrt_b64enc_start;
+    gpgrt_b64enc_write;
+    gpgrt_b64enc_finish;
+
+
   local:
     *;
 };
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 5d54a51..34e494c 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -480,10 +480,30 @@ int _gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout);
  * Local prototypes for the encoders.
  */
 
+struct _gpgrt_b64state
+{
+  int idx;
+  int quad_count;
+  estream_t stream;
+  char *title;
+  unsigned char radbuf[4];
+  unsigned int crc;
+  gpg_err_code_t lasterr;
+  unsigned int flags;
+  int stop_seen:1;
+  int invalid_encoding:1;
+  int using_decoder:1;
+};
+
+gpgrt_b64state_t _gpgrt_b64enc_start (estream_t stream, const char *title);
+gpg_err_code_t   _gpgrt_b64enc_write (gpgrt_b64state_t state,
+                                      const void *buffer, size_t nbytes);
+gpg_err_code_t   _gpgrt_b64enc_finish (gpgrt_b64state_t state);
+
 gpgrt_b64state_t _gpgrt_b64dec_start (const char *title);
-gpg_error_t _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer,
-                                size_t length, size_t *r_nbytes);
-gpg_error_t _gpgrt_b64dec_finish (gpgrt_b64state_t state);
+gpg_err_code_t _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer,
+                                   size_t length, size_t *r_nbytes);
+gpg_err_code_t _gpgrt_b64dec_finish (gpgrt_b64state_t state);
 
 
 

diff --git a/src/visibility.c b/src/visibility.c
index 315bf32..6f8bb24 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -790,6 +790,24 @@ gpgrt_getcwd (void)
 
 

 gpgrt_b64state_t
+gpgrt_b64enc_start (estream_t stream, const char *title)
+{
+  return _gpgrt_b64enc_start (stream, title);
+}
+
+gpg_err_code_t
+gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes)
+{
+  return _gpgrt_b64enc_write (state, buffer, nbytes);
+}
+
+gpg_err_code_t
+gpgrt_b64enc_finish (gpgrt_b64state_t state)
+{
+  return _gpgrt_b64enc_finish (state);
+}
+
+gpgrt_b64state_t
 gpgrt_b64dec_start (const char *title)
 {
   return _gpgrt_b64dec_start (title);
diff --git a/src/visibility.h b/src/visibility.h
index eae0f81..cfa32e5 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -161,6 +161,9 @@ MARK_VISIBLE (gpgrt_getcwd)
 MARK_VISIBLE (gpgrt_b64dec_start)
 MARK_VISIBLE (gpgrt_b64dec_proc)
 MARK_VISIBLE (gpgrt_b64dec_finish)
+MARK_VISIBLE (gpgrt_b64enc_start)
+MARK_VISIBLE (gpgrt_b64enc_write)
+MARK_VISIBLE (gpgrt_b64enc_finish)
 
 MARK_VISIBLE (gpgrt_get_errorcount)
 MARK_VISIBLE (gpgrt_inc_errorcount)
@@ -327,6 +330,9 @@ MARK_VISIBLE (gpgrt_set_usage_outfnc);
 #define gpgrt_get_syscall_clamp     _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_set_alloc_func        _gpgrt_USE_UNDERSCORED_FUNCTION
 
+#define gpgrt_b64enc_start          _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_b64enc_write          _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_b64enc_finish         _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_b64dec_start          _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_b64dec_proc           _gpgrt_USE_UNDERSCORED_FUNCTION
 #define gpgrt_b64dec_finish         _gpgrt_USE_UNDERSCORED_FUNCTION
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cc3a2ad..b14fdc8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,7 @@ endif
 
 gpg_error_lib = ../src/libgpg-error.la
 
-TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64dec \
+TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64 \
 	t-argparse
 
 AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes)
diff --git a/tests/t-b64.c b/tests/t-b64.c
new file mode 100644
index 0000000..96e8fa4
--- /dev/null
+++ b/tests/t-b64.c
@@ -0,0 +1,373 @@
+/* t-b64.c - b64dec tests.
+ * Copyright (C) 2017, 2018 g10 Code GmbH
+ *
+ * This file is part of Libgpg-error.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#define PGM "t-b64"
+#include "t-common.h"
+
+static const char *test_string = "libgpg-error is free software; "
+  "you can redistribute it and/or modify it under the terms of "
+  "the GNU Lesser General Public License as published by the Free "
+  "Software Foundation; either version 2.1 of the License, or "
+  "(at your option) any later version.";
+
+static const char *test_string_b64_0 = "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29"
+  "mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgd"
+  "W5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIEx"
+  "pY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb"
+  "247IGVpdGhlciB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXI"
+  "gb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4=";
+
+static const char *test_string_b64_1 =
+  "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n"
+  "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n"
+  "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n"
+  "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n"
+  "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n"
+  "dmVyc2lvbi4=\n";
+
+static const char *test_string_b64_2 =
+  "-----BEGIN DATA-----\n"
+  "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n"
+  "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n"
+  "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n"
+  "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n"
+  "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n"
+  "dmVyc2lvbi4=\n"
+  "-----END DATA-----\n";
+
+static const char *test_string_b64_3 =
+  "-----BEGIN PGP ARMORED FILE-----\n"
+  "\n"
+  "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n"
+  "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n"
+  "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n"
+  "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n"
+  "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n"
+  "dmVyc2lvbi4=\n"
+  "=4BMJ\n"
+  "-----END PGP ARMORED FILE-----\n";
+
+static const char *test_blob_1 = "\x01\x03\x04\xff";
+static const char *test_blob_1_b64_0 = "AQME/w==";
+static const char *test_blob_2 = "\x01\x03\x04\xff""A";
+static const char *test_blob_2_b64_0 = "AQME/0E=";
+static const char *test_blob_3 = "\x01\x03\x04\xff""AB";
+static const char *test_blob_3_b64_0 = "AQME/0FC";
+
+
+#define FAIL(a)  do { fail ("line %d: test %d failed\n", __LINE__, (a));  \
+                    } while(0)
+
+static gpg_error_t
+test_b64enc_string (const char *string, const char *expected, const char *title)
+{
+  gpg_err_code_t err;
+  estream_t fp;
+  gpgrt_b64state_t state;
+  char *result;
+
+  fp = es_fopenmem (0, "rwb");
+  if (!fp)
+    die ("es_fopenmem failed: %s\n", gpg_strerror (gpg_error_from_syserror ()));
+
+  state = gpgrt_b64enc_start (fp, title);
+  if (!state)
+    {
+      err = gpg_err_code_from_syserror ();
+      fail ("gpgrt_b64enc_start failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = gpgrt_b64enc_write (state, string, strlen (string));
+  if (err)
+    {
+      fail ("gpgrt_b64enc_write failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = gpgrt_b64enc_finish (state);
+  if (err)
+    {
+      fail ("gpgrt_b64enc_finish failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  es_fputc (0, fp);
+  if (es_fclose_snatch (fp, (void**)&result, NULL))
+    die ("es_fclose_snatch failed: %s\n",
+         gpg_strerror (gpg_error_from_syserror ()));
+
+  if (strcmp (result, expected))
+    {
+      if (verbose)
+        {
+          gpgrt_log_debug_string (result,   "result: ");
+          gpgrt_log_debug_string (expected, "expect: ");
+        }
+      return GPG_ERR_FALSE;
+    }
+
+  es_free (result);
+  return 0;
+}
+
+
+static gpg_error_t
+test_b64dec_string (const char *string, const char *expected, const char *title)
+{
+  gpg_error_t err;
+  gpgrt_b64state_t state;
+  char *buffer;
+  size_t len;
+
+  len = strlen (string);
+  buffer = malloc (strlen (string) + 1);
+  if (!buffer)
+    {
+      err = gpg_error_from_syserror ();
+      return err;
+    }
+  strcpy (buffer, string);
+
+  state = gpgrt_b64dec_start (title);
+  if (!state)
+    {
+      err = gpg_err_code_from_syserror ();
+      fail ("gpgrt_b64dec_start failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = gpgrt_b64dec_proc (state, buffer, len, &len);
+  if (err)
+    {
+      if (gpg_err_code (err) != GPG_ERR_EOF)
+        {
+          free (buffer);
+          free (state);
+          return err;
+        }
+    }
+
+  err = gpgrt_b64dec_finish (state);
+  if (err)
+    {
+      free (buffer);
+      return err;
+    }
+
+  if (len != strlen (expected) || strncmp (buffer, expected, len))
+    {
+      if (verbose)
+        {
+          gpgrt_log_debug_string (buffer,   "result(len=%zu): ", len);
+          gpgrt_log_debug_string (expected, "expect(len=%zu): ",
+                                  strlen (expected));
+        }
+      return GPG_ERR_FALSE;
+    }
+
+  free (buffer);
+  return 0;
+}
+
+
+static void
+encoder_tests (void)
+{
+  gpg_err_code_t err;
+
+  if (verbose)
+    show ("running encoder tests\n");
+
+  err = test_b64enc_string (test_string, test_string_b64_0, "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string (test_string, test_string_b64_1, NULL);
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string (test_string, test_string_b64_2, "DATA");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string (test_string, test_string_b64_3, "PGP ARMORED FILE");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  /* Note that the _test_ function dows not allow to provide a string
+   * with an empdded Nul.  */
+  err = test_b64enc_string (test_blob_1, test_blob_1_b64_0, "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string (test_blob_2, test_blob_2_b64_0, "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string (test_blob_3, test_blob_3_b64_0, "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  err = test_b64enc_string ("@", "QA==", "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string ("@", "QA==\n", NULL);
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string ("@",
+                            "-----BEGIN PGP SOMETHING-----\n"
+                            "\n"
+                            "QA==\n"
+                            "=eMoB\n"
+                            "-----END PGP SOMETHING-----\n",
+                            "PGP SOMETHING");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  err = test_b64enc_string ("", "", "");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string ("", "", NULL);
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+  err = test_b64enc_string ("", "", "PGP SOMETHING");
+  if (err)
+    fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+}
+
+
+static void
+decoder_tests (void)
+{
+  gpg_err_code_t err;
+
+  if (verbose)
+    show ("running decoder tests\n");
+
+  err = test_b64dec_string (test_string_b64_0, test_string, NULL);
+  if (err)
+    fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  err = test_b64dec_string (test_string_b64_1, test_string, NULL);
+  if (err)
+    fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  err = test_b64dec_string (test_string_b64_2, test_string, "");
+  if (err)
+    fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+  err = test_b64dec_string (test_string_b64_2, test_string, NULL);
+  if (err != GPG_ERR_BAD_DATA)
+    fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err));
+
+}
+
+
+static gpg_error_t
+extra_tests (void)
+{
+  gpg_err_code_t err;
+  gpgrt_b64state_t state;
+
+  if (verbose)
+    show ("running extra tests\n");
+
+  /* Check that we detect mismacthed use of enc and dec functions.  */
+  state = gpgrt_b64enc_start (es_stdout, NULL);
+  if (!state)
+    {
+      err = gpg_err_code_from_syserror ();
+      fail ("gpgrt_b64enc_start failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = gpgrt_b64dec_finish (state);
+  if (err != GPG_ERR_CONFLICT)
+    {
+      fail ("gpgrt_b64dec_finish failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  state = gpgrt_b64dec_start (NULL);
+  if (!state)
+    {
+      err = gpg_err_code_from_syserror ();
+      fail ("gpgrt_b64dec_start failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = gpgrt_b64enc_finish (state);
+  if (err != GPG_ERR_CONFLICT)
+    {
+      fail ("gpgrt_b64enc_finish failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  return 0;
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--help"))
+        {
+          puts (
+"usage: ./" PGM " [options]\n"
+"\n"
+"Options:\n"
+"  --verbose      Show what is going on\n"
+"  --debug        Flyswatter\n"
+);
+          exit (0);
+        }
+      if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--; argv++;
+        }
+    }
+
+  encoder_tests ();
+  decoder_tests ();
+  extra_tests ();
+
+  return !!errorcount;
+}
diff --git a/tests/t-b64dec.c b/tests/t-b64dec.c
deleted file mode 100644
index aae208b..0000000
--- a/tests/t-b64dec.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* t-b64dec.c - b64dec test.
-   Copyright (C) 2017 g10 Code GmbH
-
-   This file is part of libgpg-error.
-
-   libgpg-error is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License
-   as published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libgpg-error is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with libgpgme-error; if not, write to the Free
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
-
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include <gpg-error.h>
-
-static const char *test_b64_string = "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29"
-  "mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgd"
-  "W5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIEx"
-  "pY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb"
-  "247IGVpdGhlciB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXI"
-  "gb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4=";
-
-static const char *test_string = "libgpg-error is free software; "
-  "you can redistribute it and/or modify it under the terms of "
-  "the GNU Lesser General Public License as published by the Free "
-  "Software Foundation; either version 2.1 of the License, or "
-  "(at your option) any later version.";
-
-#define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
-                               __FILE__,__LINE__, (a));          \
-                     errcount++;                                 \
-                   } while(0)
-
-static int errcount;
-
-static gpg_error_t
-test_b64dec_string (const char *string, const char *expected)
-{
-  gpg_error_t err;
-  gpgrt_b64state_t state;
-  char *buffer;
-  size_t len;
-
-  len = strlen (string);
-  buffer = malloc (strlen (string) + 1);
-  if (!buffer)
-    {
-      err = gpg_error_from_syserror ();
-      return err;
-    }
-
-  state = gpgrt_b64dec_start ("");
-  if (!state)
-    {
-      err = gpg_error_from_syserror ();
-      free (buffer);
-      return err;
-    }
-
-  err = gpgrt_b64dec_proc (state, buffer, len, &len);
-  if (err)
-    {
-      if (gpg_err_code (err) != GPG_ERR_EOF)
-        {
-          free (buffer);
-          free (state);
-          return err;
-        }
-    }
-
-  err = gpgrt_b64dec_finish (state);
-  if (err)
-    {
-      free (buffer);
-      return err;
-    }
-
-  if (strncmp (buffer, expected, len) == 0)
-    err = 0;
-  else
-    err = GPG_ERR_INTERNAL;
-
-  free (buffer);
-  return err;
-}
-
-
-
-int
-main (int argc, char **argv)
-{
-  gpg_error_t err;
-
-  (void)argc;
-  (void)argv;
-
-  err = test_b64dec_string (test_b64_string, test_string);
-
-  if (err)
-    {
-      fail (1);
-      return 1;
-    }
-  else
-    return 0;
-}

commit b3df10d6620894bc4047af1e14239b258e440803
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Mar 22 08:26:51 2018 +0100

    core: Add file b64enc.c from gnupg
    
    --
    
    This is from GnuPG commit fa0ed1c7e2eee7c559026696e6b21acc882a97aa
    with two tabs replaced by spaces.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/b64enc.c b/src/b64enc.c
new file mode 100644
index 0000000..91960c7
--- /dev/null
+++ b/src/b64enc.c
@@ -0,0 +1,422 @@
+/* b64enc.c - Simple Base64 encoder.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ *               2011 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ *               2011 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "i18n.h"
+#include "util.h"
+
+#define B64ENC_DID_HEADER   1
+#define B64ENC_DID_TRAILER  2
+#define B64ENC_NO_LINEFEEDS 16
+#define B64ENC_USE_PGPCRC   32
+
+/* The base-64 character list */
+static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                    "abcdefghijklmnopqrstuvwxyz"
+                                    "0123456789+/";
+
+/* Stuff required to create the OpenPGP CRC.  This crc_table has been
+   created using this code:
+
+   #include <stdio.h>
+   #include <stdint.h>
+
+   #define CRCPOLY 0x864CFB
+
+   int
+   main (void)
+   {
+     int i, j;
+     uint32_t t;
+     uint32_t crc_table[256];
+
+     crc_table[0] = 0;
+     for (i=j=0; j < 128; j++ )
+       {
+         t = crc_table[j];
+         if ( (t & 0x00800000) )
+           {
+             t <<= 1;
+             crc_table[i++] = t ^ CRCPOLY;
+             crc_table[i++] = t;
+       }
+         else
+           {
+             t <<= 1;
+             crc_table[i++] = t;
+             crc_table[i++] = t ^ CRCPOLY;
+           }
+       }
+
+     puts ("static const u32 crc_table[256] = {");
+     for (i=j=0; i < 256; i++)
+       {
+         printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
+         if (i != 255)
+           {
+             putchar (',');
+             if ( ++j > 5)
+               {
+                 j = 0;
+                 putchar ('\n');
+               }
+           }
+       }
+     puts ("\n};");
+     return 0;
+   }
+*/
+#define CRCINIT 0xB704CE
+static const u32 crc_table[256] = {
+  0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
+  0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
+  0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
+  0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
+  0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
+  0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
+  0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
+  0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
+  0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
+  0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
+  0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
+  0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
+  0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
+  0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
+  0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
+  0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
+  0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
+  0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
+  0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
+  0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
+  0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
+  0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
+  0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
+  0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
+  0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
+  0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
+  0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
+  0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
+  0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
+  0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
+  0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
+  0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
+  0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
+  0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
+  0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
+  0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
+  0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
+  0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
+  0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
+  0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
+  0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
+  0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
+  0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
+};
+
+
+static gpg_error_t
+enc_start (struct b64state *state, FILE *fp, estream_t stream,
+           const char *title)
+{
+  memset (state, 0, sizeof *state);
+  state->fp = fp;
+  state->stream = stream;
+  state->lasterr = 0;
+  if (title && !*title)
+    state->flags |= B64ENC_NO_LINEFEEDS;
+  else if (title)
+    {
+      if (!strncmp (title, "PGP ", 4))
+        {
+          state->flags |= B64ENC_USE_PGPCRC;
+          state->crc = CRCINIT;
+        }
+      state->title = xtrystrdup (title);
+      if (!state->title)
+        state->lasterr = gpg_error_from_syserror ();
+    }
+  return state->lasterr;
+}
+
+
+/* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
+   and not an empty string, this string will be used as the title for
+   the armor lines, with TITLE being an empty string, we don't write
+   the header lines and furthermore even don't write any linefeeds.
+   If TITLE starts with "PGP " the OpenPGP CRC checksum will be
+   written as well.  With TITLE being NULL, we merely don't write
+   header but make sure that lines are not too long. Note, that we
+   don't write any output unless at least one byte get written using
+   b64enc_write. */
+gpg_error_t
+b64enc_start (struct b64state *state, FILE *fp, const char *title)
+{
+  return enc_start (state, fp, NULL, title);
+}
+
+/* Same as b64enc_start but takes an estream.  */
+gpg_error_t
+b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
+{
+  return enc_start (state, NULL, fp, title);
+}
+
+
+static int
+my_fputs (const char *string, struct b64state *state)
+{
+  if (state->stream)
+    return es_fputs (string, state->stream);
+  else
+    return fputs (string, state->fp);
+}
+
+
+/* Write NBYTES from BUFFER to the Base 64 stream identified by
+   STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
+   stream. */
+gpg_error_t
+b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
+{
+  unsigned char radbuf[4];
+  int idx, quad_count;
+  const unsigned char *p;
+
+  if (state->lasterr)
+    return state->lasterr;
+
+  if (!nbytes)
+    {
+      if (buffer)
+        if (state->stream? es_fflush (state->stream) : fflush (state->fp))
+          goto write_error;
+      return 0;
+    }
+
+  if (!(state->flags & B64ENC_DID_HEADER))
+    {
+      if (state->title)
+        {
+          if ( my_fputs ("-----BEGIN ", state) == EOF
+               || my_fputs (state->title, state) == EOF
+               || my_fputs ("-----\n", state) == EOF)
+            goto write_error;
+          if ( (state->flags & B64ENC_USE_PGPCRC)
+               && my_fputs ("\n", state) == EOF)
+            goto write_error;
+        }
+
+      state->flags |= B64ENC_DID_HEADER;
+    }
+
+  idx = state->idx;
+  quad_count = state->quad_count;
+  assert (idx < 4);
+  memcpy (radbuf, state->radbuf, idx);
+
+  if ( (state->flags & B64ENC_USE_PGPCRC) )
+    {
+      size_t n;
+      u32 crc = state->crc;
+
+      for (p=buffer, n=nbytes; n; p++, n-- )
+        crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
+      state->crc = (crc & 0x00ffffff);
+    }
+
+  for (p=buffer; nbytes; p++, nbytes--)
+    {
+      radbuf[idx++] = *p;
+      if (idx > 2)
+        {
+          char tmp[4];
+
+          tmp[0] = bintoasc[(*radbuf >> 2) & 077];
+          tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
+          tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+          tmp[3] = bintoasc[radbuf[2]&077];
+          if (state->stream)
+            {
+              for (idx=0; idx < 4; idx++)
+                es_putc (tmp[idx], state->stream);
+              idx = 0;
+              if (es_ferror (state->stream))
+                goto write_error;
+            }
+          else
+            {
+              for (idx=0; idx < 4; idx++)
+                putc (tmp[idx], state->fp);
+              idx = 0;
+              if (ferror (state->fp))
+                goto write_error;
+            }
+          if (++quad_count >= (64/4))
+            {
+              quad_count = 0;
+              if (!(state->flags & B64ENC_NO_LINEFEEDS)
+                  && my_fputs ("\n", state) == EOF)
+                goto write_error;
+            }
+        }
+    }
+  memcpy (state->radbuf, radbuf, idx);
+  state->idx = idx;
+  state->quad_count = quad_count;
+  return 0;
+
+ write_error:
+  state->lasterr = gpg_error_from_syserror ();
+  if (state->title)
+    {
+      xfree (state->title);
+      state->title = NULL;
+    }
+  return state->lasterr;
+}
+
+
+gpg_error_t
+b64enc_finish (struct b64state *state)
+{
+  gpg_error_t err = 0;
+  unsigned char radbuf[4];
+  int idx, quad_count;
+  char tmp[4];
+
+  if (state->lasterr)
+    return state->lasterr;
+
+  if (!(state->flags & B64ENC_DID_HEADER))
+    goto cleanup;
+
+  /* Flush the base64 encoding */
+  idx = state->idx;
+  quad_count = state->quad_count;
+  assert (idx < 4);
+  memcpy (radbuf, state->radbuf, idx);
+
+  if (idx)
+    {
+      tmp[0] = bintoasc[(*radbuf>>2)&077];
+      if (idx == 1)
+        {
+          tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
+          tmp[2] = '=';
+          tmp[3] = '=';
+        }
+      else
+        {
+          tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+          tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
+          tmp[3] = '=';
+        }
+      if (state->stream)
+        {
+          for (idx=0; idx < 4; idx++)
+            es_putc (tmp[idx], state->stream);
+          if (es_ferror (state->stream))
+            goto write_error;
+        }
+      else
+        {
+          for (idx=0; idx < 4; idx++)
+            putc (tmp[idx], state->fp);
+          if (ferror (state->fp))
+            goto write_error;
+        }
+
+      if (++quad_count >= (64/4))
+        {
+          quad_count = 0;
+          if (!(state->flags & B64ENC_NO_LINEFEEDS)
+              && my_fputs ("\n", state) == EOF)
+            goto write_error;
+        }
+    }
+
+  /* Finish the last line and write the trailer. */
+  if (quad_count
+      && !(state->flags & B64ENC_NO_LINEFEEDS)
+      && my_fputs ("\n", state) == EOF)
+    goto write_error;
+
+  if ( (state->flags & B64ENC_USE_PGPCRC) )
+    {
+      /* Write the CRC.  */
+      my_fputs ("=", state);
+      radbuf[0] = state->crc >>16;
+      radbuf[1] = state->crc >> 8;
+      radbuf[2] = state->crc;
+      tmp[0] = bintoasc[(*radbuf>>2)&077];
+      tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+      tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+      tmp[3] = bintoasc[radbuf[2]&077];
+      if (state->stream)
+        {
+          for (idx=0; idx < 4; idx++)
+            es_putc (tmp[idx], state->stream);
+          if (es_ferror (state->stream))
+            goto write_error;
+        }
+      else
+        {
+          for (idx=0; idx < 4; idx++)
+            putc (tmp[idx], state->fp);
+          if (ferror (state->fp))
+            goto write_error;
+        }
+      if (!(state->flags & B64ENC_NO_LINEFEEDS)
+          && my_fputs ("\n", state) == EOF)
+        goto write_error;
+    }
+
+  if (state->title)
+    {
+      if ( my_fputs ("-----END ", state) == EOF
+           || my_fputs (state->title, state) == EOF
+           || my_fputs ("-----\n", state) == EOF)
+        goto write_error;
+    }
+
+  goto cleanup;
+
+ write_error:
+  err = gpg_error_from_syserror ();
+
+ cleanup:
+  if (state->title)
+    {
+      xfree (state->title);
+      state->title = NULL;
+    }
+  state->fp = NULL;
+  state->stream = NULL;
+  state->lasterr = err;
+  return err;
+}

-----------------------------------------------------------------------

Summary of changes:
 NEWS                 |  15 +-
 doc/yat2m.c          |  15 +-
 src/Makefile.am      |   2 +-
 src/argparse.c       |  42 ------
 src/b64dec.c         |  43 +++---
 src/b64enc.c         | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gpg-error.def.in |   4 +
 src/gpg-error.h.in   |  14 +-
 src/gpg-error.vers   |   5 +
 src/gpgrt-int.h      |  26 +++-
 src/visibility.c     |  18 +++
 src/visibility.h     |   6 +
 tests/Makefile.am    |   2 +-
 tests/t-argparse.c   |   3 +-
 tests/t-b64.c        | 373 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/t-b64dec.c     | 123 ----------------
 16 files changed, 869 insertions(+), 208 deletions(-)
 create mode 100644 src/b64enc.c
 create mode 100644 tests/t-b64.c
 delete mode 100644 tests/t-b64dec.c


hooks/post-receive
-- 
Error codes used by GnuPG et al.
http://git.gnupg.org




More information about the Gnupg-commits mailing list