| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.xmlgraphics.util.io; |
| |
| import java.io.FilterOutputStream; |
| import java.io.OutputStream; |
| import java.io.IOException; |
| |
| |
| /** |
| * This class applies a RunLengthEncode filter to the stream. |
| * |
| * @author <a href="mailto:smwolke@geistig.com">Stephen Wolke</a> |
| * @version $Id$ |
| */ |
| public class RunLengthEncodeOutputStream extends FilterOutputStream |
| implements Finalizable { |
| |
| private static final int MAX_SEQUENCE_COUNT = 127; |
| private static final int END_OF_DATA = 128; |
| private static final int BYTE_MAX = 256; |
| |
| private static final int NOT_IDENTIFY_SEQUENCE = 0; |
| private static final int START_SEQUENCE = 1; |
| private static final int IN_SEQUENCE = 2; |
| private static final int NOT_IN_SEQUENCE = 3; |
| |
| private int runCount = 0; |
| private int isSequence = NOT_IDENTIFY_SEQUENCE; |
| private byte[] runBuffer = new byte[MAX_SEQUENCE_COUNT + 1]; |
| |
| |
| /** @see java.io.FilterOutputStream **/ |
| public RunLengthEncodeOutputStream(OutputStream out) { |
| super(out); |
| } |
| |
| |
| /** @see java.io.FilterOutputStream **/ |
| 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.FilterOutputStream **/ |
| public void write(byte[] b) |
| throws IOException { |
| |
| for (int i = 0; i < b.length; i++) { |
| this.write(b[i]); |
| } |
| } |
| |
| |
| /** @see java.io.FilterOutputStream **/ |
| public void write(byte[] b, int off, int len) |
| throws IOException { |
| |
| for (int i = 0; i < len; i++) { |
| this.write(b[off + i]); |
| } |
| } |
| |
| |
| /** @see Finalizable **/ |
| 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(); |
| } |
| } |
| |
| |
| /** @see java.io.FilterOutputStream **/ |
| public void close() |
| throws IOException { |
| finalizeStream(); |
| super.close(); |
| } |
| |
| } |
| |