From 629e18ad866917523599ed059898f4d986e49e26 Mon Sep 17 00:00:00 2001 From: Mihai Preda Date: Thu, 27 Aug 2009 22:24:30 +0200 Subject: [PATCH] Fix base64 decoder. BUG 2081740. It was broken by CL 22378. The bug was in the situation when "==" (two padding chars) were at the end, the reading did not stop after the first '=', and thus one more char of output was generated. Add more unit-test for base64 decoding. --- .../mime4j/decoder/Base64InputStream.java | 6 ++++- .../android/email/mail/AddressUnitTests.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/src/org/apache/james/mime4j/decoder/Base64InputStream.java index 8bfb33020..2461ed571 100644 --- a/src/org/apache/james/mime4j/decoder/Base64InputStream.java +++ b/src/org/apache/james/mime4j/decoder/Base64InputStream.java @@ -38,6 +38,7 @@ public class Base64InputStream extends InputStream { private int outIndex = 0; private final int[] outputBuffer = new int[3]; private final byte[] inputBuffer = new byte[4]; + private boolean done = false; public Base64InputStream(InputStream s) { this.s = s; @@ -76,12 +77,15 @@ public class Base64InputStream extends InputStream { int inCount = 0; int i; - while (true) { + // "done" is needed for the two successive '=' at the end + while (!done) { switch (i = s.read()) { case -1: // No more input - just return, let outputBuffer drain out, and be done return; case '=': + // once we meet the first '=', avoid reading the second '=' + done = true; decodeAndEnqueue(inCount); return; default: diff --git a/tests/src/com/android/email/mail/AddressUnitTests.java b/tests/src/com/android/email/mail/AddressUnitTests.java index 17c00d4cf..ca9520f7b 100644 --- a/tests/src/com/android/email/mail/AddressUnitTests.java +++ b/tests/src/com/android/email/mail/AddressUnitTests.java @@ -18,6 +18,7 @@ package com.android.email.mail; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import org.apache.james.mime4j.decoder.DecoderUtil; /** * This is a series of unit tests for the Address class. These tests must be locally @@ -54,6 +55,27 @@ public class AddressUnitTests extends AndroidTestCase { mAddress3 = new Address("address3", null); } + // see documentation of DecoderUtil.decodeEncodedWords() for details + private String padEncoded(String s) { + return "=?UTF-8?B?" + s + "?="; + } + + /** + * Generate strings of incresing lenght by taking prefix substrings. + * For each of them, compare with the decoding of the precomputed base-64 encoding. + */ + public void testBase64Decode() { + String testString = "xyza\0\""; + String base64Encoded[] = {"", "eA==", "eHk=", "eHl6", "eHl6YQ==", "eHl6YQA=", "eHl6YQAi"}; + int len = testString.length(); + for (int i = 1; i <= len; ++i) { + String encoded = padEncoded(base64Encoded[i]); + String decoded = DecoderUtil.decodeEncodedWords(encoded); + String prefix = testString.substring(0, i); + assertEquals(""+i, prefix, decoded); + } + } + /** * Test for setAddress(). */