package com.jotuntech.sketcher.client; import java.io.DataOutput; import java.io.IOException; import java.io.OutputStream; public class PackBitsOutputStream extends OutputStream { private DataOutput mdo; private final static int IN_BUFFER_SIZE = 2048; private final static int IN_BUFFER_MASK = IN_BUFFER_SIZE - 1; private final static int OUT_BUFFER_SIZE = 4096; private int[] inBuffer; private int inBufferWritePos, inBufferReadPos, inBufferMark; private byte[] outBuffer; private int outBufferWritePos; public PackBitsOutputStream(DataOutput mdo) { this.mdo = mdo; this.inBuffer = new int[IN_BUFFER_SIZE]; this.inBufferWritePos = 0; this.inBufferReadPos = 0; this.inBufferMark = 0; this.outBuffer = new byte[OUT_BUFFER_SIZE]; this.outBufferWritePos = 0; } public void write(int b) throws IOException { inBuffer[inBufferWritePos++ & IN_BUFFER_MASK] = b; if(inBufferWritePos - inBufferReadPos == IN_BUFFER_SIZE) { pack(); } } public void write(byte[] b) throws IOException { for(int i = 0; i < b.length; i++) { inBuffer[inBufferWritePos++ & IN_BUFFER_MASK] = b[i]; if(inBufferWritePos - inBufferReadPos == IN_BUFFER_SIZE) { pack(); } } } public void write(byte[] b, int off, int len) throws IOException { for(int i = off; i < off + len; i++) { inBuffer[inBufferWritePos++ & IN_BUFFER_MASK] = b[i]; if(inBufferWritePos - inBufferReadPos == IN_BUFFER_SIZE) { pack(); } } } public void flush() throws IOException { pack(); } private void output(int b) { outBuffer[outBufferWritePos++] = (byte) b; } private void pack() throws IOException { outBufferWritePos = 0; while(available() > 0) { int b = read(); int repeat = 1; while(available() > 0 && peek() == b && repeat < 128) { ++repeat; skip(); } if(repeat == 1) { mark(); int b2 = read(); int literal = 0; while(available() > 0 && peek() != b2 && literal < 127) { b2 = read(); ++literal; } if(available() == 0 && literal < 127) { ++literal; } if(literal == 0) { reset(); output(0); output(b); } else { reset(); output(literal); output(b); for(int i = 0; i < literal; i++) { output(read()); } } } else if(repeat == 2) { output(1); output(b); output(b); } else { output(1 - repeat); output(b); } } mdo.write(outBuffer, 0, outBufferWritePos); } public void close() throws IOException { pack(); } private int available() { return inBufferWritePos - inBufferReadPos; } private int peek() { return inBuffer[inBufferReadPos & IN_BUFFER_MASK]; } private int read() { return inBuffer[inBufferReadPos++ & IN_BUFFER_MASK]; } private void skip() { ++inBufferReadPos; } private void mark() { inBufferMark = inBufferReadPos; } private void reset() { inBufferReadPos = inBufferMark; } }