Base64OutputStream.java revision d2affae13dfdb116adaee1bb10aaaac80a885481
1d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/* 2d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Copyright (C) 2010 The Android Open Source Project 3d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 4d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Licensed under the Apache License, Version 2.0 (the "License"); 5d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * you may not use this file except in compliance with the License. 6d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * You may obtain a copy of the License at 7d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 8d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * http://www.apache.org/licenses/LICENSE-2.0 9d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 10d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Unless required by applicable law or agreed to in writing, software 11d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * distributed under the License is distributed on an "AS IS" BASIS, 12d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * See the License for the specific language governing permissions and 14d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * limitations under the License. 15d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 16d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 17d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpackage android.util.base64; 18d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 19d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.FilterOutputStream; 20d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.IOException; 21d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.OutputStream; 22d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 23d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/** 24d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * An OutputStream that does either Base64 encoding or decoding on the 25d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * data written to it, writing the resulting data to another 26d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * OutputStream. 27d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 28d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpublic class Base64OutputStream extends FilterOutputStream { 29d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private final boolean encode; 30d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private final Base64.EncoderState estate; 31d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private final Base64.DecoderState dstate; 32d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private final int flags; 33d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 34d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private byte[] buffer = null; 35d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private int bpos = 0; 36d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 37d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private static byte[] EMPTY = new byte[0]; 38d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 39d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 40d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Performs Base64 encoding on the data written to the stream, 41d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * writing the encoded data to another OutputStream. 42d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 43d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param out the OutputStream to write the encoded data to 44d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the encoder; see the 45d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 46d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 47d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64OutputStream(OutputStream out, int flags) { 48d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this(out, flags, true); 49d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 50d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 51d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 52d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Performs Base64 encoding or decoding on the data written to the 53d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * stream, writing the encoded/decoded data to another 54d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * OutputStream. 55d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 56d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param out the OutputStream to write the encoded data to 57d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the encoder; see the 58d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 59d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param encode true to encode, false to decode 60d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 61d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64OutputStream(OutputStream out, int flags, boolean encode) { 62d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker super(out); 63d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this.flags = flags; 64d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this.encode = encode; 65d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (encode) { 66d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker estate = new Base64.EncoderState(flags, null); 67d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker dstate = null; 68d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 69d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker estate = null; 70d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker dstate = new Base64.DecoderState(flags, null); 71d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 72d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 73d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 74d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void write(int b) throws IOException { 75d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // To avoid invoking the encoder/decoder routines for single 76d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // bytes, we buffer up calls to write(int) in an internal 77d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // byte array to transform them into writes of decently-sized 78d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // arrays. 79d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 80d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (buffer == null) { 81d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker buffer = new byte[1024]; 82d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 83d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (bpos >= buffer.length) { 84d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // internal buffer full; write it out. 85d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(buffer, 0, bpos, false); 86d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker bpos = 0; 87d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 88d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker buffer[bpos++] = (byte) b; 89d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 90d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 91d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 92d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Flush any buffered data from calls to write(int). Needed 93d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * before doing a write(byte[], int, int) or a close(). 94d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 95d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private void flushBuffer() throws IOException { 96d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (bpos > 0) { 97d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(buffer, 0, bpos, false); 98d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker bpos = 0; 99d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 100d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 101d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 102d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void write(byte[] b, int off, int len) throws IOException { 103d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (len <= 0) return; 104d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker flushBuffer(); 105d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(b, off, len, false); 106d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 107d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 108d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void close() throws IOException { 109d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker flushBuffer(); 110d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(EMPTY, 0, 0, true); 111d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if ((flags & Base64.NO_CLOSE) == 0) { 112d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker out.close(); 113d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 114d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker out.flush(); 115d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 116d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 117d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 118d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 119d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Write the given bytes to the encoder/decoder. 120d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 121d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param finish true if this is the last batch of input, to cause 122d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * encoder/decoder state to be finalized. 123d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 124d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException { 125d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (encode) { 126d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // len*8/5+10 is an overestimate of the most bytes the 127d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // encoder can produce for len bytes of input. 128d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker estate.output = embiggen(estate.output, len*8/5+10); 129d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker Base64.encodeInternal(b, off, len, estate, finish); 130d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker out.write(estate.output, 0, estate.op); 131d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 132d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // len*3/4+10 is an overestimate of the most bytes the 133d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // decoder can produce for len bytes of input. 134d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker dstate.output = embiggen(dstate.output, len*3/4+10); 135d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (!Base64.decodeInternal(b, off, len, dstate, finish)) { 136d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker throw new IOException("bad base-64"); 137d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 138d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker out.write(dstate.output, 0, dstate.op); 139d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 140d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 141d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 142d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 143d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * If b.length is at least len, return b. Otherwise return a new 144d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * byte array of length len. 145d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 146d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private byte[] embiggen(byte[] b, int len) { 147d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (b == null || b.length < len) { 148d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return new byte[len]; 149d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 150d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return b; 151d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 152d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 153d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker} 154