aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java')
-rw-r--r--src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java404
1 files changed, 404 insertions, 0 deletions
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;
+ }
+
+}