/* base64.c -- Encode binary data using printable characters.
- Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006 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
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. */
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* FAIL: input too long
* if (out == NULL)
* FAIL: memory allocation error
- * OK: data in OUT/LEN.
+ * OK: data in OUT/OUTLEN.
*
*/
/* Get malloc. */
#include <stdlib.h>
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
/* C89 compliant way to cast 'char' to 'unsigned char'. */
static inline unsigned char
to_uchar (char ch)
base64_encode (const char *restrict in, size_t inlen,
char *restrict out, size_t outlen)
{
- const char b64[64] =
+ static const char b64str[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
while (inlen && outlen)
{
- *out++ = b64[to_uchar (in[0]) >> 2];
+ *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
- *out++ = b64[((to_uchar (in[0]) << 4)
- + (--inlen ? to_uchar (in[1]) >> 4 : 0)) & 0x3f];
+ *out++ = b64str[((to_uchar (in[0]) << 4)
+ + (--inlen ? to_uchar (in[1]) >> 4 : 0))
+ & 0x3f];
if (!--outlen)
break;
*out++ =
(inlen
- ? b64[((to_uchar (in[1]) << 2)
- + (--inlen ? to_uchar (in[2]) >> 6 : 0)) & 0x3f] : '=');
+ ? b64str[((to_uchar (in[1]) << 2)
+ + (--inlen ? to_uchar (in[2]) >> 6 : 0))
+ & 0x3f]
+ : '=');
if (!--outlen)
break;
- *out++ = inlen ? b64[to_uchar (in[2]) & 0x3f] : '=';
+ *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
if (!--outlen)
break;
if (inlen)
inlen--;
- in += 3;
+ if (inlen)
+ in += 3;
}
if (outlen)
return, the OUT variable will hold a pointer to newly allocated
memory that must be deallocated by the caller. If output string
length would overflow, 0 is returned and OUT is set to NULL. If
- memory allocation fail, OUT is set to NULL, and the return value
- indicate length of the requested memory block, i.e.,
+ memory allocation failed, OUT is set to NULL, and the return value
+ indicates length of the requested memory block, i.e.,
BASE64_LENGTH(inlen) + 1. */
size_t
base64_encode_alloc (const char *in, size_t inlen, char **out)
}
*out = malloc (outlen);
- if (*out)
- base64_encode (in, inlen, *out, outlen);
+ if (!*out)
+ return outlen;
+
+ base64_encode (in, inlen, *out, outlen);
return outlen - 1;
}
B64 (252), B64 (253), B64 (254), B64 (255)
};
-static inline bool
-isb64 (unsigned char ch)
+#if UCHAR_MAX == 255
+# define uchar_in_range(c) true
+#else
+# define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base64 alphabet, and
+ false otherwise. Note that '=' is padding and not considered to be
+ part of the alphabet. */
+bool
+isbase64 (char ch)
{
- return ch <= 255 && 0 <= b64[ch];
+ return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
}
/* Decode base64 encoded input array IN of length INLEN to output
otherwise. If *OUTLEN is too small, as many bytes as possible will
be written to OUT. On return, *OUTLEN holds the length of decoded
bytes in OUT. Note that as soon as any non-alphabet characters are
- encountered, decoding is stopped and false is returned. */
+ encountered, decoding is stopped and false is returned. This means
+ that, when applicable, you must de-fold any CRLF that is part of
+ the data stream before calling this function. */
bool
base64_decode (const char *restrict in, size_t inlen,
- char *restrict out, size_t * outlen)
+ char *restrict out, size_t *outlen)
{
size_t outleft = *outlen;
while (inlen >= 2)
{
- if (!isb64 (in[0]) || !isb64 (in[1]))
+ if (!isbase64 (in[0]) || !isbase64 (in[1]))
break;
if (outleft)
}
else
{
- if (!isb64 (in[2]))
+ if (!isbase64 (in[2]))
break;
if (outleft)
}
else
{
- if (!isb64 (in[3]))
+ if (!isbase64 (in[3]))
break;
if (outleft)
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
if the caller is not interested in the decoded length. *OUT may be
NULL to indicate an out of memory error, in which case *OUTLEN
- contain the size of the memory block needed. The function return
+ contains the size of the memory block needed. The function returns
true on successful decoding and memory allocation errors. (Use the
*OUT and *OUTLEN parameters to differentiate between successful
- decoding and memory error.) The function return false if the input
- was invalid, in which case *OUT is NULL and *OUTLEN is
+ decoding and memory error.) The function returns false if the
+ input was invalid, in which case *OUT is NULL and *OUTLEN is
undefined. */
bool
base64_decode_alloc (const char *in, size_t inlen, char **out,
- size_t * outlen)
+ size_t *outlen)
{
/* This may allocate a few bytes too much, depending on input,
but it's not worth the extra CPU time to compute the exact amount.