001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: RunLengthEncodeOutputStream.java 426584 2006-07-28 16:01:47Z jeremias $ */
019:
020: package org.apache.xmlgraphics.util.io;
021:
022: import java.io.FilterOutputStream;
023: import java.io.OutputStream;
024: import java.io.IOException;
025:
026: /**
027: * This class applies a RunLengthEncode filter to the stream.
028: *
029: * @author <a href="mailto:smwolke@geistig.com">Stephen Wolke</a>
030: * @version $Id: RunLengthEncodeOutputStream.java 426584 2006-07-28 16:01:47Z jeremias $
031: */
032: public class RunLengthEncodeOutputStream extends FilterOutputStream
033: implements Finalizable {
034:
035: private static final int MAX_SEQUENCE_COUNT = 127;
036: private static final int END_OF_DATA = 128;
037: private static final int BYTE_MAX = 256;
038:
039: private static final int NOT_IDENTIFY_SEQUENCE = 0;
040: private static final int START_SEQUENCE = 1;
041: private static final int IN_SEQUENCE = 2;
042: private static final int NOT_IN_SEQUENCE = 3;
043:
044: private int runCount = 0;
045: private int isSequence = NOT_IDENTIFY_SEQUENCE;
046: private byte[] runBuffer = new byte[MAX_SEQUENCE_COUNT + 1];
047:
048: /** @see java.io.FilterOutputStream **/
049: public RunLengthEncodeOutputStream(OutputStream out) {
050: super (out);
051: }
052:
053: /** @see java.io.FilterOutputStream **/
054: public void write(byte b) throws java.io.IOException {
055: runBuffer[runCount] = b;
056:
057: switch (runCount) {
058: case 0:
059: runCount = 0;
060: isSequence = NOT_IDENTIFY_SEQUENCE;
061: runCount++;
062: break;
063: case 1:
064: if (runBuffer[runCount] != runBuffer[runCount - 1]) {
065: isSequence = NOT_IN_SEQUENCE;
066: }
067: runCount++;
068: break;
069: case 2:
070: if (runBuffer[runCount] != runBuffer[runCount - 1]) {
071: isSequence = NOT_IN_SEQUENCE;
072: } else {
073: if (isSequence == NOT_IN_SEQUENCE) {
074: isSequence = START_SEQUENCE;
075: } else {
076: isSequence = IN_SEQUENCE;
077: }
078: }
079: runCount++;
080: break;
081: case MAX_SEQUENCE_COUNT:
082: if (isSequence == IN_SEQUENCE) {
083: out.write(BYTE_MAX - (MAX_SEQUENCE_COUNT - 1));
084: out.write(runBuffer[runCount - 1]);
085: runBuffer[0] = runBuffer[runCount];
086: runCount = 1;
087: } else {
088: out.write(MAX_SEQUENCE_COUNT);
089: out.write(runBuffer, 0, runCount + 1);
090: runCount = 0;
091: }
092: isSequence = NOT_IDENTIFY_SEQUENCE;
093: break;
094: default:
095: switch (isSequence) {
096: case IN_SEQUENCE:
097: if (runBuffer[runCount] != runBuffer[runCount - 1]) {
098: out.write(BYTE_MAX - (runCount - 1));
099: out.write(runBuffer[runCount - 1]);
100: runBuffer[0] = runBuffer[runCount];
101: runCount = 1;
102: isSequence = NOT_IDENTIFY_SEQUENCE;
103: break;
104: }
105: runCount++;
106: break;
107: case NOT_IN_SEQUENCE:
108: if (runBuffer[runCount] == runBuffer[runCount - 1]) {
109: isSequence = START_SEQUENCE;
110: }
111: runCount++;
112: break;
113: case START_SEQUENCE:
114: if (runBuffer[runCount] == runBuffer[runCount - 1]) {
115: out.write(runCount - 3);
116: out.write(runBuffer, 0, runCount - 2);
117: runBuffer[0] = runBuffer[runCount];
118: runBuffer[1] = runBuffer[runCount];
119: runBuffer[2] = runBuffer[runCount];
120: runCount = 3;
121: isSequence = IN_SEQUENCE;
122: break;
123: } else {
124: isSequence = NOT_IN_SEQUENCE;
125: runCount++;
126: break;
127: }
128: }
129: }
130: }
131:
132: /** @see java.io.FilterOutputStream **/
133: public void write(byte[] b) throws IOException {
134:
135: for (int i = 0; i < b.length; i++) {
136: this .write(b[i]);
137: }
138: }
139:
140: /** @see java.io.FilterOutputStream **/
141: public void write(byte[] b, int off, int len) throws IOException {
142:
143: for (int i = 0; i < len; i++) {
144: this .write(b[off + i]);
145: }
146: }
147:
148: /** @see Finalizable **/
149: public void finalizeStream() throws IOException {
150: switch (isSequence) {
151: case IN_SEQUENCE:
152: out.write(BYTE_MAX - (runCount - 1));
153: out.write(runBuffer[runCount - 1]);
154: break;
155: default:
156: out.write(runCount - 1);
157: out.write(runBuffer, 0, runCount);
158: }
159:
160: out.write(END_OF_DATA);
161:
162: flush();
163: if (out instanceof Finalizable) {
164: ((Finalizable) out).finalizeStream();
165: }
166: }
167:
168: /** @see java.io.FilterOutputStream **/
169: public void close() throws IOException {
170: finalizeStream();
171: super.close();
172: }
173:
174: }
|