Skip to content

Commit

Permalink
Reverted base64 encoder optimizations to support chunked base64
Browse files Browse the repository at this point in the history
Fixes issue #150
  • Loading branch information
jstedfast committed May 28, 2023
1 parent c376dc9 commit 0a65aed
Showing 1 changed file with 83 additions and 88 deletions.
171 changes: 83 additions & 88 deletions gmime/gmime-encodings.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static unsigned char gmime_base64_rank[256] = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
Expand Down Expand Up @@ -382,37 +382,35 @@ g_mime_encoding_flush (GMimeEncoding *state, const char *inbuf, size_t inlen, ch
size_t
g_mime_encoding_base64_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
{
register unsigned char *outptr = outbuf;
register int quartets;
unsigned char *saved;

unsigned char *outptr = outbuf;
int c1, c2;

if (inlen > 0)
outptr += g_mime_encoding_base64_encode_step (inbuf, inlen, outbuf, state, save);

saved = (unsigned char *) save;
quartets = *state;

if (*saved > 0) {
int c1 = saved[1];
int c2 = saved[2];

*outptr++ = base64_alphabet[c1 >> 2];
*outptr++ = base64_alphabet[c2 >> 4 | ((c1 & 0x3) << 4)];
if (*saved == 2)
*outptr++ = base64_alphabet[(c2 & 0x0f) << 2];
else
*outptr++ = '=';
*outptr++ = '=';
quartets++;
outptr += g_mime_encoding_base64_encode_step (inbuf, inlen, outptr, state, save);
c1 = ((unsigned char *)save)[1];
c2 = ((unsigned char *)save)[2];
switch (((unsigned char *)save)[0]) {
case 2:
outptr[2] = base64_alphabet [(c2 & 0x0f) << 2];
goto skip;
case 1:
outptr[2] = '=';
skip:
outptr[0] = base64_alphabet [c1 >> 2];
outptr[1] = base64_alphabet [c2 >> 4 | ((c1 & 0x3) << 4)];
outptr[3] = '=';
outptr += 4;
break;
}

if (quartets > 0)
*outptr++ = '\n';

*state = 0;

*outptr++ = '\n';

*save = 0;

return (size_t) (outptr - outbuf);
*state = 0;

return (outptr - outbuf);
}


Expand All @@ -436,74 +434,71 @@ g_mime_encoding_base64_encode_step (const unsigned char *inbuf, size_t inlen, un
{
register const unsigned char *inptr;
register unsigned char *outptr;
register int quartets;
unsigned char *saved;
size_t remaining;


if (inlen == 0)
return 0;

saved = (unsigned char *) save;
quartets = *state;

outptr = outbuf;
inptr = inbuf;

if (inlen + *saved > 2) {
if (inlen + ((unsigned char *)save)[0] > 2) {
const unsigned char *inend = inbuf + inlen - 2;
register int c1, c2, c3;

c1 = *saved < 1 ? *inptr++ : saved[1];
c2 = *saved < 2 ? *inptr++ : saved[2];
c3 = *inptr++;

loop:
/* encode our triplet into a quartet */
*outptr++ = base64_alphabet[c1 >> 2];
*outptr++ = base64_alphabet[(c2 >> 4) | ((c1 & 0x3) << 4)];
*outptr++ = base64_alphabet[((c2 & 0x0f) << 2) | (c3 >> 6)];
*outptr++ = base64_alphabet[c3 & 0x3f];

/* encode 19 quartets per line */
if ((++quartets) >= 19) {
*outptr++ = '\n';
quartets = 0;
register int c1 = 0, c2 = 0, c3 = 0;
register int already;

already = *state;

switch (((char *)save)[0]) {
case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
case 2: c1 = ((unsigned char *)save)[1];
c2 = ((unsigned char *)save)[2]; goto skip2;
}

if (inptr >= inend)
goto loop_exit;

c1 = *inptr++;
c2 = *inptr++;
c3 = *inptr++;
goto loop;

loop_exit:
remaining = 2 - (size_t) (inptr - inend);
*save = 0;
} else {
remaining = inlen;

/* yes, we jump into the loop, no i'm not going to change it, its beautiful! */
while (inptr < inend) {
c1 = *inptr++;
skip1:
c2 = *inptr++;
skip2:
c3 = *inptr++;
*outptr++ = base64_alphabet [c1 >> 2];
*outptr++ = base64_alphabet [(c2 >> 4) | ((c1 & 0x3) << 4)];
*outptr++ = base64_alphabet [((c2 & 0x0f) << 2) | (c3 >> 6)];
*outptr++ = base64_alphabet [c3 & 0x3f];
/* this is a bit ugly ... */
if ((++already) >= 19) {
*outptr++ = '\n';
already = 0;
}
}

((unsigned char *)save)[0] = 0;
inlen = 2 - (inptr - inend);
*state = already;
}

if (remaining > 0) {
/* At this point, saved can only be 0 or 1. */
if (*saved == 0) {
/* We can have up to 2 remaining input bytes. */
saved[0] = (unsigned char) remaining;
saved[1] = *inptr++;
if (remaining == 2)
saved[2] = *inptr;
else
saved[2] = 0;
} else {
/* We have 1 remaining input byte. */
saved[2] = *inptr;
saved[0] = 2;

d(printf ("state = %d, inlen = %d\n", (int)((char *)save)[0], inlen));

if (inlen > 0) {
register char *saveout;

/* points to the slot for the next char to save */
saveout = & (((char *)save)[1]) + ((char *)save)[0];

/* inlen can only be 0, 1 or 2 */
switch (inlen) {
case 2: *saveout++ = *inptr++;
case 1: *saveout++ = *inptr++;
}
((char *)save)[0] += (char) inlen;
}

*state = quartets;

return (size_t) (outptr - outbuf);

d(printf ("mode = %d\nc1 = %c\nc2 = %c\n",
(int)((char *)save)[0],
(int)((char *)save)[1],
(int)((char *)save)[2]));

return (outptr - outbuf);
}


Expand Down

0 comments on commit 0a65aed

Please sign in to comment.