2010-12-20 [colin] 3.7.8cvs12
[claws.git] / src / common / base64.c
index d38719f5b738a594b59a0ccf64580623693c7ee3..334a8655b9804155adf8881eb2446f7d814ab732 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto and the Claws Mail team
  *
  * 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
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #include <glib.h>
@@ -27,7 +27,7 @@
 static const gchar base64char[64] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-static const gchar base64val[128] = {
+static const signed char 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,
@@ -128,42 +128,44 @@ void base64_decoder_free(Base64Decoder *decoder)
 }
 
 gint base64_decoder_decode(Base64Decoder *decoder,
-                          const gchar *in, guchar *out)
+                          const gchar *in, guchar *out, gint inlen)
 {
+       const gchar *in_end = in + inlen;
        gint len, total_len = 0;
+       gboolean in_more = inlen > 0;
+       gboolean got_eq = FALSE;
        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);
+       cm_return_val_if_fail(decoder != NULL, -1);
+       cm_return_val_if_fail(in != NULL, -1);
+       cm_return_val_if_fail(out != NULL, -1);
 
+       /* Start with previous saved tail */    
        buf_len = decoder->buf_len;
        memcpy(buf, decoder->buf, sizeof(buf));
 
-       for (;;) {
-               while (buf_len < 4) {
+       while (in_more) {
+               while (buf_len < 4 && in_more) {
                        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;
+                       got_eq = (c == '=');
+                       if (got_eq || BASE64VAL(c) >= 0)
+                               buf[buf_len++] = c;
+                       in_more = (in < in_end) && !(got_eq && (buf_len == 4));
                }
-               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;
+               if (buf_len == 4) {
+                       len = base64_decode(out, buf, 4);
+                       out += len;
+                       total_len += len;
+                       buf_len = 0;
                }
        }
+       if (buf_len < 4) { 
+               /* Save tail for next iteration call. It wll be ignored if ends here. */
+               decoder->buf_len = buf_len;
+               memcpy(decoder->buf, buf, buf_len);
+       }
+       return total_len;
 }