[Pkg-gnupg-commit] [libgpg-error] 09/29: Add Base64 decoder.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Sun Mar 5 00:41:33 UTC 2017
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch master
in repository libgpg-error.
commit 4bfc2117b70415a5c5d3f0a0ac9086e168350d83
Author: NIIBE Yutaka <gniibe at fsij.org>
Date: Wed Feb 1 19:45:39 2017 +0900
Add Base64 decoder.
* NEWS: Add interface changes.
* src/Makefile.am (libgpg_error_la_SOURCES): Add b64dec.c.
* src/b64dec.c: New. Taken from gpgme. Prefix function names with
_gpgrt_. Change API a bit, not exposing the structure.
* src/gpg-error.def.in: Export Base64 functions.
* src/gpg-error.vers: Likewise.
* src/visibility.c, src/visibility.h: Likewise.
* src/gpg-error.h.in: Add Base64 struct and functions.
* src/gpgrt-int.h: Add Base64 internal functions.
* tests/Makefile.am (TESTS): Add t-b64dec.
* tests/t-b64dec.c: New.
Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
---
NEWS | 7 ++
src/Makefile.am | 2 +-
src/b64dec.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/gpg-error.def.in | 4 +
src/gpg-error.h.in | 10 ++
src/gpg-error.vers | 4 +
src/gpgrt-int.h | 6 ++
src/visibility.c | 19 ++++
src/visibility.h | 7 ++
tests/Makefile.am | 2 +-
tests/t-b64dec.c | 123 +++++++++++++++++++++++
11 files changed, 461 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 572385f..912dd0c 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,13 @@ Noteworthy changes in version 1.27 (unreleased) [C2_/A2_/R_]
* Fixed macro GPGRT_GCC_VERSION.
+ * Interface changes relative to the 1.26 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgrt_b64state_t NEW type.
+ gpgrt_b64dec_start NEW.
+ gpgrt_b64dec_proc NEW.
+ gpgrt_b64dec_finish NEW.
+
Noteworthy changes in version 1.26 (2016-12-21) [C21/A21/R0]
-----------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 1eb8287..d849c42 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -179,7 +179,7 @@ libgpg_error_la_SOURCES = gettext.h $(arch_sources) \
gpgrt-int.h init.c init.h version.c lock.h thread.h \
estream.c estream-printf.c estream-printf.h \
strsource.c strerror.c code-to-errno.c code-from-errno.c \
- visibility.c visibility.h
+ visibility.c visibility.h b64dec.c
nodist_libgpg_error_la_SOURCES = gpg-error.h
# libgpg_error_la_DEPENDENCIES = \
diff --git a/src/b64dec.c b/src/b64dec.c
new file mode 100644
index 0000000..d846a6a
--- /dev/null
+++ b/src/b64dec.c
@@ -0,0 +1,279 @@
+/* b64dec.c - Simple Base64 decoder.
+ * 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 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/>.
+ */
+
+#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] =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+enum decoder_states
+ {
+ s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
+ s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+ s_waitendtitle, s_waitend
+ };
+
+
+
+/* Allocate and initialize the context for the base64 decoder. If
+ TITLE is NULL a plain base64 decoding is done. If it is the empty
+ string the decoder will skip everything until a "-----BEGIN " line
+ has been seen, decoding ends at a "----END " line. */
+gpgrt_b64state_t
+_gpgrt_b64dec_start (const char *title)
+{
+ gpgrt_b64state_t state;
+ char *t = NULL;
+
+ if (title)
+ {
+ t = strdup (title);
+ if (!t)
+ return NULL;
+ }
+
+ state = calloc (1, sizeof (struct _gpgrt_b64state));
+ if (!state)
+ {
+ free (t);
+ return NULL;
+ }
+
+ if (t)
+ {
+ state->title = t;
+ state->idx = s_init;
+ }
+ else
+ state->idx = s_b64_0;
+
+ 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
+_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
+ size_t *r_nbytes)
+{
+ enum decoder_states ds = state->idx;
+ unsigned char val = state->radbuf[0];
+ int pos = state->quad_count;
+ char *d, *s;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (state->stop_seen)
+ {
+ *r_nbytes = 0;
+ state->lasterr = gpg_error (GPG_ERR_EOF);
+ free (state->title);
+ state->title = NULL;
+ return state->lasterr;
+ }
+
+ for (s=d=buffer; length && !state->stop_seen; length--, s++)
+ {
+ again:
+ switch (ds)
+ {
+ case s_idle:
+ if (*s == '\n')
+ {
+ ds = s_lfseen;
+ pos = 0;
+ }
+ break;
+ case s_init:
+ ds = s_lfseen;
+ case s_lfseen:
+ if (*s != "-----BEGIN "[pos])
+ {
+ ds = s_idle;
+ goto again;
+ }
+ else if (pos == 10)
+ {
+ pos = 0;
+ ds = s_beginseen;
+ }
+ else
+ pos++;
+ break;
+ case s_beginseen:
+ if (*s != "PGP "[pos])
+ ds = s_begin; /* Not a PGP armor. */
+ else if (pos == 3)
+ ds = s_waitheader;
+ else
+ pos++;
+ break;
+ case s_waitheader:
+ if (*s == '\n')
+ ds = s_waitblank;
+ break;
+ case s_waitblank:
+ if (*s == '\n')
+ ds = s_b64_0; /* blank line found. */
+ else if (*s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Ignore spaces. */
+ else
+ {
+ /* Armor header line. Note that we don't care that our
+ * FSM accepts a header prefixed with spaces. */
+ ds = s_waitheader; /* Wait for next header. */
+ }
+ break;
+ case s_begin:
+ if (*s == '\n')
+ ds = s_b64_0;
+ break;
+ case s_b64_0:
+ case s_b64_1:
+ case s_b64_2:
+ case s_b64_3:
+ {
+ int c;
+
+ if (*s == '-' && state->title)
+ {
+ /* Not a valid Base64 character: assume end
+ header. */
+ ds = s_waitend;
+ }
+ else if (*s == '=')
+ {
+ /* Pad character: stop */
+ if (ds == s_b64_1)
+ *d++ = val;
+ ds = state->title? s_waitendtitle : s_waitend;
+ }
+ else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Skip white spaces. */
+ else if ( (*s & 0x80)
+ || (c = asctobin[*(unsigned char *)s]) == 255)
+ {
+ /* Skip invalid encodings. */
+ state->invalid_encoding = 1;
+ }
+ else if (ds == s_b64_0)
+ {
+ val = c << 2;
+ ds = s_b64_1;
+ }
+ else if (ds == s_b64_1)
+ {
+ val |= (c>>4)&3;
+ *d++ = val;
+ val = (c<<4)&0xf0;
+ ds = s_b64_2;
+ }
+ else if (ds == s_b64_2)
+ {
+ val |= (c>>2)&15;
+ *d++ = val;
+ val = (c<<6)&0xc0;
+ ds = s_b64_3;
+ }
+ else
+ {
+ val |= c&0x3f;
+ *d++ = val;
+ ds = s_b64_0;
+ }
+ }
+ break;
+ case s_waitendtitle:
+ if (*s == '-')
+ ds = s_waitend;
+ break;
+ case s_waitend:
+ if ( *s == '\n')
+ state->stop_seen = 1;
+ break;
+ default:
+ assert (!"invalid state");
+ }
+ }
+
+
+ state->idx = ds;
+ state->radbuf[0] = val;
+ state->quad_count = pos;
+ *r_nbytes = (d -(char*) buffer);
+ return 0;
+}
+
+
+/* Return an error code in case an encoding error has been found
+ during decoding. */
+gpg_error_t
+_gpgrt_b64dec_finish (gpgrt_b64state_t state)
+{
+ gpg_error_t err;
+
+ if (state->lasterr)
+ err = state->lasterr;
+ else
+ {
+ free (state->title);
+ err = state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
+ }
+ free (state);
+
+ return err;
+}
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 19e87fa..ad65f8c 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -152,4 +152,8 @@ EXPORTS
gpgrt_get_syscall_clamp @112
+ gpgrt_b64dec_start @113
+ gpgrt_b64dec_proc @114
+ gpgrt_b64dec_finish @115
+
;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index c603314..19bdeed 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -853,6 +853,16 @@ int gpgrt_vsnprintf (char *buf,size_t bufsize,
# define es_bsprintf gpgrt_bsprintf
# define es_vbsprintf gpgrt_vbsprintf
#endif /*GPGRT_ENABLE_ES_MACROS*/
+
+/* Base64 decode functions. */
+
+struct _gpgrt_b64state;
+typedef struct _gpgrt_b64state *gpgrt_b64state_t;
+
+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);
#ifdef __cplusplus
}
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index 802ff3d..e44128c 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -126,6 +126,10 @@ GPG_ERROR_1.0 {
gpg_err_deinit;
gpgrt_set_alloc_func;
+ gpgrt_b64dec_start;
+ gpgrt_b64dec_proc;
+ gpgrt_b64dec_finish;
+
local:
*;
};
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index fba2585..d624e84 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -312,4 +312,10 @@ int _gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
int _gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout);
#endif
+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);
+
+
#endif /*_GPGRT_GPGRT_INT_H*/
diff --git a/src/visibility.c b/src/visibility.c
index 89b5623..b637e7a 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -711,3 +711,22 @@ gpgrt_vsnprintf (char *buf, size_t bufsize,
{
return _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr);
}
+
+gpgrt_b64state_t
+gpgrt_b64dec_start (const char *title)
+{
+ return _gpgrt_b64dec_start (title);
+}
+
+gpg_error_t
+gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer,
+ size_t length, size_t *r_nbytes)
+{
+ return _gpgrt_b64dec_proc (state, buffer, length, r_nbytes);
+}
+
+gpg_error_t
+gpgrt_b64dec_finish (gpgrt_b64state_t state)
+{
+ return _gpgrt_b64dec_finish (state);
+}
diff --git a/src/visibility.h b/src/visibility.h
index 479186f..da8e228 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -145,6 +145,10 @@ MARK_VISIBLE (gpgrt_set_syscall_clamp)
MARK_VISIBLE (gpgrt_get_syscall_clamp)
MARK_VISIBLE (gpgrt_set_alloc_func)
+MARK_VISIBLE (gpgrt_b64dec_start)
+MARK_VISIBLE (gpgrt_b64dec_proc)
+MARK_VISIBLE (gpgrt_b64dec_finish)
+
#undef MARK_VISIBLE
#else /*!_GPGRT_INCL_BY_VISIBILITY_C*/
@@ -255,6 +259,9 @@ MARK_VISIBLE (gpgrt_set_alloc_func)
#define gpgrt_get_syscall_clamp _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_set_alloc_func _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
#endif /*!_GPGRT_INCL_BY_VISIBILITY_C*/
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 92b97f2..a3c6cbd 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
+TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64dec
AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes)
diff --git a/tests/t-b64dec.c b/tests/t-b64dec.c
new file mode 100644
index 0000000..aae208b
--- /dev/null
+++ b/tests/t-b64dec.c
@@ -0,0 +1,123 @@
+/* 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;
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/libgpg-error.git
More information about the Pkg-gnupg-commit
mailing list