| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.util; |
| |
| import java.io.FilterOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| /** |
| * An OutputStream that does Base64 encoding on the data written to |
| * it, writing the resulting data to another OutputStream. |
| */ |
| public class Base64OutputStream extends FilterOutputStream { |
| private final Base64.Coder coder; |
| private final int flags; |
| |
| private byte[] buffer = null; |
| private int bpos = 0; |
| |
| private static byte[] EMPTY = new byte[0]; |
| |
| /** |
| * Performs Base64 encoding on the data written to the stream, |
| * writing the encoded data to another OutputStream. |
| * |
| * @param out the OutputStream to write the encoded data to |
| * @param flags bit flags for controlling the encoder; see the |
| * constants in {@link Base64} |
| */ |
| public Base64OutputStream(OutputStream out, int flags) { |
| this(out, flags, true); |
| } |
| |
| /** |
| * Performs Base64 encoding or decoding on the data written to the |
| * stream, writing the encoded/decoded data to another |
| * OutputStream. |
| * |
| * @param out the OutputStream to write the encoded data to |
| * @param flags bit flags for controlling the encoder; see the |
| * constants in {@link Base64} |
| * @param encode true to encode, false to decode |
| * |
| * @hide |
| */ |
| public Base64OutputStream(OutputStream out, int flags, boolean encode) { |
| super(out); |
| this.flags = flags; |
| if (encode) { |
| coder = new Base64.Encoder(flags, null); |
| } else { |
| coder = new Base64.Decoder(flags, null); |
| } |
| } |
| |
| public void write(int b) throws IOException { |
| // To avoid invoking the encoder/decoder routines for single |
| // bytes, we buffer up calls to write(int) in an internal |
| // byte array to transform them into writes of decently-sized |
| // arrays. |
| |
| if (buffer == null) { |
| buffer = new byte[1024]; |
| } |
| if (bpos >= buffer.length) { |
| // internal buffer full; write it out. |
| internalWrite(buffer, 0, bpos, false); |
| bpos = 0; |
| } |
| buffer[bpos++] = (byte) b; |
| } |
| |
| /** |
| * Flush any buffered data from calls to write(int). Needed |
| * before doing a write(byte[], int, int) or a close(). |
| */ |
| private void flushBuffer() throws IOException { |
| if (bpos > 0) { |
| internalWrite(buffer, 0, bpos, false); |
| bpos = 0; |
| } |
| } |
| |
| public void write(byte[] b, int off, int len) throws IOException { |
| if (len <= 0) return; |
| flushBuffer(); |
| internalWrite(b, off, len, false); |
| } |
| |
| public void close() throws IOException { |
| IOException thrown = null; |
| try { |
| flushBuffer(); |
| internalWrite(EMPTY, 0, 0, true); |
| } catch (IOException e) { |
| thrown = e; |
| } |
| |
| try { |
| if ((flags & Base64.NO_CLOSE) == 0) { |
| out.close(); |
| } else { |
| out.flush(); |
| } |
| } catch (IOException e) { |
| if (thrown != null) { |
| thrown = e; |
| } |
| } |
| |
| if (thrown != null) { |
| throw thrown; |
| } |
| } |
| |
| /** |
| * Write the given bytes to the encoder/decoder. |
| * |
| * @param finish true if this is the last batch of input, to cause |
| * encoder/decoder state to be finalized. |
| */ |
| private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException { |
| coder.output = embiggen(coder.output, coder.maxOutputSize(len)); |
| if (!coder.process(b, off, len, finish)) { |
| throw new Base64DataException("bad base-64"); |
| } |
| out.write(coder.output, 0, coder.op); |
| } |
| |
| /** |
| * If b.length is at least len, return b. Otherwise return a new |
| * byte array of length len. |
| */ |
| private byte[] embiggen(byte[] b, int len) { |
| if (b == null || b.length < len) { |
| return new byte[len]; |
| } else { |
| return b; |
| } |
| } |
| } |