package com.colloquial.arithcode;
import java.io.OutputStream;
import java.io.IOException;
/** Writes to an underlying output stream a bit at a time. A bit is can be input
* as a boolean, with <code>true=1</code> and <code>false=0</code>, or
* as a number, in which case any non-zero input will be converted to
* <code>1</code>. If the number of bits written before closing the output
* does not land on a byte boundary, the remaining fractional byte is
* filled with <code>0</code> bits.
*
* @author <a href="http://www.colloquial.com/carp/">Bob Carpenter</a>
* @version 1.1
* @see BitInput
* @since 1.0
*/
public final class BitOutput {
/** Construct a bit output from the specified output stream.
* @param out Underlying output stream.
*/
public BitOutput(OutputStream out) {
_out = out;
reset();
}
/** Closes underlying output stream after filling to a byte
* boundary with <code>0</code> bits.
* @throws IOException If there is an I/O exception writing the next byte or closing the underlying output stream.
*/
public void close() throws IOException {
if (_nextBitIndex < 7) // there's something in the buffer
_out.write(_nextByte << _nextBitIndex); // shift to fill last byte
_out.close();
}
/** Flushes the underlying output stream.
* @throws IOException If there is an exception flushing the underlying output stream.
*/
public void flush() throws IOException {
_out.flush();
}
/** Writes the single specified bit to the underlying output stream,
* <code>1</code> for <code>true</code> and <code>0</code> for <code>false</code>.
* @param bit Value to write.
* @throws IOException If there is an exception in the underlying output stream.
*/
public void writeBit(boolean bit) throws IOException {
if (bit) writeBitTrue();
else writeBitFalse();
}
/** Writes a single <code>true</code> (<code>1</code>) bit.
* @throws IOException If there is an exception in the underlying output stream.
* @since 1.1
*/
public void writeBitTrue() throws IOException {
if (_nextBitIndex == 0) {
_out.write(_nextByte + 1);
reset();
} else {
_nextByte = (_nextByte + 1) << 1;
--_nextBitIndex;
}
}
/** Writes a single <code>false</code> (<code>0</code>) bit.
* @throws IOException If there is an exception in the underlying output stream.
* @since 1.1
*/
public void writeBitFalse() throws IOException {
if (_nextBitIndex == 0) {
_out.write(_nextByte);
reset();
} else {
_nextByte <<= 1;
--_nextBitIndex;
}
}
/** Buffering for output. Bytes are represented as integers,
* primarily for efficiency of bit fiddling and for compatibility
* with underlying output stream.
*/
private int _nextByte;
/** The indexof the next bit to write into the next byte.
*/
private int _nextBitIndex;
/** Underlying output stream.
*/
private final OutputStream _out;
/** Resets the bit buffer.
*/
private void reset() {
_nextByte = 0;
_nextBitIndex = 7;
}
}