From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../pdfbox/io/ByteArrayPushBackInputStream.java | 404 +++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java (limited to 'src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java') diff --git a/src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java b/src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java new file mode 100644 index 0000000..e72cbbb --- /dev/null +++ b/src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java @@ -0,0 +1,404 @@ +/** + * Copyright (c) 2004, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.io; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * PushBackInputStream for byte arrays. + * + * The inheritance from PushBackInputStream is only to avoid the + * introduction of an interface with all PushBackInputStream + * methods. The parent PushBackInputStream is not used in any way and + * all methods are overridden. (Thus when adding new methods to PushBackInputStream + * override them in this class as well!) + * unread() is limited to the number of bytes already read from this stream (i.e. + * the current position in the array). This limitation usually poses no problem + * to a parser, but allows for some optimization since only one array has to + * be dealt with. + * + * Note: This class is not thread safe. Clients must provide synchronization + * if needed. + * + * Note: Calling unread() after mark() will cause (part of) the unread data to be + * read again after reset(). Thus do not call unread() between mark() and reset(). + * + * @author Andreas Weiss (andreas.weiss@switzerland.org) + * @version $Revision: 1.2 $ + */ +public class ByteArrayPushBackInputStream extends PushBackInputStream +{ + private byte[] data; + private int datapos; + private int datalen; + private int save; + + // dummy for base class constructor + private static final InputStream DUMMY = new ByteArrayInputStream("".getBytes()); + + /** + * Constructor. + * @param input Data to read from. Note that calls to unread() will + * modify this array! If this is not desired, pass a copy. + * + * @throws IOException If there is an IO error. + */ + public ByteArrayPushBackInputStream(byte[] input) throws IOException + { + super(DUMMY, 1); + data = input; + datapos = 0; + save = datapos; + datalen = input != null ? input.length : 0; + } + + /** + * This will peek at the next byte. + * + * @return The next byte on the stream, leaving it as available to read. + */ + public int peek() + { + try + { + // convert negative values to 128..255 + return (data[datapos] + 0x100) & 0xff; + } + catch (ArrayIndexOutOfBoundsException ex) + { + // could check this before, but this is a rare case + // and this method is called sufficiently often to justify this + // optimization + return -1; + } + } + + /** + * A simple test to see if we are at the end of the stream. + * + * @return true if we are at the end of the stream. + */ + public boolean isEOF() + { + return datapos >= datalen; + } + + /** + * Save the state of this stream. + * @param readlimit Has no effect. + * @see InputStream#mark(int) + */ + public void mark(int readlimit) + { + if (false) + { + ++readlimit; // avoid unused param warning + } + save = datapos; + } + + /** + * Check if mark is supported. + * @return Always true. + * @see InputStream#markSupported() + */ + public boolean markSupported() + { + return true; + } + + /** + * Restore the state of this stream to the last saveState call. + * @see InputStream#reset() + */ + public void reset() + { + datapos = save; + } + + /** Available bytes. + * @see InputStream#available() + * @return Available bytes. + */ + public int available() + { + int av = datalen - datapos; + return av > 0 ? av : 0; + } + + /** Totally available bytes in the underlying array. + * @return Available bytes. + */ + public int size() + { + return datalen; + } + + /** + * Pushes back a byte. + * After this method returns, the next byte to be read will have the value (byte)by. + * @param by the int value whose low-order byte is to be pushed back. + * @throws IOException - If there is not enough room in the buffer for the byte. + * @see java.io.PushbackInputStream#unread(int) + */ + public void unread(int by) throws IOException + { + if (datapos == 0) + { + throw new IOException("ByteArrayParserInputStream.unread(int): " + + "cannot unread 1 byte at buffer position " + datapos); + } + --datapos; + data[datapos] = (byte)by; + } + + /** + * Pushes back a portion of an array of bytes by copying it to the + * front of the pushback buffer. After this method returns, the next byte + * to be read will have the value b[off], the byte after that will have + * the value b[off+1], and so forth. + * @param buffer the byte array to push back. + * @param off the start offset of the data. + * @param len the number of bytes to push back. + * @throws IOException If there is not enough room in the pushback buffer + * for the specified number of bytes. + * @see java.io.PushbackInputStream#unread(byte[], int, int) + */ + public void unread(byte[] buffer, int off, int len) throws IOException + { + if (len <= 0 || off >= buffer.length) + { + return; + } + if (off < 0) + { + off = 0; + } + if (len > buffer.length) + { + len = buffer.length; + } + localUnread(buffer, off, len); + } + + /** + * Pushes back a portion of an array of bytes by copying it to the + * front of the pushback buffer. After this method returns, the next byte + * to be read will have the value buffer[0], the byte after that will have + * the value buffer[1], and so forth. + * @param buffer the byte array to push back. + * @throws IOException If there is not enough room in the pushback buffer + * for the specified number of bytes. + * @see java.io.PushbackInputStream#unread(byte[]) + */ + public void unread(byte[] buffer) throws IOException + { + localUnread(buffer, 0, buffer.length); + } + + /** + * Pushes back a portion of an array of bytes by copying it to the + * front of the pushback buffer. After this method returns, the next byte + * to be read will have the value buffer[off], the byte after that will have + * the value buffer[off+1], and so forth. + * Internal method that assumes off and len to be valid. + * @param buffer the byte array to push back. + * @param off the start offset of the data. + * @param len the number of bytes to push back. + * @throws IOException If there is not enough room in the pushback buffer + * for the specified number of bytes. + * @see java.io.PushbackInputStream#unread(byte[], int, int) + */ + private void localUnread(byte[] buffer, int off, int len) throws IOException + { + if (datapos < len) + { + throw new IOException("ByteArrayParserInputStream.unread(int): " + + "cannot unread " + len + + " bytes at buffer position " + datapos); + } + datapos -= len; + System.arraycopy(buffer, off, data, datapos, len); + } + + /** + * Read a byte. + * @see InputStream#read() + * @return Byte read or -1 if no more bytes are available. + */ + public int read() + { + try + { + // convert negative values to 128..255 + return (data[datapos++] + 0x100) & 0xff; + } + catch (ArrayIndexOutOfBoundsException ex) + { + // could check this before, but this is a rare case + // and this method is called sufficiently often to justify this + // optimization + datapos = datalen; + return -1; + } + } + + /** + * Read a number of bytes. + * @see InputStream#read(byte[]) + * @param buffer the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or -1 if there + * is no more data because the end of the stream has been reached. + */ + public int read(byte[] buffer) + { + return localRead(buffer, 0, buffer.length); + } + + /** + * Read a number of bytes. + * @see InputStream#read(byte[], int, int) + * @param buffer the buffer into which the data is read. + * @param off the start offset in array buffer at which the data is written. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or -1 if there + * is no more data because the end of the stream has been reached. + */ + public int read(byte[] buffer, int off, int len) + { + if (len <= 0 || off >= buffer.length) + { + return 0; + } + if (off < 0) + { + off = 0; + } + if (len > buffer.length) + { + len = buffer.length; + } + return localRead(buffer, off, len); + } + + + /** + * Read a number of bytes. Internal method that assumes off and len to be + * valid. + * @see InputStream#read(byte[], int, int) + * @param buffer the buffer into which the data is read. + * @param off the start offset in array buffer at which the data is written. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or -1 if there + * is no more data because the end of the stream has been reached. + */ + public int localRead(byte[] buffer, int off, int len) + { + if (len == 0) + { + return 0; // must return 0 even if at end! + } + else if (datapos >= datalen) + { + return -1; + } + else + { + int newpos = datapos + len; + if (newpos > datalen) + { + newpos = datalen; + len = newpos - datapos; + } + System.arraycopy(data, datapos, buffer, off, len); + datapos = newpos; + return len; + } + } + + /** + * Skips over and discards n bytes of data from this input stream. + * The skip method may, for a variety of reasons, end up skipping over some + * smaller number of bytes, possibly 0. This may result from any of a number + * of conditions; reaching end of file before n bytes have been skipped is + * only one possibility. The actual number of bytes skipped is returned. + * If n is negative, no bytes are skipped. + * @param num the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @see InputStream#skip(long) + */ + public long skip(long num) + { + if (num <= 0) + { + return 0; + } + else + { + long newpos = datapos + num; + if (newpos >= datalen) + { + num = datalen - datapos; + datapos = datalen; + } + else + { + datapos = (int)newpos; + } + return num; + } + } + + /** Position the stream at a given index. Positioning the stream + * at position size() will cause the next call to read() to return -1. + * + * @param newpos Position in the underlying array. A negative value will be + * interpreted as 0, a value greater than size() as size(). + * @return old position. + */ + public int seek(int newpos) + { + if (newpos < 0) + { + newpos = 0; + } + else if (newpos > datalen) + { + newpos = datalen; + } + int oldpos = pos; + pos = newpos; + return oldpos; + } + +} -- cgit v1.2.3