001 /* 002 * Java Base64 - A pure Java library for reading and writing Base64 003 * encoded streams. 004 * 005 * Copyright (C) 2007-2009 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 Lesser General Public License version 009 * 2.1, as published by the Free Software Foundation. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License version 2.1 along with this program. 018 * 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 read() throws IOException { 074 if (buffer == null || bufferCounter == buffer.length) { 075 if (eof) { 076 return -1; 077 } 078 acquire(); 079 if (buffer.length == 0) { 080 buffer = null; 081 return -1; 082 } 083 bufferCounter = 0; 084 } 085 return buffer[bufferCounter++]; 086 } 087 088 /** 089 * Reads from the underlying stream, decodes the data and puts the decoded 090 * bytes into the buffer. 091 */ 092 private void acquire() throws IOException { 093 char[] four = new char[4]; 094 int i = 0; 095 do { 096 int b = inputStream.read(); 097 if (b == -1) { 098 if (i != 0) { 099 throw new IOException("Bad base64 stream"); 100 } else { 101 buffer = new int[0]; 102 eof = true; 103 return; 104 } 105 } 106 char c = (char) b; 107 if (Shared.chars.indexOf(c) != -1 || c == Shared.pad) { 108 four[i++] = c; 109 } else if (c != '\r' && c != '\n') { 110 throw new IOException("Bad base64 stream"); 111 } 112 } while (i < 4); 113 boolean padded = false; 114 for (i = 0; i < 4; i++) { 115 if (four[i] != Shared.pad) { 116 if (padded) { 117 throw new IOException("Bad base64 stream"); 118 } 119 } else { 120 if (!padded) { 121 padded = true; 122 } 123 } 124 } 125 int l; 126 if (four[3] == Shared.pad) { 127 if (inputStream.read() != -1) { 128 throw new IOException("Bad base64 stream"); 129 } 130 eof = true; 131 if (four[2] == Shared.pad) { 132 l = 1; 133 } else { 134 l = 2; 135 } 136 } else { 137 l = 3; 138 } 139 int aux = 0; 140 for (i = 0; i < 4; i++) { 141 if (four[i] != Shared.pad) { 142 aux = aux | (Shared.chars.indexOf(four[i]) << (6 * (3 - i))); 143 } 144 } 145 buffer = new int[l]; 146 for (i = 0; i < l; i++) { 147 buffer[i] = (aux >>> (8 * (2 - i))) & 0xFF; 148 } 149 } 150 151 public void close() throws IOException { 152 inputStream.close(); 153 } 154 }