From 868beb15ae02c352005a2df8857f4ebb9bd758fd Mon Sep 17 00:00:00 2001
From: RincewindsHat <12514511+RincewindsHat@users.noreply.github.com>
Date: Tue, 23 Aug 2022 19:42:51 +0200
Subject: Sync with the latest Gnulib code (d27c820595)
---
gl/base64.c | 126 ++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 75 insertions(+), 51 deletions(-)
(limited to 'gl/base64.c')
diff --git a/gl/base64.c b/gl/base64.c
index 8da969c0..6b6e5b09 100644
--- a/gl/base64.c
+++ b/gl/base64.c
@@ -1,24 +1,24 @@
/* base64.c -- Encode binary data using printable characters.
- Copyright (C) 1999-2001, 2004-2006, 2009-2013 Free Software Foundation, Inc.
+ Copyright (C) 1999-2001, 2004-2006, 2009-2022 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 3, or (at your option)
- any later version.
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
+ This file 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.
+ GNU Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see . */
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see . */
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
*
- * See also RFC 4648 .
+ * See also RFC 4648 .
*
* Be careful with error checking. Here is how you would typically
* use these functions:
@@ -30,7 +30,7 @@
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
- * size_t outlen = base64_encode_alloc (in, inlen, &out);
+ * idx_t outlen = base64_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
@@ -44,51 +44,84 @@
/* Get prototype. */
#include "base64.h"
-/* Get malloc. */
-#include
+/* Get imalloc. */
+#include
+
+#include
/* Get UCHAR_MAX. */
#include
#include
-/* C89 compliant way to cast 'char' to 'unsigned char'. */
+/* Convert 'char' to 'unsigned char' without casting. */
static unsigned char
to_uchar (char ch)
{
return ch;
}
+static const char b64c[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* Base64 encode IN array of size INLEN into OUT array. OUT needs
+ to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be
+ a multiple of 3. */
+static void
+base64_encode_fast (const char *restrict in, idx_t inlen, char *restrict out)
+{
+ while (inlen)
+ {
+ *out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
+ *out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
+ *out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
+ *out++ = b64c[to_uchar (in[2]) & 0x3f];
+
+ inlen -= 3;
+ in += 3;
+ }
+}
+
/* 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 *restrict in, size_t inlen,
- char *restrict out, size_t outlen)
+base64_encode (const char *restrict in, idx_t inlen,
+ char *restrict out, idx_t outlen)
{
- static const char b64str[64] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ /* Note this outlen constraint can be enforced at compile time.
+ I.E. that the output buffer is exactly large enough to hold
+ the encoded inlen bytes. The inlen constraints (of corresponding
+ to outlen, and being a multiple of 3) can change at runtime
+ at the end of input. However the common case when reading
+ large inputs is to have both constraints satisfied, so we depend
+ on both in base_encode_fast(). */
+ if (outlen % 4 == 0 && inlen == (outlen >> 2) * 3)
+ {
+ base64_encode_fast (in, inlen, out);
+ return;
+ }
while (inlen && outlen)
{
- *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
+ *out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
- *out++ = b64str[((to_uchar (in[0]) << 4)
+ *out++ = b64c[((to_uchar (in[0]) << 4)
+ (--inlen ? to_uchar (in[1]) >> 4 : 0))
& 0x3f];
if (!--outlen)
break;
*out++ =
(inlen
- ? b64str[((to_uchar (in[1]) << 2)
+ ? b64c[((to_uchar (in[1]) << 2)
+ (--inlen ? to_uchar (in[2]) >> 6 : 0))
& 0x3f]
: '=');
if (!--outlen)
break;
- *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
+ *out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '=';
if (!--outlen)
break;
if (inlen)
@@ -110,30 +143,21 @@ base64_encode (const char *restrict in, size_t inlen,
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)
+idx_t
+base64_encode_alloc (const char *in, idx_t inlen, char **out)
{
- size_t outlen = 1 + BASE64_LENGTH (inlen);
-
/* Check for overflow in outlen computation.
- *
- * If there is no overflow, outlen >= inlen.
- *
- * If the operation (inlen + 2) overflows then it yields at most +1, so
- * outlen is 0.
- *
- * If the multiplication overflows, we lose at least half of the
- * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
- * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
- * (inlen > 4).
- */
- if (inlen > outlen)
+ Treat negative INLEN as overflow, for better compatibility with
+ pre-2021-08-27 API, which used size_t. */
+ idx_t in_over_3 = inlen / 3 + (inlen % 3 != 0), outlen;
+ if (! INT_MULTIPLY_OK (in_over_3, 4, &outlen) || inlen < 0)
{
*out = NULL;
return 0;
}
+ outlen++;
- *out = malloc (outlen);
+ *out = imalloc (outlen);
if (!*out)
return outlen;
@@ -317,7 +341,7 @@ base64_decode_ctx_init (struct base64_decode_context *ctx)
static char *
get_4 (struct base64_decode_context *ctx,
char const *restrict *in, char const *restrict in_end,
- size_t *n_non_newline)
+ idx_t *n_non_newline)
{
if (ctx->i == 4)
ctx->i = 0;
@@ -369,8 +393,8 @@ get_4 (struct base64_decode_context *ctx,
*OUT to point to the byte after the last one written, and decrement
*OUTLEN to reflect the number of bytes remaining in *OUT. */
static bool
-decode_4 (char const *restrict in, size_t inlen,
- char *restrict *outp, size_t *outleft)
+decode_4 (char const *restrict in, idx_t inlen,
+ char *restrict *outp, idx_t *outleft)
{
char *out = *outp;
if (inlen < 2)
@@ -455,10 +479,10 @@ decode_4 (char const *restrict in, size_t inlen,
bool
base64_decode_ctx (struct base64_decode_context *ctx,
- const char *restrict in, size_t inlen,
- char *restrict out, size_t *outlen)
+ const char *restrict in, idx_t inlen,
+ char *restrict out, idx_t *outlen)
{
- size_t outleft = *outlen;
+ idx_t outleft = *outlen;
bool ignore_newlines = ctx != NULL;
bool flush_ctx = false;
unsigned int ctx_i = 0;
@@ -472,7 +496,7 @@ base64_decode_ctx (struct base64_decode_context *ctx,
while (true)
{
- size_t outleft_save = outleft;
+ idx_t outleft_save = outleft;
if (ctx_i == 0 && !flush_ctx)
{
while (true)
@@ -546,17 +570,17 @@ base64_decode_ctx (struct base64_decode_context *ctx,
undefined. */
bool
base64_decode_alloc_ctx (struct base64_decode_context *ctx,
- const char *in, size_t inlen, char **out,
- size_t *outlen)
+ const char *in, idx_t inlen, char **out,
+ idx_t *outlen)
{
/* This may allocate a few bytes too many, depending on input,
but it's not worth the extra CPU time to compute the exact size.
The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
input ends with "=" and minus another 1 if the input ends with "==".
- Dividing before multiplying avoids the possibility of overflow. */
- size_t needlen = 3 * (inlen / 4) + 3;
+ Shifting before multiplying avoids the possibility of overflow. */
+ idx_t needlen = 3 * ((inlen >> 2) + 1);
- *out = malloc (needlen);
+ *out = imalloc (needlen);
if (!*out)
return true;
--
cgit v1.2.3-74-g34f1