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.

The algorithm is quite naive and slow because it checks each byte
independently. There is definitely room for improvement.
  • Loading branch information
aklomp committed Jan 9, 2024
1 parent 6756832 commit 7f3c2d9
Showing 1 changed file with 56 additions and 11 deletions.
67 changes: 56 additions & 11 deletions bin/base64.c
Expand Up @@ -340,7 +340,20 @@ encode (const struct config *config, struct buffer *buf)
return true;
}

static int
static inline size_t
find_newline (const char *p, const size_t avail)
{
// This is very naive and can definitely be improved.
for (size_t len = 0; len < avail; len++) {
if (p[len] == '\n') {
return len;
}
}

return avail;
}

static bool
decode (const struct config *config, struct buffer *buf)
{
size_t nread, nout;
Expand All @@ -352,18 +365,50 @@ 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. Tokenize the input on newline characters.
// This is quite slow, and at some point we will want to
// vectorize this.
while (avail > 0) {

// Find the offset of the next newline character.
size_t len = find_newline(s, avail);

// 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 (len == avail) {
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 7f3c2d9

Please sign in to comment.