aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/pdfbox/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/pdfbox/io')
-rw-r--r--src/main/java/org/pdfbox/io/ASCII85InputStream.java269
-rw-r--r--src/main/java/org/pdfbox/io/ASCII85OutputStream.java304
-rw-r--r--src/main/java/org/pdfbox/io/ByteArrayPushBackInputStream.java404
-rw-r--r--src/main/java/org/pdfbox/io/FastByteArrayOutputStream.java62
-rw-r--r--src/main/java/org/pdfbox/io/NBitInputStream.java124
-rw-r--r--src/main/java/org/pdfbox/io/NBitOutputStream.java116
-rw-r--r--src/main/java/org/pdfbox/io/PushBackInputStream.java92
-rw-r--r--src/main/java/org/pdfbox/io/RandomAccessFileInputStream.java132
-rw-r--r--src/main/java/org/pdfbox/io/RandomAccessFileOutputStream.java145
-rw-r--r--src/main/java/org/pdfbox/io/package.html9
10 files changed, 1657 insertions, 0 deletions
diff --git a/src/main/java/org/pdfbox/io/ASCII85InputStream.java b/src/main/java/org/pdfbox/io/ASCII85InputStream.java
new file mode 100644
index 0000000..863d64d
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/ASCII85InputStream.java
@@ -0,0 +1,269 @@
+/**
+ * Copyright (c) 2003, 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.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class represents an ASCII85 stream.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.5 $
+ */
+public class ASCII85InputStream extends FilterInputStream
+{
+ private int index;
+ private int n;
+ private boolean eof;
+
+ private byte[] ascii;
+ private byte[] b;
+
+ /**
+ * Constructor.
+ *
+ * @param is The input stream to actually read from.
+ */
+ public ASCII85InputStream( InputStream is )
+ {
+ super(is);
+ index = 0;
+ n = 0;
+ eof = false;
+ ascii = new byte[5];
+ b = new byte[4];
+ }
+
+ /**
+ * This will read the next byte from the stream.
+ *
+ * @return The next byte read from the stream.
+ *
+ * @throws IOException If there is an error reading from the wrapped stream.
+ */
+ public final int read() throws IOException
+ {
+ if( index >= n )
+ {
+ if(eof)
+ {
+ return -1;
+ }
+ index = 0;
+ int k;
+ byte z;
+ do
+ {
+ int zz=(byte)in.read();
+ if(zz==-1)
+ {
+ eof=true;
+ return -1;
+ }
+ z = (byte)zz;
+ } while( z=='\n' || z=='\r' || z==' ');
+
+ if (z == '~' || z=='x')
+ {
+ eof=true;
+ ascii=b=null;
+ n = 0;
+ return -1;
+ }
+ else if (z == 'z')
+ {
+ b[0]=b[1]=b[2]=b[3]=0;
+ n = 4;
+ }
+ else
+ {
+ ascii[0]=z; // may be EOF here....
+ for (k=1;k<5;++k)
+ {
+ do
+ {
+ int zz=(byte)in.read();
+ if(zz==-1)
+ {
+ eof=true;
+ return -1;
+ }
+ z=(byte)zz;
+ } while ( z=='\n' || z=='\r' || z==' ' );
+ ascii[k]=z;
+ if (z == '~' || z=='x')
+ {
+ break;
+ }
+ }
+ n = k - 1;
+ if ( n==0 )
+ {
+ eof = true;
+ ascii = null;
+ b = null;
+ return -1;
+ }
+ if ( k < 5 )
+ {
+ for (++k; k < 5; ++k )
+ {
+ ascii[k] = 0x21;
+ }
+ eof=true;
+ }
+ // decode stream
+ long t=0;
+ for ( k=0; k<5; ++k)
+ {
+ z=(byte)(ascii[k] - 0x21);
+ if (z < 0 || z > 93)
+ {
+ n = 0;
+ eof = true;
+ ascii = null;
+ b = null;
+ throw new IOException("Invalid data in Ascii85 stream");
+ }
+ t = (t * 85L) + z;
+ }
+ for ( k = 3; k>=0; --k)
+ {
+ b[k] = (byte)(t & 0xFFL);
+ t>>>=8;
+ }
+ }
+ }
+ return b[index++] & 0xFF;
+ }
+
+ /**
+ * This will read a chunk of data.
+ *
+ * @param data The buffer to write data to.
+ * @param offset The offset into the data stream.
+ * @param len The number of byte to attempt to read.
+ *
+ * @return The number of bytes actually read.
+ *
+ * @throws IOException If there is an error reading data from the underlying stream.
+ */
+ public final int read(byte[] data, int offset, int len) throws IOException
+ {
+ if(eof && index>=n)
+ {
+ return -1;
+ }
+ for(int i=0;i<len;i++)
+ {
+ if(index<n)
+ {
+ data[i+offset]=b[index++];
+ }
+ else
+ {
+ int t = read();
+ if ( t == -1 )
+ {
+ return i;
+ }
+ data[i+offset]=(byte)t;
+ }
+ }
+ return len;
+ }
+
+ /**
+ * This will close the underlying stream and release any resources.
+ *
+ * @throws IOException If there is an error closing the underlying stream.
+ */
+ public void close() throws IOException
+ {
+ ascii = null;
+ eof = true;
+ b = null;
+ super.close();
+ }
+
+ /**
+ * non supported interface methods.
+ *
+ * @return False always.
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @param nValue ignored.
+ *
+ * @return Always zero.
+ */
+ public long skip(long nValue)
+ {
+ return 0;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @return Always zero.
+ */
+ public int available()
+ {
+ return 0;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @param readlimit ignored.
+ */
+ public void mark(int readlimit)
+ {
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @throws IOException telling that this is an unsupported action.
+ */
+ public void reset() throws IOException
+ {
+ throw new IOException("Reset is not supported");
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/ASCII85OutputStream.java b/src/main/java/org/pdfbox/io/ASCII85OutputStream.java
new file mode 100644
index 0000000..a59f2df
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/ASCII85OutputStream.java
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) 2003, 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.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class represents an ASCII85 output stream.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.6 $
+ */
+public class ASCII85OutputStream extends FilterOutputStream
+{
+
+ private int lineBreak;
+ private int count;
+
+ private byte[] indata;
+ private byte[] outdata;
+
+ /**
+ * Function produces five ASCII printing characters from
+ * four bytes of binary data.
+ */
+ private int maxline;
+ private boolean flushed;
+ private char terminator;
+
+ /**
+ * Constructor.
+ *
+ * @param out The output stream to write to.
+ */
+ public ASCII85OutputStream( OutputStream out )
+ {
+ super( out );
+ lineBreak = 36*2;
+ maxline = 36*2;
+ count=0;
+ indata=new byte[4];
+ outdata=new byte[5];
+ flushed=true;
+ terminator='~';
+ }
+
+ /**
+ * This will set the terminating character.
+ *
+ * @param term The terminating character.
+ */
+ public void setTerminator(char term)
+ {
+ if(term<118 || term>126 || term=='z')
+ {
+ throw new IllegalArgumentException("Terminator must be 118-126 excluding z");
+ }
+ terminator=term;
+ }
+
+ /**
+ * This will get the terminating character.
+ *
+ * @return The terminating character.
+ */
+ public char getTerminator()
+ {
+ return terminator;
+ }
+
+ /**
+ * This will set the line length that will be used.
+ *
+ * @param l The length of the line to use.
+ */
+ public void setLineLength(int l)
+ {
+ if( lineBreak > l )
+ {
+ lineBreak = l;
+ }
+ maxline=l;
+ }
+
+ /**
+ * This will get the length of the line.
+ *
+ * @return The line length attribute.
+ */
+ public int getLineLength()
+ {
+ return maxline;
+ }
+
+ /**
+ * This will transform the next four ascii bytes.
+ */
+ private final void transformASCII85()
+ {
+ long word;
+ word=( (((indata[0] << 8) | (indata[1] &0xFF)) << 16) |
+ ( (indata[2] & 0xFF) << 8) | (indata[3] & 0xFF)
+ ) & 0xFFFFFFFFL;
+ // System.out.println("word=0x"+Long.toString(word,16)+" "+word);
+
+ if (word == 0 )
+ {
+ outdata[0]=(byte)'z';
+ outdata[1]=0;
+ return;
+ }
+ long x;
+ x=word/(85L*85L*85L*85L);
+ // System.out.println("x0="+x);
+ outdata[0]=(byte)(x+'!');
+ word-=x*85L*85L*85L*85L;
+
+ x=word/(85L*85L*85L);
+ // System.out.println("x1="+x);
+ outdata[1]=(byte)(x+'!');
+ word-=x*85L*85L*85L;
+
+ x=word/(85L*85L);
+ // System.out.println("x2="+x);
+ outdata[2]=(byte)(x+'!');
+ word-=x*85L*85L;
+
+ x=word/85L;
+ // System.out.println("x3="+x);
+ outdata[3]=(byte)(x+'!');
+
+ // word-=x*85L;
+
+ // System.out.println("x4="+(word % 85L));
+ outdata[4]=(byte)((word%85L)+'!');
+ }
+
+ /**
+ * This will write a single byte.
+ *
+ * @param b The byte to write.
+ *
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public final void write(int b) throws IOException
+ {
+ flushed=false;
+ indata[count++]=(byte)b;
+ if(count < 4 )
+ {
+ return;
+ }
+ transformASCII85();
+ for(int i=0;i<5;i++)
+ {
+ if(outdata[i]==0)
+ {
+ break;
+ }
+ out.write(outdata[i]);
+ if(--lineBreak==0)
+ {
+ out.write('\n');
+ lineBreak=maxline;
+ }
+ }
+ count = 0;
+ }
+
+ /**
+ * This will write a chunk of data to the stream.
+ *
+ * @param b The byte buffer to read from.
+ * @param off The offset into the buffer.
+ * @param sz The number of bytes to read from the buffer.
+ *
+ * @throws IOException If there is an error writing to the underlying stream.
+ */
+ public final void write(byte[] b,int off, int sz) throws IOException
+ {
+ for(int i=0;i<sz;i++)
+ {
+ if(count < 3)
+ {
+ indata[count++]=b[off+i];
+ }
+ else
+ {
+ write(b[off+i]);
+ }
+ }
+ }
+
+ /**
+ * This will flush the data to the stream.
+ *
+ * @throws IOException If there is an error writing the data to the stream.
+ */
+ public final void flush() throws IOException
+ {
+ if(flushed)
+ {
+ return;
+ }
+ if(count > 0 )
+ {
+ for( int i=count; i<4; i++ )
+ {
+ indata[i]=0;
+ }
+ transformASCII85();
+ if(outdata[0]=='z')
+ {
+ for(int i=0;i<5;i++) // expand 'z',
+ {
+ outdata[i]=(byte)'!';
+ }
+ }
+ for(int i=0;i<count+1;i++)
+ {
+ out.write(outdata[i]);
+ if(--lineBreak==0)
+ {
+ out.write('\n');
+ lineBreak=maxline;
+ }
+ }
+ }
+ if(--lineBreak==0)
+ {
+ out.write('\n');
+ }
+ out.write(terminator);
+ out.write('\n');
+ count = 0;
+ lineBreak=maxline;
+ flushed=true;
+ super.flush();
+ }
+
+ /**
+ * This will close the stream.
+ *
+ * @throws IOException If there is an error closing the wrapped stream.
+ */
+ public void close() throws IOException
+ {
+ try
+ {
+ super.close();
+ }
+ finally
+ {
+ indata=outdata=null;
+ }
+ }
+
+ /**
+ * This will flush the stream.
+ *
+ * @throws Throwable If there is an error.
+ */
+ protected void finalize() throws Throwable
+ {
+ try
+ {
+ flush();
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+} \ No newline at end of file
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;
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/io/FastByteArrayOutputStream.java b/src/main/java/org/pdfbox/io/FastByteArrayOutputStream.java
new file mode 100644
index 0000000..1e5fdc6
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/FastByteArrayOutputStream.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2003, 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.ByteArrayOutputStream;
+
+/**
+ * An byte array output stream that allows direct access to the byte array.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class FastByteArrayOutputStream extends ByteArrayOutputStream
+{
+ /**
+ * Constructor.
+ *
+ * @param size An initial size of the stream.
+ */
+ public FastByteArrayOutputStream( int size )
+ {
+ super( size );
+ }
+
+ /**
+ * This will get the underlying byte array.
+ *
+ * @return The underlying byte array at this moment in time.
+ */
+ public byte[] getByteArray()
+ {
+ return buf;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/NBitInputStream.java b/src/main/java/org/pdfbox/io/NBitInputStream.java
new file mode 100644
index 0000000..d8254b2
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/NBitInputStream.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2003, 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.InputStream;
+import java.io.IOException;
+
+/**
+ * This is an n-bit input stream. This means that you can read chunks of data
+ * as any number of bits, not just 8 bits like the regular input stream. Just set the
+ * number of bits that you would like to read on each call. The default is 8.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class NBitInputStream
+{
+ private int bitsInChunk;
+ private InputStream in;
+
+ private int currentByte;
+ private int bitsLeftInCurrentByte;
+
+ /**
+ * Constructor.
+ *
+ * @param is The input stream to read from.
+ */
+ public NBitInputStream( InputStream is )
+ {
+ in = is;
+ bitsLeftInCurrentByte = 0;
+ bitsInChunk = 8;
+ }
+
+ /**
+ * This will unread some data.
+ *
+ * @param data The data to put back into the stream.
+ */
+ public void unread( long data )
+ {
+ data <<= bitsLeftInCurrentByte;
+ currentByte |= data;
+ bitsLeftInCurrentByte += bitsInChunk;
+ }
+
+ /**
+ * This will read the next n bits from the stream and return the unsigned
+ * value of those bits.
+ *
+ * @return The next n bits from the stream.
+ *
+ * @throws IOException If there is an error reading from the underlying stream.
+ */
+ public long read() throws IOException
+ {
+ long retval = 0;
+ for( int i=0; i<bitsInChunk && retval != -1; i++ )
+ {
+ if( bitsLeftInCurrentByte == 0 )
+ {
+ currentByte = in.read();
+ bitsLeftInCurrentByte = 8;
+ }
+ if( currentByte == -1 )
+ {
+ retval = -1;
+ }
+ else
+ {
+ retval <<= 1;
+ retval |= ((currentByte >> (bitsLeftInCurrentByte-1))&0x1);
+ bitsLeftInCurrentByte--;
+ }
+ }
+ return retval;
+ }
+
+ /** Getter for property bitsToRead.
+ * @return Value of property bitsToRead.
+ */
+ public int getBitsInChunk()
+ {
+ return bitsInChunk;
+ }
+
+ /** Setter for property bitsToRead.
+ * @param bitsInChunkValue New value of property bitsToRead.
+ */
+ public void setBitsInChunk(int bitsInChunkValue)
+ {
+ bitsInChunk = bitsInChunkValue;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/NBitOutputStream.java b/src/main/java/org/pdfbox/io/NBitOutputStream.java
new file mode 100644
index 0000000..f944b8a
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/NBitOutputStream.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2003, 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.OutputStream;
+import java.io.IOException;
+
+/**
+ * This is an n-bit output stream. This means that you write data in n-bit chunks.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class NBitOutputStream
+{
+ private int bitsInChunk;
+ private OutputStream out;
+
+ private int currentByte;
+ private int positionInCurrentByte;
+
+ /**
+ * Constructor.
+ *
+ * @param os The output stream to write to.
+ */
+ public NBitOutputStream( OutputStream os )
+ {
+ out = os;
+ currentByte = 0;
+ positionInCurrentByte = 7;
+ }
+
+ /**
+ * This will write the next n-bits to the stream.
+ *
+ * @param chunk The next chunk of data to write.
+ *
+ * @throws IOException If there is an error writing the chunk.
+ */
+ public void write( long chunk ) throws IOException
+ {
+ long bitToWrite;
+ for( int i=(bitsInChunk-1); i>=0; i-- )
+ {
+ bitToWrite = (chunk >> i) & 0x1;
+ bitToWrite <<= positionInCurrentByte;
+ currentByte |= bitToWrite;
+ positionInCurrentByte--;
+ if( positionInCurrentByte < 0 )
+ {
+ out.write( currentByte );
+ currentByte = 0;
+ positionInCurrentByte = 7;
+ }
+ }
+ }
+
+ /**
+ * This will close the stream.
+ *
+ * @throws IOException if there is an error closing the stream.
+ */
+ public void close() throws IOException
+ {
+ if( positionInCurrentByte < 7 )
+ {
+ out.write( currentByte );
+ }
+ }
+
+ /** Getter for property bitsToRead.
+ * @return Value of property bitsToRead.
+ */
+ public int getBitsInChunk()
+ {
+ return bitsInChunk;
+ }
+
+ /** Setter for property bitsToRead.
+ * @param bitsInChunkValue New value of property bitsToRead.
+ */
+ public void setBitsInChunk(int bitsInChunkValue)
+ {
+ bitsInChunk = bitsInChunkValue;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/PushBackInputStream.java b/src/main/java/org/pdfbox/io/PushBackInputStream.java
new file mode 100644
index 0000000..d519900
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/PushBackInputStream.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2003, 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.InputStream;
+import java.io.IOException;
+
+/**
+ * A simple subclass that adds a few convience methods.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PushBackInputStream extends java.io.PushbackInputStream
+{
+
+ /**
+ * Constructor.
+ *
+ * @param input The input stream.
+ * @param size The size of the push back buffer.
+ *
+ * @throws IOException If there is an error with the stream.
+ */
+ public PushBackInputStream( InputStream input, int size ) throws IOException
+ {
+ super( input, size );
+ if( input == null )
+ {
+ throw new IOException( "Error: input was null" );
+ }
+ }
+
+ /**
+ * This will peek at the next byte.
+ *
+ * @return The next byte on the stream, leaving it as available to read.
+ *
+ * @throws IOException If there is an error reading the next byte.
+ */
+ public int peek() throws IOException
+ {
+ int result = read();
+ if( result != -1 )
+ {
+ unread( result );
+ }
+ return result;
+ }
+
+ /**
+ * 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.
+ *
+ * @throws IOException If there is an error reading the next byte.
+ */
+ public boolean isEOF() throws IOException
+ {
+ int peek = peek();
+ return peek == -1;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/RandomAccessFileInputStream.java b/src/main/java/org/pdfbox/io/RandomAccessFileInputStream.java
new file mode 100644
index 0000000..6589bcb
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/RandomAccessFileInputStream.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2003, 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.InputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * This class allows a section of a RandomAccessFile to be accessed as an
+ * input stream.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class RandomAccessFileInputStream extends InputStream
+{
+ private RandomAccessFile file;
+ private long currentPosition;
+ private long endPosition;
+
+ /**
+ * Constructor.
+ *
+ * @param raFile The file to read the data from.
+ * @param startPosition The position in the file that this stream starts.
+ * @param length The length of the input stream.
+ */
+ public RandomAccessFileInputStream( RandomAccessFile raFile, long startPosition, long length )
+ {
+ file = raFile;
+ currentPosition = startPosition;
+ endPosition = currentPosition+length;
+ }
+ /**
+ * @see InputStream#available()
+ */
+ public int available()
+ {
+ return (int)(endPosition - currentPosition);
+ }
+ /**
+ * @see InputStream#close()
+ */
+ public void close()
+ {
+ //do nothing because we want to leave the random access file open.
+ }
+ /**
+ * @see InputStream#read()
+ */
+ public int read() throws IOException
+ {
+ synchronized(file)
+ {
+ int retval = -1;
+ if( currentPosition < endPosition )
+ {
+ file.seek( currentPosition );
+ currentPosition++;
+ retval = file.read();
+ }
+ return retval;
+ }
+ }
+ /**
+ * @see InputStream#read( byte[], int, int )
+ */
+ public int read( byte[] b, int offset, int length ) throws IOException
+ {
+ //only allow a read of the amount available.
+ if( length > available() )
+ {
+ length = available();
+ }
+ int amountRead = -1;
+ //only read if there are bytes actually available, otherwise
+ //return -1 if the EOF has been reached.
+ if( available() > 0 )
+ {
+ synchronized(file)
+ {
+ file.seek( currentPosition );
+ amountRead = file.read( b, offset, length );
+ }
+ }
+ //update the current cursor position.
+ if( amountRead > 0 )
+ {
+ currentPosition += amountRead;
+ }
+ return amountRead;
+ }
+
+ /**
+ * @see InputStream#skip( long )
+ */
+ public long skip( long amountToSkip )
+ {
+ long amountSkipped = Math.min( amountToSkip, available() );
+ currentPosition+= amountSkipped;
+ return amountSkipped;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/RandomAccessFileOutputStream.java b/src/main/java/org/pdfbox/io/RandomAccessFileOutputStream.java
new file mode 100644
index 0000000..b2e7511
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/RandomAccessFileOutputStream.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2003, 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.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSObject;
+import org.pdfbox.cos.COSNumber;
+
+/**
+ * This will write to a RandomAccessFile in the filesystem and keep track
+ * of the position it is writing to and the length of the stream.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class RandomAccessFileOutputStream extends OutputStream
+{
+ private RandomAccessFile file;
+ private long position;
+ private long lengthWritten = 0;
+ private COSBase expectedLength = null;
+
+ /**
+ * Constructor to create an output stream that will write to the end of a
+ * random access file.
+ *
+ * @param raf The file to write to.
+ *
+ * @throws IOException If there is a problem accessing the raf.
+ */
+ public RandomAccessFileOutputStream( RandomAccessFile raf ) throws IOException
+ {
+ file = raf;
+ //first get the position that we will be writing to
+ position = raf.length();
+ }
+
+ /**
+ * This will get the position in the RAF that the stream was written
+ * to.
+ *
+ * @return The position in the raf where the file can be obtained.
+ */
+ public long getPosition()
+ {
+ return position;
+ }
+
+ /**
+ * The number of bytes written to the stream.
+ *
+ * @return The number of bytes read to the stream.
+ */
+ public long getLength()
+ {
+ long length = -1;
+ if( expectedLength instanceof COSNumber )
+ {
+ length = ((COSNumber)expectedLength).intValue();
+ }
+ else if( expectedLength instanceof COSObject &&
+ ((COSObject)expectedLength).getObject() instanceof COSNumber )
+ {
+ length = ((COSNumber)((COSObject)expectedLength).getObject()).intValue();
+ }
+ if( length == -1 )
+ {
+ length = lengthWritten;
+ }
+ return length;
+ }
+
+ /**
+ * @see OutputStream#write( byte[], int, int )
+ */
+ public void write( byte[] b, int offset, int length ) throws IOException
+ {
+ file.seek( position+lengthWritten );
+ lengthWritten += length;
+ file.write( b, offset, length );
+
+ }
+ /**
+ * @see OutputStream#write( int )
+ */
+ public void write( int b ) throws IOException
+ {
+ file.seek( position+lengthWritten );
+ lengthWritten++;
+ file.write( b );
+ }
+
+ /**
+ * This will get the length that the PDF document specified this stream
+ * should be. This may not match the number of bytes read.
+ *
+ * @return The expected length.
+ */
+ public COSBase getExpectedLength()
+ {
+ return expectedLength;
+ }
+
+ /**
+ * This will set the expected length of this stream.
+ *
+ * @param value The expected value.
+ */
+ public void setExpectedLength(COSBase value)
+ {
+ expectedLength = value;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/io/package.html b/src/main/java/org/pdfbox/io/package.html
new file mode 100644
index 0000000..12261f4
--- /dev/null
+++ b/src/main/java/org/pdfbox/io/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package contains IO streams.
+</body>
+</html>