Skip to content

Commit 008b234

Browse files
author
Egor Martsynkovsky
committed
Close only streams created by IText in PdfReader constructor
Add tests DEVSIX-5705
1 parent d88a362 commit 008b234

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,12 @@ public class PdfReader implements Closeable, Serializable {
130130
* @throws IOException if an I/O error occurs
131131
*/
132132
public PdfReader(IRandomAccessSource byteSource, ReaderProperties properties) throws IOException {
133+
this(byteSource, properties, false);
134+
}
135+
136+
PdfReader(IRandomAccessSource byteSource, ReaderProperties properties, boolean closeStream) throws IOException {
133137
this.properties = properties;
134-
this.tokens = getOffsetTokeniser(byteSource);
138+
this.tokens = getOffsetTokeniser(byteSource, closeStream);
135139
}
136140

137141
/**
@@ -143,7 +147,7 @@ public PdfReader(IRandomAccessSource byteSource, ReaderProperties properties) th
143147
* @throws IOException on error
144148
*/
145149
public PdfReader(InputStream is, ReaderProperties properties) throws IOException {
146-
this(new RandomAccessSourceFactory().createSource(is), properties);
150+
this(new RandomAccessSourceFactory().createSource(is), properties, true);
147151
}
148152

149153
/**
@@ -180,7 +184,8 @@ public PdfReader(String filename, ReaderProperties properties) throws IOExceptio
180184
new RandomAccessSourceFactory()
181185
.setForceRead(false)
182186
.createBestSource(filename),
183-
properties
187+
properties,
188+
true
184189
);
185190
this.sourcePath = filename;
186191
}
@@ -1303,6 +1308,10 @@ private void readDecryptObj() {
13031308
}
13041309
}
13051310

1311+
private static PdfTokenizer getOffsetTokeniser(IRandomAccessSource byteSource) throws IOException {
1312+
return getOffsetTokeniser(byteSource, true);
1313+
}
1314+
13061315
/**
13071316
* Utility method that checks the provided byte source to see if it has junk bytes at the beginning. If junk bytes
13081317
* are found, construct a tokeniser that ignores the junk. Otherwise, construct a tokeniser for the byte source as it is
@@ -1311,7 +1320,8 @@ private void readDecryptObj() {
13111320
* @return a tokeniser that is guaranteed to start at the PDF header
13121321
* @throws IOException if there is a problem reading the byte source
13131322
*/
1314-
private static PdfTokenizer getOffsetTokeniser(IRandomAccessSource byteSource) throws IOException {
1323+
private static PdfTokenizer getOffsetTokeniser(IRandomAccessSource byteSource, boolean closeStream)
1324+
throws IOException {
13151325
com.itextpdf.io.IOException possibleException = null;
13161326
PdfTokenizer tok = new PdfTokenizer(new RandomAccessFileOrArray(byteSource));
13171327
int offset;
@@ -1321,7 +1331,7 @@ private static PdfTokenizer getOffsetTokeniser(IRandomAccessSource byteSource) t
13211331
possibleException = ex;
13221332
throw possibleException;
13231333
} finally {
1324-
if (possibleException != null) {
1334+
if (possibleException != null && closeStream) {
13251335
tok.close();
13261336
}
13271337
}

kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ This file is part of the iText (R) project.
4545
import com.itextpdf.io.LogMessageConstant;
4646
import com.itextpdf.io.source.ByteArrayOutputStream;
4747
import com.itextpdf.io.source.ByteUtils;
48+
import com.itextpdf.io.source.IRandomAccessSource;
49+
import com.itextpdf.io.source.RandomAccessSourceFactory;
4850
import com.itextpdf.io.util.FileUtil;
4951
import com.itextpdf.io.util.MessageFormatUtil;
5052
import com.itextpdf.kernel.PdfException;
@@ -53,6 +55,11 @@ This file is part of the iText (R) project.
5355
import com.itextpdf.test.annotations.LogMessage;
5456
import com.itextpdf.test.annotations.LogMessages;
5557
import com.itextpdf.test.annotations.type.IntegrationTest;
58+
59+
import java.io.FileInputStream;
60+
import java.io.InputStream;
61+
import java.nio.file.Files;
62+
import java.nio.file.Paths;
5663
import org.junit.Assert;
5764
import org.junit.BeforeClass;
5865
import org.junit.Ignore;
@@ -2012,6 +2019,38 @@ public void pdf11VersionValidTest() throws IOException {
20122019
new PdfDocument(new PdfReader(fileName));
20132020
}
20142021

2022+
@Test
2023+
public void closeStreamCreatedByITextTest() throws IOException {
2024+
String fileName = sourceFolder + "emptyPdf.pdf";
2025+
String copiedFileName = destinationFolder + "emptyPdf.pdf";
2026+
//Later in the test we will need to delete a file. Since we do not want to delete it from sources, we will
2027+
// copy it to destination folder.
2028+
File copiedFile = copyFileForTest(fileName, copiedFileName);
2029+
Exception e = Assert.assertThrows(com.itextpdf.io.IOException.class, () -> new PdfReader(fileName));
2030+
Assert.assertEquals(com.itextpdf.io.IOException.PdfHeaderNotFound, e.getMessage());
2031+
//This check is meaningfull only on Windows, since on other OS the fact of a stream being open doesn't
2032+
// prevent the stream from being deleted.
2033+
Assert.assertTrue(FileUtil.deleteFile(copiedFile));
2034+
}
2035+
2036+
@Test
2037+
public void notCloseUserStreamTest() throws IOException {
2038+
String fileName = sourceFolder + "emptyPdf.pdf";
2039+
try (InputStream pdfStream = new FileInputStream(fileName)) {
2040+
IRandomAccessSource randomAccessSource = new RandomAccessSourceFactory()
2041+
.createSource(pdfStream);
2042+
Exception e = Assert.assertThrows(com.itextpdf.io.IOException.class,
2043+
() -> new PdfReader(randomAccessSource, new ReaderProperties()));
2044+
//An exception would be thrown, if stream is closed.
2045+
Assert.assertEquals(-1, pdfStream.read());
2046+
}
2047+
}
2048+
private File copyFileForTest(String fileName, String copiedFileName) throws IOException {
2049+
File copiedFile = new File(copiedFileName);
2050+
Files.copy(Paths.get(fileName), Paths.get(copiedFileName));
2051+
return copiedFile;
2052+
}
2053+
20152054
private PdfReader pdfDocumentNotReadTestInit() throws IOException {
20162055
String filename = sourceFolder + "XrefWithNullOffsets.pdf";
20172056

kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfReaderTest/emptyPdf.pdf

Whitespace-only changes.

0 commit comments

Comments
 (0)