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 2026/09/26 10:45:58 UTC

svn commit: r1938531 - pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser

Author: lehmi
Date: Sat Sep 26 10:45:58 2026
New Revision: 1938531

Log:
PDFBOX-5032: don't access the underlying source of the COSParser in classes which don't subclass COSParser

Modified:
   pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
   pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BruteForceParser.java
   pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefParser.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java	Sat Sep 26 10:27:43 2026	(r1938530)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java	Sat Sep 26 10:45:58 2026	(r1938531)
@@ -684,6 +684,18 @@ public abstract class BaseParser
     }
 
     /**
+     * Read a single byte of data.
+     *
+     * @return The byte of data that is being read.
+     *
+     * @throws IOException If there is an error while reading the data.
+     */
+    protected int read() throws IOException
+    {
+        return source.read();
+    }
+
+    /**
      * Read a buffer of data.
      *
      * @param b The buffer to write the data to.
@@ -698,6 +710,18 @@ public abstract class BaseParser
     }
 
     /**
+     * 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.
+     */
+    protected int peek() throws IOException
+    {
+        return source.peek();
+    }
+
+    /**
      * The total number of bytes that are available.
      * 
      * @return The number of bytes available.
@@ -709,4 +733,16 @@ public abstract class BaseParser
         return source.length();
     }
 
+    /**
+     * Returns offset of next byte to be returned by a read method.
+     * 
+     * @return offset of next byte which will be returned with next {@link #read()} (if no more bytes are left it
+     * returns a value >= length of source)
+     * 
+     * @throws IOException If there was an error while getting the current position
+     */
+    protected long getPosition() throws IOException
+    {
+        return source.getPosition();
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BruteForceParser.java
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BruteForceParser.java	Sat Sep 26 10:27:43 2026	(r1938530)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BruteForceParser.java	Sat Sep 26 10:45:58 2026	(r1938531)
@@ -35,7 +35,6 @@ import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSObject;
 import org.apache.pdfbox.cos.COSObjectKey;
 import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.io.RandomAccessRead;
 import org.apache.pdfbox.pdfparser.XrefTrailerResolver.XRefType;
 import org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy;
 import org.apache.pdfbox.pdmodel.encryption.SecurityHandler;
@@ -80,7 +79,6 @@ public class BruteForceParser
 
     private final COSParser parser;
     private final COSDocument document;
-    private final RandomAccessRead source;
 
     /**
      * Constructor. Triggers a brute force search for all objects of the document.
@@ -94,7 +92,6 @@ public class BruteForceParser
     {
         document = cosDocument;
         parser = cosParser;
-        source = parser.source;
     }
 
     /**
@@ -133,7 +130,7 @@ public class BruteForceParser
     private void bfSearchForObjects() throws IOException
     {
         long lastEOFMarker = bfSearchForLastEOFMarker();
-        long originOffset = source.getPosition();
+        long originOffset = parser.getPosition();
         long currentOffset = MINIMUM_SEARCH_OFFSET;
         long lastObjectId = Long.MIN_VALUE;
         int lastGenID = Integer.MIN_VALUE;
@@ -143,35 +140,35 @@ public class BruteForceParser
         boolean endOfObjFound = false;
         do
         {
-            source.seek(currentOffset);
-            int nextChar = source.read();
+            parser.seek(currentOffset);
+            int nextChar = parser.read();
             currentOffset++;
             if (BaseParser.isWhitespace(nextChar) && parser.isString(OBJ_MARKER))
             {
                 long tempOffset = currentOffset - 2;
-                source.seek(tempOffset);
-                int genID = source.peek();
+                parser.seek(tempOffset);
+                int genID = parser.peek();
                 // is the next char a digit?
                 if (BaseParser.isDigit(genID))
                 {
                     genID -= 48;
                     tempOffset--;
-                    source.seek(tempOffset);
+                    parser.seek(tempOffset);
                     if (parser.isWhitespace())
                     {
                         while (tempOffset > MINIMUM_SEARCH_OFFSET && parser.isWhitespace())
                         {
-                            source.seek(--tempOffset);
+                            parser.seek(--tempOffset);
                         }
                         boolean objectIDFound = false;
                         while (tempOffset > MINIMUM_SEARCH_OFFSET && parser.isDigit())
                         {
-                            source.seek(--tempOffset);
+                            parser.seek(--tempOffset);
                             objectIDFound = true;
                         }
                         if (objectIDFound)
                         {
-                            source.read();
+                            parser.read();
                             long objectId = parser.readObjectNumber();
                             if (lastObjOffset > 0)
                             {
@@ -194,7 +191,7 @@ public class BruteForceParser
             else if (nextChar == 'e' && parser.isString(endobjString))
             {
                 currentOffset += endobjString.length;
-                source.seek(currentOffset);
+                parser.seek(currentOffset);
                 if (parser.isEOF())
                 {
                     endOfObjFound = true;
@@ -214,7 +211,7 @@ public class BruteForceParser
                     lastObjOffset);
         }
         // reestablish origin position
-        source.seek(originOffset);
+        parser.seek(originOffset);
     }
 
     /**
@@ -304,7 +301,7 @@ public class BruteForceParser
     protected void bfSearchForObjStreams(Map<COSObjectKey, Long> xrefTable) throws IOException
     {
         // save origin offset
-        long originOffset = source.getPosition();
+        long originOffset = parser.getPosition();
 
         Map<Long, COSObjectKey> bfSearchForObjStreamOffsets = bfSearchForObjStreamOffsets();
         Map<COSObjectKey, Long> bfCOSObjectOffsets = getBFCOSObjectOffsets();
@@ -325,7 +322,7 @@ public class BruteForceParser
         SecurityHandler<? extends ProtectionPolicy> securityHandler = parser.getSecurityHandler();
         for (Long offset : objStreamOffsets)
         {
-            source.seek(offset);
+            parser.seek(offset);
             long stmObjNumber = parser.readObjectNumber();
             int stmGenNumber = parser.readGenerationNumber();
             parser.readExpectedString(OBJ_MARKER, true);
@@ -371,7 +368,7 @@ public class BruteForceParser
             }
         }
         // restore origin offset
-        source.seek(originOffset);
+        parser.seek(originOffset);
     }
 
     /**
@@ -383,8 +380,8 @@ public class BruteForceParser
      */
     private boolean bfSearchForTrailer(COSDictionary trailer) throws IOException
     {
-        long originOffset = source.getPosition();
-        source.seek(MINIMUM_SEARCH_OFFSET);
+        long originOffset = parser.getPosition();
+        parser.seek(MINIMUM_SEARCH_OFFSET);
         // search for trailer marker
         long trailerOffset = findString(TRAILER_MARKER);
         while (trailerOffset != -1)
@@ -441,7 +438,7 @@ public class BruteForceParser
             }
             trailerOffset = findString(TRAILER_MARKER);
         }
-        source.seek(originOffset);
+        parser.seek(originOffset);
         return false;
     }
 
@@ -520,8 +517,8 @@ public class BruteForceParser
     private long bfSearchForLastEOFMarker() throws IOException
     {
         long lastEOFMarker = -1;
-        long originOffset = source.getPosition();
-        source.seek(MINIMUM_SEARCH_OFFSET);
+        long originOffset = parser.getPosition();
+        parser.seek(MINIMUM_SEARCH_OFFSET);
         long tempMarker = findString(EOF_MARKER);
         while (tempMarker != -1)
         {
@@ -546,7 +543,7 @@ public class BruteForceParser
             }
             tempMarker = findString(EOF_MARKER);
         }
-        source.seek(originOffset);
+        parser.seek(originOffset);
         // no EOF marker found
         if (lastEOFMarker == -1)
         {
@@ -564,7 +561,7 @@ public class BruteForceParser
     private Map<Long, COSObjectKey> bfSearchForObjStreamOffsets() throws IOException
     {
         HashMap<Long, COSObjectKey> bfSearchObjStreamsOffsets = new HashMap<>();
-        source.seek(MINIMUM_SEARCH_OFFSET);
+        parser.seek(MINIMUM_SEARCH_OFFSET);
         char[] string = " obj".toCharArray();
         // search for object stream marker
         long positionObjStream = findString(OBJ_STREAM);
@@ -578,31 +575,31 @@ public class BruteForceParser
                 long currentOffset = positionObjStream - (i * 10);
                 if (currentOffset > 0)
                 {
-                    source.seek(currentOffset);
+                    parser.seek(currentOffset);
                     for (int j = 0; j < 10; j++)
                     {
                         if (parser.isString(string))
                         {
                             long tempOffset = currentOffset - 1;
-                            source.seek(tempOffset);
+                            parser.seek(tempOffset);
                             // is the next char a digit?
                             if (parser.isDigit())
                             {
                                 tempOffset--;
-                                source.seek(tempOffset);
+                                parser.seek(tempOffset);
                                 if (parser.isSpace())
                                 {
                                     int length = 0;
-                                    source.seek(--tempOffset);
+                                    parser.seek(--tempOffset);
                                     while (tempOffset > MINIMUM_SEARCH_OFFSET && parser.isDigit())
                                     {
-                                        source.seek(--tempOffset);
+                                        parser.seek(--tempOffset);
                                         length++;
                                     }
                                     if (length > 0)
                                     {
-                                        source.read();
-                                        newOffset = source.getPosition();
+                                        parser.read();
+                                        newOffset = parser.getPosition();
                                         long objNumber = parser.readObjectNumber();
                                         int genNumber = parser.readGenerationNumber();
                                         COSObjectKey streamObjectKey = new COSObjectKey(objNumber,
@@ -618,12 +615,12 @@ public class BruteForceParser
                         else
                         {
                             currentOffset++;
-                            source.read();
+                            parser.read();
                         }
                     }
                 }
             }
-            source.seek(positionObjStream + OBJ_STREAM.length);
+            parser.seek(positionObjStream + OBJ_STREAM.length);
             positionObjStream = findString(OBJ_STREAM);
         }
         return bfSearchObjStreamsOffsets;
@@ -638,18 +635,18 @@ public class BruteForceParser
     {
         List<Long> bfSearchXRefTablesOffsets = new ArrayList<>();
         // a pdf may contain more than one xref entry
-        source.seek(MINIMUM_SEARCH_OFFSET);
+        parser.seek(MINIMUM_SEARCH_OFFSET);
         // search for xref tables
         long newOffset = findString(XREF_TABLE);
         while (newOffset != -1)
         {
-            source.seek(newOffset - 1);
+            parser.seek(newOffset - 1);
             // ensure that we don't read "startxref" instead of "xref"
             if (parser.isWhitespace())
             {
                 bfSearchXRefTablesOffsets.add(newOffset);
             }
-            source.seek(newOffset + 4);
+            parser.seek(newOffset + 4);
             newOffset = findString(XREF_TABLE);
         }
         return bfSearchXRefTablesOffsets;
@@ -664,7 +661,7 @@ public class BruteForceParser
     {
         List<Long> bfSearchXRefStreamsOffsets = new ArrayList<>();
         // a pdf may contain more than one /XRef entry
-        source.seek(MINIMUM_SEARCH_OFFSET);
+        parser.seek(MINIMUM_SEARCH_OFFSET);
         // search for XRef streams
         String objString = " obj";
         char[] string = objString.toCharArray();
@@ -679,31 +676,31 @@ public class BruteForceParser
                 long currentOffset = xrefOffset - (i * 10);
                 if (currentOffset > 0)
                 {
-                    source.seek(currentOffset);
+                    parser.seek(currentOffset);
                     for (int j = 0; j < 10; j++)
                     {
                         if (parser.isString(string))
                         {
                             long tempOffset = currentOffset - 1;
-                            source.seek(tempOffset);
+                            parser.seek(tempOffset);
                             // is the next char a digit?
                             if (parser.isDigit())
                             {
                                 tempOffset--;
-                                source.seek(tempOffset);
+                                parser.seek(tempOffset);
                                 if (parser.isSpace())
                                 {
                                     int length = 0;
-                                    source.seek(--tempOffset);
+                                    parser.seek(--tempOffset);
                                     while (tempOffset > MINIMUM_SEARCH_OFFSET && parser.isDigit())
                                     {
-                                        source.seek(--tempOffset);
+                                        parser.seek(--tempOffset);
                                         length++;
                                     }
                                     if (length > 0)
                                     {
-                                        source.read();
-                                        newOffset = source.getPosition();
+                                        parser.read();
+                                        newOffset = parser.getPosition();
                                     }
                                 }
                             }
@@ -715,7 +712,7 @@ public class BruteForceParser
                         else
                         {
                             currentOffset++;
-                            source.read();
+                            parser.read();
                         }
                     }
                 }
@@ -724,7 +721,7 @@ public class BruteForceParser
             {
                 bfSearchXRefStreamsOffsets.add(newOffset);
             }
-            source.seek(xrefOffset + 5);
+            parser.seek(xrefOffset + 5);
             xrefOffset = findString(XREF_STREAM);
         }
         return bfSearchXRefStreamsOffsets;
@@ -778,14 +775,14 @@ public class BruteForceParser
         long position = -1L;
         int stringLength = string.length;
         int counter = 0;
-        int readChar = source.read();
+        int readChar = parser.read();
         while (readChar != -1)
         {
             if (readChar == string[counter])
             {
                 if (counter == 0)
                 {
-                    position = source.getPosition() - 1;
+                    position = parser.getPosition() - 1;
                 }
                 counter++;
                 if (counter == stringLength)
@@ -799,7 +796,7 @@ public class BruteForceParser
                 position = -1L;
                 continue;
             }
-            readChar = source.read();
+            readChar = parser.read();
         }
         return position;
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefParser.java
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefParser.java	Sat Sep 26 10:27:43 2026	(r1938530)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefParser.java	Sat Sep 26 10:45:58 2026	(r1938531)
@@ -32,7 +32,6 @@ import org.apache.pdfbox.cos.COSDocument
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSObjectKey;
 import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.io.RandomAccessRead;
 import org.apache.pdfbox.pdfparser.XrefTrailerResolver.XRefType;
 
 /**
@@ -55,7 +54,6 @@ public class XrefParser
     private final XrefTrailerResolver xrefTrailerResolver = new XrefTrailerResolver();
 
     private final COSParser parser;
-    private final RandomAccessRead source;
 
     /**
      * Default constructor.
@@ -66,7 +64,6 @@ public class XrefParser
     public XrefParser(COSParser cosParser)
     {
         parser = cosParser;
-        source = parser.source;
     }
 
     /**
@@ -91,7 +88,7 @@ public class XrefParser
      */
     public COSDictionary parseXref(COSDocument document, long startXRefOffset) throws IOException
     {
-        source.seek(startXRefOffset);
+        parser.seek(startXRefOffset);
         long startXrefOffset = Math.max(0, parseStartXref());
         // check the startxref offset
         long fixedOffset = checkXRefOffset(startXrefOffset);
@@ -109,20 +106,20 @@ public class XrefParser
             // save expected position for loop detection
             prevSet.add(prev);
             // seek to xref table
-            source.seek(prev);
+            parser.seek(prev);
             // skip white spaces
             parser.skipSpaces();
             // save current position as well due to skipped spaces
-            prevSet.add(source.getPosition());
+            prevSet.add(parser.getPosition());
             // -- parse xref
-            if (source.peek() == X)
+            if (parser.peek() == X)
             {
                 // xref table and trailer
                 // use existing parser to parse xref table
                 if (!parseXrefTable(prev) || !parseTrailer())
                 {
                     throw new IOException("Expected trailer object at offset "
-                            + source.getPosition());
+                            + parser.getPosition());
                 }
                 trailer = xrefTrailerResolver.getCurrentTrailer();
                 // check for a XRef stream, it may contain some object ids of compressed objects 
@@ -140,7 +137,7 @@ public class XrefParser
                     }
                     if (streamOffset > 0)
                     {
-                        source.seek(streamOffset);
+                        parser.seek(streamOffset);
                         parser.skipSpaces();
                         try
                         {
@@ -208,25 +205,25 @@ public class XrefParser
     private boolean parseTrailer() throws IOException
     {
         // parse the last trailer.
-        long trailerOffset = source.getPosition();
+        long trailerOffset = parser.getPosition();
         // PDFBOX-1739 skip extra xref entries in RegisSTAR documents
-        int nextCharacter = source.peek();
+        int nextCharacter = parser.peek();
         while (nextCharacter != 't' && BaseParser.isDigit(nextCharacter))
         {
-            if (source.getPosition() == trailerOffset)
+            if (parser.getPosition() == trailerOffset)
             {
                 // warn only the first time
                 LOG.warn("Expected trailer object at offset {}, keep trying", trailerOffset);
             }
             parser.readLine();
-            nextCharacter = source.peek();
+            nextCharacter = parser.peek();
         }
-        if (source.peek() != 't')
+        if (parser.peek() != 't')
         {
             return false;
         }
         // read "trailer"
-        long currentOffset = source.getPosition();
+        long currentOffset = parser.getPosition();
         String nextLine = parser.readLine();
         if (!nextLine.trim().equals("trailer"))
         {
@@ -239,7 +236,7 @@ public class XrefParser
                 // we can't just unread a portion of the read data as we don't know if the EOL consist of 1 or 2 bytes
                 int len = "trailer".length();
                 // jump back right after "trailer"
-                source.seek(currentOffset + len);
+                parser.seek(currentOffset + len);
             }
             else
             {
@@ -296,7 +293,7 @@ public class XrefParser
      */
     private long checkXRefOffset(long startXRefOffset) throws IOException
     {
-        source.seek(startXRefOffset);
+        parser.seek(startXRefOffset);
         parser.skipSpaces();
         if (parser.isString(XREF_TABLE))
         {
@@ -358,8 +355,8 @@ public class XrefParser
             return true;
         }
         // seek to offset-1 
-        source.seek(startXRefOffset - 1);
-        int nextValue = source.read();
+        parser.seek(startXRefOffset - 1);
+        int nextValue = parser.read();
         // the first character has to be a whitespace, and then a digit
         if (BaseParser.isWhitespace(nextValue))
         {
@@ -374,7 +371,7 @@ public class XrefParser
                     parser.readObjectMarker();
                     // check the dictionary to avoid false positives
                     COSDictionary dict = parser.parseCOSDictionary(false);
-                    source.seek(startXRefOffset);
+                    parser.seek(startXRefOffset);
                     if ("XRef".equals(dict.getNameAsString(COSName.TYPE)))
                     {
                         return true;
@@ -384,7 +381,7 @@ public class XrefParser
                 {
                     // there wasn't an object of a xref stream
                     LOG.debug("No Xref stream at given location {}", startXRefOffset, exception);
-                    source.seek(startXRefOffset);
+                    parser.seek(startXRefOffset);
                 }
             }
         }
@@ -484,25 +481,25 @@ public class XrefParser
         }
         try 
         {
-            source.seek(offset);
+            parser.seek(offset);
             parser.skipWhiteSpaces();
-            if (source.getPosition() == offset)
+            if (parser.getPosition() == offset)
             {
                 // ensure that at least one whitespace is skipped in front of the object number
-                source.seek(offset - 1);
-                if (source.getPosition() < offset)
+                parser.seek(offset - 1);
+                if (parser.getPosition() < offset)
                 {
                     if (!parser.isDigit())
                     {
                         // anything else but a digit may be some garbage of the previous object -> just ignore it
-                        source.read();
+                        parser.read();
                     }
                     else
                     {
-                        long current = source.getPosition();
-                        source.seek(--current);
+                        long current = parser.getPosition();
+                        parser.seek(--current);
                         while (parser.isDigit())
-                            source.seek(--current);
+                            parser.seek(--current);
                         long newObjNr = parser.readObjectNumber();
                         int newGenNr = parser.readGenerationNumber();
                         COSObjectKey newObjKey = new COSObjectKey(newObjNr, newGenNr);
@@ -517,7 +514,7 @@ public class XrefParser
                             return null;
                         }
                         // something seems to be wrong but it's hard to determine what exactly -> simply continue
-                        source.seek(offset);
+                        parser.seek(offset);
                     }
                 }
             }
@@ -578,7 +575,7 @@ public class XrefParser
      */
     private boolean parseXrefTable(long startByteOffset) throws IOException
     {
-        if (source.peek() != 'x')
+        if (parser.peek() != 'x')
         {
             return false;
         }
@@ -591,7 +588,7 @@ public class XrefParser
         // check for trailer after xref
         String str = parser.readString();
         byte[] b = str.getBytes(StandardCharsets.ISO_8859_1);
-        source.seek(source.getPosition() - b.length);
+        parser.seek(parser.getPosition() - b.length);
         
         // signal start of new XRef
         xrefTrailerResolver.nextXrefObj( startByteOffset, XRefType.TABLE );
@@ -643,7 +640,7 @@ public class XrefParser
                 {
                     break;
                 }
-                int nextChar = source.peek();
+                int nextChar = parser.peek();
                 if (nextChar == 't' || BaseParser.isEndOfName(nextChar))
                 {
                     break;