001    /*
002     * Copyright (c) 2003, www.pdfbox.org
003     * All rights reserved.
004     *
005     * Redistribution and use in source and binary forms, with or without
006     * modification, are permitted provided that the following conditions are met:
007     *
008     * 1. Redistributions of source code must retain the above copyright notice,
009     *    this list of conditions and the following disclaimer.
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     *    this list of conditions and the following disclaimer in the documentation
012     *    and/or other materials provided with the distribution.
013     * 3. Neither the name of pdfbox; nor the names of its
014     *    contributors may be used to endorse or promote products derived from this
015     *    software without specific prior written permission.
016     *
017     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020     * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021     * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027     *
028     * http://www.pdfbox.org
029     *
030     */
031    package com.imagero.uio.io;
032    
033    import java.io.FilterInputStream;
034    import java.io.IOException;
035    import java.io.InputStream;
036    
037    /**
038     * This class represents an ASCII85 stream.
039     *
040     * @author Ben Litchfield
041     * @version $Revision: 1.2 $
042     */
043    public class ASCII85InputStream extends FilterInputStream {
044        private int index;
045        private int n;
046        private boolean eof;
047    
048        private byte[] ascii;
049        private byte[] b;
050    
051        /**
052         * Constructor.
053         *
054         * @param is The input stream to actually read from.
055         */
056        public ASCII85InputStream(InputStream is) {
057            super(is);
058            ascii = new byte[5];
059            b = new byte[4];
060        }
061    
062        /**
063         * This will read the next byte from the stream.
064         *
065         * @return The next byte read from the stream.
066         *
067         * @throws IOException If there is an error reading from the wrapped stream.
068         */
069        public final int read() throws IOException {
070            if (index >= n) {
071                if (eof) {
072                    return -1;
073                }
074                index = 0;
075                int k;
076                byte z;
077                do {
078                    int zz = (byte) in.read();
079                    if (zz == -1) {
080                        eof = true;
081                        return -1;
082                    }
083                    z = (byte) zz;
084                }
085                while (z == '\n' || z == '\r' || z == ' ');
086    
087                if (z == '~' || z == 'x') {
088                    eof = true;
089                    ascii = b = null;
090                    n = 0;
091                    return -1;
092                }
093                else if (z == 'z') {
094                    b[0] = b[1] = b[2] = b[3] = 0;
095                    n = 4;
096                }
097                else {
098                    ascii[0] = z; // may be EOF here....
099                    for (k = 1; k < 5; ++k) {
100                        do {
101                            int zz = (byte) in.read();
102                            if (zz == -1) {
103                                eof = true;
104                                return -1;
105                            }
106                            z = (byte) zz;
107                        }
108                        while (z == '\n' || z == '\r' || z == ' ');
109                        ascii[k] = z;
110                        if (z == '~' || z == 'x') {
111                            break;
112                        }
113                    }
114                    n = k - 1;
115                    if (n == 0) {
116                        eof = true;
117                        ascii = null;
118                        b = null;
119                        return -1;
120                    }
121                    if (k < 5) {
122                        for (++k; k < 5; ++k) {
123                            ascii[k] = 0x21;
124                        }
125                        eof = true;
126                    }
127                    // decode stream
128                    long t = 0;
129                    for (k = 0; k < 5; ++k) {
130                        z = (byte) (ascii[k] - 0x21);
131                        if (z < 0 || z > 93) {
132                            n = 0;
133                            eof = true;
134                            ascii = null;
135                            b = null;
136                            throw new IOException("Invalid data in Ascii85 stream");
137                        }
138                        t = (t * 85L) + z;
139                    }
140                    for (k = 3; k >= 0; --k) {
141                        b[k] = (byte) (t & 0xFFL);
142                        t >>>= 8;
143                    }
144                }
145            }
146            return b[index++] & 0xFF;
147        }
148    
149        /**
150         * This will read a chunk of data.
151         *
152         * @param data The buffer to write data to.
153         * @param offset The offset into the data stream.
154         * @param len The number of byte to attempt to read.
155         *
156         * @return The number of bytes actually read.
157         *
158         * @throws IOException If there is an error reading data from the underlying stream.
159         */
160        public final int read(byte[] data, int offset, int len) throws IOException {
161            if (eof && index >= n) {
162                return -1;
163            }
164            for (int i = 0; i < len; i++) {
165                if (index < n) {
166                    data[i + offset] = b[index++];
167                }
168                else {
169                    int t = read();
170                    if (t == -1) {
171                        return i;
172                    }
173                    data[i + offset] = (byte) t;
174                }
175            }
176            return len;
177        }
178    
179        /**
180         * This will close the underlying stream and release any resources.
181         *
182         * @throws IOException If there is an error closing the underlying stream.
183         */
184        public void close() throws IOException {
185            ascii = null;
186            eof = true;
187            b = null;
188            super.close();
189        }
190    
191        /**
192         * non supported interface methods.
193         *
194         * @return False always.
195         */
196        public boolean markSupported() {
197            return false;
198        }
199    
200        /**
201         * Unsupported.
202         *
203         * @param nValue ignored.
204         *
205         * @return Always zero.
206         */
207        public long skip(long nValue) {
208            return 0;
209        }
210    
211        /**
212         * Unsupported.
213         *
214         * @return Always zero.
215         */
216        public int available() {
217            if (eof) {
218                return 0;
219            }
220            else {
221                return 1;
222            }
223        }
224    
225        /**
226         * Unsupported.
227         *
228         * @param readlimit ignored.
229         */
230        public void mark(int readlimit) {
231        }
232    
233        /**
234         * Unsupported.
235         *
236         * @throws IOException telling that this is an unsupported action.
237         */
238        public void reset() throws IOException {
239            throw new IOException("Reset is not supported");
240        }
241    }