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 }