com.ibm.commons.util.io.base64.Base64OutputStream Maven / Gradle / Ivy
/*
* © Copyright IBM Corp. 2012-2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.ibm.commons.util.io.base64;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* A Base64 content transfer encoding filter stream.
*
* From RFC 2045, section 6.8:
*
* The Base64 Content-Transfer-Encoding is designed to represent
* arbitrary sequences of octets in a form that need not be humanly
* readable. The encoding and decoding algorithms are simple, but the
* encoded data are consistently only about 33 percent larger than the
* unencoded data.
* @ibm-api
*/
public class Base64OutputStream extends FilterOutputStream {
private byte[] _buffer;
private int _buflen;
private int _count;
private int _lineLength;
/**
* Default constructor.
* @param out the underlying output stream to encode
* @pre out != null
* @post out != null
*/
public Base64OutputStream(OutputStream out) {
this(out, Integer.MAX_VALUE);
}
/**
* Constructor.
* @param out the underlying output stream to encode
* @param lineLength the line length
* @pre out != null
* @pre lineLength > 0
* @post out != null
*/
public Base64OutputStream(OutputStream out, int lineLength) {
super(out);
_buflen = 0;
_count = 0;
_buffer = new byte[3];
_lineLength = lineLength;
}
/**
* Writes the specified byte to this output stream.
* @param ch character to write/encode
* @throws IOException IO Exception occurred
* @pre out != null
* @post out != null
*/
public void write(int ch) throws IOException {
_buffer[_buflen++] = (byte)ch;
if (_buflen == 3) {
encode();
_buflen = 0;
}
}
/**
* Writes b.length
bytes from the specified byte array
* to this output stream.
* @param b buffer to write/encode
* @throws IOException IO Exception occurred
* @pre out != null
* @post out != null
*/
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
/**
* Writes len
bytes from the specified byte array
* starting at offset off
to this output stream.
* @param b buffer to write/encode
* @param off offset to start of buffer to write/encode
* @param len number of bytes from buffer to write/encode
* @throws IOException IO Exception occurred
* @pre off < b.length
* @pre off+len < b.length
* @pre out != null
* @post out != null
*/
public void write(byte[] b, int off, int len) throws IOException {
for (int i = 0; i < len; i++) {
write(b[off+i]);
}
}
/**
* Flushes this output stream and forces any buffered output bytes to be
* written out.
* @throws IOException IO Exception occurred
* @pre out != null
* @post _buflen == 0
*/
public void flush() throws IOException {
if (_buflen > 0) {
encode();
_buflen = 0;
}
out.flush();
}
/**
* Closes this output stream and releases any system resources
* associated with this stream.
* @throws IOException IO Exception occurred
* @pre out != null
* @post $none
*/
public void close() throws IOException {
flush();
out.close();
}
/**
* Encode current buffer bytes
* @throws IOException IO Exception occurred
* @pre out != null
*/
private void encode() throws IOException {
if ((_count + 4) > _lineLength) {
out.write(Ascii.CR);
out.write(Ascii.LF);
_count = 0;
}
if (_buflen==1) {
byte b = _buffer[0];
int i = 0;
out.write(IoConstants.B64_SRC_MAP[b>>>2 & 0x3f]);
out.write(IoConstants.B64_SRC_MAP[(b<<4 & 0x30) + (i>>>4 & 0xf)]);
out.write(Ascii.EQUALS);
out.write(Ascii.EQUALS);
}
else if (_buflen==2) {
byte b1 = _buffer[0], b2 = _buffer[1];
int i = 0;
out.write(IoConstants.B64_SRC_MAP[b1>>>2 & 0x3f]);
out.write(IoConstants.B64_SRC_MAP[(b1<<4 & 0x30) + (b2>>>4 & 0xf)]);
out.write(IoConstants.B64_SRC_MAP[(b2<<2 & 0x3c) + (i>>>6 & 0x3)]);
out.write(Ascii.EQUALS);
}
else {
byte b1 = _buffer[0], b2 = _buffer[1], b3 = _buffer[2];
out.write(IoConstants.B64_SRC_MAP[b1>>>2 & 0x3f]);
out.write(IoConstants.B64_SRC_MAP[(b1<<4 & 0x30) + (b2>>>4 & 0xf)]);
out.write(IoConstants.B64_SRC_MAP[(b2<<2 & 0x3c) + (b3>>>6 & 0x3)]);
out.write(IoConstants.B64_SRC_MAP[b3 & 0x3f]);
}
_count += 4;
}
}