diff options
Diffstat (limited to 'gl/base64.c')
-rw-r--r-- | gl/base64.c | 126 |
1 files changed, 75 insertions, 51 deletions
diff --git a/gl/base64.c b/gl/base64.c index 8da969c..95b669a 100644 --- a/gl/base64.c +++ b/gl/base64.c | |||
@@ -1,24 +1,24 @@ | |||
1 | /* base64.c -- Encode binary data using printable characters. | 1 | /* base64.c -- Encode binary data using printable characters. |
2 | Copyright (C) 1999-2001, 2004-2006, 2009-2013 Free Software Foundation, Inc. | 2 | Copyright (C) 1999-2001, 2004-2006, 2009-2023 Free Software Foundation, Inc. |
3 | 3 | ||
4 | This program is free software; you can redistribute it and/or modify | 4 | This file is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU Lesser General Public License as |
6 | the Free Software Foundation; either version 3, or (at your option) | 6 | published by the Free Software Foundation; either version 2.1 of the |
7 | any later version. | 7 | License, or (at your option) any later version. |
8 | 8 | ||
9 | This program is distributed in the hope that it will be useful, | 9 | This file is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. | 12 | GNU Lesser General Public License for more details. |
13 | 13 | ||
14 | You should have received a copy of the GNU General Public License | 14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with this program; if not, see <http://www.gnu.org/licenses/>. */ | 15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
16 | 16 | ||
17 | /* Written by Simon Josefsson. Partially adapted from GNU MailUtils | 17 | /* Written by Simon Josefsson. Partially adapted from GNU MailUtils |
18 | * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review | 18 | * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review |
19 | * from Paul Eggert, Bruno Haible, and Stepan Kasal. | 19 | * from Paul Eggert, Bruno Haible, and Stepan Kasal. |
20 | * | 20 | * |
21 | * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>. | 21 | * See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>. |
22 | * | 22 | * |
23 | * Be careful with error checking. Here is how you would typically | 23 | * Be careful with error checking. Here is how you would typically |
24 | * use these functions: | 24 | * use these functions: |
@@ -30,7 +30,7 @@ | |||
30 | * FAIL: memory allocation error | 30 | * FAIL: memory allocation error |
31 | * OK: data in OUT/OUTLEN | 31 | * OK: data in OUT/OUTLEN |
32 | * | 32 | * |
33 | * size_t outlen = base64_encode_alloc (in, inlen, &out); | 33 | * idx_t outlen = base64_encode_alloc (in, inlen, &out); |
34 | * if (out == NULL && outlen == 0 && inlen != 0) | 34 | * if (out == NULL && outlen == 0 && inlen != 0) |
35 | * FAIL: input too long | 35 | * FAIL: input too long |
36 | * if (out == NULL) | 36 | * if (out == NULL) |
@@ -44,51 +44,84 @@ | |||
44 | /* Get prototype. */ | 44 | /* Get prototype. */ |
45 | #include "base64.h" | 45 | #include "base64.h" |
46 | 46 | ||
47 | /* Get malloc. */ | 47 | /* Get imalloc. */ |
48 | #include <stdlib.h> | 48 | #include <ialloc.h> |
49 | |||
50 | #include <intprops.h> | ||
49 | 51 | ||
50 | /* Get UCHAR_MAX. */ | 52 | /* Get UCHAR_MAX. */ |
51 | #include <limits.h> | 53 | #include <limits.h> |
52 | 54 | ||
53 | #include <string.h> | 55 | #include <string.h> |
54 | 56 | ||
55 | /* C89 compliant way to cast 'char' to 'unsigned char'. */ | 57 | /* Convert 'char' to 'unsigned char' without casting. */ |
56 | static unsigned char | 58 | static unsigned char |
57 | to_uchar (char ch) | 59 | to_uchar (char ch) |
58 | { | 60 | { |
59 | return ch; | 61 | return ch; |
60 | } | 62 | } |
61 | 63 | ||
64 | static const char b64c[64] = | ||
65 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
66 | |||
67 | /* Base64 encode IN array of size INLEN into OUT array. OUT needs | ||
68 | to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be | ||
69 | a multiple of 3. */ | ||
70 | static void | ||
71 | base64_encode_fast (const char *restrict in, idx_t inlen, char *restrict out) | ||
72 | { | ||
73 | while (inlen) | ||
74 | { | ||
75 | *out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f]; | ||
76 | *out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f]; | ||
77 | *out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f]; | ||
78 | *out++ = b64c[to_uchar (in[2]) & 0x3f]; | ||
79 | |||
80 | inlen -= 3; | ||
81 | in += 3; | ||
82 | } | ||
83 | } | ||
84 | |||
62 | /* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. | 85 | /* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. |
63 | If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as | 86 | If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as |
64 | possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero | 87 | possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero |
65 | terminate the output buffer. */ | 88 | terminate the output buffer. */ |
66 | void | 89 | void |
67 | base64_encode (const char *restrict in, size_t inlen, | 90 | base64_encode (const char *restrict in, idx_t inlen, |
68 | char *restrict out, size_t outlen) | 91 | char *restrict out, idx_t outlen) |
69 | { | 92 | { |
70 | static const char b64str[64] = | 93 | /* Note this outlen constraint can be enforced at compile time. |
71 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 94 | I.E. that the output buffer is exactly large enough to hold |
95 | the encoded inlen bytes. The inlen constraints (of corresponding | ||
96 | to outlen, and being a multiple of 3) can change at runtime | ||
97 | at the end of input. However the common case when reading | ||
98 | large inputs is to have both constraints satisfied, so we depend | ||
99 | on both in base_encode_fast(). */ | ||
100 | if (outlen % 4 == 0 && inlen == (outlen >> 2) * 3) | ||
101 | { | ||
102 | base64_encode_fast (in, inlen, out); | ||
103 | return; | ||
104 | } | ||
72 | 105 | ||
73 | while (inlen && outlen) | 106 | while (inlen && outlen) |
74 | { | 107 | { |
75 | *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f]; | 108 | *out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f]; |
76 | if (!--outlen) | 109 | if (!--outlen) |
77 | break; | 110 | break; |
78 | *out++ = b64str[((to_uchar (in[0]) << 4) | 111 | *out++ = b64c[((to_uchar (in[0]) << 4) |
79 | + (--inlen ? to_uchar (in[1]) >> 4 : 0)) | 112 | + (--inlen ? to_uchar (in[1]) >> 4 : 0)) |
80 | & 0x3f]; | 113 | & 0x3f]; |
81 | if (!--outlen) | 114 | if (!--outlen) |
82 | break; | 115 | break; |
83 | *out++ = | 116 | *out++ = |
84 | (inlen | 117 | (inlen |
85 | ? b64str[((to_uchar (in[1]) << 2) | 118 | ? b64c[((to_uchar (in[1]) << 2) |
86 | + (--inlen ? to_uchar (in[2]) >> 6 : 0)) | 119 | + (--inlen ? to_uchar (in[2]) >> 6 : 0)) |
87 | & 0x3f] | 120 | & 0x3f] |
88 | : '='); | 121 | : '='); |
89 | if (!--outlen) | 122 | if (!--outlen) |
90 | break; | 123 | break; |
91 | *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '='; | 124 | *out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '='; |
92 | if (!--outlen) | 125 | if (!--outlen) |
93 | break; | 126 | break; |
94 | if (inlen) | 127 | if (inlen) |
@@ -110,30 +143,21 @@ base64_encode (const char *restrict in, size_t inlen, | |||
110 | memory allocation failed, OUT is set to NULL, and the return value | 143 | memory allocation failed, OUT is set to NULL, and the return value |
111 | indicates length of the requested memory block, i.e., | 144 | indicates length of the requested memory block, i.e., |
112 | BASE64_LENGTH(inlen) + 1. */ | 145 | BASE64_LENGTH(inlen) + 1. */ |
113 | size_t | 146 | idx_t |
114 | base64_encode_alloc (const char *in, size_t inlen, char **out) | 147 | base64_encode_alloc (const char *in, idx_t inlen, char **out) |
115 | { | 148 | { |
116 | size_t outlen = 1 + BASE64_LENGTH (inlen); | ||
117 | |||
118 | /* Check for overflow in outlen computation. | 149 | /* Check for overflow in outlen computation. |
119 | * | 150 | Treat negative INLEN as overflow, for better compatibility with |
120 | * If there is no overflow, outlen >= inlen. | 151 | pre-2021-08-27 API, which used size_t. */ |
121 | * | 152 | idx_t in_over_3 = inlen / 3 + (inlen % 3 != 0), outlen; |
122 | * If the operation (inlen + 2) overflows then it yields at most +1, so | 153 | if (! INT_MULTIPLY_OK (in_over_3, 4, &outlen) || inlen < 0) |
123 | * outlen is 0. | ||
124 | * | ||
125 | * If the multiplication overflows, we lose at least half of the | ||
126 | * correct value, so the result is < ((inlen + 2) / 3) * 2, which is | ||
127 | * less than (inlen + 2) * 0.66667, which is less than inlen as soon as | ||
128 | * (inlen > 4). | ||
129 | */ | ||
130 | if (inlen > outlen) | ||
131 | { | 154 | { |
132 | *out = NULL; | 155 | *out = NULL; |
133 | return 0; | 156 | return 0; |
134 | } | 157 | } |
158 | outlen++; | ||
135 | 159 | ||
136 | *out = malloc (outlen); | 160 | *out = imalloc (outlen); |
137 | if (!*out) | 161 | if (!*out) |
138 | return outlen; | 162 | return outlen; |
139 | 163 | ||
@@ -317,7 +341,7 @@ base64_decode_ctx_init (struct base64_decode_context *ctx) | |||
317 | static char * | 341 | static char * |
318 | get_4 (struct base64_decode_context *ctx, | 342 | get_4 (struct base64_decode_context *ctx, |
319 | char const *restrict *in, char const *restrict in_end, | 343 | char const *restrict *in, char const *restrict in_end, |
320 | size_t *n_non_newline) | 344 | idx_t *n_non_newline) |
321 | { | 345 | { |
322 | if (ctx->i == 4) | 346 | if (ctx->i == 4) |
323 | ctx->i = 0; | 347 | ctx->i = 0; |
@@ -369,8 +393,8 @@ get_4 (struct base64_decode_context *ctx, | |||
369 | *OUT to point to the byte after the last one written, and decrement | 393 | *OUT to point to the byte after the last one written, and decrement |
370 | *OUTLEN to reflect the number of bytes remaining in *OUT. */ | 394 | *OUTLEN to reflect the number of bytes remaining in *OUT. */ |
371 | static bool | 395 | static bool |
372 | decode_4 (char const *restrict in, size_t inlen, | 396 | decode_4 (char const *restrict in, idx_t inlen, |
373 | char *restrict *outp, size_t *outleft) | 397 | char *restrict *outp, idx_t *outleft) |
374 | { | 398 | { |
375 | char *out = *outp; | 399 | char *out = *outp; |
376 | if (inlen < 2) | 400 | if (inlen < 2) |
@@ -455,10 +479,10 @@ decode_4 (char const *restrict in, size_t inlen, | |||
455 | 479 | ||
456 | bool | 480 | bool |
457 | base64_decode_ctx (struct base64_decode_context *ctx, | 481 | base64_decode_ctx (struct base64_decode_context *ctx, |
458 | const char *restrict in, size_t inlen, | 482 | const char *restrict in, idx_t inlen, |
459 | char *restrict out, size_t *outlen) | 483 | char *restrict out, idx_t *outlen) |
460 | { | 484 | { |
461 | size_t outleft = *outlen; | 485 | idx_t outleft = *outlen; |
462 | bool ignore_newlines = ctx != NULL; | 486 | bool ignore_newlines = ctx != NULL; |
463 | bool flush_ctx = false; | 487 | bool flush_ctx = false; |
464 | unsigned int ctx_i = 0; | 488 | unsigned int ctx_i = 0; |
@@ -472,7 +496,7 @@ base64_decode_ctx (struct base64_decode_context *ctx, | |||
472 | 496 | ||
473 | while (true) | 497 | while (true) |
474 | { | 498 | { |
475 | size_t outleft_save = outleft; | 499 | idx_t outleft_save = outleft; |
476 | if (ctx_i == 0 && !flush_ctx) | 500 | if (ctx_i == 0 && !flush_ctx) |
477 | { | 501 | { |
478 | while (true) | 502 | while (true) |
@@ -546,17 +570,17 @@ base64_decode_ctx (struct base64_decode_context *ctx, | |||
546 | undefined. */ | 570 | undefined. */ |
547 | bool | 571 | bool |
548 | base64_decode_alloc_ctx (struct base64_decode_context *ctx, | 572 | base64_decode_alloc_ctx (struct base64_decode_context *ctx, |
549 | const char *in, size_t inlen, char **out, | 573 | const char *in, idx_t inlen, char **out, |
550 | size_t *outlen) | 574 | idx_t *outlen) |
551 | { | 575 | { |
552 | /* This may allocate a few bytes too many, depending on input, | 576 | /* This may allocate a few bytes too many, depending on input, |
553 | but it's not worth the extra CPU time to compute the exact size. | 577 | but it's not worth the extra CPU time to compute the exact size. |
554 | The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the | 578 | The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the |
555 | input ends with "=" and minus another 1 if the input ends with "==". | 579 | input ends with "=" and minus another 1 if the input ends with "==". |
556 | Dividing before multiplying avoids the possibility of overflow. */ | 580 | Shifting before multiplying avoids the possibility of overflow. */ |
557 | size_t needlen = 3 * (inlen / 4) + 3; | 581 | idx_t needlen = 3 * ((inlen >> 2) + 1); |
558 | 582 | ||
559 | *out = malloc (needlen); | 583 | *out = imalloc (needlen); |
560 | if (!*out) | 584 | if (!*out) |
561 | return true; | 585 | return true; |
562 | 586 | ||