Skip to content

Commit 9a7f5ab

Browse files
committed
Add checks that Pdf Document has been completely read to the PdfReader.
DEVSIX-3139
1 parent 21d8ac2 commit 9a7f5ab

File tree

4 files changed

+379
-4
lines changed

4 files changed

+379
-4
lines changed

kernel/src/main/java/com/itextpdf/kernel/PdfException.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public class PdfException extends RuntimeException {
142142
public static final String DocumentDoesntContainStructTreeRoot = "Document doesn't contain StructTreeRoot.";
143143
public static final String DocumentHasNoPages = "Document has no pages.";
144144
public static final String DocumentHasNoPdfCatalogObject = "Document has no PDF Catalog object.";
145+
public static final String DocumentHasNotBeenReadYet = "The PDF document has not been read yet. Document reading occurs in PdfDocument class constructor";
145146
public static final String DocumentMustBePreClosed = "Document must be preClosed.";
146147
public static final String DocumentForCopyToCannotBeNull = "Document for copyTo cannot be null.";
147148
public static final String DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed = "During decompression multiple streams in sum occupied more memory than allowed. Please either check your pdf or increase the allowed single decompressed pdf stream maximum size value by setting the appropriate parameter of ReaderProperties's MemoryLimitsAwareHandler.";

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

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,13 @@ public void setCloseStream(boolean closeStream) {
225225
* If any exception generated while reading XRef section, PdfReader will try to rebuild it.
226226
*
227227
* @return true, if PdfReader rebuilt Cross-Reference section.
228+
* @throws PdfException, if the method has been invoked before the PDF document was read.
228229
*/
229230
public boolean hasRebuiltXref() {
231+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
232+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
233+
}
234+
230235
return rebuiltXref;
231236
}
232237

@@ -235,35 +240,57 @@ public boolean hasRebuiltXref() {
235240
* That Do Not Support Compressed Reference Streams" in PDF 32000-1:2008 spec.
236241
*
237242
* @return true, if the document has hybrid Cross-Reference section.
243+
* @throws PdfException, if the method has been invoked before the PDF document was read.
238244
*/
239245
public boolean hasHybridXref() {
246+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
247+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
248+
}
249+
240250
return hybridXref;
241251
}
242252

243253
/**
244254
* Indicates whether the document has Cross-Reference Streams.
245255
*
246256
* @return true, if the document has Cross-Reference Streams.
257+
* @throws PdfException, if the method has been invoked before the PDF document was read.
247258
*/
248259
public boolean hasXrefStm() {
260+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
261+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
262+
}
263+
249264
return xrefStm;
250265
}
251266

252267
/**
253268
* If any exception generated while reading PdfObject, PdfReader will try to fix offsets of all objects.
254-
*
269+
* <p>
270+
* This method's returned value might change over time, because PdfObjects reading
271+
* can be postponed even up to document closing.
255272
* @return true, if PdfReader fixed offsets of PdfObjects.
273+
* @throws PdfException, if the method has been invoked before the PDF document was read.
256274
*/
257275
public boolean hasFixedXref() {
276+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
277+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
278+
}
279+
258280
return fixedXref;
259281
}
260282

261283
/**
262284
* Gets position of the last Cross-Reference table.
263285
*
264286
* @return -1 if Cross-Reference table has rebuilt, otherwise position of the last Cross-Reference table.
287+
* @throws PdfException, if the method has been invoked before the PDF document was read.
265288
*/
266289
public long getLastXref() {
290+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
291+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
292+
}
293+
267294
return lastXref;
268295
}
269296

@@ -478,8 +505,13 @@ public long getFileLength() throws IOException {
478505
*
479506
* @return {@code true} if the document was opened with the owner password or if it's not encrypted,
480507
* {@code false} if the document was opened with the user password.
508+
* @throws PdfException, if the method has been invoked before the PDF document was read.
481509
*/
482510
public boolean isOpenedWithFullPermission() {
511+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
512+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
513+
}
514+
483515
return !encrypted || decrypt.isOpenedWithFullPermission() || unethicalReading;
484516
}
485517

@@ -489,8 +521,19 @@ public boolean isOpenedWithFullPermission() {
489521
* See ISO 32000-1, Table 22 for more details.
490522
*
491523
* @return the encryption permissions, an unsigned 32-bit quantity.
524+
* @throws PdfException, if the method has been invoked before the PDF document was read.
492525
*/
493526
public long getPermissions() {
527+
528+
/* !pdfDocument.getXref().isReadingCompleted() can be used for encryption properties as well,
529+
* because decrypt object is initialized in private readDecryptObj method which is called in our code
530+
* in the next line after the setting isReadingCompleted line. This means that there's no way for users
531+
* when this method would work incorrectly right now.
532+
*/
533+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
534+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
535+
}
536+
494537
long perm = 0;
495538
if (encrypted && decrypt.getPermissions() != null) {
496539
perm = (long) decrypt.getPermissions();
@@ -502,8 +545,13 @@ public long getPermissions() {
502545
* Gets encryption algorithm and access permissions.
503546
*
504547
* @see EncryptionConstants
548+
* @throws PdfException, if the method has been invoked before the PDF document was read.
505549
*/
506550
public int getCryptoMode() {
551+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
552+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
553+
}
554+
507555
if (decrypt == null)
508556
return -1;
509557
else
@@ -525,9 +573,17 @@ public PdfAConformanceLevel getPdfAConformanceLevel() {
525573
* Computes user password if standard encryption handler is used with Standard40, Standard128 or AES128 encryption algorithm.
526574
*
527575
* @return user password, or null if not a standard encryption handler was used or if ownerPasswordUsed wasn't use to open the document.
576+
* @throws PdfException, if the method has been invoked before the PDF document was read.
528577
*/
529578
public byte[] computeUserPassword() {
530-
if (!encrypted || !decrypt.isOpenedWithFullPermission()) return null;
579+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
580+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
581+
}
582+
583+
if (!encrypted || !decrypt.isOpenedWithFullPermission()) {
584+
return null;
585+
}
586+
531587
return decrypt.computeUserPassword(properties.password);
532588
}
533589

@@ -540,8 +596,13 @@ public byte[] computeUserPassword() {
540596
*
541597
* @return byte array represents original file ID.
542598
* @see PdfDocument#getOriginalDocumentId()
599+
* @throws PdfException, if the method has been invoked before the PDF document was read.
543600
*/
544601
public byte[] getOriginalFileId() {
602+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
603+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
604+
}
605+
545606
PdfArray id = trailer.getAsArray(PdfName.ID);
546607
if (id != null && id.size() == 2) {
547608
return ByteUtils.getIsoBytes(id.getAsString(0).getValue());
@@ -559,8 +620,13 @@ public byte[] getOriginalFileId() {
559620
*
560621
* @return byte array represents modified file ID.
561622
* @see PdfDocument#getModifiedDocumentId()
623+
* @throws PdfException, if the method has been invoked before the PDF document was read.
562624
*/
563625
public byte[] getModifiedFileId() {
626+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
627+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
628+
}
629+
564630
PdfArray id = trailer.getAsArray(PdfName.ID);
565631
if (id != null && id.size() == 2) {
566632
return ByteUtils.getIsoBytes(id.getAsString(1).getValue());
@@ -569,7 +635,14 @@ public byte[] getModifiedFileId() {
569635
}
570636
}
571637

638+
/**
639+
* @throws PdfException, if the method has been invoked before the PDF document was read.
640+
*/
572641
public boolean isEncrypted() {
642+
if (pdfDocument == null || !pdfDocument.getXref().isReadingCompleted()) {
643+
throw new PdfException(PdfException.DocumentHasNotBeenReadYet);
644+
}
645+
573646
return encrypted;
574647
}
575648

@@ -737,7 +810,7 @@ protected PdfObject readObject(boolean readAsDirect, boolean objStm) throws IOEx
737810
return new PdfNumber(tokens.getByteContent());
738811
case String: {
739812
PdfString pdfString = new PdfString(tokens.getByteContent(), tokens.isHexString());
740-
if (isEncrypted() && !decrypt.isEmbeddedFilesOnly() && !objStm) {
813+
if (encrypted && !decrypt.isEmbeddedFilesOnly() && !objStm) {
741814
pdfString.setDecryption(currentIndirectReference.getObjNumber(), currentIndirectReference.getGenNumber(), decrypt);
742815
}
743816
return pdfString;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ public void copying3() throws IOException {
170170
pdfDoc.close();
171171

172172
PdfReader reader = new PdfReader(destinationFolder + "copying3_1.pdf");
173-
assertEquals("Rebuilt", false, reader.hasRebuiltXref());
174173
pdfDoc = new PdfDocument(reader);
174+
assertEquals("Rebuilt", false, reader.hasRebuiltXref());
175175

176176
PdfDictionary dic0 = pdfDoc.getPage(1).getPdfObject().getAsDictionary(new PdfName("HelloWorld"));
177177
assertEquals(4, dic0.getIndirectReference().getObjNumber());

0 commit comments

Comments
 (0)