📄 bytearraypushbackinputstream.java
字号:
/**
* 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;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -