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());
}
/**