001: /*
002: * $Id: ASCII85Decode.java,v 1.2 2007/12/20 18:33:33 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package com.sun.pdfview.decode;
023:
024: import java.io.ByteArrayOutputStream;
025: import java.nio.ByteBuffer;
026:
027: import com.sun.pdfview.PDFFile;
028: import com.sun.pdfview.PDFObject;
029: import com.sun.pdfview.PDFParseException;
030:
031: /**
032: * decode ASCII85 text into a byte array.
033: *
034: * @author Mike Wessler
035: */
036: public class ASCII85Decode {
037: private ByteBuffer buf;
038:
039: /**
040: * initialize the decoder with byte buffer in ASCII85 format
041: */
042: private ASCII85Decode(ByteBuffer buf) {
043: this .buf = buf;
044: }
045:
046: /**
047: * get the next character from the input.
048: * @return the next character, or -1 if at end of stream
049: */
050: private int nextChar() {
051: // skip whitespace
052: // returns next character, or -1 if end of stream
053: while (buf.remaining() > 0) {
054: char c = (char) buf.get();
055:
056: if (!PDFFile.isWhiteSpace(c)) {
057: return c;
058: }
059: }
060:
061: // EOF reached
062: return -1;
063: }
064:
065: /**
066: * decode the next five ASCII85 characters into up to four decoded
067: * bytes. Return false when finished, or true otherwise.
068: *
069: * @param baos the ByteArrayOutputStream to write output to, set to the
070: * correct position
071: * @return false when finished, or true otherwise.
072: */
073: private boolean decode5(ByteArrayOutputStream baos)
074: throws PDFParseException {
075: // stream ends in ~>
076: int[] five = new int[5];
077: int i;
078: for (i = 0; i < 5; i++) {
079: five[i] = nextChar();
080: if (five[i] == '~') {
081: if (nextChar() == '>') {
082: break;
083: } else {
084: throw new PDFParseException(
085: "Bad character in ASCII85Decode: not ~>");
086: }
087: } else if (five[i] >= '!' && five[i] <= 'u') {
088: five[i] -= '!';
089: } else if (five[i] == 'z') {
090: if (i == 0) {
091: five[i] = 0;
092: i = 4;
093: } else {
094: throw new PDFParseException(
095: "Inappropriate 'z' in ASCII85Decode");
096: }
097: } else {
098: throw new PDFParseException(
099: "Bad character in ASCII85Decode: " + five[i]
100: + " (" + (char) five[i] + ")");
101: }
102: }
103:
104: if (i > 0) {
105: i -= 1;
106: }
107:
108: int value = five[0] * 85 * 85 * 85 * 85 + five[1] * 85 * 85
109: * 85 + five[2] * 85 * 85 + five[3] * 85 + five[4];
110:
111: for (int j = 0; j < i; j++) {
112: int shift = 8 * (3 - j);
113: baos.write((byte) ((value >> shift) & 0xff));
114: }
115:
116: return (i == 4);
117: }
118:
119: /**
120: * decode the bytes
121: * @return the decoded bytes
122: */
123: private ByteBuffer decode() throws PDFParseException {
124: // start from the beginning of the data
125: buf.rewind();
126:
127: // allocate the output buffer
128: ByteArrayOutputStream baos = new ByteArrayOutputStream();
129:
130: // decode the bytes
131: while (decode5(baos)) {
132: }
133:
134: return ByteBuffer.wrap(baos.toByteArray());
135: }
136:
137: /**
138: * decode an array of bytes in ASCII85 format.
139: * <p>
140: * In ASCII85 format, every 5 characters represents 4 decoded
141: * bytes in base 85. The entire stream can contain whitespace,
142: * and ends in the characters '~>'.
143: *
144: * @param buf the encoded ASCII85 characters in a byte buffer
145: * @param params parameters to the decoder (ignored)
146: * @return the decoded bytes
147: */
148: public static ByteBuffer decode(ByteBuffer buf, PDFObject params)
149: throws PDFParseException {
150: ASCII85Decode me = new ASCII85Decode(buf);
151: return me.decode();
152: }
153:
154: }
|