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: ASCII85InputStream.java 426584 2006-07-28 16:01:47Z jeremias $ */
019:
020: package org.apache.xmlgraphics.util.io;
021:
022: import java.io.InputStream;
023: import java.io.IOException;
024:
025: /**
026: * This class applies a ASCII85 decoding to the stream.
027: * <p>
028: * The class is derived from InputStream instead of FilteredInputStream because
029: * we can use the read(byte[], int, int) method from InputStream which simply
030: * delegates to read(). This makes the implementation easier.
031: * <p>
032: * The filter is described in chapter 3.13.3 of the PostScript Language
033: * Reference (third edition).
034: *
035: * @version $Id: ASCII85InputStream.java 426584 2006-07-28 16:01:47Z jeremias $
036: */
037: public class ASCII85InputStream extends InputStream implements
038: ASCII85Constants {
039:
040: private InputStream in;
041: private boolean eodReached = false;
042: private int[] b = new int[4]; //decoded
043: private int bSize = 0;
044: private int bIndex = 0;
045:
046: /** @see java.io.FilterInputStream **/
047: public ASCII85InputStream(InputStream in) {
048: super ();
049: this .in = in;
050: }
051:
052: /** @see java.io.FilterInputStream **/
053: public int read() throws IOException {
054: //Check if we need to read the next tuple
055: if (bIndex >= bSize) {
056: if (eodReached) {
057: return -1;
058: }
059: readNextTuple();
060: if (bSize == 0) {
061: if (!eodReached) {
062: throw new IllegalStateException("Internal error");
063: }
064: return -1;
065: }
066: }
067: int result = b[bIndex];
068: result = (result < 0 ? 256 + result : result);
069: bIndex++;
070: return result;
071: }
072:
073: private int filteredRead() throws IOException {
074: int buf;
075: while (true) {
076: buf = in.read();
077: switch (buf) {
078: case 0: //null
079: case 9: //tab
080: case 10: //LF
081: case 12: //FF
082: case 13: //CR
083: case 32: //space
084: continue; //ignore
085: case ZERO:
086: case 126: //= EOD[0] = '~'
087: return buf;
088: default:
089: if ((buf >= START) && (buf <= END)) {
090: return buf;
091: } else {
092: throw new IOException(
093: "Illegal character detected: " + buf);
094: }
095: }
096: }
097: }
098:
099: private void handleEOD() throws IOException {
100: final int buf = in.read();
101: if (buf != EOD[1]) {
102: throw new IOException("'>' expected after '~' (EOD)");
103: }
104: eodReached = true;
105: bSize = 0;
106: bIndex = 0;
107: }
108:
109: private void readNextTuple() throws IOException {
110: int buf;
111: long tuple = 0;
112: //Read ahead and check for special "z"
113: buf = filteredRead();
114: if (buf == ZERO) {
115: java.util.Arrays.fill(b, 0);
116: bSize = 4;
117: bIndex = 0;
118: } else if (buf == EOD[0]) {
119: handleEOD();
120: } else {
121: int cIndex = 0;
122: tuple = (buf - START) * POW85[cIndex];
123: cIndex++;
124: while (cIndex < 5) {
125: buf = filteredRead();
126: if (buf == EOD[0]) {
127: handleEOD();
128: break;
129: } else if (buf == ZERO) {
130: //Violation 2
131: throw new IOException("Illegal 'z' within tuple");
132: } else {
133: tuple += (buf - START) * POW85[cIndex];
134: cIndex++;
135: }
136: }
137: int cSize = cIndex;
138: if (cSize == 1) {
139: //Violation 3
140: throw new IOException("Only one character in tuple");
141: }
142: //Handle optional, trailing, incomplete tuple
143: while (cIndex < 5) {
144: tuple += POW85[cIndex - 1];
145: cIndex++;
146: }
147: if (tuple > (2L << 31) - 1) {
148: //Violation 1
149: throw new IOException("Illegal tuple (> 2^32 - 1)");
150: }
151: //Convert tuple
152: b[0] = (byte) ((tuple >> 24) & 0xFF);
153: b[1] = (byte) ((tuple >> 16) & 0xFF);
154: b[2] = (byte) ((tuple >> 8) & 0xFF);
155: b[3] = (byte) ((tuple) & 0xFF);
156: bSize = cSize - 1;
157: bIndex = 0;
158: }
159: }
160:
161: }
|