Allow for modules to show an arbitrary notice.
[gnulib.git] / lib / base64.c
index 98d933a..f237cd6 100644 (file)
@@ -1,5 +1,6 @@
 /* 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
@@ -13,7 +14,7 @@
 
    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.
  *
  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 /* Get prototype. */
 #include "base64.h"
@@ -50,6 +49,9 @@
 /* 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)
@@ -65,30 +67,34 @@ void
 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)
@@ -101,8 +107,8 @@ base64_encode (const char *restrict in, size_t inlen,
    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)
@@ -128,8 +134,10 @@ 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;
 }
@@ -139,72 +147,75 @@ base64_encode_alloc (const char *in, size_t inlen, char **out)
    Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255.  POSIX
    1003.1-2001 require that char and unsigned char are 8-bit
    quantities, though, taking care of that problem.  But this may be a
-   potential problem on non-POSIX C99 platforms.  */
-#define B64(x)                                 \
-  ((x) == 'A' ? 0                              \
-   : (x) == 'B' ? 1                            \
-   : (x) == 'C' ? 2                            \
-   : (x) == 'D' ? 3                            \
-   : (x) == 'E' ? 4                            \
-   : (x) == 'F' ? 5                            \
-   : (x) == 'G' ? 6                            \
-   : (x) == 'H' ? 7                            \
-   : (x) == 'I' ? 8                            \
-   : (x) == 'J' ? 9                            \
-   : (x) == 'K' ? 10                           \
-   : (x) == 'L' ? 11                           \
-   : (x) == 'M' ? 12                           \
-   : (x) == 'N' ? 13                           \
-   : (x) == 'O' ? 14                           \
-   : (x) == 'P' ? 15                           \
-   : (x) == 'Q' ? 16                           \
-   : (x) == 'R' ? 17                           \
-   : (x) == 'S' ? 18                           \
-   : (x) == 'T' ? 19                           \
-   : (x) == 'U' ? 20                           \
-   : (x) == 'V' ? 21                           \
-   : (x) == 'W' ? 22                           \
-   : (x) == 'X' ? 23                           \
-   : (x) == 'Y' ? 24                           \
-   : (x) == 'Z' ? 25                           \
-   : (x) == 'a' ? 26                           \
-   : (x) == 'b' ? 27                           \
-   : (x) == 'c' ? 28                           \
-   : (x) == 'd' ? 29                           \
-   : (x) == 'e' ? 30                           \
-   : (x) == 'f' ? 31                           \
-   : (x) == 'g' ? 32                           \
-   : (x) == 'h' ? 33                           \
-   : (x) == 'i' ? 34                           \
-   : (x) == 'j' ? 35                           \
-   : (x) == 'k' ? 36                           \
-   : (x) == 'l' ? 37                           \
-   : (x) == 'm' ? 38                           \
-   : (x) == 'n' ? 39                           \
-   : (x) == 'o' ? 40                           \
-   : (x) == 'p' ? 41                           \
-   : (x) == 'q' ? 42                           \
-   : (x) == 'r' ? 43                           \
-   : (x) == 's' ? 44                           \
-   : (x) == 't' ? 45                           \
-   : (x) == 'u' ? 46                           \
-   : (x) == 'v' ? 47                           \
-   : (x) == 'w' ? 48                           \
-   : (x) == 'x' ? 49                           \
-   : (x) == 'y' ? 50                           \
-   : (x) == 'z' ? 51                           \
-   : (x) == '0' ? 52                           \
-   : (x) == '1' ? 53                           \
-   : (x) == '2' ? 54                           \
-   : (x) == '3' ? 55                           \
-   : (x) == '4' ? 56                           \
-   : (x) == '5' ? 57                           \
-   : (x) == '6' ? 58                           \
-   : (x) == '7' ? 59                           \
-   : (x) == '8' ? 60                           \
-   : (x) == '9' ? 61                           \
-   : (x) == '+' ? 62                           \
-   : (x) == '/' ? 63                           \
+   potential problem on non-POSIX C99 platforms.
+
+   IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
+   as the formal parameter rather than "x".  */
+#define B64(_)                                 \
+  ((_) == 'A' ? 0                              \
+   : (_) == 'B' ? 1                            \
+   : (_) == 'C' ? 2                            \
+   : (_) == 'D' ? 3                            \
+   : (_) == 'E' ? 4                            \
+   : (_) == 'F' ? 5                            \
+   : (_) == 'G' ? 6                            \
+   : (_) == 'H' ? 7                            \
+   : (_) == 'I' ? 8                            \
+   : (_) == 'J' ? 9                            \
+   : (_) == 'K' ? 10                           \
+   : (_) == 'L' ? 11                           \
+   : (_) == 'M' ? 12                           \
+   : (_) == 'N' ? 13                           \
+   : (_) == 'O' ? 14                           \
+   : (_) == 'P' ? 15                           \
+   : (_) == 'Q' ? 16                           \
+   : (_) == 'R' ? 17                           \
+   : (_) == 'S' ? 18                           \
+   : (_) == 'T' ? 19                           \
+   : (_) == 'U' ? 20                           \
+   : (_) == 'V' ? 21                           \
+   : (_) == 'W' ? 22                           \
+   : (_) == 'X' ? 23                           \
+   : (_) == 'Y' ? 24                           \
+   : (_) == 'Z' ? 25                           \
+   : (_) == 'a' ? 26                           \
+   : (_) == 'b' ? 27                           \
+   : (_) == 'c' ? 28                           \
+   : (_) == 'd' ? 29                           \
+   : (_) == 'e' ? 30                           \
+   : (_) == 'f' ? 31                           \
+   : (_) == 'g' ? 32                           \
+   : (_) == 'h' ? 33                           \
+   : (_) == 'i' ? 34                           \
+   : (_) == 'j' ? 35                           \
+   : (_) == 'k' ? 36                           \
+   : (_) == 'l' ? 37                           \
+   : (_) == 'm' ? 38                           \
+   : (_) == 'n' ? 39                           \
+   : (_) == 'o' ? 40                           \
+   : (_) == 'p' ? 41                           \
+   : (_) == 'q' ? 42                           \
+   : (_) == 'r' ? 43                           \
+   : (_) == 's' ? 44                           \
+   : (_) == 't' ? 45                           \
+   : (_) == 'u' ? 46                           \
+   : (_) == 'v' ? 47                           \
+   : (_) == 'w' ? 48                           \
+   : (_) == 'x' ? 49                           \
+   : (_) == 'y' ? 50                           \
+   : (_) == 'z' ? 51                           \
+   : (_) == '0' ? 52                           \
+   : (_) == '1' ? 53                           \
+   : (_) == '2' ? 54                           \
+   : (_) == '3' ? 55                           \
+   : (_) == '4' ? 56                           \
+   : (_) == '5' ? 57                           \
+   : (_) == '6' ? 58                           \
+   : (_) == '7' ? 59                           \
+   : (_) == '8' ? 60                           \
+   : (_) == '9' ? 61                           \
+   : (_) == '+' ? 62                           \
+   : (_) == '/' ? 63                           \
    : -1)
 
 static const signed char b64[0x100] = {
@@ -274,10 +285,19 @@ static const signed char b64[0x100] = {
   B64 (252), B64 (253), B64 (254), B64 (255)
 };
 
+#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 to_uchar (ch) <= 255 && 0 <= b64[to_uchar (ch)];
+  return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
 }
 
 /* Decode base64 encoded input array IN of length INLEN to output
@@ -286,10 +306,12 @@ isbase64 (char ch)
    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 remove any line terminators 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;
 
@@ -368,15 +390,15 @@ base64_decode (const char *restrict in, size_t inlen,
    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.