Fix invalid substring range parameters

Fix the fix in decodeEncodedWords to do proper checking of -1 return
values from String.indexOf, and make similar fixes in decodeEncodedWord.
Add unit tests.

Bug:15016488
Change-Id: I607c363bd2dcf76a95d233644e00de74b69770d2
diff --git a/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/src/org/apache/james/mime4j/decoder/DecoderUtil.java
index 8a5dfb4..48fe07d 100644
--- a/src/org/apache/james/mime4j/decoder/DecoderUtil.java
+++ b/src/org/apache/james/mime4j/decoder/DecoderUtil.java
@@ -160,7 +160,7 @@
         if (body.indexOf("=?") == -1) {
             return body;
         }
-        
+
         int previousEnd = 0;
         boolean previousWasEncoded = false;
 
@@ -168,26 +168,24 @@
 
         while (true) {
             int begin = body.indexOf("=?", previousEnd);
-            
+
             // ANDROID:  The mime4j original version has an error here.  It gets confused if
             // the encoded string begins with an '=' (just after "?Q?").  This patch seeks forward
             // to find the two '?' in the "header", before looking for the final "?=".
-            int endScan = begin + 2;
-            if (begin != -1) {
-                int qm1 = body.indexOf('?', endScan + 2);
-                int qm2 = body.indexOf('?', qm1 + 1);
-                if (qm2 != -1) {
-                    endScan = qm2 + 1;
-                }
+            if (begin == -1) {
+                break;
             }
-            
-            int end = begin == -1 ? -1 : body.indexOf("?=", endScan);
+            int qm1 = body.indexOf('?', begin + 2);
+            if (qm1 == -1) {
+                break;
+            }
+            int qm2 = body.indexOf('?', qm1 + 1);
+            if (qm2 == -1) {
+                break;
+            }
+            int end = body.indexOf("?=", qm2 + 1);
             if (end == -1) {
-                if (previousEnd == 0)
-                    return body;
-
-                sb.append(body.substring(previousEnd));
-                return sb.toString();
+                break;
             }
             end += 2;
 
@@ -207,16 +205,23 @@
             previousEnd = end;
             previousWasEncoded = decoded != null;
         }
+
+        if (previousEnd == 0)
+            return body;
+
+        sb.append(body.substring(previousEnd));
+        return sb.toString();
     }
 
-    // return null on error
-    private static String decodeEncodedWord(String body, int begin, int end) {
+    // return null on error. Begin is index of '=?' in body.
+    public static String decodeEncodedWord(String body, int begin, int end) {
+        // Skip the '?=' chars in body and scan forward from there for next '?'
         int qm1 = body.indexOf('?', begin + 2);
-        if (qm1 == end - 2)
+        if (qm1 == -1 || qm1 == end - 2)
             return null;
 
         int qm2 = body.indexOf('?', qm1 + 1);
-        if (qm2 == end - 2)
+        if (qm2 == -1 || qm2 == end - 2)
             return null;
 
         String mimeCharset = body.substring(begin + 2, qm1);
diff --git a/tests/src/com/android/emailcommon/mail/AddressUnitTests.java b/tests/src/com/android/emailcommon/mail/AddressUnitTests.java
index 32a10f9..ee46dff 100644
--- a/tests/src/com/android/emailcommon/mail/AddressUnitTests.java
+++ b/tests/src/com/android/emailcommon/mail/AddressUnitTests.java
@@ -88,6 +88,24 @@
         }
     }
 
+    @SmallTest
+    public void testEncodedWords() {
+        final String body = "=?UTF-8?B?Foobar?=";
+        DecoderUtil.decodeEncodedWords(body);
+
+        final String body2 = "=?UTF-8?B?Foobar?==?";
+        DecoderUtil.decodeEncodedWords(body2);
+    }
+
+    @SmallTest
+    public void testEncodedWord() {
+        final String body = "=?UTF-8?B?Foobar?=";
+        DecoderUtil.decodeEncodedWord(body, 0, body.length());
+
+        final String body2 = "=?Foobar";
+        DecoderUtil.decodeEncodedWord(body2, 0, body2.length());
+    }
+
     /**
      * Test for setAddress().
      */