Author: tilman
Date: Thu Aug 27 19:50:06 2026
New Revision: 1937535

Log:
PDFBOX-5660: refactor, as suggested by Valery Bokov; closes #498; improve test 
coverage

Modified:
   pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java
   pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/pfb/PfbParserTest.java

Modified: 
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java    
Thu Aug 27 19:27:57 2026        (r1937534)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java    
Thu Aug 27 19:50:06 2026        (r1937535)
@@ -17,12 +17,12 @@
 package org.apache.fontbox.pfb;
 
 import java.io.ByteArrayInputStream;
+import java.io.BufferedInputStream;
 import java.io.EOFException;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -88,7 +88,10 @@ public class PfbParser
      */
     public PfbParser(final String filename) throws IOException 
     {
-        this(Files.readAllBytes(Paths.get(filename)));
+        try (InputStream is = new FileInputStream(filename))
+        {
+            parsePfb(is);
+        }
     }
 
     /**
@@ -98,8 +101,7 @@ public class PfbParser
      */
     public PfbParser(final InputStream in) throws IOException 
     {
-        byte[] pfb = in.readAllBytes();
-        parsePfb(pfb);
+        parsePfb(in);
     }
 
     /**
@@ -109,24 +111,30 @@ public class PfbParser
      */
     public PfbParser(final byte[] bytes) throws IOException
     {
-        parsePfb(bytes);
+        parsePfb(new ByteArrayInputStream(bytes));
     }
 
     /**
-     * Parse the pfb-array.
-     * @param pfb   The pfb-Array
+     * Parse the pfb-stream.
+     * @param pfbStream The pfb-stream
      * @throws IOException in an IO-error occurs.
      */
-    private void parsePfb(final byte[] pfb) throws IOException 
+    private void parsePfb(InputStream pfbStream) throws IOException
     {
-        if (pfb.length < PFB_HEADER_LENGTH)
+        InputStream in;
+
+        if (pfbStream.markSupported())
         {
-            throw new IOException("PFB header missing");
+            in = pfbStream;
         }
+        else
+        {
+            in = new BufferedInputStream(pfbStream);
+        }
+
         // read into segments and keep them
         List<Integer> typeList = new ArrayList<>(3);
         List<byte[]> barrList = new ArrayList<>(3);
-        ByteArrayInputStream in = new ByteArrayInputStream(pfb);
         long total = 0;
         do
         {
@@ -158,14 +166,11 @@ public class PfbParser
             {
                 throw new IOException("record size " + size + " is negative");
             }
-            if (size > pfb.length)
-            {
-                // PDFBOX-6044: avoid potential OOM
-                throw new IOException("record size " + size + " would be 
larger than the input");
-            }
-            byte[] ar = new byte[size];
-            int got = in.read(ar);
-            if (got != size)
+            // PDFBOX-6044: avoid potential OOM. readNBytes() grows its buffer
+            // incrementally as bytes actually arrive, so a bogus/huge size can
+            // never force an allocation larger than what the stream really 
holds.
+            byte[] ar = in.readNBytes(size);
+            if (ar.length != size)
             {
                 throw new EOFException("EOF while reading PFB font");
             }
@@ -174,16 +179,16 @@ public class PfbParser
             barrList.add(ar);
         }
         while (true);
-        
+
+        if (total < PFB_HEADER_LENGTH)
+        {
+            throw new IOException("PFB header missing");
+        }
+
         // We now have ASCII and binary segments. Lets arrange these so that 
the ASCII segments
         // come first, then the binary segments, then the last ASCII segment 
if it is
         // 0000... cleartomark
 
-        if (total > pfb.length)
-        {
-            // PDFBOX-6044: avoid potential OOM
-            throw new IOException("total record size " + total + " would be 
larger than the input");
-        }
         pfbdata = new byte[(int) total];
         byte[] cleartomarkSegment = null;
         int dstPos = 0;

Modified: 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/pfb/PfbParserTest.java
==============================================================================
--- 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/pfb/PfbParserTest.java    
    Thu Aug 27 19:27:57 2026        (r1937534)
+++ 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/pfb/PfbParserTest.java    
    Thu Aug 27 19:50:06 2026        (r1937535)
@@ -104,7 +104,7 @@ class PfbParserTest
     {
         IOException ex1 = Assertions.assertThrows(IOException.class,
                 () -> Type1Font.createWithPFB(new byte[0]));
-        Assertions.assertEquals("PFB header missing", ex1.getMessage());
+        Assertions.assertEquals("Start marker missing", ex1.getMessage());
     }
 
     /**
@@ -163,7 +163,24 @@ class PfbParserTest
             (byte) 0xD2, 0x40
         };
         IOException ex = Assertions.assertThrows(IOException.class, () -> new 
PfbParser(crashInput));
-        Assertions.assertEquals("record size 127 would be larger than the 
input", ex.getMessage());
+        Assertions.assertEquals("EOF while reading PFB font", ex.getMessage());
+    }
+
+    /**
+     * Test that a PFB with only 1 short segment throws an exception
+     */
+    @Test
+    void test1SegmentOnly()
+    {
+        // 18-byte crafted PFB: start marker 0x80, ASCII type 0x01,
+        // size field 0x04 0x00 0x00 0x00 = 0x04
+        byte[] crashInput = {
+            (byte) 0x80, 0x01,                         // header
+            0x03, 0x00, 0x00, 0x00,                    // size
+            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF      // garbage data
+        };
+        IOException ex = Assertions.assertThrows(IOException.class, () -> new 
PfbParser(crashInput));
+        Assertions.assertEquals("PFB header missing", ex.getMessage());
     }
 
     /**

Reply via email to