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