From 5c5eb3de6a5e2061ba1926529347694571c7845f Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Mon, 12 Aug 2002 16:56:22 +0000 Subject: [PATCH] Replaced the PostScript filters with the refactored ones from the maintenance branch. (JM) Added a RunLengthEncode filter for the PostScript renderer. Submitted by: "Stephen Wolke" git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195079 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/ps/ASCII85EncodeFilter.java | 159 -------------- .../fop/render/ps/ASCII85OutputStream.java | 201 +++++++++++++++++ .../fop/render/ps/ASCIIHexEncodeFilter.java | 69 ------ .../fop/render/ps/ASCIIHexOutputStream.java | 81 +++++++ src/org/apache/fop/render/ps/Filter.java | 18 -- .../apache/fop/render/ps/FilterThread.java | 49 ----- src/org/apache/fop/render/ps/Finalizable.java | 30 +++ .../fop/render/ps/FlateEncodeFilter.java | 42 ---- .../render/ps/FlateEncodeOutputStream.java | 39 ++++ .../ps/RunLengthEncodeOutputStream.java | 205 ++++++++++++++++++ 10 files changed, 556 insertions(+), 337 deletions(-) delete mode 100644 src/org/apache/fop/render/ps/ASCII85EncodeFilter.java create mode 100644 src/org/apache/fop/render/ps/ASCII85OutputStream.java delete mode 100644 src/org/apache/fop/render/ps/ASCIIHexEncodeFilter.java create mode 100644 src/org/apache/fop/render/ps/ASCIIHexOutputStream.java delete mode 100644 src/org/apache/fop/render/ps/Filter.java delete mode 100644 src/org/apache/fop/render/ps/FilterThread.java create mode 100644 src/org/apache/fop/render/ps/Finalizable.java delete mode 100644 src/org/apache/fop/render/ps/FlateEncodeFilter.java create mode 100644 src/org/apache/fop/render/ps/FlateEncodeOutputStream.java create mode 100644 src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java diff --git a/src/org/apache/fop/render/ps/ASCII85EncodeFilter.java b/src/org/apache/fop/render/ps/ASCII85EncodeFilter.java deleted file mode 100644 index 887598868..000000000 --- a/src/org/apache/fop/render/ps/ASCII85EncodeFilter.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. - * For details on use and redistribution please refer to the - * LICENSE file included with these sources. - */ - -package org.apache.fop.render.ps; - -import java.io.*; - -public class ASCII85EncodeFilter implements Filter { - - private static final char ASCII85_ZERO = 'z'; - private static final char ASCII85_START = '!'; - private static final char ASCII85_EOL = '\n'; - private static final String ASCII85_EOD = "~>"; - private static final String ENCODING = "US-ASCII"; - - private static final long base85_4 = 85; - private static final long base85_3 = base85_4 * base85_4; - private static final long base85_2 = base85_3 * base85_4; - private static final long base85_1 = base85_2 * base85_4; - - protected ASCII85EncodeFilter() {} - - public long write(OutputStream out, byte[] buf, int len, - long bw) throws IOException { - // Assumption: len<80 - int line = (int)(bw % 80) + len; - if (line >= 80) { - int first = len - (line - 80); - out.write(buf, 0, first); - out.write(ASCII85_EOL); - out.write(buf, first, len - first); - } else { - out.write(buf, 0, len); - } - return bw + len; - } - - public void doFilter(InputStream in, - OutputStream out) throws IOException { - int total = 0; - int diff = 0; - long bw = 0; - - // first encode the majority of the data - // each 4 byte group becomes a 5 byte group - byte[] data = new byte[4]; - int bytes_read; - while ((bytes_read = in.read(data)) == data.length) { - long val = ((data[0] << 24) - & 0xff000000L) // note: must have the L at the - + ((data[1] << 16) & 0xff0000L) // end, otherwise you get into - + ((data[2] << 8) & 0xff00L) // weird signed value problems - + (data[3] & 0xffL); // cause we're using a full 32 bits - byte[] conv = convertWord(val); - - bw = write(out, conv, conv.length, bw); - } - - // now take care of the trailing few bytes. - // with n leftover bytes, we append 0 bytes to make a full group of 4 - // then convert like normal (except not applying the special zero rule) - // and write out the first n+1 bytes from the result - if ((bytes_read < data.length) && (bytes_read >= 0)) { - int n = data.length - bytes_read; - byte[] lastdata = new byte[4]; - int i = 0; - for (int j = 0; j < 4; j++) { - if (j < n) { - lastdata[j] = data[i++]; - } else { - lastdata[j] = 0; - } - } - - long val = ((lastdata[0] << 24) & 0xff000000L) - + ((lastdata[1] << 16) & 0xff0000L) - + ((lastdata[2] << 8) & 0xff00L) - + (lastdata[3] & 0xffL); - - byte[] conv; - // special rule for handling zeros at the end - if (val != 0) { - conv = convertWord(val); - } else { - conv = new byte[5]; - for (int j = 0; j < 5; j++) { - conv[j] = (byte)'!'; - } - } - // assert n+1 <= 5 - bw = write(out, conv, n + 1, bw); - // System.out.println("ASCII85 end of data was "+n+" bytes long"); - - } - // finally write the two character end of data marker - byte[] EOD = ASCII85_EOD.getBytes(); - bw = write(out, EOD, EOD.length, bw); - } - - /** - * This converts a 32 bit value (4 bytes) into 5 bytes using base 85. - * each byte in the result starts with zero at the '!' character so - * the resulting base85 number fits into printable ascii chars - * - * @param word the 32 bit unsigned (hence the long datatype) word - * @return 5 bytes (or a single byte of the 'z' character for word - * values of 0) - */ - private byte[] convertWord(long word) { - word = word & 0xffffffff; - if (word < 0) { - word = -word; - } - - if (word == 0) { - byte[] result = { - (byte)ASCII85_ZERO - }; - return result; - } else { - byte c1 = (byte)((word / base85_1) & 0xFF); - byte c2 = (byte)(((word - (c1 * base85_1)) / base85_2) & 0xFF); - byte c3 = - (byte)(((word - (c1 * base85_1) - (c2 * base85_2)) / base85_3) - & 0xFF); - byte c4 = - (byte)(((word - (c1 * base85_1) - (c2 * base85_2) - (c3 * base85_3)) / base85_4) - & 0xFF); - byte c5 = - (byte)(((word - (c1 * base85_1) - (c2 * base85_2) - (c3 * base85_3) - (c4 * base85_4))) - & 0xFF); - - byte[] ret = { - (byte)(c1 + ASCII85_START), (byte)(c2 + ASCII85_START), - (byte)(c3 + ASCII85_START), (byte)(c4 + ASCII85_START), - (byte)(c5 + ASCII85_START) - }; - - for (int i = 0; i < ret.length; i++) { - if (ret[i] < 33 || ret[i] > 117) { - System.out.println("Illegal char value " - + new Integer(ret[i])); - } - } - return ret; - } - } - - - public static InputStream filter(InputStream in) throws IOException { - ASCII85EncodeFilter myfilter = new ASCII85EncodeFilter(); - return FilterThread.filter(in, myfilter); - } - -} diff --git a/src/org/apache/fop/render/ps/ASCII85OutputStream.java b/src/org/apache/fop/render/ps/ASCII85OutputStream.java new file mode 100644 index 000000000..80adf8dab --- /dev/null +++ b/src/org/apache/fop/render/ps/ASCII85OutputStream.java @@ -0,0 +1,201 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; + +/** + * This class applies a ASCII85 encoding to the stream. + * + * @author Jeremias Maerki + * @version $Id$ + */ +public class ASCII85OutputStream extends FilterOutputStream + implements Finalizable { + + private static final int ZERO = 0x7A; //"z" + private static final byte[] ZERO_ARRAY = {(byte)ZERO}; + private static final int START = 0x21; //"!" + private static final int EOL = 0x0A; //"\n" + private static final byte[] EOD = {0x7E, 0x3E}; //"~>" + + private static final long base85_4 = 85; + private static final long base85_3 = base85_4 * base85_4; + private static final long base85_2 = base85_3 * base85_4; + private static final long base85_1 = base85_2 * base85_4; + + private static final boolean DEBUG = false; + + private int pos = 0; + private long buffer = 0; + private int posinline = 0; + private int bw = 0; + + + public ASCII85OutputStream(OutputStream out) { + super(out); + } + + + public void write(int b) throws IOException { + if (pos == 0) { + buffer += (b << 24) & 0xff000000L; + } else if (pos == 1) { + buffer += (b << 16) & 0xff0000L; + } else if (pos == 2) { + buffer += (b << 8) & 0xff00L; + } else { + buffer += b & 0xffL; + } + pos++; + + if (pos > 3) { + checkedWrite(convertWord(buffer)); + buffer = 0; + pos = 0; + } + } + + + private void checkedWrite(int b) throws IOException { + if (posinline == 80) { + out.write(EOL); bw++; + posinline = 0; + } + checkedWrite(b); + posinline++; + bw++; + } + + + private void checkedWrite(byte[] buf) throws IOException { + checkedWrite(buf, buf.length); + } + + + private void checkedWrite(byte[] buf , int len) throws IOException { + if (posinline + len > 80) { + int firstpart = len - (posinline + len - 80); + if (firstpart > 0) out.write(buf, 0, firstpart); + out.write(EOL); bw++; + int rest = len - firstpart; + if (rest > 0) out.write(buf, firstpart, rest); + posinline = rest; + } else { + out.write(buf, 0, len); + posinline += len; + } + bw += len; + } + + + /** + * This converts a 32 bit value (4 bytes) into 5 bytes using base 85. + * each byte in the result starts with zero at the '!' character so + * the resulting base85 number fits into printable ascii chars + * + * @param word the 32 bit unsigned (hence the long datatype) word + * @return 5 bytes (or a single byte of the 'z' character for word + * values of 0) + */ + private byte[] convertWord(long word) { + word = word & 0xffffffff; + + if (word == 0) { + return ZERO_ARRAY; + } else { + if (word < 0) { + word = -word; + } + byte c1 = (byte)((word / base85_1) & 0xFF); + byte c2 = (byte)(((word - (c1 * base85_1)) / base85_2) & 0xFF); + byte c3 = + (byte)(((word - (c1 * base85_1) - (c2 * base85_2)) / base85_3) + & 0xFF); + byte c4 = + (byte)(((word - (c1 * base85_1) - (c2 * base85_2) - (c3 * base85_3)) / base85_4) + & 0xFF); + byte c5 = + (byte)(((word - (c1 * base85_1) - (c2 * base85_2) - (c3 * base85_3) - (c4 * base85_4))) + & 0xFF); + + byte[] ret = { + (byte)(c1 + START), (byte)(c2 + START), + (byte)(c3 + START), (byte)(c4 + START), + (byte)(c5 + START) + }; + + if (DEBUG) { + for (int i = 0; i < ret.length; i++) { + if (ret[i] < 33 || ret[i] > 117) { + System.out.println("Illegal char value " + + new Integer(ret[i])); + } + } + } + return ret; + } + } + + + public void finalizeStream() throws IOException { + // now take care of the trailing few bytes. + // with n leftover bytes, we append 0 bytes to make a full group of 4 + // then convert like normal (except not applying the special zero rule) + // and write out the first n+1 bytes from the result + if (pos > 0) { + int rest = pos; + /* + byte[] lastdata = new byte[4]; + int i = 0; + for (int j = 0; j < 4; j++) { + if (j < rest) { + lastdata[j] = data[i++]; + } else { + lastdata[j] = 0; + } + } + + long val = ((lastdata[0] << 24) & 0xff000000L) + + ((lastdata[1] << 16) & 0xff0000L) + + ((lastdata[2] << 8) & 0xff00L) + + (lastdata[3] & 0xffL); + */ + + byte[] conv; + // special rule for handling zeros at the end + if (buffer != 0) { + conv = convertWord(buffer); + } else { + conv = new byte[5]; + for (int j = 0; j < 5; j++) { + conv[j] = (byte)'!'; + } + } + // assert rest+1 <= 5 + checkedWrite(conv, rest + 1); + } + // finally write the two character end of data marker + checkedWrite(EOD); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable)out).finalizeStream(); + } + } + + + public void close() throws IOException { + finalizeStream(); + super.close(); + } + +} + + diff --git a/src/org/apache/fop/render/ps/ASCIIHexEncodeFilter.java b/src/org/apache/fop/render/ps/ASCIIHexEncodeFilter.java deleted file mode 100644 index 8a8c2d837..000000000 --- a/src/org/apache/fop/render/ps/ASCIIHexEncodeFilter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. - * For details on use and redistribution please refer to the - * LICENSE file included with these sources. - */ - -package org.apache.fop.render.ps; - -import java.io.*; - -public class ASCIIHexEncodeFilter implements Filter { - - private static final char ASCIIHEX_EOL = '\n'; - private static final String ASCIIHEX_EOD = ">"; - private static final String ENCODING = "US-ASCII"; - - protected ASCIIHexEncodeFilter() {} - - public long write(OutputStream out, byte[] buf, int len, - long bw) throws IOException { - boolean last = false; - int pos = 0; - int rest = len; - while (rest > 0) { - int restofline = 80 - (int)((bw + pos) % 80); - if (rest < restofline) { - // last line - restofline = rest; - last = true; - } - if (restofline > 0) { - out.write(buf, pos, restofline); - pos += restofline; - if (!last) - out.write(ASCIIHEX_EOL); - } - rest = len - pos; - } - return bw + len; - } - - public void doFilter(InputStream in, - OutputStream out) throws IOException { - long bw = 0; - byte[] buf = new byte[2048]; - int bytes_read; - StringBuffer sb = new StringBuffer(2048 * 2); - while ((bytes_read = in.read(buf)) != -1) { - sb.setLength(0); - for (int i = 0; i < bytes_read; i++) { - int val = (int)(buf[i] & 0xFF); - if (val < 16) - sb.append("0"); - sb.append(Integer.toHexString(val)); - } - bw = write(out, sb.toString().getBytes(ENCODING), bytes_read * 2, - bw); - } - byte[] eod = ASCIIHEX_EOD.getBytes(ENCODING); - bw = write(out, eod, eod.length, bw); - } - - public static InputStream filter(InputStream in) throws IOException { - ASCIIHexEncodeFilter myfilter = new ASCIIHexEncodeFilter(); - return FilterThread.filter(in, myfilter); - } - -} diff --git a/src/org/apache/fop/render/ps/ASCIIHexOutputStream.java b/src/org/apache/fop/render/ps/ASCIIHexOutputStream.java new file mode 100644 index 000000000..af37a73b4 --- /dev/null +++ b/src/org/apache/fop/render/ps/ASCIIHexOutputStream.java @@ -0,0 +1,81 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; + +/** + * This class applies a ASCII Hex encoding to the stream. + * + * @author Jeremias Maerki + * @version $Id$ + */ +public class ASCIIHexOutputStream extends FilterOutputStream { + + private static final int EOL = 0x0A; //"\n" + private static final int EOD = 0x3E; //">" + private static final int ZERO = 0x30; //"0" + private static final int NINE = 0x39; //"9" + private static final int A = 0x41; //"A" + private static final int ADIFF = A - NINE -1; + + private int posinline = 0; + + + public ASCIIHexOutputStream(OutputStream out) { + super(out); + } + + + public void write(int b) throws IOException { + b &= 0xFF; + + int digit1 = ((b & 0xF0) >> 4) + ZERO; + if (digit1 > NINE) digit1 += ADIFF; + out.write(digit1); + + int digit2 = (b & 0x0F) + ZERO; + if (digit2 > NINE) digit2 += ADIFF; + out.write(digit2); + + posinline++; + checkLineWrap(); + } + + + private void checkLineWrap() throws IOException { + //Maximum line length is 80 characters + if (posinline >= 40) { + out.write(EOL); + posinline = 0; + } + } + + + public void finalizeStream() throws IOException { + checkLineWrap(); + //Write closing character ">" + super.write(EOD); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable)out).finalizeStream(); + } + } + + + public void close() throws IOException { + finalizeStream(); + super.close(); + } + + +} + + diff --git a/src/org/apache/fop/render/ps/Filter.java b/src/org/apache/fop/render/ps/Filter.java deleted file mode 100644 index 3d6f0034c..000000000 --- a/src/org/apache/fop/render/ps/Filter.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. - * For details on use and redistribution please refer to the - * LICENSE file included with these sources. - */ - -package org.apache.fop.render.ps; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public interface Filter { - - public void doFilter(InputStream in, OutputStream out) throws IOException; -} - diff --git a/src/org/apache/fop/render/ps/FilterThread.java b/src/org/apache/fop/render/ps/FilterThread.java deleted file mode 100644 index b690c3225..000000000 --- a/src/org/apache/fop/render/ps/FilterThread.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. - * For details on use and redistribution please refer to the - * LICENSE file included with these sources. - */ - -package org.apache.fop.render.ps; - -import java.io.*; - -public class FilterThread extends Thread { - - private Filter filter; - private InputStream in; - private OutputStream out; - - private FilterThread(Filter filter, InputStream in, OutputStream out) { - this.filter = filter; - this.in = in; - this.out = out; - } - - public void run() { - try { - try { - this.filter.doFilter(in, out); - this.out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - finally { - this.filter = null; - this.in = null; - this.out = null; - } - } - - public static InputStream filter(InputStream in, - Filter filter) throws IOException { - PipedInputStream pin = new PipedInputStream(); - PipedOutputStream pout = new PipedOutputStream(pin); - FilterThread thread = new FilterThread(filter, in, pout); - thread.start(); - return pin; - } - -} diff --git a/src/org/apache/fop/render/ps/Finalizable.java b/src/org/apache/fop/render/ps/Finalizable.java new file mode 100644 index 000000000..d7c77d668 --- /dev/null +++ b/src/org/apache/fop/render/ps/Finalizable.java @@ -0,0 +1,30 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render.ps; + +/** + * This interface is used for special FilteredOutputStream classes that won't + * be closed (since this causes the target OutputStream to be closed, too) but + * where flush() is not enough, for example because a final marker has to be + * written to the target stream. + * + * @author Jeremias Maerki + * @version $Id$ + */ +public interface Finalizable { + + /** + * This method can be called instead of close() on a subclass of + * FilteredOutputStream when a final marker has to be written to the target + * stream, but close() cannot be called. + * + * @exception java.io.IOException In case of an IO problem + */ + public void finalizeStream() + throws java.io.IOException; + +} diff --git a/src/org/apache/fop/render/ps/FlateEncodeFilter.java b/src/org/apache/fop/render/ps/FlateEncodeFilter.java deleted file mode 100644 index bde626713..000000000 --- a/src/org/apache/fop/render/ps/FlateEncodeFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. - * For details on use and redistribution please refer to the - * LICENSE file included with these sources. - */ - -package org.apache.fop.render.ps; - -import java.io.*; -import java.util.zip.DeflaterOutputStream; - -public class FlateEncodeFilter implements Filter { - - protected FlateEncodeFilter() {} - - private long copyStream(InputStream in, OutputStream out, - int bufferSize) throws IOException { - long bytes_total = 0; - byte[] buf = new byte[bufferSize]; - int bytes_read; - while ((bytes_read = in.read(buf)) != -1) { - bytes_total += bytes_read; - out.write(buf, 0, bytes_read); - } - return bytes_total; - } - - public void doFilter(InputStream in, - OutputStream out) throws IOException { - DeflaterOutputStream dout = new DeflaterOutputStream(out); - copyStream(in, dout, 2048); - // dout.flush(); - dout.close(); - } - - public static InputStream filter(InputStream in) throws IOException { - FlateEncodeFilter myfilter = new FlateEncodeFilter(); - return FilterThread.filter(in, myfilter); - } - -} diff --git a/src/org/apache/fop/render/ps/FlateEncodeOutputStream.java b/src/org/apache/fop/render/ps/FlateEncodeOutputStream.java new file mode 100644 index 000000000..e6d96b8e9 --- /dev/null +++ b/src/org/apache/fop/render/ps/FlateEncodeOutputStream.java @@ -0,0 +1,39 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; + +/** + * This class applies a FlateEncode filter to the stream. It is basically the + * normal DeflaterOutputStream except now conformi + * + * @author Jeremias Maerki + * @version $Id$ + */ +public class FlateEncodeOutputStream extends java.util.zip.DeflaterOutputStream + implements Finalizable { + + + public FlateEncodeOutputStream(OutputStream out) { + super(out); + } + + + public void finalizeStream() throws IOException { + finish(); + flush(); + if (out instanceof Finalizable) { + ((Finalizable)out).finalizeStream(); + } + } + +} + + diff --git a/src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java b/src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java new file mode 100644 index 000000000..a006bc5b6 --- /dev/null +++ b/src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java @@ -0,0 +1,205 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render.ps; + +import java.io.FilterOutputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * This class applies a RunLengthEncode filter to the stream. + * + * @author Stephen Wolke + * @version $Id$ + */ + +public class RunLengthEncodeOutputStream extends FilterOutputStream + implements Finalizable { + + private final static int MAX_SEQUENCE_COUNT = 127; + private final static int END_OF_DATA = 128; + private final static int BYTE_MAX = 256; + + private final static int NOT_IDENTIFY_SEQUENCE = 0; + private final static int START_SEQUENCE = 1; + private final static int IN_SEQUENCE = 2; + private final static int NOT_IN_SEQUENCE = 3; + + private int runCount = 0; + private int isSequence = NOT_IDENTIFY_SEQUENCE; + private byte[] runBuffer = new byte[MAX_SEQUENCE_COUNT + 1]; + + + /** + * Constructor for the RunLengthEncode Filter. + * + * @param out The OutputStream to write to + */ + public RunLengthEncodeOutputStream(OutputStream out) { + super(out); + } + + + /** + * @see java.io.OutputStream#write(int) + * @param b the byte. + * @exception IOException if an I/O error occurs. In particular, + * an IOException may be thrown if the + * output stream has been closed. + */ + public void write(byte b) + throws java.io.IOException { + runBuffer[runCount] = b; + + switch (runCount) { + case 0: + runCount = 0; + isSequence = NOT_IDENTIFY_SEQUENCE; + runCount++; + break; + case 1: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + isSequence = NOT_IN_SEQUENCE; + } + runCount++; + break; + case 2: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + isSequence = NOT_IN_SEQUENCE; + } else { + if (isSequence == NOT_IN_SEQUENCE) { + isSequence = START_SEQUENCE; + } else { + isSequence = IN_SEQUENCE; + } + } + runCount++; + break; + case MAX_SEQUENCE_COUNT: + if (isSequence == IN_SEQUENCE) { + out.write(BYTE_MAX - (MAX_SEQUENCE_COUNT - 1)); + out.write(runBuffer[runCount - 1]); + runBuffer[0] = runBuffer[runCount]; + runCount = 1; + } else { + out.write(MAX_SEQUENCE_COUNT); + out.write(runBuffer, 0, runCount + 1); + runCount = 0; + } + isSequence = NOT_IDENTIFY_SEQUENCE; + break; + default: + switch (isSequence) { + case IN_SEQUENCE: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + out.write(BYTE_MAX - (runCount - 1)); + out.write(runBuffer[runCount - 1]); + runBuffer[0] = runBuffer[runCount]; + runCount = 1; + isSequence = NOT_IDENTIFY_SEQUENCE; + break; + } + runCount++; + break; + case NOT_IN_SEQUENCE: + if (runBuffer[runCount] == runBuffer[runCount - 1]) { + isSequence = START_SEQUENCE; + } + runCount++; + break; + case START_SEQUENCE: + if (runBuffer[runCount] == runBuffer[runCount - 1]) { + out.write(runCount - 3); + out.write(runBuffer, 0, runCount - 2); + runBuffer[0] = runBuffer[runCount]; + runBuffer[1] = runBuffer[runCount]; + runBuffer[2] = runBuffer[runCount]; + runCount = 3; + isSequence = IN_SEQUENCE; + break; + } else { + isSequence = NOT_IN_SEQUENCE; + runCount++; + break; + } + } + } + } + + + /** + * @see java.io.OutputStream#write(byte[]) + * @param b the data. + * @exception IOException if an I/O error occurs. + */ + public void write(byte[] b) + throws IOException { + + for (int i = 0; i < b.length; i++) { + this.write(b[i]); + } + } + + + /** + * @see java.io.OutputStream#write(byte[], int, int) + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception IOException if an I/O error occurs. In particular, + * an IOException is thrown if the output + * stream is closed. + */ + public void write(byte[] b, int off, int len) + throws IOException { + + for (int i = 0; i < len; i++) { + this.write(b[off + i]); + } + } + + + /** + * Flushes the the stream and writes out the trailer, but, unlike close(), + * without closing the stream. + * + * @exception IOException if an I/O error occurs. + */ + public void finalizeStream() + throws IOException { + switch (isSequence) { + case IN_SEQUENCE: + out.write(BYTE_MAX - (runCount - 1)); + out.write(runBuffer[runCount - 1]); + break; + default: + out.write(runCount - 1); + out.write(runBuffer, 0, runCount); + } + + out.write(END_OF_DATA); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable) out).finalizeStream(); + } + } + + + /** + * Closes the stream. + * + * @exception IOException if an I/O error occurs. + */ + public void close() + throws IOException { + finalizeStream(); + super.close(); + } + +} + -- 2.39.5