Home | History | Annotate | Download | only in decoder
      1 /****************************************************************
      2  * Licensed to the Apache Software Foundation (ASF) under one   *
      3  * or more contributor license agreements.  See the NOTICE file *
      4  * distributed with this work for additional information        *
      5  * regarding copyright ownership.  The ASF licenses this file   *
      6  * to you under the Apache License, Version 2.0 (the            *
      7  * "License"); you may not use this file except in compliance   *
      8  * with the License.  You may obtain a copy of the License at   *
      9  *                                                              *
     10  *   http://www.apache.org/licenses/LICENSE-2.0                 *
     11  *                                                              *
     12  * Unless required by applicable law or agreed to in writing,   *
     13  * software distributed under the License is distributed on an  *
     14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
     15  * KIND, either express or implied.  See the License for the    *
     16  * specific language governing permissions and limitations      *
     17  * under the License.                                           *
     18  ****************************************************************/
     19 
     20 /**
     21  * Modified to improve efficiency by Android   21-Aug-2009
     22  */
     23 
     24 package org.apache.james.mime4j.decoder;
     25 
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 
     29 /**
     30  * Performs Base-64 decoding on an underlying stream.
     31  *
     32  *
     33  * @version $Id: Base64InputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $
     34  */
     35 public class Base64InputStream extends InputStream {
     36     private final InputStream s;
     37     private int outCount = 0;
     38     private int outIndex = 0;
     39     private final int[] outputBuffer = new int[3];
     40     private final byte[] inputBuffer = new byte[4];
     41     private boolean done = false;
     42 
     43     public Base64InputStream(InputStream s) {
     44         this.s = s;
     45     }
     46 
     47     /**
     48      * Closes the underlying stream.
     49      *
     50      * @throws IOException on I/O errors.
     51      */
     52     @Override
     53     public void close() throws IOException {
     54         s.close();
     55     }
     56 
     57     @Override
     58     public int read() throws IOException {
     59         if (outIndex == outCount) {
     60             fillBuffer();
     61             if (outIndex == outCount) {
     62                 return -1;
     63             }
     64         }
     65 
     66         return outputBuffer[outIndex++];
     67     }
     68 
     69     /**
     70      * Retrieve data from the underlying stream, decode it,
     71      * and put the results in the byteq.
     72      * @throws IOException
     73      */
     74     private void fillBuffer() throws IOException {
     75         outCount = 0;
     76         outIndex = 0;
     77         int inCount = 0;
     78 
     79         int i;
     80         // "done" is needed for the two successive '=' at the end
     81         while (!done) {
     82             switch (i = s.read()) {
     83                 case -1:
     84                     // No more input - just return, let outputBuffer drain out, and be done
     85                     return;
     86                 case '=':
     87                     // once we meet the first '=', avoid reading the second '='
     88                     done = true;
     89                     decodeAndEnqueue(inCount);
     90                     return;
     91                 default:
     92                     byte sX = TRANSLATION[i];
     93                     if (sX < 0) continue;
     94                     inputBuffer[inCount++] = sX;
     95                     if (inCount == 4) {
     96                         decodeAndEnqueue(inCount);
     97                         return;
     98                     }
     99                     break;
    100             }
    101         }
    102     }
    103 
    104     private void decodeAndEnqueue(int len) {
    105         int accum = 0;
    106         accum |= inputBuffer[0] << 18;
    107         accum |= inputBuffer[1] << 12;
    108         accum |= inputBuffer[2] << 6;
    109         accum |= inputBuffer[3];
    110 
    111         // There's a bit of duplicated code here because we want to have straight-through operation
    112         // for the most common case of len==4
    113         if (len == 4) {
    114             outputBuffer[0] = (accum >> 16) & 0xFF;
    115             outputBuffer[1] = (accum >> 8) & 0xFF;
    116             outputBuffer[2] = (accum) & 0xFF;
    117             outCount = 3;
    118             return;
    119         } else if (len == 3) {
    120             outputBuffer[0] = (accum >> 16) & 0xFF;
    121             outputBuffer[1] = (accum >> 8) & 0xFF;
    122             outCount = 2;
    123             return;
    124         } else {    // len == 2
    125             outputBuffer[0] = (accum >> 16) & 0xFF;
    126             outCount = 1;
    127             return;
    128         }
    129     }
    130 
    131     private static byte[] TRANSLATION = {
    132         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
    133         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
    134         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
    135         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
    136         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
    137         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
    138         -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
    139         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 */
    140         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */
    141         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 */
    142         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 */
    143         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 */
    144         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */
    145         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 */
    146         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 */
    147         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1     /* 0xF0 */
    148     };
    149 
    150 
    151 }
    152