X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fbase64.c;h=7ed3c40afde9a8de55227e8e4efd3c60591d2951;hp=3cd3bcb7989a3f2b75dd80c937edbc116a6db6cc;hb=8bd1d905d643bdb7b71dd9db298bae35399c05fc;hpb=036b63d8fc5a8c6e1ff150737226122c174c39cb diff --git a/src/base64.c b/src/base64.c index 3cd3bcb79..7ed3c40af 100644 --- a/src/base64.c +++ b/src/base64.c @@ -1,98 +1,168 @@ /* - * base64.c -- base-64 conversion routines. + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2002 Hiroyuki Yamamoto * - * For license terms, see the file COPYING in this directory. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This base 64 encoding is defined in RFC2045 section 6.8, - * "Base64 Content-Transfer-Encoding", but lines must not be broken in the - * scheme used here. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Modified by Hiroyuki Yamamoto + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include #include +#include + +#include "base64.h" -static const char base64digits[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -#define BAD -1 -static const char base64val[] = { - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, - BAD, 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,BAD, BAD,BAD,BAD,BAD, - BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD +static const gchar base64char[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const gchar base64val[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 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, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 }; -#define DECODE64(c) (isascii(c) ? base64val[c] : BAD) -void to64frombits(unsigned char *out, const unsigned char *in, int inlen) -/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ +#define BASE64VAL(c) (isascii(c) ? base64val[(gint)(c)] : -1) + +void base64_encode(gchar *out, const guchar *in, gint inlen) { - for (; inlen >= 3; inlen -= 3) - { - *out++ = base64digits[in[0] >> 2]; - *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; - *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; - *out++ = base64digits[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - unsigned char fragment; - - *out++ = base64digits[in[0] >> 2]; - fragment = (in[0] << 4) & 0x30; - if (inlen > 1) - fragment |= in[1] >> 4; - *out++ = base64digits[fragment]; - *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c]; - *out++ = '='; - } - *out = '\0'; + const guchar *inp = in; + gchar *outp = out; + + while (inlen >= 3) { + *outp++ = base64char[(inp[0] >> 2) & 0x3f]; + *outp++ = base64char[((inp[0] & 0x03) << 4) | + ((inp[1] >> 4) & 0x0f)]; + *outp++ = base64char[((inp[1] & 0x0f) << 2) | + ((inp[2] >> 6) & 0x03)]; + *outp++ = base64char[inp[2] & 0x3f]; + + inp += 3; + inlen -= 3; + } + + if (inlen > 0) { + *outp++ = base64char[(inp[0] >> 2) & 0x3f]; + if (inlen == 1) { + *outp++ = base64char[(inp[0] & 0x03) << 4]; + *outp++ = '='; + } else { + *outp++ = base64char[((inp[0] & 0x03) << 4) | + ((inp[1] >> 4) & 0x0f)]; + *outp++ = base64char[((inp[1] & 0x0f) << 2)]; + } + *outp++ = '='; + } + + *outp = '\0'; } -int from64tobits(char *out, const char *in) -/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */ +gint base64_decode(guchar *out, const gchar *in, gint inlen) { - int len = 0; - register unsigned char digit1, digit2, digit3, digit4; - - if (in[0] == '+' && in[1] == ' ') - in += 2; - if (*in == '\r' || *in == '\n') - return 0; - - do { - digit1 = in[0]; - if (DECODE64(digit1) == BAD) - return -1; - digit2 = in[1]; - if (DECODE64(digit2) == BAD) - return -1; - digit3 = in[2]; - if (digit3 != '=' && DECODE64(digit3) == BAD) - return -1; - digit4 = in[3]; - if (digit4 != '=' && DECODE64(digit4) == BAD) - return -1; - in += 4; - *out++ = (DECODE64(digit1) << 2) | ((DECODE64(digit2) >> 4) & 0x03); - ++len; - if (digit3 != '=') - { - *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); - ++len; - if (digit4 != '=') - { - *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); - ++len; - } + const gchar *inp = in; + guchar *outp = out; + gchar buf[4]; + + if (inlen < 0) + inlen = G_MAXINT; + + while (inlen >= 4 && *inp != '\0') { + buf[0] = *inp++; + inlen--; + if (BASE64VAL(buf[0]) == -1) break; + + buf[1] = *inp++; + inlen--; + if (BASE64VAL(buf[1]) == -1) break; + + buf[2] = *inp++; + inlen--; + if (buf[2] != '=' && BASE64VAL(buf[2]) == -1) break; + + buf[3] = *inp++; + inlen--; + if (buf[3] != '=' && BASE64VAL(buf[3]) == -1) break; + + *outp++ = ((BASE64VAL(buf[0]) << 2) & 0xfc) | + ((BASE64VAL(buf[1]) >> 4) & 0x03); + if (buf[2] != '=') { + *outp++ = ((BASE64VAL(buf[1]) & 0x0f) << 4) | + ((BASE64VAL(buf[2]) >> 2) & 0x0f); + if (buf[3] != '=') { + *outp++ = ((BASE64VAL(buf[2]) & 0x03) << 6) | + (BASE64VAL(buf[3]) & 0x3f); + } + } } - } while (*in && *in != '\r' && *in != '\n' && digit4 != '='); - return len; + return outp - out; +} + +Base64Decoder *base64_decoder_new(void) +{ + Base64Decoder *decoder; + + decoder = g_new0(Base64Decoder, 1); + return decoder; +} + +void base64_decoder_free(Base64Decoder *decoder) +{ + g_free(decoder); } -/* base64.c ends here */ +gint base64_decoder_decode(Base64Decoder *decoder, + const gchar *in, guchar *out) +{ + gint len, total_len = 0; + gint buf_len; + gchar buf[4]; + + g_return_val_if_fail(decoder != NULL, -1); + g_return_val_if_fail(in != NULL, -1); + g_return_val_if_fail(out != NULL, -1); + + buf_len = decoder->buf_len; + memcpy(buf, decoder->buf, sizeof(buf)); + + for (;;) { + while (buf_len < 4) { + gchar c = *in; + + in++; + if (c == '\0') break; + if (c == '\r' || c == '\n') continue; + if (c != '=' && BASE64VAL(c) == -1) + return -1; + buf[buf_len++] = c; + } + if (buf_len < 4 || buf[0] == '=' || buf[1] == '=') { + decoder->buf_len = buf_len; + memcpy(decoder->buf, buf, sizeof(buf)); + return total_len; + } + len = base64_decode(out, buf, 4); + out += len; + total_len += len; + buf_len = 0; + if (len < 3) { + decoder->buf_len = 0; + return total_len; + } + } +}