org.apache.xmlgraphics.util.io.ASCII85InputStream Maven / Gradle / Ivy
Show all versions of xmlgraphics-commons Show documentation
/*
* 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: ASCII85InputStream.java 1610846 2014-07-15 20:44:18Z vhennebert $ */
package org.apache.xmlgraphics.util.io;
import java.io.IOException;
import java.io.InputStream;
/**
* This class applies a ASCII85 decoding to the stream.
*
* The class is derived from InputStream instead of FilteredInputStream because
* we can use the read(byte[], int, int) method from InputStream which simply
* delegates to read(). This makes the implementation easier.
*
* The filter is described in chapter 3.13.3 of the PostScript Language
* Reference (third edition).
*
* @version $Id: ASCII85InputStream.java 1610846 2014-07-15 20:44:18Z vhennebert $
*/
public class ASCII85InputStream extends InputStream
implements ASCII85Constants {
private InputStream in;
private boolean eodReached;
private int[] b = new int[4]; //decoded
private int bSize;
private int bIndex;
/** @see java.io.FilterInputStream **/
public ASCII85InputStream(InputStream in) {
super();
this.in = in;
}
/** @see java.io.FilterInputStream **/
public int read() throws IOException {
//Check if we need to read the next tuple
if (bIndex >= bSize) {
if (eodReached) {
return -1;
}
readNextTuple();
if (bSize == 0) {
if (!eodReached) {
throw new IllegalStateException("Internal error");
}
return -1;
}
}
int result = b[bIndex];
result = (result < 0 ? 256 + result : result);
bIndex++;
return result;
}
private int filteredRead() throws IOException {
int buf;
while (true) {
buf = in.read();
switch (buf) {
case 0: //null
case 9: //tab
case 10: //LF
case 12: //FF
case 13: //CR
case 32: //space
continue; //ignore
case ZERO:
case 126: //= EOD[0] = '~'
return buf;
default:
if ((buf >= START) && (buf <= END)) {
return buf;
} else {
throw new IOException("Illegal character detected: " + buf);
}
}
}
}
private void handleEOD() throws IOException {
final int buf = in.read();
if (buf != EOD[1]) {
throw new IOException("'>' expected after '~' (EOD)");
}
eodReached = true;
bSize = 0;
bIndex = 0;
}
private void readNextTuple() throws IOException {
int buf;
long tuple = 0;
//Read ahead and check for special "z"
buf = filteredRead();
if (buf == ZERO) {
java.util.Arrays.fill(b, 0);
bSize = 4;
bIndex = 0;
} else if (buf == EOD[0]) {
handleEOD();
} else {
int cIndex = 0;
tuple = (buf - START) * POW85[cIndex];
cIndex++;
while (cIndex < 5) {
buf = filteredRead();
if (buf == EOD[0]) {
handleEOD();
break;
} else if (buf == ZERO) {
//Violation 2
throw new IOException("Illegal 'z' within tuple");
} else {
tuple += (buf - START) * POW85[cIndex];
cIndex++;
}
}
int cSize = cIndex;
if (cSize == 1) {
//Violation 3
throw new IOException("Only one character in tuple");
}
//Handle optional, trailing, incomplete tuple
while (cIndex < 5) {
tuple += POW85[cIndex - 1];
cIndex++;
}
if (tuple > (2L << 31) - 1) {
//Violation 1
throw new IOException("Illegal tuple (> 2^32 - 1)");
}
//Convert tuple
b[0] = (byte)((tuple >> 24) & 0xFF);
b[1] = (byte)((tuple >> 16) & 0xFF);
b[2] = (byte)((tuple >> 8) & 0xFF);
b[3] = (byte)((tuple) & 0xFF);
bSize = cSize - 1;
bIndex = 0;
}
}
}