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 17ab69e29c1927bdc6143324eba5ccd78f7c43128dDoug Zongkerpackage android.util; 18d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 19d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.FilterOutputStream; 20d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.IOException; 21d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.OutputStream; 22d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 23d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/** 2433f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * An OutputStream that does Base64 encoding on the data written to 2533f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * it, writing the resulting data to another OutputStream. 26d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 27d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpublic class Base64OutputStream extends FilterOutputStream { 289df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker private final Base64.Coder coder; 29d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private final int flags; 30d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 31d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private byte[] buffer = null; 32d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private int bpos = 0; 33d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 34d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private static byte[] EMPTY = new byte[0]; 35d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 36d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 37d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Performs Base64 encoding on the data written to the stream, 38d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * writing the encoded data to another OutputStream. 39d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 40d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param out the OutputStream to write the encoded data to 41d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the encoder; see the 42d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 43d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 44d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64OutputStream(OutputStream out, int flags) { 45d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this(out, flags, true); 46d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 47d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 48d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 49d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Performs Base64 encoding or decoding on the data written to the 50d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * stream, writing the encoded/decoded data to another 51d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * OutputStream. 52d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 53d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param out the OutputStream to write the encoded data to 54d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the encoder; see the 55d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 56d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param encode true to encode, false to decode 5733f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * 5833f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * @hide 59d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 60d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64OutputStream(OutputStream out, int flags, boolean encode) { 61d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker super(out); 62d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this.flags = flags; 63d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (encode) { 649df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder = new Base64.Encoder(flags, null); 65d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder = new Base64.Decoder(flags, null); 67d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 68d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 69d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 70d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void write(int b) throws IOException { 71d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // To avoid invoking the encoder/decoder routines for single 72d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // bytes, we buffer up calls to write(int) in an internal 73d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // byte array to transform them into writes of decently-sized 74d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // arrays. 75d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 76d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (buffer == null) { 77d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker buffer = new byte[1024]; 78d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 79d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (bpos >= buffer.length) { 80d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker // internal buffer full; write it out. 81d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(buffer, 0, bpos, false); 82d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker bpos = 0; 83d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 84d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker buffer[bpos++] = (byte) b; 85d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 86d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 87d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 88d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Flush any buffered data from calls to write(int). Needed 89d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * before doing a write(byte[], int, int) or a close(). 90d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 91d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private void flushBuffer() throws IOException { 92d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (bpos > 0) { 93d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(buffer, 0, bpos, false); 94d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker bpos = 0; 95d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 96d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 97d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 98d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void write(byte[] b, int off, int len) throws IOException { 99d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (len <= 0) return; 100d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker flushBuffer(); 101d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker internalWrite(b, off, len, false); 102d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 103d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 104d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void close() throws IOException { 1059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker IOException thrown = null; 1069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker try { 1079df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker flushBuffer(); 1089df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker internalWrite(EMPTY, 0, 0, true); 1099df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } catch (IOException e) { 1109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker thrown = e; 1119df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } 1129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker 1139df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker try { 1149df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if ((flags & Base64.NO_CLOSE) == 0) { 1159df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker out.close(); 1169df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } else { 1179df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker out.flush(); 1189df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } 1199df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } catch (IOException e) { 1209df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if (thrown != null) { 1219df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker thrown = e; 1229df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } 1239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } 1249df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker 1259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if (thrown != null) { 1269df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker throw thrown; 127d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 128d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 129d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 130d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 131d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Write the given bytes to the encoder/decoder. 132d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 133d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param finish true if this is the last batch of input, to cause 134d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * encoder/decoder state to be finalized. 135d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 136d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException { 1379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder.output = embiggen(coder.output, coder.maxOutputSize(len)); 1389df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if (!coder.process(b, off, len, finish)) { 139c5a0ce242f3794972599163927b58bebf8c354b5Andy Stadler throw new Base64DataException("bad base-64"); 140d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 1419df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker out.write(coder.output, 0, coder.op); 142d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 143d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 144d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 145d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * If b.length is at least len, return b. Otherwise return a new 146d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * byte array of length len. 147d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 148d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private byte[] embiggen(byte[] b, int len) { 149d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (b == null || b.length < len) { 150d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return new byte[len]; 151d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 152d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return b; 153d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 154d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 155d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker} 156