#include <sys/types.h>
#include "system.h"
+#include "assure.h"
#include "c-ctype.h"
#include "fadvise.h"
#include "quote.h"
exit (status);
}
+#if BASE_TYPE != 64
+static int
+base32_required_padding (int len)
+{
+ int partial = len % 8;
+ return partial ? 8 - partial : 0;
+}
+#endif
+
+#if BASE_TYPE != 32
+static int
+base64_required_padding (int len)
+{
+ int partial = len % 4;
+ return partial ? 4 - partial : 0;
+}
+#endif
+
+#if BASE_TYPE == 42
+static int
+no_required_padding (int len)
+{
+ return 0;
+}
+#endif
+
#define ENC_BLOCKSIZE (1024 * 3 * 10)
#if BASE_TYPE == 32
# define BASE_LENGTH BASE32_LENGTH
+# define REQUIRED_PADDING base32_required_padding
/* Note that increasing this may decrease performance if --ignore-garbage
is used, because of the memmove operation below. */
# define DEC_BLOCKSIZE (1024 * 5)
# define isbase isbase32
#elif BASE_TYPE == 64
# define BASE_LENGTH BASE64_LENGTH
+# define REQUIRED_PADDING base64_required_padding
/* Note that increasing this may decrease performance if --ignore-garbage
is used, because of the memmove operation below. */
# define DEC_BLOCKSIZE (1024 * 3)
# define BASE_LENGTH base_length
+# define REQUIRED_PADDING required_padding
/* Note that increasing this may decrease performance if --ignore-garbage
is used, because of the memmove operation below. */
static_assert (DEC_BLOCKSIZE % 12 == 0); /* complete encoded blocks for base64*/
static int (*base_length) (int i);
+static int (*required_padding) (int i);
static bool (*isbase) (char ch);
static void (*base_encode) (char const *restrict in, idx_t inlen,
char *restrict out, idx_t outlen);
return b;
}
-
static bool
isbase16 (char ch)
{
idx_t sum;
struct base_decode_context ctx;
+ char padbuf[8] = "========";
inbuf = xmalloc (BASE_LENGTH (DEC_BLOCKSIZE));
outbuf = xmalloc (DEC_BLOCKSIZE);
telling it to flush what is in CTX. */
for (int k = 0; k < 1 + !!feof (in); k++)
{
- if (k == 1 && ctx.i == 0)
- break;
+ if (k == 1)
+ {
+ if (ctx.i == 0)
+ break;
+
+ /* auto pad input (at eof). */
+ idx_t auto_padding = REQUIRED_PADDING (ctx.i);
+ if (auto_padding && (sum == 0 || inbuf[sum - 1] != '='))
+ {
+ affirm (auto_padding <= sizeof (padbuf));
+ IF_LINT (free (inbuf));
+ sum = auto_padding;
+ inbuf = padbuf;
+ }
+ else
+ sum = 0; /* process ctx buffer only */
+ }
idx_t n = DEC_BLOCKSIZE;
- ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
+ ok = base_decode_ctx (&ctx, inbuf, sum, outbuf, &n);
if (fwrite (outbuf, 1, n, out) < n)
write_error ();
{
case BASE64_OPTION:
base_length = base64_length_wrapper;
+ required_padding = base64_required_padding;
isbase = isbase64;
base_encode = base64_encode;
base_decode_ctx_init = base64_decode_ctx_init_wrapper;
case BASE64URL_OPTION:
base_length = base64_length_wrapper;
+ required_padding = base64_required_padding;
isbase = isbase64url;
base_encode = base64url_encode;
base_decode_ctx_init = base64url_decode_ctx_init_wrapper;
case BASE32_OPTION:
base_length = base32_length_wrapper;
+ required_padding = base32_required_padding;
isbase = isbase32;
base_encode = base32_encode;
base_decode_ctx_init = base32_decode_ctx_init_wrapper;
case BASE32HEX_OPTION:
base_length = base32_length_wrapper;
+ required_padding = base32_required_padding;
isbase = isbase32hex;
base_encode = base32hex_encode;
base_decode_ctx_init = base32hex_decode_ctx_init_wrapper;
case BASE16_OPTION:
base_length = base16_length;
+ required_padding = no_required_padding;
isbase = isbase16;
base_encode = base16_encode;
base_decode_ctx_init = base16_decode_ctx_init;
case BASE2MSBF_OPTION:
base_length = base2_length;
+ required_padding = no_required_padding;
isbase = isbase2;
base_encode = base2msbf_encode;
base_decode_ctx_init = base2_decode_ctx_init;
case BASE2LSBF_OPTION:
base_length = base2_length;
+ required_padding = no_required_padding;
isbase = isbase2;
base_encode = base2lsbf_encode;
base_decode_ctx_init = base2_decode_ctx_init;
case Z85_OPTION:
base_length = z85_length;
+ required_padding = no_required_padding;
isbase = isz85;
base_encode = z85_encode;
base_decode_ctx_init = z85_decode_ctx_init;
push @Tests, (
['baddecode', '--decode', {IN=>'a'}, {OUT=>""},
{ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
- ['baddecode2', '--decode', {IN=>'ab'}, {OUT=>"i"},
- {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
- ['baddecode3', '--decode', {IN=>'Zzz'}, {OUT=>"g<"},
- {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+ ['paddecode2', '--decode', {IN=>'ab'}, {OUT=>"i"}],
+ ['paddecode3', '--decode', {IN=>'Zzz'}, {OUT=>"g<"}],
['baddecode4', '--decode', {IN=>'Zz='}, {OUT=>"g"},
{ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
['baddecode5', '--decode', {IN=>'Z==='}, {OUT=>""},