Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import java.io.FilterInputStream;
     20 import java.io.IOException;
     21 import java.io.InputStream;
     22 
     23 /**
     24  * An InputStream that does Base64 decoding on the data read through
     25  * it.
     26  */
     27 public class Base64InputStream extends FilterInputStream {
     28     private final Base64.Coder coder;
     29 
     30     private static byte[] EMPTY = new byte[0];
     31 
     32     private static final int BUFFER_SIZE = 2048;
     33     private boolean eof;
     34     private byte[] inputBuffer;
     35     private int outputStart;
     36     private int outputEnd;
     37 
     38     /**
     39      * An InputStream that performs Base64 decoding on the data read
     40      * from the wrapped stream.
     41      *
     42      * @param in the InputStream to read the source data from
     43      * @param flags bit flags for controlling the decoder; see the
     44      *        constants in {@link Base64}
     45      */
     46     public Base64InputStream(InputStream in, int flags) {
     47         this(in, flags, false);
     48     }
     49 
     50     /**
     51      * Performs Base64 encoding or decoding on the data read from the
     52      * wrapped InputStream.
     53      *
     54      * @param in the InputStream to read the source data from
     55      * @param flags bit flags for controlling the decoder; see the
     56      *        constants in {@link Base64}
     57      * @param encode true to encode, false to decode
     58      *
     59      * @hide
     60      */
     61     public Base64InputStream(InputStream in, int flags, boolean encode) {
     62         super(in);
     63         eof = false;
     64         inputBuffer = new byte[BUFFER_SIZE];
     65         if (encode) {
     66             coder = new Base64.Encoder(flags, null);
     67         } else {
     68             coder = new Base64.Decoder(flags, null);
     69         }
     70         coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)];
     71         outputStart = 0;
     72         outputEnd = 0;
     73     }
     74 
     75     public boolean markSupported() {
     76         return false;
     77     }
     78 
     79     public void mark(int readlimit) {
     80         throw new UnsupportedOperationException();
     81     }
     82 
     83     public void reset() {
     84         throw new UnsupportedOperationException();
     85     }
     86 
     87     public void close() throws IOException {
     88         in.close();
     89         inputBuffer = null;
     90     }
     91 
     92     public int available() {
     93         return outputEnd - outputStart;
     94     }
     95 
     96     public long skip(long n) throws IOException {
     97         if (outputStart >= outputEnd) {
     98             refill();
     99         }
    100         if (outputStart >= outputEnd) {
    101             return 0;
    102         }
    103         long bytes = Math.min(n, outputEnd-outputStart);
    104         outputStart += bytes;
    105         return bytes;
    106     }
    107 
    108     public int read() throws IOException {
    109         if (outputStart >= outputEnd) {
    110             refill();
    111         }
    112         if (outputStart >= outputEnd) {
    113             return -1;
    114         } else {
    115             return coder.output[outputStart++] & 0xff;
    116         }
    117     }
    118 
    119     public int read(byte[] b, int off, int len) throws IOException {
    120         if (outputStart >= outputEnd) {
    121             refill();
    122         }
    123         if (outputStart >= outputEnd) {
    124             return -1;
    125         }
    126         int bytes = Math.min(len, outputEnd-outputStart);
    127         System.arraycopy(coder.output, outputStart, b, off, bytes);
    128         outputStart += bytes;
    129         return bytes;
    130     }
    131 
    132     /**
    133      * Read data from the input stream into inputBuffer, then
    134      * decode/encode it into the empty coder.output, and reset the
    135      * outputStart and outputEnd pointers.
    136      */
    137     private void refill() throws IOException {
    138         if (eof) return;
    139         int bytesRead = in.read(inputBuffer);
    140         boolean success;
    141         if (bytesRead == -1) {
    142             eof = true;
    143             success = coder.process(EMPTY, 0, 0, true);
    144         } else {
    145             success = coder.process(inputBuffer, 0, bytesRead, false);
    146         }
    147         if (!success) {
    148             throw new Base64DataException("bad base-64");
    149         }
    150         outputEnd = coder.op;
    151         outputStart = 0;
    152     }
    153 }
    154