001 /* 002 * Java Base64 - A pure Java library for reading and writing Base64 003 * encoded streams. 004 * 005 * Copyright (C) 2008 Carlo Pelliccia (www.sauronsoftware.it) 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020 package it.sauronsoftware.base64; 021 022 import java.io.IOException; 023 import java.io.InputStream; 024 025 /** 026 * <p> 027 * A base64 encoding input stream. 028 * </p> 029 * 030 * <p> 031 * A <em>Base64InputStream</em> reads from an underlying stream which is 032 * supposed to be a base64 encoded stream. <em>Base64InputStream</em> decodes 033 * the data read from the underlying stream and returns the decoded bytes to the 034 * caller. 035 * </p> 036 * 037 * @author Carlo Pelliccia 038 */ 039 public class Base64InputStream extends InputStream { 040 041 /** 042 * The underlying stream. 043 */ 044 private InputStream inputStream; 045 046 /** 047 * The buffer. 048 */ 049 private int[] buffer; 050 051 /** 052 * A counter for values in the buffer. 053 */ 054 private int bufferCounter = 0; 055 056 /** 057 * End-of-stream flag. 058 */ 059 private boolean eof = false; 060 061 /** 062 * <p> 063 * It builds a base64 decoding input stream. 064 * </p> 065 * 066 * @param inputStream 067 * The underlying stream, from which the encoded data is read. 068 */ 069 public Base64InputStream(InputStream inputStream) { 070 this.inputStream = inputStream; 071 } 072 073 public int available() throws IOException { 074 return buffer != null ? buffer.length : 0; 075 } 076 077 public int read() throws IOException { 078 if (buffer == null || bufferCounter == buffer.length) { 079 if (eof) { 080 return -1; 081 } 082 acquire(); 083 if (buffer.length == 0) { 084 buffer = null; 085 return -1; 086 } 087 bufferCounter = 0; 088 } 089 return buffer[bufferCounter++]; 090 } 091 092 /** 093 * Reads from the underlying stream, decodes the data and puts the decoded 094 * bytes into the buffer. 095 */ 096 private void acquire() throws IOException { 097 char[] four = new char[4]; 098 int i = 0; 099 do { 100 int b = inputStream.read(); 101 if (b == -1) { 102 if (i != 0) { 103 throw new IOException("Bad base64 stream"); 104 } else { 105 buffer = new int[0]; 106 eof = true; 107 return; 108 } 109 } 110 char c = (char) b; 111 if (Shared.chars.indexOf(c) != -1 || c == Shared.pad) { 112 four[i++] = c; 113 } else { 114 throw new IOException("Bad base64 stream"); 115 } 116 } while (i < 4); 117 boolean padded = false; 118 for (i = 0; i < 4; i++) { 119 if (four[i] != Shared.pad) { 120 if (padded) { 121 throw new IOException("Bad base64 stream"); 122 } 123 } else { 124 if (!padded) { 125 padded = true; 126 } 127 } 128 } 129 int l; 130 if (four[3] == Shared.pad) { 131 if (inputStream.read() != -1) { 132 throw new IOException("Bad base64 stream"); 133 } 134 eof = true; 135 if (four[2] == Shared.pad) { 136 l = 1; 137 } else { 138 l = 2; 139 } 140 } else { 141 l = 3; 142 } 143 int aux = 0; 144 for (i = 0; i < 4; i++) { 145 if (four[i] != Shared.pad) { 146 aux = aux | (Shared.chars.indexOf(four[i]) << (6 * (3 - i))); 147 } 148 } 149 buffer = new int[l]; 150 for (i = 0; i < l; i++) { 151 buffer[i] = (aux >>> (8 * (2 - i))) & 0xFF; 152 } 153 } 154 155 public void close() throws IOException { 156 inputStream.close(); 157 } 158 159 }