Skip to content

Commit 51cd040

Browse files
Fix for reading very small PDF files (#1334)
1 parent e97338d commit 51cd040

File tree

3 files changed

+70
-10
lines changed

3 files changed

+70
-10
lines changed

openpdf/src/main/java/com/lowagie/text/pdf/MappedRandomAccessFile.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
import java.io.FileInputStream;
5353
import java.io.FileNotFoundException;
5454
import java.io.IOException;
55-
import java.nio.BufferUnderflowException;
5655
import java.nio.channels.FileChannel;
5756

5857
/**
@@ -114,20 +113,24 @@ public FileChannel getChannel() {
114113
}
115114

116115
/**
117-
* @return int next integer or -1 on EOF
116+
* @return int next byte value or -1 on EOF
118117
* @see java.io.RandomAccessFile#read()
119118
*/
120119
public int read() {
121-
try {
122-
byte b = mappedByteBuffer.get();
123-
int n = b & 0xff;
120+
long pos = mappedByteBuffer.position();
121+
long limit = mappedByteBuffer.limit();
124122

125-
return n;
126-
} catch (BufferUnderflowException e) {
123+
if (pos >= limit) {
127124
return -1; // EOF
128125
}
126+
127+
byte b = mappedByteBuffer.get(pos);
128+
mappedByteBuffer.position(pos + 1);
129+
return b & 0xFF;
129130
}
130131

132+
133+
131134
/**
132135
* @param bytes byte[]
133136
* @param off int offset

openpdf/src/main/java/com/lowagie/text/utils/LongMappedByteBuffer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
package com.lowagie.text.utils;
5151

5252
import java.io.IOException;
53+
import java.nio.BufferUnderflowException;
5354
import java.nio.ByteBuffer;
5455
import java.nio.MappedByteBuffer;
5556
import java.nio.channels.FileChannel;
@@ -91,16 +92,17 @@ public byte get() {
9192
}
9293

9394
public byte get(long pos) {
95+
if (pos >= size) {
96+
throw new BufferUnderflowException(); // triggers EOF handling in MappedRandomAccessFile
97+
}
9498
int chunkIndex = (int) (pos / CHUNK_SIZE);
9599
int offset = (int) (pos % CHUNK_SIZE);
96100
MappedByteBuffer chunk = chunks[chunkIndex];
97-
if (offset >= chunk.limit()) {
98-
throw new IndexOutOfBoundsException("Offset " + offset + " >= chunk limit " + chunk.limit());
99-
}
100101
return chunk.get(offset);
101102
}
102103

103104

105+
104106
public void get(long pos, byte[] dst, int off, int len) {
105107
if (off < 0 || len < 0 || off + len > dst.length) {
106108
throw new IndexOutOfBoundsException("Invalid offset/length");
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.lowagie.text.pdf;
2+
3+
import com.lowagie.text.Document;
4+
import com.lowagie.text.DocumentException;
5+
import com.lowagie.text.Paragraph;
6+
import java.io.File;
7+
import java.io.FileOutputStream;
8+
import java.io.IOException;
9+
import java.io.OutputStream;
10+
import org.junit.jupiter.api.Assertions;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.io.TempDir;
13+
14+
15+
/**
16+
* Test for small PDF files in MappedRandomAccessFile
17+
*/
18+
public class SmallPdfReadTest {
19+
20+
@Test
21+
public void testEOFHandlingInMappedRandomAccessFile(@TempDir File tempDir) throws IOException, DocumentException {
22+
File pdfFile = new File(tempDir, "tiny.pdf");
23+
pdfFile.deleteOnExit();
24+
25+
// 1. Create a tiny PDF file
26+
try (OutputStream outputStream = new FileOutputStream(pdfFile)) {
27+
Document document = new Document();
28+
PdfWriter.getInstance(document, outputStream);
29+
document.open();
30+
document.add(new Paragraph("Minimal content"));
31+
document.close();
32+
}
33+
34+
Assertions.assertTrue(pdfFile.length() < 1024, "PDF should be under 1KiB");
35+
36+
// 2. Open with MappedRandomAccessFile and seek to EOF
37+
try (MappedRandomAccessFile raf = new MappedRandomAccessFile(pdfFile.getAbsolutePath(), "r")) {
38+
long length = pdfFile.length();
39+
raf.seek(length); // Seek to exactly EOF
40+
41+
// 3. Try to read past EOF — should return -1, not throw
42+
int result = raf.read();
43+
44+
// BUG: This currently throws IndexOutOfBoundsException instead of returning -1
45+
Assertions.assertEquals(-1, result, "Expected -1 at EOF, but read returned: " + result);
46+
}
47+
48+
System.gc();
49+
try {
50+
Thread.sleep(100); // give GC time to release mapped file
51+
} catch (InterruptedException e) {
52+
throw new RuntimeException(e);
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)