Blame gnulib/base64.c

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