You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2020/05/24 17:24:15 UTC

svn commit: r1878086 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/io/ main/java/org/apache/pdfbox/pdfparser/ test/java/org/apache/pdfbox/io/ test/java/org/apache/pdfbox/pdfparser/

Author: lehmi
Date: Sun May 24 17:24:15 2020
New Revision: 1878086

URL: http://svn.apache.org/viewvc?rev=1878086&view=rev
Log:
PDFBOX-4845: merge SequentialSource into RandomAccessRead

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java   (with props)
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/InputStreamSource.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/RandomAccessSource.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/SequentialSource.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfparser/InputStreamSourceTest.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfparser/RandomAccessSourceTest.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java?rev=1878086&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java Sun May 24 17:24:15 2020
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pdfbox.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+
+/**
+ * A RandomAccessRead backed by an InputStream.
+ */
+public final class InputStreamRandomAccessRead implements RandomAccessRead
+{
+    private final PushbackInputStream input;
+    private int position;
+    private boolean isClosed = false;
+
+    /**
+     * Constructor.
+     * 
+     * @param input The input stream to wrap.
+     */
+    public InputStreamRandomAccessRead(InputStream input)
+    {
+        this.input = new PushbackInputStream(input, 32767); // maximum length of a PDF string
+        this.position = 0;
+    }
+
+    @Override
+    public int read() throws IOException
+    {
+        int b = input.read();
+        position++;
+        return b;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException
+    {
+        int n = input.read(b);
+        if (n > 0)
+        {
+            position += n;
+            return n;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int offset, int length) throws IOException
+    {
+        int n = input.read(b, offset, length);
+        if (n > 0)
+        {
+            position += n;
+            return n;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    @Override
+    public long getPosition() throws IOException
+    {
+        return position;
+    }
+
+    @Override
+    public int peek() throws IOException
+    {
+        int b = input.read();
+        if (b != -1)
+        {
+            input.unread(b);
+        }
+        return b;
+    }
+
+    @Override
+    public boolean isEOF() throws IOException
+    {
+        return peek() == -1;
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        input.close();
+        isClosed = true;
+    }
+
+
+    @Override
+    public boolean isClosed()
+    {
+        return isClosed;
+    }
+
+    @Override
+    public int available() throws IOException
+    {
+        return input.available();
+    }
+
+    @Override
+    public void unread(int b) throws IOException
+    {
+        input.unread(b);
+        position--;
+    }
+
+    @Override
+    public void unread(byte[] bytes) throws IOException
+    {
+        input.unread(bytes);
+        position -= bytes.length;
+    }
+
+    @Override
+    public void unread(byte[] bytes, int start, int len) throws IOException
+    {
+        input.unread(bytes, start, len);
+        position -= len;
+    }
+
+    @Override
+    public boolean seekSupported()
+    {
+        return false;
+    }
+
+    @Override
+    public void rewind(int bytes) throws IOException
+    {
+        throw new UnsupportedOperationException(getClass().getName() + ".rewind is not supported!");
+    }
+
+    @Override
+    public void seek(long position) throws IOException
+    {
+        throw new UnsupportedOperationException(getClass().getName() + ".seek is not supported!");
+    }
+
+    @Override
+    public long length() throws IOException
+    {
+        throw new UnsupportedOperationException(getClass().getName() + ".length is not supported!");
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/InputStreamRandomAccessRead.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java Sun May 24 17:24:15 2020
@@ -65,6 +65,8 @@ public interface RandomAccessRead extend
     
     /**
      * Seek to a position in the data.
+     * 
+     * Only supported if {@link #seekSupported()} returns true.
      *
      * @param position The position to seek to.
      * @throws IOException If there is an error while seeking.
@@ -72,12 +74,27 @@ public interface RandomAccessRead extend
     void seek(long position) throws IOException;
 
     /**
+     * Indicates if seek operations are supported.
+     * 
+     * @return true if seek operations are supported
+     * 
+     * @see org.apache.pdfbox.io.RandomAccessRead#seek(long)
+     * @see org.apache.pdfbox.io.RandomAccessRead#length()
+     * @see org.apache.pdfbox.io.RandomAccessRead#rewind(int)
+     */
+    default boolean seekSupported()
+    {
+        // default implementation for all non input stream based sources
+        return true;
+    }
+    /**
      * The total number of bytes that are available.
+     * 
+     * Only supported if {@link #seekSupported()} returns true.
      *
      * @return The number of bytes available.
      *
-     * @throws IOException If there is an IO error while determining the
-     * length of the data stream.
+     * @throws IOException If there is an IO error while determining the length of the data stream.
      */
     long length() throws IOException;
 
@@ -98,6 +115,8 @@ public interface RandomAccessRead extend
     /**
      * Seek backwards the given number of bytes.
      * 
+     * Only supported if {@link #seekSupported()} returns true.
+     * 
      * @param bytes the number of bytes to be seeked backwards
      * @throws IOException If there is an error while seeking
      */
@@ -119,4 +138,60 @@ public interface RandomAccessRead extend
      * @throws IOException if this random access has been closed
      */
     int available() throws IOException;
+
+    /**
+     * Skips a given number of bytes.
+     *
+     * @param length the number of bytes to be skipped
+     * @throws IOException if an I/O error occurs while reading data
+     */
+    default void skip(int length) throws IOException
+    {
+        int i = 0;
+        while (i++ < length)
+        {
+            int value = read();
+            if (value == -1)
+                break;
+        }
+    }
+
+    /**
+     * Pushes back a byte.
+     * 
+     * @param b the int to push back.
+     * @throws IOException if an I/O error occurs while reading data
+     */
+    default void unread(int b) throws IOException
+    {
+        // default implementation for all non input stream based sources
+        rewind(1);
+    }
+
+    /**
+     * Pushes back an array of bytes.
+     * 
+     * @param bytes the byte array to push back.
+     * @throws IOException if an I/O error occurs while reading data
+     */
+    default void unread(byte[] bytes) throws IOException
+    {
+        // default implementation for all non input stream based sources
+        rewind(bytes.length);
+    }
+
+    /**
+     * Pushes back a portion of an array of bytes.
+     * 
+     * @param bytes the byte array to push back.
+     * @param start the start offset of the data.
+     * @param len the number of bytes to push back.
+     * @throws IOException if an I/O error occurs while reading data
+     */
+    default void unread(byte[] bytes, int start, int len) throws IOException
+    {
+        // default implementation for all non input stream based sources
+        rewind(len);
+    }
+
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java Sun May 24 17:24:15 2020
@@ -37,6 +37,7 @@ import org.apache.pdfbox.cos.COSNumber;
 import org.apache.pdfbox.cos.COSObject;
 import org.apache.pdfbox.cos.COSObjectKey;
 import org.apache.pdfbox.cos.COSString;
+import org.apache.pdfbox.io.RandomAccessRead;
 
 /**
  * This class is used to contain parsing logic that will be used by both the
@@ -117,7 +118,7 @@ public abstract class BaseParser
     /**
      * This is the stream that will be read from.
      */
-    final SequentialSource seqSource;
+    protected final RandomAccessRead source;
 
     /**
      * This is the document that will be parsed.
@@ -127,9 +128,9 @@ public abstract class BaseParser
     /**
      * Default constructor.
      */
-    BaseParser(SequentialSource pdfSource)
+    BaseParser(RandomAccessRead pdfSource)
     {
-        this.seqSource = pdfSource;
+        this.source = pdfSource;
     }
 
     private static boolean isHexDigit(char ch)
@@ -148,7 +149,7 @@ public abstract class BaseParser
      */
     private COSBase parseCOSDictionaryValue() throws IOException
     {
-        long numOffset = seqSource.getPosition();
+        long numOffset = source.getPosition();
         COSBase value = parseDirObject();
         skipSpaces();
         // proceed if the given object is a number and the following is a number as well
@@ -157,7 +158,7 @@ public abstract class BaseParser
             return value;
         }
         // read the remaining information of the object number
-        long genOffset = seqSource.getPosition();
+        long genOffset = source.getPosition();
         COSBase generationNumber = parseDirObject();
         skipSpaces();
         readExpectedChar('R');
@@ -181,7 +182,8 @@ public abstract class BaseParser
     {
         if (document == null)
         {
-            throw new IOException("object reference " + key + " at offset " + seqSource.getPosition()
+            throw new IOException("object reference " + key + " at offset " + source
+                    .getPosition()
                     + " in content stream");
         }
         return document.getObjectFromPool(key);
@@ -204,7 +206,7 @@ public abstract class BaseParser
         while (!done)
         {
             skipSpaces();
-            char c = (char) seqSource.peek();
+            char c = (char) source.peek();
             if (c == '>')
             {
                 done = true;
@@ -216,7 +218,8 @@ public abstract class BaseParser
             else
             {
                 // invalid dictionary, we were expecting a /Name, read until the end or until we can recover
-                LOG.warn("Invalid dictionary, found: '" + c + "' but expected: '/' at offset " + seqSource.getPosition());
+                LOG.warn("Invalid dictionary, found: '" + c + "' but expected: '/' at offset "
+                        + source.getPosition());
                 if (readUntilEndOfCOSDictionary())
                 {
                     // we couldn't recover
@@ -240,23 +243,24 @@ public abstract class BaseParser
      */
     private boolean readUntilEndOfCOSDictionary() throws IOException
     {
-        int c = seqSource.read();
+        int c = source.read();
         while (c != -1 && c != '/' && c != '>')
         {
             // in addition to stopping when we find / or >, we also want
             // to stop when we find endstream or endobj.
             if (c == E)
             {
-                c = seqSource.read();
+                c = source.read();
                 if (c == N)
                 {
-                    c = seqSource.read();
+                    c = source.read();
                     if (c == D)
                     {
-                        c = seqSource.read();
-                        boolean isStream = c == S && seqSource.read() == T && seqSource.read() == R
-                                && seqSource.read() == E && seqSource.read() == A && seqSource.read() == M;
-                        boolean isObj = !isStream && c == O && seqSource.read() == B && seqSource.read() == J;
+                        c = source.read();
+                        boolean isStream = c == S && source.read() == T && source.read() == R
+                                && source.read() == E && source.read() == A && source.read() == M;
+                        boolean isObj = !isStream && c == O && source.read() == B
+                                && source.read() == J;
                         if (isStream || isObj)
                         {
                             // we're done reading this object!
@@ -265,13 +269,13 @@ public abstract class BaseParser
                     }
                 }
             }
-            c = seqSource.read();
+            c = source.read();
         }
         if (c == -1)
         {
             return true;
         }
-        seqSource.unread(c);
+        source.unread(c);
         return false;
     }
 
@@ -280,14 +284,14 @@ public abstract class BaseParser
         COSName key = parseCOSName();
         COSBase value = parseCOSDictionaryValue();
         skipSpaces();
-        if (((char) seqSource.peek()) == 'd')
+        if (((char) source.peek()) == 'd')
         {
             // if the next string is 'def' then we are parsing a cmap stream
             // and want to ignore it, otherwise throw an exception.
             String potentialDEF = readString();
             if (!potentialDEF.equals(DEF))
             {
-                seqSource.unread(potentialDEF.getBytes(StandardCharsets.ISO_8859_1));
+                source.unread(potentialDEF.getBytes(StandardCharsets.ISO_8859_1));
             }
             else
             {
@@ -297,7 +301,7 @@ public abstract class BaseParser
 
         if (value == null)
         {
-            LOG.warn("Bad dictionary declaration at offset " + seqSource.getPosition());
+            LOG.warn("Bad dictionary declaration at offset " + source.getPosition());
         }
         else
         {
@@ -312,22 +316,22 @@ public abstract class BaseParser
         //PDF Ref 3.2.7 A stream must be followed by either
         //a CRLF or LF but nothing else.
 
-        int whitespace = seqSource.read();
+        int whitespace = source.read();
 
         //see brother_scan_cover.pdf, it adds whitespaces
         //after the stream but before the start of the
         //data, so just read those first
         while (ASCII_SPACE == whitespace)
         {
-            whitespace = seqSource.read();
+            whitespace = source.read();
         }
 
         if (ASCII_CR == whitespace)
         {
-            whitespace = seqSource.read();
+            whitespace = source.read();
             if (ASCII_LF != whitespace)
             {
-                seqSource.unread(whitespace);
+                source.unread(whitespace);
                 //The spec says this is invalid but it happens in the real
                 //world so we must support it.
             }
@@ -337,7 +341,7 @@ public abstract class BaseParser
             //we are in an error.
             //but again we will do a lenient parsing and just assume that everything
             //is fine
-            seqSource.unread(whitespace);
+            source.unread(whitespace);
         }
     }
 
@@ -360,7 +364,7 @@ public abstract class BaseParser
     {
         int braces = bracesParameter;
         byte[] nextThreeBytes = new byte[3];
-        int amountRead = seqSource.read(nextThreeBytes);
+        int amountRead = source.read(nextThreeBytes);
 
         // Check the next 3 bytes if available
         // The following cases are valid indicators for the end of the string
@@ -378,7 +382,7 @@ public abstract class BaseParser
         }
         if (amountRead > 0)
         {
-            seqSource.unread(nextThreeBytes, 0, amountRead);
+            source.unread(nextThreeBytes, 0, amountRead);
         }
         return braces;
     }
@@ -392,7 +396,7 @@ public abstract class BaseParser
      */
     protected COSString parseCOSString() throws IOException
     {
-        char nextChar = (char) seqSource.read();
+        char nextChar = (char) source.read();
         if (nextChar == '<')
         {
             return parseCOSHexString();
@@ -400,14 +404,14 @@ public abstract class BaseParser
         else if (nextChar != '(')
         {
             throw new IOException( "parseCOSString string should start with '(' or '<' and not '" +
-                    nextChar + "' at offset " + seqSource.getPosition());
+                    nextChar + "' at offset " + source.getPosition());
         }
         
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
         // This is the number of braces read
         int braces = 1;
-        int c = seqSource.read();
+        int c = source.read();
         while( braces > 0 && c != -1)
         {
             char ch = (char)c;
@@ -431,7 +435,7 @@ public abstract class BaseParser
             else if( ch == '\\' )
             {
                 //patched by ram
-                char next = (char) seqSource.read();
+                char next = (char) source.read();
                 switch(next)
                 {
                     case 'n':
@@ -468,10 +472,10 @@ public abstract class BaseParser
                     case ASCII_LF:
                     case ASCII_CR:
                         //this is a break in the line so ignore it and the newline and continue
-                        c = seqSource.read();
+                        c = source.read();
                         while( isEOL(c) && c != -1)
                         {
-                            c = seqSource.read();
+                            c = source.read();
                         }
                         nextc = c;
                         break;
@@ -486,12 +490,12 @@ public abstract class BaseParser
                     {
                         StringBuilder octal = new StringBuilder();
                         octal.append( next );
-                        c = seqSource.read();
+                        c = source.read();
                         char digit = (char)c;
                         if( digit >= '0' && digit <= '7' )
                         {
                             octal.append( digit );
-                            c = seqSource.read();
+                            c = source.read();
                             digit = (char)c;
                             if( digit >= '0' && digit <= '7' )
                             {
@@ -537,12 +541,12 @@ public abstract class BaseParser
             }
             else
             {
-                c = seqSource.read();
+                c = source.read();
             }
         }
         if (c != -1)
         {
-            seqSource.unread(c);
+            source.unread(c);
         }
         return new COSString(out.toByteArray());
     }
@@ -564,7 +568,7 @@ public abstract class BaseParser
         final StringBuilder sBuf = new StringBuilder();
         while( true )
         {
-            int c = seqSource.read();
+            int c = source.read();
             if ( isHexDigit((char)c) )
             {
                 sBuf.append( (char) c );
@@ -595,7 +599,7 @@ public abstract class BaseParser
                 // read till the closing bracket was found
                 do 
                 {
-                    c = seqSource.read();
+                    c = source.read();
                 } 
                 while ( c != '>' && c >= 0 );
                 
@@ -623,13 +627,13 @@ public abstract class BaseParser
      */
     protected COSArray parseCOSArray() throws IOException
     {
-        long startPosition = seqSource.getPosition();
+        long startPosition = source.getPosition();
         readExpectedChar('[');
         COSArray po = new COSArray();
         COSBase pbo;
         skipSpaces();
         int i;
-        while( ((i = seqSource.peek()) > 0) && ((char)i != ']') )
+        while (((i = source.peek()) > 0) && ((char) i != ']'))
         {
             pbo = parseDirObject();
             if( pbo instanceof COSObject )
@@ -663,12 +667,12 @@ public abstract class BaseParser
             {
                 //it could be a bad object in the array which is just skipped
                 LOG.warn("Corrupt object reference at offset " +
-                        seqSource.getPosition() + ", start offset: " + startPosition);
+                        source.getPosition() + ", start offset: " + startPosition);
 
                 // This could also be an "endobj" or "endstream" which means we can assume that
                 // the array has ended.
                 String isThisTheEnd = readString();
-                seqSource.unread(isThisTheEnd.getBytes(StandardCharsets.ISO_8859_1));
+                source.unread(isThisTheEnd.getBytes(StandardCharsets.ISO_8859_1));
                 if(ENDOBJ_STRING.equals(isThisTheEnd) || ENDSTREAM_STRING.equals(isThisTheEnd))
                 {
                     return po;
@@ -677,7 +681,7 @@ public abstract class BaseParser
             skipSpaces();
         }
         // read ']'
-        seqSource.read(); 
+        source.read();
         skipSpaces();
         return po;
     }
@@ -705,14 +709,14 @@ public abstract class BaseParser
     {
         readExpectedChar('/');
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-        int c = seqSource.read();
+        int c = source.read();
         while (c != -1)
         {
             int ch = c;
             if (ch == '#')
             {
-                int ch1 = seqSource.read();
-                int ch2 = seqSource.read();
+                int ch1 = source.read();
+                int ch2 = source.read();
                 // Prior to PDF v1.2, the # was not a special character.  Also,
                 // it has been observed that various PDF tools do not follow the
                 // spec with respect to the # escape, even though they report
@@ -730,7 +734,7 @@ public abstract class BaseParser
                     {
                         throw new IOException("Error: expected hex digit, actual='" + hex + "'", e);
                     }
-                    c = seqSource.read();
+                    c = source.read();
                 }
                 else
                 {
@@ -741,7 +745,7 @@ public abstract class BaseParser
                         c = -1;
                         break;
                     }
-                    seqSource.unread(ch2);
+                    source.unread(ch2);
                     c = ch1;
                     buffer.write(ch);
                 }
@@ -753,12 +757,12 @@ public abstract class BaseParser
             else
             {
                 buffer.write(ch);
-                c = seqSource.read();
+                c = source.read();
             }
         }
         if (c != -1)
         {
-            seqSource.unread(c);
+            source.unread(c);
         }
         
         byte[] bytes = buffer.toByteArray();
@@ -804,17 +808,17 @@ public abstract class BaseParser
         COSBase retval = null;
 
         skipSpaces();
-        int nextByte = seqSource.peek();
+        int nextByte = source.peek();
         char c = (char)nextByte;
         switch(c)
         {
         case '<':
         {
             // pull off first left bracket
-            int leftBracket = seqSource.read();
+            int leftBracket = source.read();
             // check for second left bracket
-            c = (char) seqSource.peek();
-            seqSource.unread(leftBracket);
+            c = (char) source.peek();
+            source.unread(leftBracket);
             if(c == '<')
             {
 
@@ -860,7 +864,7 @@ public abstract class BaseParser
             break;
         }
         case 'R':
-            seqSource.read();
+            source.read();
             retval = new COSObject(null);
             break;
         case (char)-1:
@@ -870,7 +874,7 @@ public abstract class BaseParser
             if( Character.isDigit(c) || c == '-' || c == '+' || c == '.')
             {
                 StringBuilder buf = new StringBuilder();
-                int ic = seqSource.read();
+                int ic = source.read();
                 c = (char)ic;
                 while( Character.isDigit( c )||
                         c == '-' ||
@@ -880,12 +884,12 @@ public abstract class BaseParser
                         c == 'e' )
                 {
                     buf.append( c );
-                    ic = seqSource.read();
+                    ic = source.read();
                     c = (char)ic;
                 }
                 if( ic != -1 )
                 {
-                    seqSource.unread(ic);
+                    source.unread(ic);
                 }
                 retval = COSNumber.get( buf.toString() );
             }
@@ -897,17 +901,17 @@ public abstract class BaseParser
                 String badString = readString();
                 if (badString.isEmpty())
                 {
-                    int peek = seqSource.peek();
+                    int peek = source.peek();
                     // we can end up in an infinite loop otherwise
                     throw new IOException( "Unknown dir object c='" + c +
                             "' cInt=" + (int)c + " peek='" + (char)peek 
-                            + "' peekInt=" + peek + " at offset " + seqSource.getPosition() );
+                            + "' peekInt=" + peek + " at offset " + source.getPosition());
                 }
 
                 // if it's an endstream/endobj, we want to put it back so the caller will see it
                 if(ENDOBJ_STRING.equals(badString) || ENDSTREAM_STRING.equals(badString))
                 {
-                    seqSource.unread(badString.getBytes(StandardCharsets.ISO_8859_1));
+                    source.unread(badString.getBytes(StandardCharsets.ISO_8859_1));
                 }
             }
         }
@@ -926,15 +930,15 @@ public abstract class BaseParser
     {
         skipSpaces();
         StringBuilder buffer = new StringBuilder();
-        int c = seqSource.read();
+        int c = source.read();
         while( !isEndOfName((char)c) && c != -1 )
         {
             buffer.append( (char)c );
-            c = seqSource.read();
+            c = source.read();
         }
         if (c != -1)
         {
-            seqSource.unread(c);
+            source.unread(c);
         }
         return buffer.toString();
     }
@@ -963,11 +967,11 @@ public abstract class BaseParser
         skipSpaces();
         for (char c : expectedString)
         {
-            if (seqSource.read() != c)
+            if (source.read() != c)
             {
                 throw new IOException("Expected string '" + new String(expectedString)
                         + "' but missed at character '" + c + "' at offset "
-                        + seqSource.getPosition());
+                        + source.getPosition());
             }
         }
         skipSpaces();
@@ -982,10 +986,11 @@ public abstract class BaseParser
      */
     protected void readExpectedChar(char ec) throws IOException
     {
-        char c = (char) seqSource.read();
+        char c = (char) source.read();
         if (c != ec)
         {
-            throw new IOException("expected='" + ec + "' actual='" + c + "' at offset " + seqSource.getPosition());
+            throw new IOException(
+                    "expected='" + ec + "' actual='" + c + "' at offset " + source.getPosition());
         }
     }
     
@@ -1002,7 +1007,7 @@ public abstract class BaseParser
     {
         skipSpaces();
 
-        int c = seqSource.read();
+        int c = source.read();
 
         //average string size is around 2 and the normal string buffer size is
         //about 16 so lets save some space.
@@ -1014,11 +1019,11 @@ public abstract class BaseParser
                 c != '/' )
         {
             buffer.append( (char)c );
-            c = seqSource.read();
+            c = source.read();
         }
         if (c != -1)
         {
-            seqSource.unread(c);
+            source.unread(c);
         }
         return buffer.toString();
     }
@@ -1032,7 +1037,7 @@ public abstract class BaseParser
      */
     protected boolean isClosing() throws IOException
     {
-        return isClosing(seqSource.peek());
+        return isClosing(source.peek());
     }
 
     /**
@@ -1057,7 +1062,7 @@ public abstract class BaseParser
      */
     protected String readLine() throws IOException
     {
-        if (seqSource.isEOF())
+        if (source.isEOF())
         {
             throw new IOException( "Error: End-of-File, expected line");
         }
@@ -1065,7 +1070,7 @@ public abstract class BaseParser
         StringBuilder buffer = new StringBuilder( 11 );
 
         int c;
-        while ((c = seqSource.read()) != -1)
+        while ((c = source.read()) != -1)
         {
             // CR and LF are valid EOLs
             if (isEOL(c))
@@ -1075,9 +1080,9 @@ public abstract class BaseParser
             buffer.append( (char)c );
         }
         // CR+LF is also a valid EOL 
-        if (isCR(c) && isLF(seqSource.peek()))
+        if (isCR(c) && isLF(source.peek()))
         {
-            seqSource.read();
+            source.read();
         }
         return buffer.toString();
     }
@@ -1091,7 +1096,7 @@ public abstract class BaseParser
      */
     protected boolean isEOL() throws IOException
     {
-        return isEOL(seqSource.peek());
+        return isEOL(source.peek());
     }
 
     /**
@@ -1102,7 +1107,7 @@ public abstract class BaseParser
      */
     protected boolean isEOF() throws IOException
     {
-        return seqSource.isEOF();
+        return source.isEOF();
     }
 
     /**
@@ -1135,7 +1140,7 @@ public abstract class BaseParser
      */
     protected boolean isWhitespace() throws IOException
     {
-        return isWhitespace(seqSource.peek());
+        return isWhitespace(source.peek());
     }
 
     /**
@@ -1159,7 +1164,7 @@ public abstract class BaseParser
      */
     protected boolean isSpace() throws IOException
     {
-        return isSpace(seqSource.peek());
+        return isSpace(source.peek());
     }
     
     /**
@@ -1182,7 +1187,7 @@ public abstract class BaseParser
      */
     protected boolean isDigit() throws IOException
     {
-        return isDigit(seqSource.peek());
+        return isDigit(source.peek());
     }
 
     /**
@@ -1203,27 +1208,27 @@ public abstract class BaseParser
      */
     protected void skipSpaces() throws IOException
     {
-        int c = seqSource.read();
+        int c = source.read();
         // 37 is the % character, a comment
         while( isWhitespace(c) || c == 37)
         {
             if ( c == 37 )
             {
                 // skip past the comment section
-                c = seqSource.read();
+                c = source.read();
                 while(!isEOL(c) && c != -1)
                 {
-                    c = seqSource.read();
+                    c = source.read();
                 }
             }
             else
             {
-                c = seqSource.read();
+                c = source.read();
             }
         }
         if (c != -1)
         {
-            seqSource.unread(c);
+            source.unread(c);
         }
     }
 
@@ -1281,9 +1286,9 @@ public abstract class BaseParser
         }
         catch( NumberFormatException e )
         {
-            seqSource.unread(intBuffer.toString().getBytes(StandardCharsets.ISO_8859_1));
+            source.unread(intBuffer.toString().getBytes(StandardCharsets.ISO_8859_1));
             throw new IOException("Error: Expected an integer type at offset " +
-                                  seqSource.getPosition() +
+                    source.getPosition() +
                                   ", instead got '" + intBuffer + "'", e);
         }
         return retval;
@@ -1310,9 +1315,9 @@ public abstract class BaseParser
         }
         catch( NumberFormatException e )
         {
-            seqSource.unread(longBuffer.toString().getBytes(StandardCharsets.ISO_8859_1));
+            source.unread(longBuffer.toString().getBytes(StandardCharsets.ISO_8859_1));
             throw new IOException( "Error: Expected a long type at offset "
-                    + seqSource.getPosition() + ", instead got '" + longBuffer + "'", e);
+                    + source.getPosition() + ", instead got '" + longBuffer + "'", e);
         }
         return retval;
     }
@@ -1328,18 +1333,18 @@ public abstract class BaseParser
     {
         int lastByte;
         StringBuilder buffer = new StringBuilder();
-        while ((lastByte = seqSource.read()) >= '0' && lastByte <= '9')
+        while ((lastByte = source.read()) >= '0' && lastByte <= '9')
         {
             buffer.append( (char)lastByte );
             if (buffer.length() > MAX_LENGTH_LONG)
             {
                 throw new IOException("Number '" + buffer + 
-                        "' is getting too long, stop reading at offset " + seqSource.getPosition());
+                        "' is getting too long, stop reading at offset " + source.getPosition());
             }
         }
         if( lastByte != -1 )
         {
-            seqSource.unread(lastByte);
+            source.unread(lastByte);
         }
         return buffer;
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java Sun May 24 17:24:15 2020
@@ -83,8 +83,6 @@ public class COSParser extends BaseParse
     private static final int STRMBUFLEN = 2048;
     private final byte[] strmBuf = new byte[ STRMBUFLEN ];
 
-    protected final RandomAccessRead source;
-
     private AccessPermission accessPermission;
     private InputStream keyStoreInputStream = null;
     @SuppressWarnings({"squid:S2068"})
@@ -172,8 +170,7 @@ public class COSParser extends BaseParse
      */
     public COSParser(RandomAccessRead source) throws IOException
     {
-        super(new RandomAccessSource(source));
-        this.source = source;
+        super(source);
         fileLen = source.length();
     }
 
@@ -189,8 +186,7 @@ public class COSParser extends BaseParse
     public COSParser(RandomAccessRead source, String password, InputStream keyStore,
             String keyAlias) throws IOException
     {
-        super(new RandomAccessSource(source));
-        this.source = source;
+        super(source);
         this.password = password;
         this.keyAlias = keyAlias;
         fileLen = source.length();

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java Sun May 24 17:24:15 2020
@@ -24,6 +24,7 @@ import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDocument;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.io.InputStreamRandomAccessRead;
 
 /**
  * This will parse a PDF 1.5 object stream and extract the object with given object number from the stream.
@@ -45,7 +46,7 @@ public class PDFObjectStreamParser exten
      */
     public PDFObjectStreamParser(COSStream stream, COSDocument document) throws IOException
     {
-        super(new InputStreamSource(stream.createInputStream()));
+        super(new InputStreamRandomAccessRead(stream.createInputStream()));
         this.document = document;
         // get mandatory number of objects
         numberOfObjects = stream.getInt(COSName.N);
@@ -78,19 +79,19 @@ public class PDFObjectStreamParser exten
             if (objectOffset != null) 
             {
                 // jump to the offset of the first object
-                long currentPosition = seqSource.getPosition();
+                long currentPosition = source.getPosition();
                 if (firstObject > 0 && currentPosition < firstObject)
                 {
-                    seqSource.skip(firstObject - (int) currentPosition);
+                    source.skip(firstObject - (int) currentPosition);
                 }
                 // jump to the offset of the object to be parsed
-                seqSource.skip(objectOffset);
+                source.skip(objectOffset);
                 streamObject = parseDirObject();
             }
         }
         finally
         {
-            seqSource.close();
+            source.close();
         }
         return streamObject;
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java Sun May 24 17:24:15 2020
@@ -32,6 +32,7 @@ import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNull;
 import org.apache.pdfbox.cos.COSNumber;
 import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.io.InputStreamRandomAccessRead;
 import org.apache.pdfbox.io.RandomAccessReadBuffer;
 
 /**
@@ -57,7 +58,7 @@ public class PDFStreamParser extends Bas
      */
     public PDFStreamParser(InputStream stream) throws IOException
     {
-        super(new InputStreamSource(stream));
+        super(new InputStreamRandomAccessRead(stream));
     }
     
     /**
@@ -68,7 +69,7 @@ public class PDFStreamParser extends Bas
      */
     public PDFStreamParser(byte[] bytes) throws IOException
     {
-        super(new RandomAccessSource(new RandomAccessReadBuffer(bytes)));
+        super(new RandomAccessReadBuffer(bytes));
     }
 
     /**
@@ -85,7 +86,7 @@ public class PDFStreamParser extends Bas
         {
             streamObjects.add( token );
         }
-        seqSource.close();
+        source.close();
         return streamObjects;
     }
 
@@ -101,10 +102,10 @@ public class PDFStreamParser extends Bas
         Object retval;
 
         skipSpaces();
-        int nextByte = seqSource.peek();
+        int nextByte = source.peek();
         if( ((byte)nextByte) == -1 )
         {
-            seqSource.close();
+            source.close();
             return null;
         }
         char c = (char)nextByte;
@@ -113,13 +114,13 @@ public class PDFStreamParser extends Bas
             case '<':
             {
                 // pull off first left bracket
-                int leftBracket = seqSource.read();
+                int leftBracket = source.read();
 
                 // check for second left bracket
-                c = (char) seqSource.peek();
+                c = (char) source.peek();
 
                 // put back first bracket
-                seqSource.unread(leftBracket);
+                source.unread(leftBracket);
 
                 if (c == '<')
                 {
@@ -209,23 +210,24 @@ public class PDFStreamParser extends Bas
                  * allow 1 "." and "-" and "+" at start of number. */
                 StringBuilder buf = new StringBuilder();
                 buf.append( c );
-                seqSource.read();
+                source.read();
                 
                 // Ignore double negative (this is consistent with Adobe Reader)
-                if (c == '-' && seqSource.peek() == c)
+                if (c == '-' && source.peek() == c)
                 {
-                    seqSource.read();
+                    source.read();
                 }
 
                 boolean dotNotRead = c != '.';
-                while( Character.isDigit(c = (char) seqSource.peek()) || dotNotRead && c == '.' || c == '-')
+                while (Character.isDigit(c = (char) source.peek()) || dotNotRead && c == '.'
+                        || c == '-')
                 {
                     if (c != '-')
                     {
                         // PDFBOX-4064: ignore "-" in the middle of a number
                         buf.append(c);
                     }
-                    seqSource.read();
+                    source.read();
 
                     if (dotNotRead && c == '.')
                     {
@@ -256,7 +258,7 @@ public class PDFStreamParser extends Bas
                         Operator imageData = (Operator) nextToken;
                         if (imageData.getImageData() == null || imageData.getImageData().length == 0)
                         {
-                            LOG.warn("empty inline image at stream offset " + seqSource.getPosition());
+                            LOG.warn("empty inline image at stream offset " + source.getPosition());
                         }
                         beginImageOP.setImageData(imageData.getImageData());
                     }
@@ -266,20 +268,20 @@ public class PDFStreamParser extends Bas
             case 'I':
             {
                 //Special case for ID operator
-                String id = Character.toString((char) seqSource.read()) + (char) seqSource.read();
+                String id = Character.toString((char) source.read()) + (char) source.read();
                 if (!id.equals(OperatorName.BEGIN_INLINE_IMAGE_DATA))
                 {
                     throw new IOException( "Error: Expected operator 'ID' actual='" + id +
-                                           "' at stream offset " + seqSource.getPosition());
+                            "' at stream offset " + source.getPosition());
                 }
                 ByteArrayOutputStream imageData = new ByteArrayOutputStream();
                 if( isWhitespace() )
                 {
                     //pull off the whitespace character
-                    seqSource.read();
+                    source.read();
                 }
-                int lastByte = seqSource.read();
-                int currentByte = seqSource.read();
+                int lastByte = source.read();
+                int currentByte = source.read();
                 // PDF spec is kinda unclear about this. Should a whitespace
                 // always appear before EI? Not sure, so that we just read
                 // until EI<whitespace>.
@@ -292,7 +294,7 @@ public class PDFStreamParser extends Bas
                 {
                     imageData.write( lastByte );
                     lastByte = currentByte;
-                    currentByte = seqSource.read();
+                    currentByte = source.read();
                 }
                 // the EI operator isn't unread, as it won't be processed anyway
                 retval = Operator.getOperator(OperatorName.BEGIN_INLINE_IMAGE_DATA);
@@ -304,7 +306,7 @@ public class PDFStreamParser extends Bas
             {
                 // some ']' around without its previous '['
                 // this means a PDF is somewhat corrupt but we will continue to parse.
-                seqSource.read();
+                source.read();
                 
                 // must be a better solution than null...
                 retval = COSNull.NULL;  
@@ -339,7 +341,7 @@ public class PDFStreamParser extends Bas
     private boolean hasNoFollowingBinData() throws IOException
     {
         // as suggested in PDFBOX-1164
-        final int readBytes = seqSource.read(binCharTestArr, 0, MAX_BIN_CHAR_TEST_LENGTH);
+        final int readBytes = source.read(binCharTestArr, 0, MAX_BIN_CHAR_TEST_LENGTH);
         boolean noBinData = true;
         int startOpIdx = -1;
         int endOpIdx = -1;
@@ -391,12 +393,12 @@ public class PDFStreamParser extends Bas
                     noBinData = false;
                 }
             }
-            seqSource.unread(binCharTestArr, 0, readBytes);
+            source.unread(binCharTestArr, 0, readBytes);
         }
         if (!noBinData)
         {
             LOG.warn("ignoring 'EI' assumed to be in the middle of inline image at stream offset " + 
-                    seqSource.getPosition());
+                    source.getPosition());
         }
         return noBinData;
     }
@@ -415,7 +417,7 @@ public class PDFStreamParser extends Bas
         //average string size is around 2 and the normal string buffer size is
         //about 16 so lets save some space.
         StringBuilder buffer = new StringBuilder(4);
-        int nextChar = seqSource.peek();
+        int nextChar = source.peek();
         while(
             nextChar != -1 && // EOF
             !isWhitespace(nextChar) &&
@@ -427,14 +429,14 @@ public class PDFStreamParser extends Bas
             (nextChar < '0' ||
              nextChar > '9' ) )
         {
-            char currentChar = (char) seqSource.read();
-            nextChar = seqSource.peek();
+            char currentChar = (char) source.read();
+            nextChar = source.peek();
             buffer.append( currentChar );
             // Type3 Glyph description has operators with a number in the name
             if (currentChar == 'd' && (nextChar == '0' || nextChar == '1') ) 
             {
-                buffer.append( (char) seqSource.read() );
-                nextChar = seqSource.peek();
+                buffer.append((char) source.read());
+                nextChar = source.peek();
             }
         }
         return buffer.toString();
@@ -454,6 +456,6 @@ public class PDFStreamParser extends Bas
      */
     private boolean hasNextSpaceOrReturn() throws IOException
     {
-        return isSpaceOrReturn( seqSource.peek() );
+        return isSpaceOrReturn(source.peek());
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java?rev=1878086&r1=1878085&r2=1878086&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java Sun May 24 17:24:15 2020
@@ -28,6 +28,7 @@ import org.apache.pdfbox.cos.COSDocument
 import org.apache.pdfbox.cos.COSInteger;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.io.InputStreamRandomAccessRead;
 import org.apache.pdfbox.cos.COSObjectKey;
 
 /**
@@ -53,7 +54,7 @@ public class PDFXrefStreamParser extends
     public PDFXrefStreamParser(COSStream stream, COSDocument document, XrefTrailerResolver resolver)
             throws IOException
     {
-        super(new InputStreamSource(stream.createInputStream()));
+        super(new InputStreamRandomAccessRead(stream.createInputStream()));
         this.stream = stream;
         this.document = document;
         this.xrefTrailerResolver = resolver;
@@ -121,7 +122,7 @@ public class PDFXrefStreamParser extends
         while (!isEOF() && objIter.hasNext())
         {
             byte[] currLine = new byte[lineSize];
-            seqSource.read(currLine);
+            source.read(currLine);
 
             int type;            
             if (w0 == 0)

Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java?rev=1878086&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java Sun May 24 17:24:15 2020
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pdfbox.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unittest for org.apache.pdfbox.io.InputStreamRandomAccessRead
+ */
+public class InputStreamRandomAccessReadTest
+{
+    @Test
+    public void testPositionSkip() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        InputStreamRandomAccessRead inputStreamSource = new InputStreamRandomAccessRead(bais);
+
+        Assert.assertEquals(0, inputStreamSource.getPosition());
+        inputStreamSource.skip(5);
+        Assert.assertEquals(5, inputStreamSource.getPosition());
+
+        inputStreamSource.close();
+    }
+
+    @Test
+    public void testPositionRead() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        InputStreamRandomAccessRead inputStreamSource = new InputStreamRandomAccessRead(bais);
+
+        Assert.assertEquals(0, inputStreamSource.getPosition());
+        inputStreamSource.read();
+        inputStreamSource.read();
+        inputStreamSource.read();
+        Assert.assertEquals(3, inputStreamSource.getPosition());
+
+        inputStreamSource.close();
+    }
+
+    @Test
+    public void testPositionReadBytes() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        InputStreamRandomAccessRead inputStreamSource = new InputStreamRandomAccessRead(bais);
+
+        Assert.assertEquals(0, inputStreamSource.getPosition());
+        byte[] buffer = new byte[4];
+        inputStreamSource.read(buffer);
+        Assert.assertEquals(4, inputStreamSource.getPosition());
+
+        inputStreamSource.read(buffer, 1, 2);
+        Assert.assertEquals(6, inputStreamSource.getPosition());
+
+        inputStreamSource.close();
+    }
+
+    @Test
+    public void testPositionPeek() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        InputStreamRandomAccessRead inputStreamSource = new InputStreamRandomAccessRead(bais);
+
+        Assert.assertEquals(0, inputStreamSource.getPosition());
+        inputStreamSource.skip(6);
+        Assert.assertEquals(6, inputStreamSource.getPosition());
+
+        inputStreamSource.peek();
+        Assert.assertEquals(6, inputStreamSource.getPosition());
+
+        inputStreamSource.close();
+    }
+
+    @Test
+    public void testPositionUnreadBytes() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        InputStreamRandomAccessRead inputStreamSource = new InputStreamRandomAccessRead(bais);
+
+        Assert.assertEquals(0, inputStreamSource.getPosition());
+        inputStreamSource.read();
+        inputStreamSource.read();
+        byte[] readBytes = new byte[6];
+        inputStreamSource.read(readBytes);
+        Assert.assertEquals(8, inputStreamSource.getPosition());
+        inputStreamSource.unread(readBytes);
+        Assert.assertEquals(2, inputStreamSource.getPosition());
+        inputStreamSource.read();
+        Assert.assertEquals(3, inputStreamSource.getPosition());
+        inputStreamSource.read(readBytes, 2, 4);
+        Assert.assertEquals(7, inputStreamSource.getPosition());
+        inputStreamSource.unread(readBytes, 2, 4);
+        Assert.assertEquals(3, inputStreamSource.getPosition());
+
+        inputStreamSource.close();
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/InputStreamRandomAccessReadTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java?rev=1878086&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java Sun May 24 17:24:15 2020
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pdfbox.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unittest for org.apache.pdfbox.io.RandomAccessReadBuffer
+ */
+public class RandomAccessReadBufferTest
+{
+    @Test
+    public void testPositionSkip() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        RandomAccessReadBuffer randomAccessSource = new RandomAccessReadBuffer(bais);
+
+        Assert.assertEquals(0, randomAccessSource.getPosition());
+        randomAccessSource.skip(5);
+        Assert.assertEquals(5, randomAccessSource.getPosition());
+
+        randomAccessSource.close();
+    }
+
+    @Test
+    public void testPositionRead() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        RandomAccessReadBuffer randomAccessSource = new RandomAccessReadBuffer(bais);
+
+        Assert.assertEquals(0, randomAccessSource.getPosition());
+        randomAccessSource.read();
+        randomAccessSource.read();
+        randomAccessSource.read();
+        Assert.assertEquals(3, randomAccessSource.getPosition());
+
+        randomAccessSource.close();
+    }
+
+    @Test
+    public void testPositionReadBytes() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        RandomAccessReadBuffer randomAccessSource = new RandomAccessReadBuffer(bais);
+
+        Assert.assertEquals(0, randomAccessSource.getPosition());
+        byte[] buffer = new byte[4];
+        randomAccessSource.read(buffer);
+        Assert.assertEquals(4, randomAccessSource.getPosition());
+
+        randomAccessSource.read(buffer, 1, 2);
+        Assert.assertEquals(6, randomAccessSource.getPosition());
+
+        randomAccessSource.close();
+    }
+
+    @Test
+    public void testPositionPeek() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        RandomAccessReadBuffer randomAccessSource = new RandomAccessReadBuffer(bais);
+
+        Assert.assertEquals(0, randomAccessSource.getPosition());
+        randomAccessSource.skip(6);
+        Assert.assertEquals(6, randomAccessSource.getPosition());
+
+        randomAccessSource.peek();
+        Assert.assertEquals(6, randomAccessSource.getPosition());
+
+        randomAccessSource.close();
+    }
+
+    @Test
+    public void testPositionUnreadBytes() throws IOException
+    {
+        byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
+
+        RandomAccessReadBuffer randomAccessSource = new RandomAccessReadBuffer(bais);
+
+        Assert.assertEquals(0, randomAccessSource.getPosition());
+        randomAccessSource.read();
+        randomAccessSource.read();
+        byte[] readBytes = new byte[6];
+        randomAccessSource.read(readBytes);
+        Assert.assertEquals(8, randomAccessSource.getPosition());
+        randomAccessSource.unread(readBytes);
+        Assert.assertEquals(2, randomAccessSource.getPosition());
+        randomAccessSource.read();
+        Assert.assertEquals(3, randomAccessSource.getPosition());
+        randomAccessSource.read(readBytes, 2, 4);
+        Assert.assertEquals(7, randomAccessSource.getPosition());
+        randomAccessSource.unread(readBytes, 2, 4);
+        Assert.assertEquals(3, randomAccessSource.getPosition());
+
+        randomAccessSource.close();
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/io/RandomAccessReadBufferTest.java
------------------------------------------------------------------------------
    svn:eol-style = native