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 2022/05/16 05:27:01 UTC

svn commit: r1900937 - in /pdfbox/trunk: fontbox/src/main/java/org/apache/fontbox/ttf/ fontbox/src/test/java/org/apache/fontbox/cmap/ fontbox/src/test/java/org/apache/fontbox/ttf/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ pdfbox/src/test/jav...

Author: lehmi
Date: Mon May 16 05:27:00 2022
New Revision: 1900937

URL: http://svn.apache.org/viewvc?rev=1900937&view=rev
Log:
PDFBOX-5435: use org.apache.pdfbox.io for TTFParser

Added:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java   (with props)
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java   (with props)
Removed:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RAFDataStreamTest.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TestMemoryTTFDataStream.java
Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cmap/TestCMap.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GSUBTableDebugger.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java Mon May 16 05:27:00 2022
@@ -21,6 +21,8 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.pdfbox.io.RandomAccessRead;
+
 /**
  * OpenType font file parser.
  */
@@ -56,21 +58,21 @@ public final class OTFParser extends TTF
     }
 
     @Override
-    public OpenTypeFont parse(String file) throws IOException
+    public OpenTypeFont parse(File file) throws IOException
     {
         return (OpenTypeFont)super.parse(file);
     }
 
     @Override
-    public OpenTypeFont parse(File file) throws IOException
+    public OpenTypeFont parse(InputStream data) throws IOException
     {
-        return (OpenTypeFont)super.parse(file);
+        return (OpenTypeFont)super.parse(data);
     }
 
     @Override
-    public OpenTypeFont parse(InputStream data) throws IOException
+    public OpenTypeFont parse(RandomAccessRead RandomAccessRead) throws IOException
     {
-        return (OpenTypeFont)super.parse(data);
+        return (OpenTypeFont) super.parse(RandomAccessRead);
     }
 
     @Override

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java?rev=1900937&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java Mon May 16 05:27:00 2022
@@ -0,0 +1,186 @@
+/*
+ * 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.fontbox.ttf;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.pdfbox.io.RandomAccessRead;
+
+/**
+ * An implementation of the TTFDataStream using RandomAccessRead as sourece.
+ * 
+ */
+class RandomAccessReadDataStream extends TTFDataStream
+{
+    private final RandomAccessRead randomAccessRead;
+    private final long length;
+    private final byte[] data;
+    
+    /**
+     * Constructor.
+     * 
+     * @param file The file to be read.
+     * 
+     * @throws IOException If there is a problem creating the RandomAccessReadBufferedFile.
+     */
+    RandomAccessReadDataStream(RandomAccessRead randomAccessRead) throws IOException
+    {
+        this.randomAccessRead = randomAccessRead;
+        length = randomAccessRead.length();
+        data = new byte[(int) length];
+        int bytesRead = randomAccessRead.read(data, 0, (int) length);
+        while (bytesRead > -1 && bytesRead < length)
+        {
+            bytesRead += randomAccessRead.read(data, bytesRead, (int) length - bytesRead);
+        }
+        randomAccessRead.read(data);
+        randomAccessRead.seek(0);
+    }
+    
+    /**
+     * Read a signed short.
+     * 
+     * @return An signed short.
+     * @throws IOException If there is an error reading the data.
+     */
+    @Override
+    public short readSignedShort() throws IOException
+    {
+        return (short) readUnsignedShort();
+    }
+    
+    /**
+     * Get the current position in the stream.
+     * @return The current position in the stream.
+     * @throws IOException If an error occurs while reading the stream.
+     */
+    @Override
+    public long getCurrentPosition() throws IOException
+    {
+        return randomAccessRead.getPosition();
+    }
+    
+    /**
+     * Close the underlying resources.
+     * 
+     * @throws IOException If there is an error closing the resources.
+     */
+    @Override
+    public void close() throws IOException
+    {
+        randomAccessRead.close();
+    }
+    
+    /**
+     * Read an unsigned byte.
+     * @return An unsigned byte.
+     * @throws IOException If there is an error reading the data.
+     */
+    @Override
+    public int read() throws IOException
+    {
+        return randomAccessRead.read();
+    }
+    
+    /**
+     * Read an unsigned short.
+     * 
+     * @return An unsigned short.
+     * @throws IOException If there is an error reading the data.
+     */
+    public int readUnsignedShort() throws IOException
+    {
+        int b1 = read();
+        int b2 = read();
+        return (b1 << 8) + b2;
+    }
+    
+    /**
+     * Read a signed 64-bit integer.
+     * 
+     * @return eight bytes interpreted as a long.
+     * @throws IOException If there is an error reading the data.
+     */
+    @Override
+    public final long readLong() throws IOException
+    {
+        return (readInt() << 32) + (readInt() & 0xFFFFFFFFL);
+    }
+
+    /**
+     * Read a signed 32-bit integer.
+     * 
+     * @return 4 bytes interpreted as a int.
+     * @throws IOException If there is an error reading the data.
+     */
+    private long readInt() throws IOException
+    {
+        int b1 = read();
+        int b2 = read();
+        int b3 = read();
+        int b4 = read();
+        return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
+    }
+    /**
+     * Seek into the datasource.
+     * 
+     * @param pos The position to seek to.
+     * @throws IOException If there is an error seeking to that position.
+     */
+    @Override
+    public void seek(long pos) throws IOException
+    {
+        randomAccessRead.seek(pos);
+    }
+    
+    /**
+     * @see java.io.InputStream#read( byte[], int, int )
+     * 
+     * @param b The buffer to write to.
+     * @param off The offset into the buffer.
+     * @param len The length into the buffer.
+     * 
+     * @return The number of bytes read.
+     * 
+     * @throws IOException If there is an error reading from the stream.
+     */
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        return randomAccessRead.read(b, off, len);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public InputStream getOriginalData() throws IOException
+    {
+        return new ByteArrayInputStream(data);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getOriginalDataSize()
+    {
+        return length;
+    }
+}

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RandomAccessReadDataStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java Mon May 16 05:27:00 2022
@@ -21,6 +21,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.io.RandomAccessRead;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
+import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
 
 /**
  * TrueType font file parser.
@@ -67,33 +70,22 @@ public class TTFParser
     /**
      * Parse a file and return a TrueType font.
      *
-     * @param ttfFile The TrueType font filename.
-     * @return A TrueType font.
-     * @throws IOException If there is an error parsing the TrueType font.
-     */
-    public TrueTypeFont parse(String ttfFile) throws IOException
-    {
-        return parse(new File(ttfFile));
-    }
-
-    /**
-     * Parse a file and return a TrueType font.
-     *
      * @param ttfFile The TrueType font file.
      * @return A TrueType font.
      * @throws IOException If there is an error parsing the TrueType font.
      */
     public TrueTypeFont parse(File ttfFile) throws IOException
     {
-        RAFDataStream raf = new RAFDataStream(ttfFile);
+        RandomAccessReadBufferedFile randomAccessReadBufferedFile = new RandomAccessReadBufferedFile(
+                ttfFile);
         try
         {
-            return parse(raf);
+            return parse(randomAccessReadBufferedFile);
         }
         catch (IOException ex)
         {
             // close only on error (file is still being accessed later)
-            raf.close();
+            randomAccessReadBufferedFile.close();
             throw ex;
         }
     }
@@ -107,7 +99,19 @@ public class TTFParser
      */
     public TrueTypeFont parse(InputStream inputStream) throws IOException
     {
-        return parse(new MemoryTTFDataStream(inputStream));
+        return parse(new RandomAccessReadBuffer(inputStream));
+    }
+
+    /**
+     * Parse a RandomAccessRead and return a TrueType font.
+     *
+     * @param randomAccessRead The RandomAccessREad to be read from. It will be closed before returning.
+     * @return A TrueType font.
+     * @throws IOException If there is an error parsing the TrueType font.
+     */
+    public TrueTypeFont parse(RandomAccessRead randomAccessRead) throws IOException
+    {
+        return parse(new RandomAccessReadDataStream(randomAccessRead));
     }
 
     /**
@@ -120,7 +124,7 @@ public class TTFParser
     public TrueTypeFont parseEmbedded(InputStream inputStream) throws IOException
     {
         this.isEmbedded = true;
-        return parse(new MemoryTTFDataStream(inputStream));
+        return parse(new RandomAccessReadBuffer(inputStream));
     }
 
     /**

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java Mon May 16 05:27:00 2022
@@ -22,6 +22,10 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.pdfbox.io.RandomAccessRead;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
+import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
+
 /**
  * A TrueType Collection, now more properly known as a "Font Collection" as it may contain either
  * TrueType or OpenType fonts.
@@ -42,7 +46,7 @@ public class TrueTypeCollection implemen
      */
     public TrueTypeCollection(File file) throws IOException
     {
-        this(new RAFDataStream(file));
+        this(new RandomAccessReadBufferedFile(file));
     }
 
     /**
@@ -53,7 +57,7 @@ public class TrueTypeCollection implemen
      */
     public TrueTypeCollection(InputStream stream) throws IOException
     {
-        this(new MemoryTTFDataStream(stream));
+        this(new RandomAccessReadBuffer(stream));
     }
 
     /**
@@ -62,9 +66,9 @@ public class TrueTypeCollection implemen
      * @param stream The TTF file.
      * @throws IOException If the font could not be parsed.
      */
-    TrueTypeCollection(TTFDataStream stream) throws IOException
+    TrueTypeCollection(RandomAccessRead randomAccessRead) throws IOException
     {
-        this.stream = stream;
+        this.stream = new RandomAccessReadDataStream(randomAccessRead);
 
         // TTC header
         String tag = stream.readTag();

Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cmap/TestCMap.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cmap/TestCMap.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cmap/TestCMap.java (original)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cmap/TestCMap.java Mon May 16 05:27:00 2022
@@ -18,6 +18,7 @@ package org.apache.fontbox.cmap;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import java.io.File;
 import java.io.IOException;
 
 import org.apache.fontbox.ttf.CmapLookup;
@@ -54,7 +55,8 @@ class TestCMap
     @Test
     void testPDFBox3997() throws IOException
     {
-        try (TrueTypeFont ttf = new TTFParser().parse("target/pdfs/NotoEmoji-Regular.ttf"))
+        try (TrueTypeFont ttf = new TTFParser()
+                .parse(new File("target/pdfs/NotoEmoji-Regular.ttf")))
         {
             CmapLookup cmap = ttf.getUnicodeCmapLookup(false);
             assertEquals(886, cmap.getGlyphId(0x1F681));

Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GSUBTableDebugger.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GSUBTableDebugger.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GSUBTableDebugger.java (original)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GSUBTableDebugger.java Mon May 16 05:27:00 2022
@@ -21,6 +21,7 @@ import java.io.IOException;
 
 import org.apache.fontbox.ttf.gsub.GSUBTablePrintUtil;
 import org.apache.fontbox.ttf.model.GsubData;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -36,14 +37,16 @@ public class GSUBTableDebugger
     @Test
     public void printLohitBengaliTTF() throws IOException
     {
-        MemoryTTFDataStream memoryTTFDataStream = new MemoryTTFDataStream(
+        RandomAccessReadBuffer randomAccessReadBuffer = new RandomAccessReadBuffer(
                 GSUBTableDebugger.class.getResourceAsStream(LOHIT_BENGALI_FONT_FILE));
+        RandomAccessReadDataStream randomAccessReadBufferDataStream = new RandomAccessReadDataStream(
+                randomAccessReadBuffer);
 
-        memoryTTFDataStream.seek(GlyphSubstitutionTableTest.DATA_POSITION_FOR_GSUB_TABLE);
+        randomAccessReadBufferDataStream.seek(GlyphSubstitutionTableTest.DATA_POSITION_FOR_GSUB_TABLE);
 
         GlyphSubstitutionTable glyphSubstitutionTable = new GlyphSubstitutionTable(null);
 
-        glyphSubstitutionTable.read(null, memoryTTFDataStream);
+        glyphSubstitutionTable.read(null, randomAccessReadBufferDataStream);
 
         TrueTypeFont trueTypeFont = new TTFParser()
                 .parse(GSUBTableDebugger.class.getResourceAsStream(LOHIT_BENGALI_FONT_FILE));

Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java (original)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java Mon May 16 05:27:00 2022
@@ -35,6 +35,7 @@ import org.apache.fontbox.ttf.model.Gsub
 import org.apache.fontbox.ttf.model.Language;
 import org.apache.fontbox.ttf.model.MapBackedScriptFeature;
 import org.apache.fontbox.ttf.model.ScriptFeature;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
 import org.junit.jupiter.api.Test;
 
 class GlyphSubstitutionTableTest
@@ -49,14 +50,16 @@ class GlyphSubstitutionTableTest
     void testGetGsubData() throws IOException
     {
         // given
-        MemoryTTFDataStream memoryTTFDataStream = new MemoryTTFDataStream(
-                GlyphSubstitutionTableTest.class.getResourceAsStream("/ttf/Lohit-Bengali.ttf"));
-        memoryTTFDataStream.seek(DATA_POSITION_FOR_GSUB_TABLE);
+        RandomAccessReadBuffer randomAccessReadBuffer = new RandomAccessReadBuffer(
+                GSUBTableDebugger.class.getResourceAsStream("/ttf/Lohit-Bengali.ttf"));
+        RandomAccessReadDataStream randomAccessReadBufferDataStream = new RandomAccessReadDataStream(
+                randomAccessReadBuffer);
+        randomAccessReadBufferDataStream.seek(DATA_POSITION_FOR_GSUB_TABLE);
 
         GlyphSubstitutionTable testClass = new GlyphSubstitutionTable(null);
 
         // when
-        testClass.read(null, memoryTTFDataStream);
+        testClass.read(null, randomAccessReadBufferDataStream);
 
         // then
         GsubData gsubData = testClass.getGsubData();

Added: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java?rev=1900937&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java (added)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java Mon May 16 05:27:00 2022
@@ -0,0 +1,207 @@
+/*
+ * 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.fontbox.ttf;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.pdfbox.io.RandomAccessRead;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
+import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * @author Tilman Hausherr
+ */
+class RandomAccessReadBufferDataStreamTest
+{
+    @Test
+    void testEOF() throws IOException
+    {
+        byte[] byteArray = new byte[10];
+        RandomAccessReadBuffer randomAccessReadBuffer = new RandomAccessReadBuffer(byteArray);
+        RandomAccessReadDataStream dataStream = new RandomAccessReadDataStream(
+                randomAccessReadBuffer);
+        int value = dataStream.read();
+        try
+        {
+            while (value > -1)
+            {
+                value = dataStream.read();
+            }
+        }
+        catch (ArrayIndexOutOfBoundsException exception)
+        {
+            fail("EOF not detected!");
+        }
+        finally
+        {
+            dataStream.close();
+        }
+    }
+
+    /**
+     * Test of PDFBOX-4242: make sure that the Closeable.close() contract is fulfilled.
+     * 
+     * @throws IOException
+     */
+    @Test
+    void testDoubleClose() throws IOException
+    {
+        RandomAccessRead randomAccessRead = new RandomAccessReadBufferedFile(
+                "src/test/resources/ttf/LiberationSans-Regular.ttf");
+        RandomAccessReadDataStream randomAccessReadDataStream = new RandomAccessReadDataStream(
+                randomAccessRead);
+        randomAccessReadDataStream.close();
+        randomAccessReadDataStream.close();
+    }
+
+    /**
+     * Before solving PDFBOX-3605, this test never ended.
+     * 
+     * @throws IOException
+     */
+    @Test
+    void ensureReadFinishes() throws IOException
+    {
+        final File file = File.createTempFile("apache-pdfbox", ".dat");
+
+        try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file)))
+        {
+            final String content = "1234567890";
+            outputStream.write(content.getBytes(StandardCharsets.UTF_8));
+            outputStream.flush();
+        }
+
+        final byte[] readBuffer = new byte[2];
+        RandomAccessRead randomAccessRead = new RandomAccessReadBufferedFile(file);
+        try (RandomAccessReadDataStream randomAccessReadDataStream = new RandomAccessReadDataStream(
+                randomAccessRead))
+        {
+            int amountRead;
+            int totalAmountRead = 0;
+            while ((amountRead = randomAccessReadDataStream.read(readBuffer, 0, 2)) != -1)
+            {
+                totalAmountRead += amountRead;
+            }
+            assertEquals(10, totalAmountRead);
+        }
+        file.delete();
+    }
+
+    /**
+     * Test several reading patterns, both reading within a buffer and across buffer.
+     *
+     * @throws IOException
+     */
+    @Test
+    void testReadBuffer() throws IOException
+    {
+        final File file = File.createTempFile("apache-pdfbox", ".dat");
+
+        try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file)))
+        {
+            final String content = "012345678A012345678B012345678C012345678D";
+            outputStream.write(content.getBytes(StandardCharsets.UTF_8));
+            outputStream.flush();
+        }
+        RandomAccessRead randomAccessRead = new RandomAccessReadBufferedFile(file);
+
+        final byte[] readBuffer = new byte[40];
+        try (RandomAccessReadDataStream randomAccessReadDataStream = new RandomAccessReadDataStream(
+                randomAccessRead))
+        {
+            int count = 4;
+            int bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(4, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("0123", new String(readBuffer, 0, count));
+
+            count = 6;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(10, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("45678A", new String(readBuffer, 0, count));
+
+            count = 10;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(20, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("012345678B", new String(readBuffer, 0, count));
+
+            count = 10;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(30, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("012345678C", new String(readBuffer, 0, count));
+
+            count = 10;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(40, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("012345678D", new String(readBuffer, 0, count));
+
+            assertEquals(-1, randomAccessReadDataStream.read());
+
+            randomAccessReadDataStream.seek(0);
+            randomAccessReadDataStream.read(readBuffer, 0, 7);
+            assertEquals(7, randomAccessReadDataStream.getCurrentPosition());
+
+            count = 16;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(23, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("78A012345678B012", new String(readBuffer, 0, count));
+
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, 99);
+            assertEquals(40, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(17, bytesRead);
+            assertEquals("345678C012345678D", new String(readBuffer, 0, 17));
+
+            assertEquals(-1, randomAccessReadDataStream.read());
+
+            randomAccessReadDataStream.seek(0);
+            randomAccessReadDataStream.read(readBuffer, 0, 7);
+            assertEquals(7, randomAccessReadDataStream.getCurrentPosition());
+
+            count = 23;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(30, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("78A012345678B012345678C", new String(readBuffer, 0, count));
+
+            randomAccessReadDataStream.seek(0);
+            randomAccessReadDataStream.read(readBuffer, 0, 10);
+            assertEquals(10, randomAccessReadDataStream.getCurrentPosition());
+            count = 23;
+            bytesRead = randomAccessReadDataStream.read(readBuffer, 0, count);
+            assertEquals(33, randomAccessReadDataStream.getCurrentPosition());
+            assertEquals(count, bytesRead);
+            assertEquals("012345678B012345678C012", new String(readBuffer, 0, count));
+        }
+        file.delete();
+    }
+
+}

Propchange: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/RandomAccessReadBufferDataStreamTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java (original)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java Mon May 16 05:27:00 2022
@@ -48,7 +48,8 @@ class TTFSubsetterTest
     @Test
     void testEmptySubset() throws IOException
     {
-        TrueTypeFont x = new TTFParser().parse("src/test/resources/ttf/LiberationSans-Regular.ttf");
+        TrueTypeFont x = new TTFParser()
+                .parse(new File("src/test/resources/ttf/LiberationSans-Regular.ttf"));
         TTFSubsetter ttfSubsetter = new TTFSubsetter(x);
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -69,7 +70,8 @@ class TTFSubsetterTest
     @Test
     void testEmptySubset2() throws IOException
     {
-        TrueTypeFont x = new TTFParser().parse("src/test/resources/ttf/LiberationSans-Regular.ttf");
+        TrueTypeFont x = new TTFParser()
+                .parse(new File("src/test/resources/ttf/LiberationSans-Regular.ttf"));
         // List copied from TrueTypeEmbedder.java
         List<String> tables = new ArrayList<>();
         tables.add("head");
@@ -102,7 +104,8 @@ class TTFSubsetterTest
     @Test
     void testNonEmptySubset() throws IOException
     {
-        TrueTypeFont full = new TTFParser().parse("src/test/resources/ttf/LiberationSans-Regular.ttf");
+        TrueTypeFont full = new TTFParser()
+                .parse(new File("src/test/resources/ttf/LiberationSans-Regular.ttf"));
         TTFSubsetter ttfSubsetter = new TTFSubsetter(full);
         ttfSubsetter.add('a');
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -197,7 +200,7 @@ class TTFSubsetterTest
     @Test
     void testPDFBox3379() throws IOException
     {
-        TrueTypeFont full = new TTFParser().parse("target/pdfs/DejaVuSansMono.ttf");
+        TrueTypeFont full = new TTFParser().parse(new File("target/pdfs/DejaVuSansMono.ttf"));
         TTFSubsetter ttfSubsetter = new TTFSubsetter(full);
         ttfSubsetter.add('A');
         ttfSubsetter.add(' ');

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java Mon May 16 05:27:00 2022
@@ -36,6 +36,7 @@ import org.apache.fontbox.ttf.OpenTypeFo
 import org.apache.fontbox.ttf.TTFParser;
 import org.apache.fontbox.ttf.TrueTypeFont;
 import org.apache.fontbox.type1.Type1Font;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
 import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;
 
 /**
@@ -121,9 +122,10 @@ final class FontMapperImpl implements Fo
             {
                 throw new IOException("resource '" + resourceName + "' not found");
             }
-            InputStream ttfStream = new BufferedInputStream(resourceAsStream);
+            RandomAccessReadBuffer randomAccessReadBuffer = new RandomAccessReadBuffer(
+                    resourceAsStream);
             TTFParser ttfParser = new TTFParser();
-            lastResortFont = ttfParser.parse(ttfStream);
+            lastResortFont = ttfParser.parse(randomAccessReadBuffer);
         }
         catch (IOException e)
         {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Mon May 16 05:27:00 2022
@@ -111,7 +111,7 @@ public class PDCIDFontType2 extends PDCI
                 {
                     // embedded OTF or TTF
                     OTFParser otfParser = new OTFParser(true);
-                    OpenTypeFont otf = otfParser.parse(stream.createInputStream());
+                    OpenTypeFont otf = otfParser.parse(stream.getCOSObject().createView());
                     ttfFont = otf;
     
                     if (otf.isPostScript())

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Mon May 16 05:27:00 2022
@@ -106,7 +106,7 @@ public class PDTrueTypeFont extends PDSi
                 {
                     // embedded
                     TTFParser ttfParser = new TTFParser(true);
-                    ttfFont = ttfParser.parse(ff2Stream.createInputStream());
+                    ttfFont = ttfParser.parse(ff2Stream.getCOSObject().createView());
                 }
                 catch (IOException e)
                 {

Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java?rev=1900937&r1=1900936&r2=1900937&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java Mon May 16 05:27:00 2022
@@ -40,6 +40,7 @@ import org.apache.fontbox.ttf.TrueTypeFo
 import org.apache.fontbox.util.autodetect.FontFileFinder;
 import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -143,7 +144,7 @@ class PDFontTest
             testPDFBox3826checkFonts(testPDFBox3826createDoc(ttf1), fontFile);
         }
 
-        try (TrueTypeFont ttf2 = new TTFParser().parse(new FileInputStream(fontFile)))
+        try (TrueTypeFont ttf2 = new TTFParser().parse(new RandomAccessReadBufferedFile(fontFile)))
         {
             testPDFBox3826checkFonts(testPDFBox3826createDoc(ttf2), fontFile);
         }