FreeReferencesTest.java
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2025 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itextpdf.kernel.pdf;
import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.TestUtil;
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
@Tag("IntegrationTest")
public class FreeReferencesTest extends ExtendedITextTest {
public static final String destinationFolder = TestUtil.getOutputPath() + "/kernel/pdf/FreeReferencesTest/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/FreeReferencesTest/";
@BeforeAll
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
@AfterAll
public static void afterClass() {
CompareTool.cleanup(destinationFolder);
}
@Test
public void freeReferencesTest01() throws IOException {
String src = "freeRefsGapsAndMaxGen.pdf";
String out = "freeReferencesTest01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 15\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000000 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" };
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest02() throws IOException {
String src = "freeRefsGapsAndMaxGen.pdf";
String out = "freeReferencesTest02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 5\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000569 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"10 5\n" +
"0000000011 00000 f \n" + // Append mode, no possibility to fix subsections in first xref
"0000000000 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000480 00000 n \n",
"xref\n" +
"3 1\n" +
"0000000995 00000 n \n"};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest03() throws IOException {
String src = "freeRefsDeletedObj.pdf";
String out = "freeReferencesTest03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.addNewPage();
// fix page content
PdfStream firstPageContentStream = pdfDocument.getPage(1).getContentStream(0);
String firstPageData = new String(firstPageContentStream.getBytes());
firstPageContentStream.setData((firstPageData.substring(0, firstPageData.lastIndexOf("BT")) + "ET").getBytes());
firstPageContentStream.setModified();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000000 65535 f \n" +
"0000000265 00000 n \n" +
"0000000564 00000 n \n" +
"0000000310 00000 n \n" +
"0000000132 00000 n \n" +
"0000000015 00001 n \n" +
"0000000476 00000 n \n",
"xref\n" +
"0 1\n" +
"0000000005 65535 f \n" +
"3 3\n" +
"0000000923 00000 n \n" +
"0000001170 00000 n \n" +
"0000000000 00002 f \n" +
"7 1\n" +
"0000001303 00000 n \n",
"xref\n" +
"1 3\n" +
"0000001706 00000 n \n" +
"0000001998 00000 n \n" +
"0000001751 00000 n \n" +
"7 3\n" +
"0000002055 00000 n \n" +
"0000002171 00000 n \n" +
"0000002272 00000 n \n"};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest04() throws IOException {
String src = "simpleDoc.pdf";
String out = "freeReferencesTest04.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfObject contentsObj = pdfDocument.getPage(1).getPdfObject().remove(PdfName.Contents);
Assertions.assertTrue(contentsObj instanceof PdfIndirectReference);
PdfIndirectReference contentsRef = (PdfIndirectReference) contentsObj;
contentsRef.setFree();
PdfObject freedContentsRefRefersTo = contentsRef.getRefersTo();
Assertions.assertNull(freedContentsRefRefersTo);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000005 65535 f \n" +
"0000000133 00000 n \n" +
"0000000425 00000 n \n" +
"0000000178 00000 n \n" +
"0000000015 00000 n \n" +
"0000000000 00001 f \n" +
"0000000476 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest05() throws IOException {
String src = "simpleDocWithSubsections.pdf";
String out = "freeReferencesTest05.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 14\n" +
"0000000004 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000005 00000 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000010 00000 f \n" +
"0000000000 00000 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest06() throws IOException {
String src = "simpleDocWithSubsections.pdf";
String out = "freeReferencesTest06.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 4\n" +
"0000000000 65535 f \n" +
"0000000269 00000 n \n" +
"0000000569 00000 n \n" +
"0000000314 00000 n \n" +
"11 3\n" +
"0000000133 00000 n \n" + // Append mode, no possibility to fix subsections in first xref
"0000000015 00000 n \n" +
"0000000480 00000 n \n",
"xref\n" +
"3 1\n" +
"0000000935 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest07() throws IOException {
String out = "freeReferencesTest07.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.createNextIndirectReference();
pdfDocument.addNewPage();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000004 65535 f \n" +
"0000000203 00000 n \n" +
"0000000414 00000 n \n" +
"0000000248 00000 n \n" +
"0000000000 00001 f \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeReferencesTest08() throws IOException {
String src = "simpleDoc.pdf";
String out = "freeReferencesTest08.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
PdfObject contentsObj = pdfDocument.getPage(1).getPdfObject().remove(PdfName.Contents);
pdfDocument.getPage(1).setModified();
Assertions.assertTrue(contentsObj instanceof PdfIndirectReference);
PdfIndirectReference contentsRef = (PdfIndirectReference) contentsObj;
contentsRef.setFree();
PdfObject freedContentsRefRefersTo = contentsRef.getRefersTo();
Assertions.assertNull(freedContentsRefRefersTo);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000000 65535 f \n" +
"0000000265 00000 n \n" +
"0000000564 00000 n \n" +
"0000000310 00000 n \n" +
"0000000132 00000 n \n" +
"0000000015 00000 n \n" +
"0000000476 00000 n \n",
"xref\n" +
"0 1\n" +
"0000000005 65535 f \n" +
"3 3\n" +
"0000000923 00000 n \n" +
"0000001170 00000 n \n" +
"0000000000 00001 f \n"
};
compareXrefTables(xrefString, expected);
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ALREADY_FLUSHED_INDIRECT_OBJECT_MADE_FREE))
public void freeARefInWrongWayTest01() throws IOException {
String out = "freeARefInWrongWayTest01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.addNewPage();
PdfDictionary catalogDict = pdfDocument.getCatalog().getPdfObject();
String outerString = "Outer array. Contains inner array at both 0 and 1 index. At 0 - as pdf object, at 1 - as in ref.";
String innerString = "Inner array.";
String description = "Inner array first flushed, then it's ref is made free.";
PdfArray a1 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
PdfArray a2 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
a1.add(a2);
a1.add(a2.getIndirectReference());
a1.add(new PdfString(outerString));
a1.add(new PdfString(description));
a2.add(new PdfString(innerString));
catalogDict.put(new PdfName("TestArray"), a1);
a2.flush();
a2.getIndirectReference().setFree();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000000 65535 f \n" +
"0000000235 00000 n \n" +
"0000000462 00000 n \n" +
"0000000296 00000 n \n" +
"0000000120 00000 n \n" +
"0000000047 00000 n \n" +
"0000000513 00000 n \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.FLUSHED_OBJECT_CONTAINS_FREE_REFERENCE, count = 2))
public void freeARefInWrongWayTest02() throws IOException {
String out = "freeARefInWrongWayTest02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.addNewPage();
PdfDictionary catalogDict = pdfDocument.getCatalog().getPdfObject();
String outerString = "Outer array. Contains inner array at both 0 and 1 index. At 0 - as pdf object, at 1 - as in ref.";
String innerString = "Inner array.";
String description = "Inner array ref made free, then outer array is flushed.";
PdfArray a1 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
PdfArray a2 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
a1.add(a2);
a1.add(a2.getIndirectReference());
a1.add(new PdfString(outerString));
a1.add(new PdfString(description));
a2.add(new PdfString(innerString));
catalogDict.put(new PdfName("TestArray"), a1);
a2.getIndirectReference().setFree();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
Assertions.assertTrue(a1.get(1, false) instanceof PdfIndirectReference);
Assertions.assertTrue(((PdfIndirectReference)a1.get(1, false)).isFree());
a1.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000007 65535 f \n" +
"0000000432 00000 n \n" +
"0000000659 00000 n \n" +
"0000000493 00000 n \n" +
"0000000317 00000 n \n" +
"0000000244 00000 n \n" +
"0000000060 00000 n \n" +
"0000000000 00001 f \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.INDIRECT_REFERENCE_USED_IN_FLUSHED_OBJECT_MADE_FREE))
public void freeARefInWrongWayTest03() throws IOException {
String out = "freeARefInWrongWayTest03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.addNewPage();
PdfDictionary catalogDict = pdfDocument.getCatalog().getPdfObject();
String outerString = "Outer array. Contains inner array at both 0 and 1 index. At 0 - as pdf object, at 1 - as in ref.";
String innerString = "Inner array.";
String description = "Outer array is flushed, then inner array ref made free.";
PdfArray a1 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
PdfArray a2 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
a1.add(a2);
a1.add(a2.getIndirectReference());
a1.add(new PdfString(outerString));
a1.add(new PdfString(description));
a2.add(new PdfString(innerString));
catalogDict.put(new PdfName("TestArray"), a1);
a1.flush();
a2.getIndirectReference().setFree();
Assertions.assertFalse(a2.getIndirectReference().isFree());
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000000 65535 f \n" +
"0000000431 00000 n \n" +
"0000000658 00000 n \n" +
"0000000492 00000 n \n" +
"0000000316 00000 n \n" +
"0000000243 00000 n \n" +
"0000000015 00000 n \n" +
"0000000709 00000 n \n" +
"0000000201 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ALREADY_FLUSHED_INDIRECT_OBJECT_MADE_FREE))
public void freeARefInWrongWayTest04() throws IOException {
String out = "freeARefInWrongWayTest04.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.addNewPage();
PdfDictionary catalogDict = pdfDocument.getCatalog().getPdfObject();
String outerString = "Outer array. Contains inner array at both 0 and 1 index. At 0 - as pdf object, at 1 - as in ref.";
String innerString = "Inner array.";
String description = "Outer array is flushed, then inner array ref made free.";
PdfArray a1 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
PdfArray a2 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
a1.add(a2);
a1.add(a2.getIndirectReference());
a1.add(new PdfString(outerString));
a1.add(new PdfString(description));
a2.add(new PdfString(innerString));
catalogDict.put(new PdfName("TestArray"), a1);
a1.flush();
a2.flush();
a2.getIndirectReference().setFree();
Assertions.assertFalse(a2.getIndirectReference().isFree());
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000000 65535 f \n" +
"0000000431 00000 n \n" +
"0000000658 00000 n \n" +
"0000000492 00000 n \n" +
"0000000316 00000 n \n" +
"0000000243 00000 n \n" +
"0000000015 00000 n \n" +
"0000000709 00000 n \n" +
"0000000201 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref01() throws IOException {
String out = "freeRefsAtEndOfXref01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + out));
pdfDocument.addNewPage();
PdfDictionary catalogDict = pdfDocument.getCatalog().getPdfObject();
String outerString = "Outer array. Contains inner array at both 0 and 1 index. At 0 - as pdf object, at 1 - as ind ref.";
String innerString = "Inner array.";
String description = "Last entry in the document xref table is free";
PdfArray a1 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
PdfArray a2 = (PdfArray) new PdfArray().makeIndirect(pdfDocument);
a1.add(a2);
a1.add(a2.getIndirectReference());
a1.add(new PdfString(outerString));
a1.add(new PdfString(description));
a2.add(new PdfString(innerString));
catalogDict.put(new PdfName("TestArray"), a1);
new PdfArray()
.makeIndirect(pdfDocument)
.getIndirectReference()
.setFree();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000000 65535 f \n" +
"0000000203 00000 n \n" +
"0000000430 00000 n \n" +
"0000000264 00000 n \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n" +
"0000000481 00000 n \n" +
"0000000658 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref02() throws IOException {
String src = "lastXrefEntryFree.pdf";
String out = "freeRefsAtEndOfXref02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000000 65535 f \n" +
"0000000203 00000 n \n" +
"0000000511 00000 n \n" +
"0000000264 00000 n \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n" +
"0000000562 00000 n \n" +
"0000000739 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref03() throws IOException {
String src = "lastXrefEntryFree.pdf";
String out = "freeRefsAtEndOfXref03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
new PdfArray()
.makeIndirect(pdfDocument)
.getIndirectReference()
.setFree();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 11\n" +
"0000000008 65535 f \n" +
"0000000246 00000 n \n" +
"0000000554 00000 n \n" +
"0000000307 00000 n \n" +
"0000000131 00000 n \n" +
"0000000058 00000 n \n" +
"0000000605 00000 n \n" +
"0000000782 00000 n \n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref04() throws IOException {
String src = "lastXrefEntryFree.pdf";
String out = "freeRefsAtEndOfXref04.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000008 65535 f \n" +
"0000000203 00000 n \n" +
"0000000430 00000 n \n" +
"0000000264 00000 n \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n" +
"0000000481 00000 n \n" +
"0000000658 00000 n \n" +
"0000000000 00001 f \n",
"xref\n" +
"3 1\n" +
"0000001038 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref05() throws IOException {
String src = "lastXrefEntryFree.pdf";
String out = "freeRefsAtEndOfXref05.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
new PdfArray()
.makeIndirect(pdfDocument)
.getIndirectReference()
.setFree();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000008 65535 f \n" +
"0000000203 00000 n \n" +
"0000000430 00000 n \n" +
"0000000264 00000 n \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n" +
"0000000481 00000 n \n" +
"0000000658 00000 n \n" +
"0000000000 00001 f \n",
"xref\n" +
"3 1\n" +
"0000001038 00000 n \n" +
"8 2\n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsAtEndOfXref06() throws IOException {
String src = "lastXrefEntryFree.pdf";
String out = "freeRefsAtEndOfXref06.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
new PdfArray()
.makeIndirect(pdfDocument)
.getIndirectReference()
.setFree();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 9\n" +
"0000000008 65535 f \n" +
"0000000203 00000 n \n" +
"0000000430 00000 n \n" +
"0000000264 00000 n \n" +
"0000000088 00000 n \n" +
"0000000015 00000 n \n" +
"0000000481 00000 n \n" +
"0000000658 00000 n \n" +
"0000000000 00001 f \n",
"xref\n" +
"3 1\n" +
"0000001081 00000 n \n" +
"8 3\n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n" +
"0000001038 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void notUsedIndRef01() throws IOException {
String src = "freeRefsDeletedObj.pdf";
String out = "notUsedIndRef01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
PdfIndirectReference newIndRef1 = pdfDocument.createNextIndirectReference();
PdfIndirectReference newIndRef2 = pdfDocument.createNextIndirectReference();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 11\n" +
"0000000005 65535 f \n" +
"0000000308 00000 n \n" +
"0000000600 00000 n \n" +
"0000000353 00000 n \n" +
"0000000175 00000 n \n" +
"0000000008 00002 f \n" +
"0000000651 00000 n \n" +
"0000000058 00000 n \n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void notUsedIndRef02() throws IOException {
String src = "freeRefsDeletedObj.pdf";
String out = "notUsedIndRef02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(false);
PdfIndirectReference newIndRef1 = pdfDocument.createNextIndirectReference();
PdfIndirectReference newIndRef2 = pdfDocument.createNextIndirectReference();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 11\n" +
"0000000005 65535 f \n" +
"0000000308 00000 n \n" +
"0000000600 00000 n \n" +
"0000000353 00000 n \n" +
"0000000175 00000 n \n" +
"0000000008 00002 f \n" +
"0000000651 00000 n \n" +
"0000000058 00000 n \n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n" +
"0000000015 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void notUsedIndRef03() throws IOException {
String src = "freeRefsDeletedObj.pdf";
String out = "notUsedIndRef03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
PdfIndirectReference newIndRef1 = pdfDocument.createNextIndirectReference();
PdfIndirectReference newIndRef2 = pdfDocument.createNextIndirectReference();
List<PdfObject> objects = Arrays.asList(new PdfObject[]{new PdfString("The answer to life is "), new PdfNumber(42)});
new PdfArray(objects)
.makeIndirect(pdfDocument)
.flush();
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000000 65535 f \n" +
"0000000265 00000 n \n" +
"0000000564 00000 n \n" +
"0000000310 00000 n \n" +
"0000000132 00000 n \n" +
"0000000015 00001 n \n" +
"0000000476 00000 n \n",
"xref\n" +
"0 1\n" +
"0000000005 65535 f \n" +
"3 3\n" +
"0000000923 00000 n \n" +
"0000001170 00000 n \n" +
"0000000000 00002 f \n" +
"7 1\n" +
"0000001303 00000 n \n",
"xref\n" +
"3 1\n" +
"0000001749 00000 n \n" +
"5 1\n" +
"0000000008 00002 f \n" +
"8 3\n" +
"0000000009 00001 f \n" +
"0000000000 00001 f \n" +
"0000001706 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.INVALID_INDIRECT_REFERENCE))
public void corruptedDocIndRefToFree01() throws IOException {
String src = "corruptedDocIndRefToFree.pdf";
String out = "corruptedDocIndRefToFree01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.close();
pdfDocument = new PdfDocument(CompareTool.createOutputReader(destinationFolder + out));
PdfObject contentsObj = pdfDocument.getPage(1).getPdfObject().get(PdfName.Contents);
Assertions.assertEquals(PdfNull.PDF_NULL, contentsObj);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 7\n" +
"0000000005 65535 f \n" +
"0000000147 00000 n \n" +
"0000000439 00000 n \n" +
"0000000192 00000 n \n" +
"0000000015 00000 n \n" +
"0000000000 00001 f \n" +
"0000000490 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling01() throws IOException {
String src = "invalidFreeRefsList01.pdf";
String out = "invalidFreeRefsListHandling01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 15\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00000 f \n" +
"0000000000 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling02() throws IOException {
String src = "invalidFreeRefsList02.pdf";
String out = "invalidFreeRefsListHandling02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000000 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling03() throws IOException {
String src = "invalidFreeRefsList03.pdf";
String out = "invalidFreeRefsListHandling03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000000 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling04() throws IOException {
String src = "invalidFreeRefsList04.pdf";
String out = "invalidFreeRefsListHandling04.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000006 65535 f \n" +
"0000000004 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000000 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling05() throws IOException {
String src = "invalidFreeRefsList05.pdf";
String out = "invalidFreeRefsListHandling05.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000005 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000010 00000 f \n" +
"0000000011 00000 f \n" +
"0000000015 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000000 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling06() throws IOException {
String src = "invalidFreeRefsList06.pdf";
String out = "invalidFreeRefsListHandling06.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000000 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling07() throws IOException {
String src = "invalidFreeRefsList07.pdf";
String out = "invalidFreeRefsListHandling07.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
pdfDocument.setFlushUnusedObjects(true);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n" +
"0000000016 00001 f \n" +
"0000000004 00001 f \n" +
"0000000702 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling08() throws IOException {
String src = "invalidFreeRefsList08.pdf";
String out = "invalidFreeRefsListHandling08.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000315 00000 n \n" +
"0000000607 00000 n \n" +
"0000000360 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000179 00000 n \n" +
"0000000061 00000 n \n" +
"0000000659 00000 n \n" +
"0000000016 00001 f \n" +
"0000000002 00001 f \n" +
"0000000015 00000 n \n",
"xref\n" +
"3 1\n" +
"0000001278 00000 n \n" +
"16 1\n" +
"0000000000 00001 f \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling09() throws IOException {
String src = "invalidFreeRefsList09.pdf";
String out = "invalidFreeRefsListHandling09.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000315 00000 n \n" +
"0000000607 00000 n \n" +
"0000000360 00000 n \n" +
"0009999999 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000179 00000 n \n" +
"0000000061 00000 n \n" +
"0000000659 00000 n \n" +
"0000999999 00001 f \n" +
"0000000000 00001 f \n" +
"0000000015 00000 n \n",
"xref\n" +
"3 2\n" +
"0000001278 00000 n \n" +
"0000000016 65535 f \n" +
"15 1\n" +
"0000000004 00001 f \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void invalidFreeRefsListHandling10() throws IOException {
String src = "invalidFreeRefsList10.pdf";
String out = "invalidFreeRefsListHandling10.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out),
new StampingProperties().useAppendMode());
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 18\n" +
"0000000010 65535 f \n" +
"0000000315 00000 n \n" +
"0000000607 00000 n \n" +
"0000000360 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000002 00000 f \n" +
"0000000016 00000 f \n" +
"0000000009 00000 f \n" +
"0000000015 00000 f \n" +
"0000000011 00000 f \n" +
"0000000005 00001 f \n" +
"0000000179 00000 n \n" +
"0000000061 00000 n \n" +
"0000000659 00000 n \n" +
"0000000016 00001 f \n" +
"0000000008 00001 f \n" +
"0000000015 00000 n \n",
"xref\n" +
"3 1\n" +
"0000001278 00000 n \n" +
"6 2\n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"16 1\n" +
"0000000000 00001 f \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsXrefStream01() throws IOException {
String src = "freeRefsGapsAndListSpecificOrder.pdf";
String out1 = "freeRefsXrefStream01_xrefStream.pdf";
String out2 = "freeRefsXrefStream01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src),
CompareTool.createTestPdfWriter(destinationFolder + out1, new WriterProperties().setFullCompressionMode(true)));
pdfDocument.close();
pdfDocument = new PdfDocument(CompareTool.createOutputReader(destinationFolder + out1),
new PdfWriter(destinationFolder + out2, new WriterProperties().setFullCompressionMode(false)));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out2);
String[] expected = new String[] {
"xref\n" +
"0 15\n" +
"0000000011 65535 f \n" +
"0000000269 00000 n \n" +
"0000000561 00000 n \n" +
"0000000314 00000 n \n" +
"0000000000 65535 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000000 00000 f \n" +
"0000000005 00000 f \n" +
"0000000010 00001 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000613 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
/**
* Free refs reusing is disabled at the moment, however it might be valuable to keep an eye on such case,
* in case something will change.
*/
@Test
public void freeRefsReusingTest01() throws IOException {
String src = "simpleDoc.pdf";
String out = "freeRefsReusingTest01.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
pdfDocument.getCatalog().put(new PdfName("TestKey"), newIndObj);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000000 65535 f \n" +
"0000000265 00000 n \n" +
"0000000571 00000 n \n" +
"0000000324 00000 n \n" +
"0000000132 00000 n \n" +
"0000000015 00000 n \n" +
"0000000622 00000 n \n" +
"0000000710 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
/**
* Free refs reusing is disabled at the moment, however it might be valuable to keep an eye on such case,
* in case something will change.
*/
@Test
public void freeRefsReusingTest02() throws IOException {
String src = "simpleDocWithSubsections.pdf";
String out = "freeRefsReusingTest02.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
pdfDocument.getCatalog().put(new PdfName("TestKey"), newIndObj);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 15\n" +
"0000000004 65535 f \n" +
"0000000269 00000 n \n" +
"0000000576 00000 n \n" +
"0000000329 00000 n \n" +
"0000000005 00000 f \n" +
"0000000006 00000 f \n" +
"0000000007 00000 f \n" +
"0000000008 00000 f \n" +
"0000000009 00000 f \n" +
"0000000010 00000 f \n" +
"0000000000 00000 f \n" +
"0000000133 00000 n \n" +
"0000000015 00000 n \n" +
"0000000628 00000 n \n" +
"0000000717 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
/**
* Free refs reusing is disabled at the moment, however it might be valuable to keep an eye on such case,
* in case something will change.
*/
@Test
public void freeRefsReusingTest03() throws IOException {
String src = "simpleDocWithFreeList.pdf";
String out = "freeRefsReusingTest03.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
pdfDocument.getCatalog().put(new PdfName("TestKey"), newIndObj);
pdfDocument.getCatalog().put(new PdfName("TestKey2"), pdfDocument.getPdfObject(10));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 12\n" +
"0000000009 65535 f \n" +
"0000000265 00000 n \n" +
"0000000588 00000 n \n" +
"0000000341 00000 n \n" +
"0000000132 00000 n \n" +
"0000000000 00002 f \n" +
"0000000639 00000 n \n" +
"0000000015 00000 n \n" +
"0000000005 00001 f \n" +
"0000000008 00001 f \n" +
"0000000727 00000 n \n" +
"0000000773 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
/**
* Free refs reusing is disabled at the moment, however it might be valuable to keep an eye on such cases,
* if something will change in future.
*/
@Test
public void freeRefsReusingTest04() throws IOException {
String src = "freeRefsMaxGenOnly.pdf";
String out = "freeRefsReusingTest04.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
pdfDocument.getCatalog().put(new PdfName("TestKey"), newIndObj);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000005 65535 f \n" +
"0000000133 00000 n \n" +
"0000000439 00000 n \n" +
"0000000192 00000 n \n" +
"0000000015 00000 n \n" +
"0000000000 65535 f \n" +
"0000000490 00000 n \n" +
"0000000578 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
/**
* Free refs reusing is disabled at the moment, however it might be valuable to keep an eye on such case,
* in case something will change.
*/
@Test
public void freeRefsReusingTest05() throws IOException {
String src = "simpleDocWithFreeList.pdf";
String out = "freeRefsReusingTest05.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
newIndObj.getIndirectReference().setFree();
pdfDocument.getCatalog().put(new PdfName("TestKey"), pdfDocument.getPdfObject(10));
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 11\n" +
"0000000009 65535 f \n" +
"0000000265 00000 n \n" +
"0000000572 00000 n \n" +
"0000000325 00000 n \n" +
"0000000132 00000 n \n" +
"0000000000 00002 f \n" +
"0000000623 00000 n \n" +
"0000000015 00000 n \n" +
"0000000005 00001 f \n" +
"0000000008 00001 f \n" +
"0000000711 00000 n \n",
};
compareXrefTables(xrefString, expected);
}
@Test
public void freeRefsReusingTest06() throws IOException {
String src = "simpleDoc.pdf";
String out = "freeRefsReusingTest06.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + src), new PdfWriter(destinationFolder + out));
PdfObject contentsObj = pdfDocument.getPage(1).getPdfObject().remove(PdfName.Contents);
Assertions.assertTrue(contentsObj instanceof PdfIndirectReference);
PdfIndirectReference contentsRef = (PdfIndirectReference) contentsObj;
contentsRef.setFree();
PdfString s = new PdfString("New indirect object in the document.");
PdfArray newIndObj = (PdfArray) new PdfArray(Collections.<PdfObject>singletonList(s))
.makeIndirect(pdfDocument);
pdfDocument.getCatalog().put(new PdfName("TestKey"), newIndObj);
pdfDocument.close();
String[] xrefString = extractXrefTableAsStrings(out);
String[] expected = new String[] {
"xref\n" +
"0 8\n" +
"0000000005 65535 f \n" +
"0000000133 00000 n \n" +
"0000000439 00000 n \n" +
"0000000192 00000 n \n" +
"0000000015 00000 n \n" +
"0000000000 00001 f \n" +
"0000000490 00000 n \n" +
"0000000578 00000 n \n"
};
compareXrefTables(xrefString, expected);
}
@Test
public void readingXrefWithLotsOfFreeObjTest() throws IOException {
String input = sourceFolder + "readingXrefWithLotsOfFreeObj.pdf";
String output = destinationFolder + "result_readingXrefWithLotsOfFreeObj.pdf";
//Test for array out of bounds when a pdf contains multiple free references
PdfDocument doc = new PdfDocument(new PdfReader(input), CompareTool.createTestPdfWriter(output));
int actualNumberOfObj = doc.getNumberOfPdfObjects();
Assertions.assertEquals(68, actualNumberOfObj);
Assertions.assertNull(doc.getPdfObject(7));
PdfXrefTable xref = doc.getXref();
int freeRefsCount = 0;
for (int i = 0; i < xref.size(); i++) {
if (xref.get(i).isFree()) {
freeRefsCount = freeRefsCount + 1;
}
}
Assertions.assertEquals(31, freeRefsCount);
doc.close();
}
private void compareXrefTables(String[] xrefString, String[] expected) {
Assertions.assertEquals(expected.length, xrefString.length);
for (int i = 0; i < xrefString.length; ++i) {
if (!compareXrefSection(xrefString[i], expected[i])) {
// XrefTables are different. Use Assert method in order to show differences gracefully.
Assertions.assertArrayEquals(expected, xrefString);
}
}
}
private boolean compareXrefSection(String xrefSection, String expectedSection) {
String[] xrefEntries = xrefSection.split("\n");
String[] expectedEntries = expectedSection.split("\n");
if (xrefEntries.length != expectedEntries.length) {
return false;
}
for (int i = 0; i < xrefEntries.length; ++i) {
String actual = xrefEntries[i].trim();
String expected = expectedEntries[i].trim();
if (actual.endsWith("n")) {
actual = actual.substring(10);
expected = expected.substring(10);
}
if (!actual.equals(expected)) {
return false;
}
}
return true;
}
private String[] extractXrefTableAsStrings(String out) throws IOException {
byte[] outPdfBytes = readFile(destinationFolder + out);
String outPdfContent = new String(outPdfBytes, StandardCharsets.US_ASCII);
String xrefStr = "\nxref";
String trailerStr = "trailer";
int xrefInd = outPdfContent.indexOf(xrefStr);
int trailerInd = outPdfContent.indexOf(trailerStr);
int lastXrefInd = outPdfContent.lastIndexOf(xrefStr);
List<String> xrefs = new ArrayList<>();
while (true) {
xrefs.add(outPdfContent.substring(xrefInd + 1, trailerInd));
if (xrefInd == lastXrefInd) {
break;
}
xrefInd = outPdfContent.indexOf(xrefStr, xrefInd + 1);
trailerInd = outPdfContent.indexOf(trailerStr, trailerInd + 1);
}
return xrefs.toArray(new String[xrefs.size()]);
}
}