Skip to content

Commit

Permalink
bin/base64: decode: ignore newlines
Browse files Browse the repository at this point in the history
By popular demand, ignore newlines in the encoded input. This achieves
bug compatibility with GNU base64.

Using `memchr(3)' is probably going to slow down things, but we can
vectorize the algorithm later.
  • Loading branch information
aklomp committed Jan 9, 2024
1 parent 6756832 commit 4afd462
Showing 1 changed file with 51 additions and 11 deletions.
62 changes: 51 additions & 11 deletions bin/base64.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ encode (const struct config *config, struct buffer *buf)
return true;
}

static int
static bool
decode (const struct config *config, struct buffer *buf)
{
size_t nread, nout;
Expand All @@ -352,18 +352,58 @@ decode (const struct config *config, struct buffer *buf)
// Read encoded data into the buffer. Use the smallest buffer size to
// be on the safe side: the decoded output will fit the raw buffer.
while ((nread = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) {
char *s = buf->enc;
size_t avail = nread;

// By popular demand, this utility tries to be bug-compatible
// with GNU `base64'. That includes silently ignoring newlines
// in the input. Use `memchr(3)' to tokenize the input on
// newline characters. This is probably quite slow, and at some
// point we will want to vectorize this.
// Ignore \r for now, because there is no equivalent to
// `strpbrk(3)' in the mem* series of library functions. Also,
// this program is intended to be used in Unix-like
// environments where \r is not treated specially.
while (avail > 0) {

// Find the next newline character.
char *p = memchr(s, '\n', avail);

// Find the length of the next chunk. If no newline is
// found, use the rest of the buffer.
size_t len = p == NULL ? avail : (size_t) (p - s);

// Ignore empty chunks.
if (len == 0) {
s++;
avail--;
continue;
}

// Decode the input into the raw buffer.
if (base64_stream_decode(&state, buf->enc, nread,
buf->raw, &nout) == 0) {
fprintf(stderr, "%s: %s: decoding error\n",
config->name, config->file);
return false;
}
// Decode the input into the raw buffer.
if (base64_stream_decode(&state, s, len,
buf->raw, &nout) == 0) {
fprintf(stderr, "%s: %s: decoding error\n",
config->name, config->file);
return false;
}

// Append the raw data to the output stream.
if (write_stdout(config, buf->raw, nout) == false) {
return false;
// Append the raw data to the output stream.
if (write_stdout(config, buf->raw, nout) == false) {
return false;
}

// Bail out if the whole string has been consumed.
if (p == NULL) {
break;
}

// Add the newline to the chunk length.
len++;

// Move the start pointer and length past the chunk.
s += len;
avail -= len;
}
}

Expand Down

0 comments on commit 4afd462

Please sign in to comment.