[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-gnulib] Re: base64
From: |
Simon Josefsson |
Subject: |
[bug-gnulib] Re: base64 |
Date: |
Thu, 25 Nov 2004 14:40:01 +0100 |
User-agent: |
Gnus/5.110003 (No Gnus v0.3) Emacs/21.3.50 (gnu/linux) |
Bruno Haible <address@hidden> writes:
>> +#define BASE64_LENGTH(inlen) (((4 - (inlen) % 3) % 4) + (4 * (inlen) / 3))
>
> This is overly complex. You can also write it as
> ((inlen) + 2) / 3) * 4
I don't think that give the same result, try tabulating the two macros
for, say, inlen = 0...15.
>> + while (inlen && outlen)
>> + {
>> + if (outlen--)
>> + *optr++ = b64[iptr[0] >> 2];
>> + if (outlen--)
>> + *optr++ = b64[((iptr[0] << 4) +
>> + (--inlen ? (iptr[1] >> 4) : 0)) & 0x3f];
>> + if (outlen--)
>> + *optr++ = inlen ? b64[((iptr[1] << 2) +
>> + (--inlen ? (iptr[2] >> 6) : 0)) & 0x3f] : '=';
>> + if (outlen--)
>> + *optr++ = inlen ? b64[iptr[2] & 0x3f] : '=';
>> + if (inlen)
>> + inlen--;
>> + iptr += 3;
>> + }
>> +
>> + if (outlen)
>> + *optr = '\0';
>
> If outlen becomes zero in the loop, it continues to be decremented
> nevertheless, so that at the end of the loop it has the value
> 0xffffffff or 0xfffffffe or 0xfffffffd, and the final '\0' is stored
> where it shouldn't.
Ah, thanks, adding those checks was the last thing I did, and it seems
they were broken. New version below.
Index: MODULES.html.sh
===================================================================
RCS file: /cvsroot/gnulib/gnulib/MODULES.html.sh,v
retrieving revision 1.68
diff -u -p -r1.68 MODULES.html.sh
--- MODULES.html.sh 12 Nov 2004 00:00:47 -0000 1.68
+++ MODULES.html.sh 25 Nov 2004 13:40:31 -0000
@@ -1605,6 +1605,7 @@ func_all_modules ()
func_echo "$element"
func_begin_table
+ func_module base64
func_module diacrit
func_module getline
func_module getnline
Index: lib/base64.c
===================================================================
RCS file: lib/base64.c
diff -N lib/base64.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/base64.c 25 Nov 2004 13:40:31 -0000
@@ -0,0 +1,197 @@
+/* base64.c -- Encode binary data using printable characters.
+ Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Portions adapted from GNU MailUtils, by Simon Josefsson. For more
+ information, see RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>. */
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get prototype. */
+#include "base64.h"
+
+/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+ If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
+ possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
+ terminate the output buffer. */
+void
+base64_encode (const char *in, size_t inlen, char *out, size_t outlen)
+{
+ const char *b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const unsigned char *iptr = (const unsigned char *) in;
+ unsigned char *optr = (unsigned char *) out;
+
+ while (inlen && outlen)
+ {
+ *optr++ = b64[iptr[0] >> 2];
+ if (!--outlen)
+ break;
+ *optr++ = b64[((iptr[0] << 4) + (--inlen ? (iptr[1] >> 4) : 0)) & 0x3f];
+ if (!--outlen)
+ break;
+ *optr++ = inlen ? b64[((iptr[1] << 2) +
+ (--inlen ? (iptr[2] >> 6) : 0)) & 0x3f] : '=';
+ if (!--outlen)
+ break;
+ *optr++ = inlen ? b64[iptr[2] & 0x3f] : '=';
+ if (!--outlen)
+ break;
+ if (inlen)
+ inlen--;
+ iptr += 3;
+ }
+
+ if (outlen)
+ *optr = '\0';
+}
+
+/* Allocate a buffer and store zero terminated base64 encoded data
+ from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
+ the length of the encoded data, excluding the terminating zero. On
+ return, the OUT variable will hold a pointer to newly allocated
+ memory that must be deallocated by the caller, or NULL on memory
+ allocation failure. */
+size_t
+base64_encode_alloc (const char *in, size_t inlen, char **out)
+{
+ size_t outlen;
+
+ outlen = BASE64_LENGTH (inlen);
+ *out = malloc (outlen + 1);
+ if (!*out)
+ return outlen;
+
+ base64_encode (in, inlen, *out, outlen + 1);
+
+ return outlen;
+}
+
+/* Decode base64 encoded input array IN of length INLEN to output
+ array OUT that can hold *OUTLEN bytes. Return true if decoding was
+ successful, false otherwise. If *OUTLEN is too small, as many
+ bytes as possible will be written to OUT. On return, *OUTLEN holds
+ the length of decode bytes in OUT. Note that if any non-alphabet
+ characters are encountered, decoding is stopped and false is
+ returned. */
+bool
+base64_decode (const char *in, size_t inlen, char *out, size_t * outlen)
+{
+ static const signed char b64[0x100] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1,
+ -1, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ const unsigned char *iptr = (const unsigned char *) in;
+ unsigned char *optr = (unsigned char *) out;
+ size_t len = *outlen;
+
+ *outlen = 0;
+
+ while (inlen >= 2)
+ {
+ if (!len--)
+ return true;
+
+ if (b64[iptr[0]] < 0 || b64[iptr[1]] < 0)
+ return false;
+
+ *optr++ = (b64[iptr[0]] << 2) | (b64[iptr[1]] >> 4);
+ (*outlen)++;
+
+ if (inlen == 2)
+ return false;
+
+ if (iptr[2] == '=')
+ {
+ if (iptr[3] != '=')
+ return false;
+
+ if (inlen != 4)
+ return false;
+ }
+ else
+ {
+ if (!len--)
+ return true;
+
+ if (b64[iptr[2]] < 0)
+ return false;
+
+ *optr++ = ((b64[iptr[1]] << 4) & 0xf0) | (b64[iptr[2]] >> 2);
+ (*outlen)++;
+
+ if (inlen == 3)
+ return false;
+
+ if (iptr[3] == '=')
+ {
+ if (inlen != 4)
+ return false;
+ }
+ else
+ {
+ if (!len--)
+ return true;
+
+ if (b64[iptr[3]] < 0)
+ return false;
+
+ *optr++ = ((b64[iptr[2]] << 6) & 0xc0) | b64[iptr[3]];
+ (*outlen)++;
+ }
+ }
+ iptr += 4;
+ inlen -= 4;
+ }
+
+ if (inlen != 0)
+ return false;
+
+ return true;
+
+}
+
+/* Allocate an output buffer OUT, and decode the base64 encoded data
+ stored in IN of size INLEN. On return, the actual size of the
+ decoded data is stored in *OUTLEN. The function return true if
+ decoding was successful, or false on memory allocation or decoding
+ errors. */
+bool
+base64_decode_alloc (const char *in, size_t inlen, char **out,
+ size_t * outlen)
+{
+ *outlen = 3 * inlen / 4; /* FIXME: May allocate one 1 or 2 bytes too
+ much, depending on input. */
+ *out = malloc (*outlen);
+ if (!*out)
+ return false;
+ return base64_decode (in, inlen, *out, outlen);
+}
Index: lib/base64.h
===================================================================
RCS file: lib/base64.h
diff -N lib/base64.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/base64.h 25 Nov 2004 13:40:31 -0000
@@ -0,0 +1,41 @@
+/* base64.h -- Encode binary data using printable characters.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Simon Josefsson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef BASE64_H
+# define BASE64_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get bool. */
+#include <stdbool.h>
+
+#define BASE64_LENGTH(inlen) (((4 - (inlen) % 3) % 4) + (4 * (inlen) / 3))
+
+extern void base64_encode (const char *in, size_t inlen,
+ char *out, size_t outlen);
+
+extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
+
+extern bool base64_decode (const char *in, size_t inlen,
+ char *out, size_t * outlen);
+
+extern bool base64_decode_alloc (const char *in, size_t inlen,
+ char **out, size_t * outlen);
+
+#endif /* BASE64_H */
Index: modules/base64
===================================================================
RCS file: modules/base64
diff -N modules/base64
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/base64 25 Nov 2004 13:40:31 -0000
@@ -0,0 +1,23 @@
+Description:
+Encode binary data using printable characters (base64).
+
+Files:
+lib/base64.h
+lib/base64.c
+
+Depends-on:
+stdbool
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += base64.h base64.c
+
+Include:
+"base64.h"
+
+License:
+LGPL
+
+Maintainer:
+Simon Josefsson
Index: tests/test-base64.c
===================================================================
RCS file: tests/test-base64.c
diff -N tests/test-base64.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/test-base64.c 25 Nov 2004 13:40:31 -0000
@@ -0,0 +1,158 @@
+#include <stdio.h>
+
+#include "base64.h"
+
+int
+main (int argc, char *argv[])
+{
+ const char *in = "abcdefghijklmnop";
+ const char *b64in = "YWJjZGVmZw==";
+ char out[255];
+ char *p;
+ size_t len;
+ bool ok;
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 0, out, 0);
+ if (out[0] != '\x42')
+ fprintf (stderr, "failure\n");
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 1, out, 1);
+ if (memcmp (out, "YQ==", 1) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 1, out, 2);
+ if (memcmp (out, "YQ==", 2) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 1, out, 3);
+ if (memcmp (out, "YQ==", 3) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 1, out, 4);
+ if (memcmp (out, "YQ==", 4) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 1, out, 8);
+ if (memcmp (out, "YQ==", 4) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 2, out, 4);
+ if (memcmp (out, "YWI=", 4) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 3, out, 4);
+ if (memcmp (out, "YWJj", 4) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 4, out, 5);
+ if (memcmp (out, "YWJjZA==", 5) != 0)
+ {
+ out[5] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ base64_encode (in, 4, out, 100);
+ if (memcmp (out, "YWJjZA==", 6) != 0)
+ {
+ out[6] = '\0';
+ fprintf (stderr, "failure (%s)\n", out);
+ }
+
+ /* Decode. */
+
+ memset (out, 0x42, sizeof (out));
+ len = 0;
+ ok = base64_decode (b64in, 4, out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 0)
+ fprintf (stderr, "failure (%d)\n", len);
+
+ memset (out, 0x42, sizeof (out));
+ len = 1;
+ ok = base64_decode (b64in, 4, out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 1 || memcmp (out, "abcdefg", 1) != 0)
+ {
+ out[2] = '\0';
+ fprintf (stderr, "failure (%d: %s)\n", len, out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ len = 2;
+ ok = base64_decode (b64in, 4, out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 2 || memcmp (out, "abcdefg", 2) != 0)
+ {
+ out[3] = '\0';
+ fprintf (stderr, "failure (%d: %s)\n", len, out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ len = 3;
+ ok = base64_decode (b64in, 4, out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 3 || memcmp (out, "abcdefg", 3) != 0)
+ {
+ out[4] = '\0';
+ fprintf (stderr, "failure (%d: %s)\n", len, out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ len = 4;
+ ok = base64_decode (b64in, 4, out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 3 || memcmp (out, "abcdefg", 3) != 0)
+ {
+ out[3] = '\0';
+ fprintf (stderr, "failure (%d: %s)\n", len, out);
+ }
+
+ memset (out, 0x42, sizeof (out));
+ len = 100;
+ ok = base64_decode (b64in, strlen (b64in), out, &len);
+ if (!ok)
+ fprintf (stderr, "decode failed\n");
+ if (len != 7 || memcmp (out, "abcdefg", 7) != 0)
+ {
+ out[7] = '\0';
+ fprintf (stderr, "failure (%d: %s)\n", len, out);
+ }
+
+ return 0;
+}
- [bug-gnulib] base64, Simon Josefsson, 2004/11/23
- Re: [bug-gnulib] base64, Bruno Haible, 2004/11/24
- [bug-gnulib] Re: base64,
Simon Josefsson <=
- Re: [bug-gnulib] Re: base64, Stepan Kasal, 2004/11/25
- Re: [bug-gnulib] Re: base64, Jim Meyering, 2004/11/25
- Re: [bug-gnulib] Re: base64, Stepan Kasal, 2004/11/25
- [bug-gnulib] Re: base64, Simon Josefsson, 2004/11/25
- Re: [bug-gnulib] Re: base64, Stepan Kasal, 2004/11/25
- [bug-gnulib] Re: base64, Simon Josefsson, 2004/11/25
- Re: [bug-gnulib] Re: base64, Bruno Haible, 2004/11/25
- Re: [bug-gnulib] Re: base64, Paul Eggert, 2004/11/26