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