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.OutputStream; 024 025 /** 026 * <p> 027 * A base64 decoding output stream. 028 * </p> 029 * 030 * <p> 031 * It encodes in base64 everything passed to the stream, and it puts the encoded 032 * data into the underlying stream. 033 * </p> 034 * 035 * @author Carlo Pelliccia 036 */ 037 public class Base64OutputStream extends OutputStream { 038 039 /** 040 * The underlying stream. 041 */ 042 private OutputStream outputStream = null; 043 044 /** 045 * A value buffer. 046 */ 047 private int buffer = 0; 048 049 /** 050 * How many bytes are currently in the value buffer? 051 */ 052 private int bytecounter = 0; 053 054 /** 055 * A counter for the current line length. 056 */ 057 private int linecounter = 0; 058 059 /** 060 * The requested line length. 061 */ 062 private int linelength = 0; 063 064 /** 065 * <p> 066 * It builds a base64 encoding output stream writing the encoded data in the 067 * given underlying stream. 068 * </p> 069 * 070 * <p> 071 * The encoded data is wrapped to a new line (with a CRLF sequence) every 76 072 * bytes sent to the underlying stream. 073 * </p> 074 * 075 * @param outputStream 076 * The underlying stream. 077 */ 078 public Base64OutputStream(OutputStream outputStream) { 079 this(outputStream, 76); 080 } 081 082 /** 083 * <p> 084 * It builds a base64 encoding output stream writing the encoded data in the 085 * given underlying stream. 086 * </p> 087 * 088 * <p> 089 * The encoded data is wrapped to a new line (with a CRLF sequence) every 090 * <em>wrapAt</em> bytes sent to the underlying stream. If the 091 * <em>wrapAt</em> supplied value is less than 1 the encoded data will not 092 * be wrapped. 093 * </p> 094 * 095 * @param outputStream 096 * The underlying stream. 097 * @param wrapAt 098 * The max line length for encoded data. If less than 1 no wrap 099 * is applied. 100 */ 101 public Base64OutputStream(OutputStream outputStream, int wrapAt) { 102 this.outputStream = outputStream; 103 this.linelength = wrapAt; 104 } 105 106 public void write(int b) throws IOException { 107 int value = (b & 0xFF) << (16 - (bytecounter * 8)); 108 buffer = buffer | value; 109 bytecounter++; 110 if (bytecounter == 3) { 111 commit(); 112 } 113 } 114 115 public void close() throws IOException { 116 commit(); 117 outputStream.close(); 118 } 119 120 /** 121 * <p> 122 * It commits 4 bytes to the underlying stream. 123 * </p> 124 */ 125 protected void commit() throws IOException { 126 if (bytecounter > 0) { 127 if (linelength > 0 && linecounter == linelength) { 128 outputStream.write("\r\n".getBytes()); 129 linecounter = 0; 130 } 131 char b1 = Shared.chars.charAt((buffer << 8) >>> 26); 132 char b2 = Shared.chars.charAt((buffer << 14) >>> 26); 133 char b3 = (bytecounter < 2) ? Shared.pad : Shared.chars.charAt((buffer << 20) >>> 26); 134 char b4 = (bytecounter < 3) ? Shared.pad : Shared.chars.charAt((buffer << 26) >>> 26); 135 outputStream.write(b1); 136 outputStream.write(b2); 137 outputStream.write(b3); 138 outputStream.write(b4); 139 linecounter += 4; 140 bytecounter = 0; 141 buffer = 0; 142 } 143 } 144 145 }