ffd6ed
/* base64.c -- Encode binary data using printable characters.
ffd6ed
   Copyright (C) 1999-2001, 2004-2006, 2009-2014 Free Software Foundation, Inc.
ffd6ed
ffd6ed
   This program is free software; you can redistribute it and/or modify
ffd6ed
   it under the terms of the GNU General Public License as published by
ffd6ed
   the Free Software Foundation; either version 3, or (at your option)
ffd6ed
   any later version.
ffd6ed
ffd6ed
   This program is distributed in the hope that it will be useful,
ffd6ed
   but WITHOUT ANY WARRANTY; without even the implied warranty of
ffd6ed
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ffd6ed
   GNU General Public License for more details.
ffd6ed
ffd6ed
   You should have received a copy of the GNU General Public License
ffd6ed
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
ffd6ed
ffd6ed
/* Written by Simon Josefsson.  Partially adapted from GNU MailUtils
ffd6ed
 * (mailbox/filter_trans.c, as of 2004-11-28).  Improved by review
ffd6ed
 * from Paul Eggert, Bruno Haible, and Stepan Kasal.
ffd6ed
 *
ffd6ed
 * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
ffd6ed
 *
ffd6ed
 * Be careful with error checking.  Here is how you would typically
ffd6ed
 * use these functions:
ffd6ed
 *
ffd6ed
 * bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
ffd6ed
 * if (!ok)
ffd6ed
 *   FAIL: input was not valid base64
ffd6ed
 * if (out == NULL)
ffd6ed
 *   FAIL: memory allocation error
ffd6ed
 * OK: data in OUT/OUTLEN
ffd6ed
 *
ffd6ed
 * size_t outlen = base64_encode_alloc (in, inlen, &out;;
ffd6ed
 * if (out == NULL && outlen == 0 && inlen != 0)
ffd6ed
 *   FAIL: input too long
ffd6ed
 * if (out == NULL)
ffd6ed
 *   FAIL: memory allocation error
ffd6ed
 * OK: data in OUT/OUTLEN.
ffd6ed
 *
ffd6ed
 */
ffd6ed
ffd6ed
#include <config.h>
ffd6ed
ffd6ed
/* Get prototype. */
ffd6ed
#include "base64.h"
ffd6ed
ffd6ed
/* Get malloc. */
ffd6ed
#include <stdlib.h>
ffd6ed
ffd6ed
/* Get UCHAR_MAX. */
ffd6ed
#include <limits.h>
ffd6ed
ffd6ed
#include <string.h>
ffd6ed
ffd6ed
/* C89 compliant way to cast 'char' to 'unsigned char'. */
ffd6ed
static unsigned char
ffd6ed
to_uchar (char ch)
ffd6ed
{
ffd6ed
  return ch;
ffd6ed
}
ffd6ed
ffd6ed
static const char b64c[64] =
ffd6ed
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
ffd6ed
ffd6ed
/* Base64 encode IN array of size INLEN into OUT array. OUT needs
ffd6ed
   to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be
ffd6ed
   a multiple of 3.  */
ffd6ed
static void
ffd6ed
base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
ffd6ed
{
ffd6ed
  while (inlen)
ffd6ed
    {
ffd6ed
      *out++ = b64c[to_uchar (in[0]) >> 2];
ffd6ed
      *out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
ffd6ed
      *out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
ffd6ed
      *out++ = b64c[to_uchar (in[2]) & 0x3f];
ffd6ed
ffd6ed
      inlen -= 3;
ffd6ed
      in += 3;
ffd6ed
    }
ffd6ed
}
ffd6ed
ffd6ed
/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
ffd6ed
   If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
ffd6ed
   possible.  If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
ffd6ed
   terminate the output buffer. */
ffd6ed
void
ffd6ed
base64_encode (const char *restrict in, size_t inlen,
ffd6ed
               char *restrict out, size_t outlen)
ffd6ed
{
ffd6ed
  /* Note this outlen constraint can be enforced at compile time.
ffd6ed
     I.E. that the output buffer is exactly large enough to hold
ffd6ed
     the encoded inlen bytes.  The inlen constraints (of corresponding
ffd6ed
     to outlen, and being a multiple of 3) can change at runtime
ffd6ed
     at the end of input.  However the common case when reading
ffd6ed
     large inputs is to have both constraints satisfied, so we depend
ffd6ed
     on both in base_encode_fast().  */
ffd6ed
  if (outlen % 4 == 0 && inlen == outlen / 4 * 3)
ffd6ed
    {
ffd6ed
      base64_encode_fast (in, inlen, out);
ffd6ed
      return;
ffd6ed
    }
ffd6ed
ffd6ed
  while (inlen && outlen)
ffd6ed
    {
ffd6ed
      *out++ = b64c[to_uchar (in[0]) >> 2];
ffd6ed
      if (!--outlen)
ffd6ed
        break;
ffd6ed
      *out++ = b64c[((to_uchar (in[0]) << 4)
ffd6ed
                       + (--inlen ? to_uchar (in[1]) >> 4 : 0))
ffd6ed
                      & 0x3f];
ffd6ed
      if (!--outlen)
ffd6ed
        break;
ffd6ed
      *out++ =
ffd6ed
        (inlen
ffd6ed
         ? b64c[((to_uchar (in[1]) << 2)
ffd6ed
                   + (--inlen ? to_uchar (in[2]) >> 6 : 0))
ffd6ed
                  & 0x3f]
ffd6ed
         : '=');
ffd6ed
      if (!--outlen)
ffd6ed
        break;
ffd6ed
      *out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '=';
ffd6ed
      if (!--outlen)
ffd6ed
        break;
ffd6ed
      if (inlen)
ffd6ed
        inlen--;
ffd6ed
      if (inlen)
ffd6ed
        in += 3;
ffd6ed
    }
ffd6ed
ffd6ed
  if (outlen)
ffd6ed
    *out = '\0';
ffd6ed
}
ffd6ed
ffd6ed
/* Allocate a buffer and store zero terminated base64 encoded data
ffd6ed
   from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
ffd6ed
   the length of the encoded data, excluding the terminating zero.  On
ffd6ed
   return, the OUT variable will hold a pointer to newly allocated
ffd6ed
   memory that must be deallocated by the caller.  If output string
ffd6ed
   length would overflow, 0 is returned and OUT is set to NULL.  If
ffd6ed
   memory allocation failed, OUT is set to NULL, and the return value
ffd6ed
   indicates length of the requested memory block, i.e.,
ffd6ed
   BASE64_LENGTH(inlen) + 1. */
ffd6ed
size_t
ffd6ed
base64_encode_alloc (const char *in, size_t inlen, char **out)
ffd6ed
{
ffd6ed
  size_t outlen = 1 + BASE64_LENGTH (inlen);
ffd6ed
ffd6ed
  /* Check for overflow in outlen computation.
ffd6ed
   *
ffd6ed
   * If there is no overflow, outlen >= inlen.
ffd6ed
   *
ffd6ed
   * If the operation (inlen + 2) overflows then it yields at most +1, so
ffd6ed
   * outlen is 0.
ffd6ed
   *
ffd6ed
   * If the multiplication overflows, we lose at least half of the
ffd6ed
   * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
ffd6ed
   * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
ffd6ed
   * (inlen > 4).
ffd6ed
   */
ffd6ed
  if (inlen > outlen)
ffd6ed
    {
ffd6ed
      *out = NULL;
ffd6ed
      return 0;
ffd6ed
    }
ffd6ed
ffd6ed
  *out = malloc (outlen);
ffd6ed
  if (!*out)
ffd6ed
    return outlen;
ffd6ed
ffd6ed
  base64_encode (in, inlen, *out, outlen);
ffd6ed
ffd6ed
  return outlen - 1;
ffd6ed
}
ffd6ed
ffd6ed
/* With this approach this file works independent of the charset used
ffd6ed
   (think EBCDIC).  However, it does assume that the characters in the
ffd6ed
   Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255.  POSIX
ffd6ed
   1003.1-2001 require that char and unsigned char are 8-bit
ffd6ed
   quantities, though, taking care of that problem.  But this may be a
ffd6ed
   potential problem on non-POSIX C99 platforms.
ffd6ed
ffd6ed
   IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
ffd6ed
   as the formal parameter rather than "x".  */
ffd6ed
#define B64(_)                                  \
ffd6ed
  ((_) == 'A' ? 0                               \
ffd6ed
   : (_) == 'B' ? 1                             \
ffd6ed
   : (_) == 'C' ? 2                             \
ffd6ed
   : (_) == 'D' ? 3                             \
ffd6ed
   : (_) == 'E' ? 4                             \
ffd6ed
   : (_) == 'F' ? 5                             \
ffd6ed
   : (_) == 'G' ? 6                             \
ffd6ed
   : (_) == 'H' ? 7                             \
ffd6ed
   : (_) == 'I' ? 8                             \
ffd6ed
   : (_) == 'J' ? 9                             \
ffd6ed
   : (_) == 'K' ? 10                            \
ffd6ed
   : (_) == 'L' ? 11                            \
ffd6ed
   : (_) == 'M' ? 12                            \
ffd6ed
   : (_) == 'N' ? 13                            \
ffd6ed
   : (_) == 'O' ? 14                            \
ffd6ed
   : (_) == 'P' ? 15                            \
ffd6ed
   : (_) == 'Q' ? 16                            \
ffd6ed
   : (_) == 'R' ? 17                            \
ffd6ed
   : (_) == 'S' ? 18                            \
ffd6ed
   : (_) == 'T' ? 19                            \
ffd6ed
   : (_) == 'U' ? 20                            \
ffd6ed
   : (_) == 'V' ? 21                            \
ffd6ed
   : (_) == 'W' ? 22                            \
ffd6ed
   : (_) == 'X' ? 23                            \
ffd6ed
   : (_) == 'Y' ? 24                            \
ffd6ed
   : (_) == 'Z' ? 25                            \
ffd6ed
   : (_) == 'a' ? 26                            \
ffd6ed
   : (_) == 'b' ? 27                            \
ffd6ed
   : (_) == 'c' ? 28                            \
ffd6ed
   : (_) == 'd' ? 29                            \
ffd6ed
   : (_) == 'e' ? 30                            \
ffd6ed
   : (_) == 'f' ? 31                            \
ffd6ed
   : (_) == 'g' ? 32                            \
ffd6ed
   : (_) == 'h' ? 33                            \
ffd6ed
   : (_) == 'i' ? 34                            \
ffd6ed
   : (_) == 'j' ? 35                            \
ffd6ed
   : (_) == 'k' ? 36                            \
ffd6ed
   : (_) == 'l' ? 37                            \
ffd6ed
   : (_) == 'm' ? 38                            \
ffd6ed
   : (_) == 'n' ? 39                            \
ffd6ed
   : (_) == 'o' ? 40                            \
ffd6ed
   : (_) == 'p' ? 41                            \
ffd6ed
   : (_) == 'q' ? 42                            \
ffd6ed
   : (_) == 'r' ? 43                            \
ffd6ed
   : (_) == 's' ? 44                            \
ffd6ed
   : (_) == 't' ? 45                            \
ffd6ed
   : (_) == 'u' ? 46                            \
ffd6ed
   : (_) == 'v' ? 47                            \
ffd6ed
   : (_) == 'w' ? 48                            \
ffd6ed
   : (_) == 'x' ? 49                            \
ffd6ed
   : (_) == 'y' ? 50                            \
ffd6ed
   : (_) == 'z' ? 51                            \
ffd6ed
   : (_) == '0' ? 52                            \
ffd6ed
   : (_) == '1' ? 53                            \
ffd6ed
   : (_) == '2' ? 54                            \
ffd6ed
   : (_) == '3' ? 55                            \
ffd6ed
   : (_) == '4' ? 56                            \
ffd6ed
   : (_) == '5' ? 57                            \
ffd6ed
   : (_) == '6' ? 58                            \
ffd6ed
   : (_) == '7' ? 59                            \
ffd6ed
   : (_) == '8' ? 60                            \
ffd6ed
   : (_) == '9' ? 61                            \
ffd6ed
   : (_) == '+' ? 62                            \
ffd6ed
   : (_) == '/' ? 63                            \
ffd6ed
   : -1)
ffd6ed
ffd6ed
static const signed char b64[0x100] = {
ffd6ed
  B64 (0), B64 (1), B64 (2), B64 (3),
ffd6ed
  B64 (4), B64 (5), B64 (6), B64 (7),
ffd6ed
  B64 (8), B64 (9), B64 (10), B64 (11),
ffd6ed
  B64 (12), B64 (13), B64 (14), B64 (15),
ffd6ed
  B64 (16), B64 (17), B64 (18), B64 (19),
ffd6ed
  B64 (20), B64 (21), B64 (22), B64 (23),
ffd6ed
  B64 (24), B64 (25), B64 (26), B64 (27),
ffd6ed
  B64 (28), B64 (29), B64 (30), B64 (31),
ffd6ed
  B64 (32), B64 (33), B64 (34), B64 (35),
ffd6ed
  B64 (36), B64 (37), B64 (38), B64 (39),
ffd6ed
  B64 (40), B64 (41), B64 (42), B64 (43),
ffd6ed
  B64 (44), B64 (45), B64 (46), B64 (47),
ffd6ed
  B64 (48), B64 (49), B64 (50), B64 (51),
ffd6ed
  B64 (52), B64 (53), B64 (54), B64 (55),
ffd6ed
  B64 (56), B64 (57), B64 (58), B64 (59),
ffd6ed
  B64 (60), B64 (61), B64 (62), B64 (63),
ffd6ed
  B64 (64), B64 (65), B64 (66), B64 (67),
ffd6ed
  B64 (68), B64 (69), B64 (70), B64 (71),
ffd6ed
  B64 (72), B64 (73), B64 (74), B64 (75),
ffd6ed
  B64 (76), B64 (77), B64 (78), B64 (79),
ffd6ed
  B64 (80), B64 (81), B64 (82), B64 (83),
ffd6ed
  B64 (84), B64 (85), B64 (86), B64 (87),
ffd6ed
  B64 (88), B64 (89), B64 (90), B64 (91),
ffd6ed
  B64 (92), B64 (93), B64 (94), B64 (95),
ffd6ed
  B64 (96), B64 (97), B64 (98), B64 (99),
ffd6ed
  B64 (100), B64 (101), B64 (102), B64 (103),
ffd6ed
  B64 (104), B64 (105), B64 (106), B64 (107),
ffd6ed
  B64 (108), B64 (109), B64 (110), B64 (111),
ffd6ed
  B64 (112), B64 (113), B64 (114), B64 (115),
ffd6ed
  B64 (116), B64 (117), B64 (118), B64 (119),
ffd6ed
  B64 (120), B64 (121), B64 (122), B64 (123),
ffd6ed
  B64 (124), B64 (125), B64 (126), B64 (127),
ffd6ed
  B64 (128), B64 (129), B64 (130), B64 (131),
ffd6ed
  B64 (132), B64 (133), B64 (134), B64 (135),
ffd6ed
  B64 (136), B64 (137), B64 (138), B64 (139),
ffd6ed
  B64 (140), B64 (141), B64 (142), B64 (143),
ffd6ed
  B64 (144), B64 (145), B64 (146), B64 (147),
ffd6ed
  B64 (148), B64 (149), B64 (150), B64 (151),
ffd6ed
  B64 (152), B64 (153), B64 (154), B64 (155),
ffd6ed
  B64 (156), B64 (157), B64 (158), B64 (159),
ffd6ed
  B64 (160), B64 (161), B64 (162), B64 (163),
ffd6ed
  B64 (164), B64 (165), B64 (166), B64 (167),
ffd6ed
  B64 (168), B64 (169), B64 (170), B64 (171),
ffd6ed
  B64 (172), B64 (173), B64 (174), B64 (175),
ffd6ed
  B64 (176), B64 (177), B64 (178), B64 (179),
ffd6ed
  B64 (180), B64 (181), B64 (182), B64 (183),
ffd6ed
  B64 (184), B64 (185), B64 (186), B64 (187),
ffd6ed
  B64 (188), B64 (189), B64 (190), B64 (191),
ffd6ed
  B64 (192), B64 (193), B64 (194), B64 (195),
ffd6ed
  B64 (196), B64 (197), B64 (198), B64 (199),
ffd6ed
  B64 (200), B64 (201), B64 (202), B64 (203),
ffd6ed
  B64 (204), B64 (205), B64 (206), B64 (207),
ffd6ed
  B64 (208), B64 (209), B64 (210), B64 (211),
ffd6ed
  B64 (212), B64 (213), B64 (214), B64 (215),
ffd6ed
  B64 (216), B64 (217), B64 (218), B64 (219),
ffd6ed
  B64 (220), B64 (221), B64 (222), B64 (223),
ffd6ed
  B64 (224), B64 (225), B64 (226), B64 (227),
ffd6ed
  B64 (228), B64 (229), B64 (230), B64 (231),
ffd6ed
  B64 (232), B64 (233), B64 (234), B64 (235),
ffd6ed
  B64 (236), B64 (237), B64 (238), B64 (239),
ffd6ed
  B64 (240), B64 (241), B64 (242), B64 (243),
ffd6ed
  B64 (244), B64 (245), B64 (246), B64 (247),
ffd6ed
  B64 (248), B64 (249), B64 (250), B64 (251),
ffd6ed
  B64 (252), B64 (253), B64 (254), B64 (255)
ffd6ed
};
ffd6ed
ffd6ed
#if UCHAR_MAX == 255
ffd6ed
# define uchar_in_range(c) true
ffd6ed
#else
ffd6ed
# define uchar_in_range(c) ((c) <= 255)
ffd6ed
#endif
ffd6ed
ffd6ed
/* Return true if CH is a character from the Base64 alphabet, and
ffd6ed
   false otherwise.  Note that '=' is padding and not considered to be
ffd6ed
   part of the alphabet.  */
ffd6ed
bool
ffd6ed
isbase64 (char ch)
ffd6ed
{
ffd6ed
  return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
ffd6ed
}
ffd6ed
ffd6ed
/* Initialize decode-context buffer, CTX.  */
ffd6ed
void
ffd6ed
base64_decode_ctx_init (struct base64_decode_context *ctx)
ffd6ed
{
ffd6ed
  ctx->i = 0;
ffd6ed
}
ffd6ed
ffd6ed
/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
ffd6ed
   none of those four is a newline, then return *IN.  Otherwise, copy up to
ffd6ed
   4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
ffd6ed
   index CTX->i and setting CTX->i to reflect the number of bytes copied,
ffd6ed
   and return CTX->buf.  In either case, advance *IN to point to the byte
ffd6ed
   after the last one processed, and set *N_NON_NEWLINE to the number of
ffd6ed
   verified non-newline bytes accessible through the returned pointer.  */
ffd6ed
static char *
ffd6ed
get_4 (struct base64_decode_context *ctx,
ffd6ed
       char const *restrict *in, char const *restrict in_end,
ffd6ed
       size_t *n_non_newline)
ffd6ed
{
ffd6ed
  if (ctx->i == 4)
ffd6ed
    ctx->i = 0;
ffd6ed
ffd6ed
  if (ctx->i == 0)
ffd6ed
    {
ffd6ed
      char const *t = *in;
ffd6ed
      if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
ffd6ed
        {
ffd6ed
          /* This is the common case: no newline.  */
ffd6ed
          *in += 4;
ffd6ed
          *n_non_newline = 4;
ffd6ed
          return (char *) t;
ffd6ed
        }
ffd6ed
    }
ffd6ed
ffd6ed
  {
ffd6ed
    /* Copy non-newline bytes into BUF.  */
ffd6ed
    char const *p = *in;
ffd6ed
    while (p < in_end)
ffd6ed
      {
ffd6ed
        char c = *p++;
ffd6ed
        if (c != '\n')
ffd6ed
          {
ffd6ed
            ctx->buf[ctx->i++] = c;
ffd6ed
            if (ctx->i == 4)
ffd6ed
              break;
ffd6ed
          }
ffd6ed
      }
ffd6ed
ffd6ed
    *in = p;
ffd6ed
    *n_non_newline = ctx->i;
ffd6ed
    return ctx->buf;
ffd6ed
  }
ffd6ed
}
ffd6ed
ffd6ed
#define return_false                            \
ffd6ed
  do                                            \
ffd6ed
    {                                           \
ffd6ed
      *outp = out;                              \
ffd6ed
      return false;                             \
ffd6ed
    }                                           \
ffd6ed
  while (false)
ffd6ed
ffd6ed
/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
ffd6ed
   into the output buffer, *OUT, of size *OUTLEN bytes.  Return true if
ffd6ed
   decoding is successful, false otherwise.  If *OUTLEN is too small,
ffd6ed
   as many bytes as possible are written to *OUT.  On return, advance
ffd6ed
   *OUT to point to the byte after the last one written, and decrement
ffd6ed
   *OUTLEN to reflect the number of bytes remaining in *OUT.  */
ffd6ed
static bool
ffd6ed
decode_4 (char const *restrict in, size_t inlen,
ffd6ed
          char *restrict *outp, size_t *outleft)
ffd6ed
{
ffd6ed
  char *out = *outp;
ffd6ed
  if (inlen < 2)
ffd6ed
    return false;
ffd6ed
ffd6ed
  if (!isbase64 (in[0]) || !isbase64 (in[1]))
ffd6ed
    return false;
ffd6ed
ffd6ed
  if (*outleft)
ffd6ed
    {
ffd6ed
      *out++ = ((b64[to_uchar (in[0])] << 2)
ffd6ed
                | (b64[to_uchar (in[1])] >> 4));
ffd6ed
      --*outleft;
ffd6ed
    }
ffd6ed
ffd6ed
  if (inlen == 2)
ffd6ed
    return_false;
ffd6ed
ffd6ed
  if (in[2] == '=')
ffd6ed
    {
ffd6ed
      if (inlen != 4)
ffd6ed
        return_false;
ffd6ed
ffd6ed
      if (in[3] != '=')
ffd6ed
        return_false;
ffd6ed
    }
ffd6ed
  else
ffd6ed
    {
ffd6ed
      if (!isbase64 (in[2]))
ffd6ed
        return_false;
ffd6ed
ffd6ed
      if (*outleft)
ffd6ed
        {
ffd6ed
          *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
ffd6ed
                    | (b64[to_uchar (in[2])] >> 2));
ffd6ed
          --*outleft;
ffd6ed
        }
ffd6ed
ffd6ed
      if (inlen == 3)
ffd6ed
        return_false;
ffd6ed
ffd6ed
      if (in[3] == '=')
ffd6ed
        {
ffd6ed
          if (inlen != 4)
ffd6ed
            return_false;
ffd6ed
        }
ffd6ed
      else
ffd6ed
        {
ffd6ed
          if (!isbase64 (in[3]))
ffd6ed
            return_false;
ffd6ed
ffd6ed
          if (*outleft)
ffd6ed
            {
ffd6ed
              *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
ffd6ed
                        | b64[to_uchar (in[3])]);
ffd6ed
              --*outleft;
ffd6ed
            }
ffd6ed
        }
ffd6ed
    }
ffd6ed
ffd6ed
  *outp = out;
ffd6ed
  return true;
ffd6ed
}
ffd6ed
ffd6ed
/* Decode base64-encoded input array IN of length INLEN to output array
ffd6ed
   OUT that can hold *OUTLEN bytes.  The input data may be interspersed
ffd6ed
   with newlines.  Return true if decoding was successful, i.e. if the
ffd6ed
   input was valid base64 data, false otherwise.  If *OUTLEN is too
ffd6ed
   small, as many bytes as possible will be written to OUT.  On return,
ffd6ed
   *OUTLEN holds the length of decoded bytes in OUT.  Note that as soon
ffd6ed
   as any non-alphabet, non-newline character is encountered, decoding
ffd6ed
   is stopped and false is returned.  If INLEN is zero, then process
ffd6ed
   only whatever data is stored in CTX.
ffd6ed
ffd6ed
   Initially, CTX must have been initialized via base64_decode_ctx_init.
ffd6ed
   Subsequent calls to this function must reuse whatever state is recorded
ffd6ed
   in that buffer.  It is necessary for when a quadruple of base64 input
ffd6ed
   bytes spans two input buffers.
ffd6ed
ffd6ed
   If CTX is NULL then newlines are treated as garbage and the input
ffd6ed
   buffer is processed as a unit.  */
ffd6ed
ffd6ed
bool
ffd6ed
base64_decode_ctx (struct base64_decode_context *ctx,
ffd6ed
                   const char *restrict in, size_t inlen,
ffd6ed
                   char *restrict out, size_t *outlen)
ffd6ed
{
ffd6ed
  size_t outleft = *outlen;
ffd6ed
  bool ignore_newlines = ctx != NULL;
ffd6ed
  bool flush_ctx = false;
ffd6ed
  unsigned int ctx_i = 0;
ffd6ed
ffd6ed
  if (ignore_newlines)
ffd6ed
    {
ffd6ed
      ctx_i = ctx->i;
ffd6ed
      flush_ctx = inlen == 0;
ffd6ed
    }
ffd6ed
ffd6ed
ffd6ed
  while (true)
ffd6ed
    {
ffd6ed
      size_t outleft_save = outleft;
ffd6ed
      if (ctx_i == 0 && !flush_ctx)
ffd6ed
        {
ffd6ed
          while (true)
ffd6ed
            {
ffd6ed
              /* Save a copy of outleft, in case we need to re-parse this
ffd6ed
                 block of four bytes.  */
ffd6ed
              outleft_save = outleft;
ffd6ed
              if (!decode_4 (in, inlen, &out, &outleft))
ffd6ed
                break;
ffd6ed
ffd6ed
              in += 4;
ffd6ed
              inlen -= 4;
ffd6ed
            }
ffd6ed
        }
ffd6ed
ffd6ed
      if (inlen == 0 && !flush_ctx)
ffd6ed
        break;
ffd6ed
ffd6ed
      /* Handle the common case of 72-byte wrapped lines.
ffd6ed
         This also handles any other multiple-of-4-byte wrapping.  */
ffd6ed
      if (inlen && *in == '\n' && ignore_newlines)
ffd6ed
        {
ffd6ed
          ++in;
ffd6ed
          --inlen;
ffd6ed
          continue;
ffd6ed
        }
ffd6ed
ffd6ed
      /* Restore OUT and OUTLEFT.  */
ffd6ed
      out -= outleft_save - outleft;
ffd6ed
      outleft = outleft_save;
ffd6ed
ffd6ed
      {
ffd6ed
        char const *in_end = in + inlen;
ffd6ed
        char const *non_nl;
ffd6ed
ffd6ed
        if (ignore_newlines)
ffd6ed
          non_nl = get_4 (ctx, &in, in_end, &inlen);
ffd6ed
        else
ffd6ed
          non_nl = in;  /* Might have nl in this case. */
ffd6ed
ffd6ed
        /* If the input is empty or consists solely of newlines (0 non-newlines),
ffd6ed
           then we're done.  Likewise if there are fewer than 4 bytes when not
ffd6ed
           flushing context and not treating newlines as garbage.  */
ffd6ed
        if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
ffd6ed
          {
ffd6ed
            inlen = 0;
ffd6ed
            break;
ffd6ed
          }
ffd6ed
        if (!decode_4 (non_nl, inlen, &out, &outleft))
ffd6ed
          break;
ffd6ed
ffd6ed
        inlen = in_end - in;
ffd6ed
      }
ffd6ed
    }
ffd6ed
ffd6ed
  *outlen -= outleft;
ffd6ed
ffd6ed
  return inlen == 0;
ffd6ed
}
ffd6ed
ffd6ed
/* Allocate an output buffer in *OUT, and decode the base64 encoded
ffd6ed
   data stored in IN of size INLEN to the *OUT buffer.  On return, the
ffd6ed
   size of the decoded data is stored in *OUTLEN.  OUTLEN may be NULL,
ffd6ed
   if the caller is not interested in the decoded length.  *OUT may be
ffd6ed
   NULL to indicate an out of memory error, in which case *OUTLEN
ffd6ed
   contains the size of the memory block needed.  The function returns
ffd6ed
   true on successful decoding and memory allocation errors.  (Use the
ffd6ed
   *OUT and *OUTLEN parameters to differentiate between successful
ffd6ed
   decoding and memory error.)  The function returns false if the
ffd6ed
   input was invalid, in which case *OUT is NULL and *OUTLEN is
ffd6ed
   undefined. */
ffd6ed
bool
ffd6ed
base64_decode_alloc_ctx (struct base64_decode_context *ctx,
ffd6ed
                         const char *in, size_t inlen, char **out,
ffd6ed
                         size_t *outlen)
ffd6ed
{
ffd6ed
  /* This may allocate a few bytes too many, depending on input,
ffd6ed
     but it's not worth the extra CPU time to compute the exact size.
ffd6ed
     The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
ffd6ed
     input ends with "=" and minus another 1 if the input ends with "==".
ffd6ed
     Dividing before multiplying avoids the possibility of overflow.  */
ffd6ed
  size_t needlen = 3 * (inlen / 4) + 3;
ffd6ed
ffd6ed
  *out = malloc (needlen);
ffd6ed
  if (!*out)
ffd6ed
    return true;
ffd6ed
ffd6ed
  if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
ffd6ed
    {
ffd6ed
      free (*out);
ffd6ed
      *out = NULL;
ffd6ed
      return false;
ffd6ed
    }
ffd6ed
ffd6ed
  if (outlen)
ffd6ed
    *outlen = needlen;
ffd6ed
ffd6ed
  return true;
ffd6ed
}