Make *dst_length an input argument, should hold size of dst buffer.
Fail if decoding would exceed this size.
+2025-10-30 Niels Möller <nisse@lysator.liu.se>
+
+ * base16-decode.c (base16_decode_single): Rewrite as a call to
+ base16_decode_update.
+ (base16_decode_update): Make *dst_length an input argument, should
+ hold size of dst buffer. Fail if decoding would exceed this size.
+ Update all callers.
+ * base64-decode.c (base64_decode_single, base64_decode_update):
+ Analogous changes.
+
2025-10-29 Niels Möller <nisse@lysator.liu.se>
* base64-encode.c (base64_encode_group): Delete unused and
uint8_t *dst,
char src)
{
- /* Avoid signed char for indexing. */
- unsigned char usrc = src;
- int digit;
+ size_t dst_length = 1;
+ return base16_decode_update (ctx, &dst_length, dst, 1, &src)
+ ? dst_length : -1;
+}
- if (usrc >= 0x80)
- return -1;
+int
+base16_decode_update(struct base16_decode_ctx *ctx,
+ size_t *dst_length,
+ uint8_t *dst,
+ size_t src_length,
+ const char *src)
+{
+ size_t done;
+ size_t i;
- digit = hex_decode_table[usrc];
- switch (digit)
+ for (i = done = 0; i<src_length; i++)
{
- case -1:
- return -1;
- case -2:
- return 0;
- default:
- assert(digit >= 0);
- assert(digit < 0x10);
+ unsigned char usrc = src[i];
+ if (usrc >= 0x80)
+ return -1;
+
+ int digit = hex_decode_table[usrc];
+ if (digit == HEX_SPACE)
+ continue;
+ if (digit < 0 || done >= *dst_length)
+ return -1;
+ assert(digit < 0x10);
if (ctx->bits)
{
- *dst = (ctx->word << 4) | digit;
+ dst[done++] = (ctx->word << 4) | digit;
ctx->bits = 0;
- return 1;
}
else
{
ctx->word = digit;
ctx->bits = 4;
- return 0;
}
}
-}
-
-int
-base16_decode_update(struct base16_decode_ctx *ctx,
- size_t *dst_length,
- uint8_t *dst,
- size_t src_length,
- const char *src)
-{
- size_t done;
- size_t i;
-
- for (i = done = 0; i<src_length; i++)
- switch(base16_decode_single(ctx, dst + done, src[i]))
- {
- case -1:
- return 0;
- case 1:
- done++;
- /* Fall through */
- case 0:
- break;
- default:
- abort();
- }
-
assert(done <= BASE16_DECODE_LENGTH(src_length));
*dst_length = done;
char src);
/* Returns 1 on success, 0 on error. DST should point to an area of
- * size at least BASE16_DECODE_LENGTH(length). The amount of data
- * generated is returned in *DST_LENGTH. */
-
+ * size *DST_LENGTH. Decoding returns failure it output would exceed
+ * this size. BASE16_DECODE_LENGTH(src_length) is always sufficient.
+ * *DST_LENGTH is updated to reflect the amount of data actually
+ * generated. */
int
base16_decode_update(struct base16_decode_ctx *ctx,
size_t *dst_length,
uint8_t *dst,
char src)
{
- int data = ctx->table[(uint8_t) src];
-
- switch(data)
- {
- default:
- assert(data >= 0 && data < 0x40);
-
- if (ctx->padding)
- return -1;
-
- ctx->word = ctx->word << 6 | data;
- ctx->bits += 6;
-
- if (ctx->bits >= 8)
- {
- ctx->bits -= 8;
- dst[0] = ctx->word >> ctx->bits;
- return 1;
- }
- else return 0;
-
- case TABLE_INVALID:
- return -1;
-
- case TABLE_SPACE:
- return 0;
-
- case TABLE_END:
- /* There can be at most two padding characters. */
- if (!ctx->bits || ctx->padding > 2)
- return -1;
-
- if (ctx->word & ( (1<<ctx->bits) - 1))
- /* We shouldn't have any leftover bits */
- return -1;
-
- ctx->padding++;
- ctx->bits -= 2;
- return 0;
- }
+ size_t dst_length = 1;
+ return base64_decode_update (ctx, &dst_length, dst, 1, &src)
+ ? dst_length : -1;
}
int
size_t done;
size_t i;
- for (i = 0, done = 0; i<src_length; i++)
- switch(base64_decode_single(ctx, dst + done, src[i]))
- {
- case -1:
- return 0;
- case 1:
- done++;
- /* Fall through */
- case 0:
- break;
- default:
- abort();
- }
-
+ for (i = done = 0; i<src_length; i++)
+ {
+ int data = ctx->table[(uint8_t) src[i]];
+ switch (data)
+ {
+ default:
+ assert(data >= 0 && data < 0x40);
+
+ if (ctx->padding || (done >= *dst_length))
+ return -1;
+
+ ctx->word = ctx->word << 6 | data;
+ ctx->bits += 6;
+
+ if (ctx->bits >= 8)
+ {
+ ctx->bits -= 8;
+ dst[done++] = ctx->word >> ctx->bits;
+ }
+ break;
+ case TABLE_INVALID:
+ return -1;
+ case TABLE_SPACE:
+ continue;
+ case TABLE_END:
+ /* There can be at most two padding characters. */
+ if (!ctx->bits || ctx->padding > 2)
+ return -1;
+
+ if (ctx->word & ( (1<<ctx->bits) - 1))
+ /* We shouldn't have any leftover bits */
+ return -1;
+
+ ctx->padding++;
+ ctx->bits -= 2;
+ break;
+ }
+ }
assert(done <= BASE64_DECODE_LENGTH(src_length));
*dst_length = done;
char src);
/* Returns 1 on success, 0 on error. DST should point to an area of
- * size at least BASE64_DECODE_LENGTH(length). The amount of data
- * generated is returned in *DST_LENGTH. */
+ * size *DST_LENGTH. Decoding returns failure it output would exceed
+ * this size. BASE64_DECODE_LENGTH(length) is always sufficient.
+ * *DST_LENGTH is updated to reflect the amount of data actually
+ * generated. */
int
base64_decode_update(struct base64_decode_ctx *ctx,
size_t *dst_length,
for (;;)
{
int nbytes; /* Number of bytes read frmo disk at each iteration */
- size_t decoded_bytes; /* Bytes actually generated at each iteration */
+ size_t result_size = DECODED_SIZE;
nbytes = fread(buffer, 1, CHUNK_SIZE, stdin);
}
/* Decodes one chunk: */
- if (!base16_decode_update(&b16_ctx, &decoded_bytes, result, nbytes, buffer))
+ if (!base16_decode_update(&b16_ctx, &result_size, result, nbytes, buffer))
{
werror ("Error decoding input (not base16?)\n");
return EXIT_FAILURE;
}
- if (!write_data (stdout, decoded_bytes, result))
+ if (!write_data (stdout, result_size, result))
{
werror ("Error writing file: %s\n", strerror(errno));
return EXIT_FAILURE;
return 0;
base64_decode_init(&ctx);
-
+ coded_length = end - in;
if (base64_decode_update(&ctx, &coded_length, input + out,
end - in, (const char*) (input + in))
&& base64_decode_final(&ctx))
ASSERT (0x33 == buffer[ascii_length]);
base16_decode_init (&decode);
- done = BASE16_DECODE_LENGTH (ascii_length);
+ done = data_length;
ASSERT (base16_decode_update(&decode, &done, check, ascii_length, buffer));
ASSERT (done == data_length);
base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length,
size_t length, uint8_t *data)
{
+ *dst_length = length;
return base64_decode_update (ctx, dst_length,
data, length, (const char *) data);
}
decode_hex (size_t length, uint8_t *dst, const char *src)
{
struct base16_decode_ctx ctx;
- size_t out_size;
+ size_t out_size = length;
base16_decode_init (&ctx);
ASSERT (base16_decode_update (&ctx, &out_size, dst, 2*length, src));
ASSERT (out_size == length);
decode_hex (size_t length, uint8_t *dst, const char *src)
{
struct base16_decode_ctx ctx;
- size_t out_size;
+ size_t out_size = length;
base16_decode_init (&ctx);
ASSERT (base16_decode_update (&ctx, &out_size, dst, 2*length, src));
ASSERT (out_size == length);