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.FilterInputStream; 20d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.IOException; 21d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.InputStream; 22d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 23d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/** 2433f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * An InputStream that does Base64 decoding on the data read through 2533f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * it. 26d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 27d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpublic class Base64InputStream extends FilterInputStream { 289df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker private final Base64.Coder coder; 29d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 30d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private static byte[] EMPTY = new byte[0]; 31d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 32d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private static final int BUFFER_SIZE = 2048; 33d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private boolean eof; 34d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private byte[] inputBuffer; 35d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private int outputStart; 36d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private int outputEnd; 37d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 38d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 39d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * An InputStream that performs Base64 decoding on the data read 40d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * from the wrapped stream. 41d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 42d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param in the InputStream to read the source data from 43d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the decoder; see the 44d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 45d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 46d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64InputStream(InputStream in, int flags) { 47d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker this(in, flags, false); 48d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 49d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 50d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 51d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Performs Base64 encoding or decoding on the data read from the 52d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * wrapped InputStream. 53d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * 54d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param in the InputStream to read the source data from 55d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param flags bit flags for controlling the decoder; see the 56d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * constants in {@link Base64} 57d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * @param encode true to encode, false to decode 5833f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * 5933f7a80f767d72393c2d38b0dcbaeecdf7956c89Doug Zongker * @hide 60d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 61d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public Base64InputStream(InputStream in, int flags, boolean encode) { 62d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker super(in); 63d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker eof = false; 64d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker inputBuffer = new byte[BUFFER_SIZE]; 65d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (encode) { 669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder = new Base64.Encoder(flags, null); 67d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 689df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder = new Base64.Decoder(flags, null); 69d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 709df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)]; 71d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker outputStart = 0; 72d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker outputEnd = 0; 73d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 74d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 75d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public boolean markSupported() { 76d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return false; 77d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 78d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 79d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void mark(int readlimit) { 80d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker throw new UnsupportedOperationException(); 81d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 82d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 83d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void reset() { 84d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker throw new UnsupportedOperationException(); 85d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 86d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 87d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public void close() throws IOException { 88d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker in.close(); 89d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker inputBuffer = null; 90d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 91d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 92d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public int available() { 93d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return outputEnd - outputStart; 94d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 95d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 96d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public long skip(long n) throws IOException { 97d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 98d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker refill(); 99d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 100d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 101d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return 0; 102d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 103d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker long bytes = Math.min(n, outputEnd-outputStart); 104d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker outputStart += bytes; 105d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return bytes; 106d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 107d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 108d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public int read() throws IOException { 109d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 110d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker refill(); 111d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 112d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 113d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return -1; 114d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 11564b25cf736bc5f9b9f6d548f0694fb76fe805d0cJesse Wilson return coder.output[outputStart++] & 0xff; 116d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 117d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 118d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 119d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker public int read(byte[] b, int off, int len) throws IOException { 120d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 121d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker refill(); 122d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 123d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (outputStart >= outputEnd) { 124d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return -1; 125d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 126d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker int bytes = Math.min(len, outputEnd-outputStart); 1279df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker System.arraycopy(coder.output, outputStart, b, off, bytes); 128d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker outputStart += bytes; 129d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker return bytes; 130d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 131d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker 132d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker /** 133d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Read data from the input stream into inputBuffer, then 1349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker * decode/encode it into the empty coder.output, and reset the 135d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * outputStart and outputEnd pointers. 136d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */ 137d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker private void refill() throws IOException { 138d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker if (eof) return; 139d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker int bytesRead = in.read(inputBuffer); 1409df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker boolean success; 1419df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if (bytesRead == -1) { 1429df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker eof = true; 1439df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker success = coder.process(EMPTY, 0, 0, true); 144d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } else { 1459df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker success = coder.process(inputBuffer, 0, bytesRead, false); 1469df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker } 1479df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker if (!success) { 148c5a0ce242f3794972599163927b58bebf8c354b5Andy Stadler throw new Base64DataException("bad base-64"); 149d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 1509df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker outputEnd = coder.op; 151d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker outputStart = 0; 152d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker } 153d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker} 154