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 android.annotation.UnsupportedAppUsage;
     20 import java.io.FilterOutputStream;
     21 import java.io.IOException;
     22 import java.io.OutputStream;
     23 
     24 /**
     25  * An OutputStream that does Base64 encoding on the data written to
     26  * it, writing the resulting data to another OutputStream.
     27  */
     28 public class Base64OutputStream extends FilterOutputStream {
     29     private final Base64.Coder coder;
     30     private final int flags;
     31 
     32     private byte[] buffer = null;
     33     private int bpos = 0;
     34 
     35     private static byte[] EMPTY = new byte[0];
     36 
     37     /**
     38      * Performs Base64 encoding on the data written to the stream,
     39      * writing the encoded data to another OutputStream.
     40      *
     41      * @param out the OutputStream to write the encoded data to
     42      * @param flags bit flags for controlling the encoder; see the
     43      *        constants in {@link Base64}
     44      */
     45     public Base64OutputStream(OutputStream out, int flags) {
     46         this(out, flags, true);
     47     }
     48 
     49     /**
     50      * Performs Base64 encoding or decoding on the data written to the
     51      * stream, writing the encoded/decoded data to another
     52      * OutputStream.
     53      *
     54      * @param out the OutputStream to write the encoded data to
     55      * @param flags bit flags for controlling the encoder; see the
     56      *        constants in {@link Base64}
     57      * @param encode true to encode, false to decode
     58      *
     59      * @hide
     60      */
     61     @UnsupportedAppUsage
     62     public Base64OutputStream(OutputStream out, int flags, boolean encode) {
     63         super(out);
     64         this.flags = flags;
     65         if (encode) {
     66             coder = new Base64.Encoder(flags, null);
     67         } else {
     68             coder = new Base64.Decoder(flags, null);
     69         }
     70     }
     71 
     72     public void write(int b) throws IOException {
     73         // To avoid invoking the encoder/decoder routines for single
     74         // bytes, we buffer up calls to write(int) in an internal
     75         // byte array to transform them into writes of decently-sized
     76         // arrays.
     77 
     78         if (buffer == null) {
     79             buffer = new byte[1024];
     80         }
     81         if (bpos >= buffer.length) {
     82             // internal buffer full; write it out.
     83             internalWrite(buffer, 0, bpos, false);
     84             bpos = 0;
     85         }
     86         buffer[bpos++] = (byte) b;
     87     }
     88 
     89     /**
     90      * Flush any buffered data from calls to write(int).  Needed
     91      * before doing a write(byte[], int, int) or a close().
     92      */
     93     private void flushBuffer() throws IOException {
     94         if (bpos > 0) {
     95             internalWrite(buffer, 0, bpos, false);
     96             bpos = 0;
     97         }
     98     }
     99 
    100     public void write(byte[] b, int off, int len) throws IOException {
    101         if (len <= 0) return;
    102         flushBuffer();
    103         internalWrite(b, off, len, false);
    104     }
    105 
    106     public void close() throws IOException {
    107         IOException thrown = null;
    108         try {
    109             flushBuffer();
    110             internalWrite(EMPTY, 0, 0, true);
    111         } catch (IOException e) {
    112             thrown = e;
    113         }
    114 
    115         try {
    116             if ((flags & Base64.NO_CLOSE) == 0) {
    117                 out.close();
    118             } else {
    119                 out.flush();
    120             }
    121         } catch (IOException e) {
    122             if (thrown == null) {
    123                 thrown = e;
    124             } else {
    125                 thrown.addSuppressed(e);
    126             }
    127         }
    128 
    129         if (thrown != null) {
    130             throw thrown;
    131         }
    132     }
    133 
    134     /**
    135      * Write the given bytes to the encoder/decoder.
    136      *
    137      * @param finish true if this is the last batch of input, to cause
    138      *        encoder/decoder state to be finalized.
    139      */
    140     private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
    141         coder.output = embiggen(coder.output, coder.maxOutputSize(len));
    142         if (!coder.process(b, off, len, finish)) {
    143             throw new Base64DataException("bad base-64");
    144         }
    145         out.write(coder.output, 0, coder.op);
    146     }
    147 
    148     /**
    149      * If b.length is at least len, return b.  Otherwise return a new
    150      * byte array of length len.
    151      */
    152     private byte[] embiggen(byte[] b, int len) {
    153         if (b == null || b.length < len) {
    154             return new byte[len];
    155         } else {
    156             return b;
    157         }
    158     }
    159 }
    160