Skip to content

Commit a0fc8b8

Browse files
committed
Fix cyclic references handling in struct tree parent
DEVSIX-8616
1 parent a6e77ae commit a0fc8b8

File tree

4 files changed

+25
-4
lines changed

4 files changed

+25
-4
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopier.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ This file is part of the iText (R) project.
4343
import java.util.List;
4444
import java.util.Map;
4545
import java.util.Set;
46+
47+
import com.itextpdf.kernel.pdf.tagutils.TagTreeIterator;
4648
import org.slf4j.Logger;
4749
import org.slf4j.LoggerFactory;
4850

@@ -629,11 +631,14 @@ private static PdfDictionary getTopmostParent(PdfMcr mcr) {
629631
}
630632

631633
private static List<PdfDictionary> retrieveParents(PdfMcr mcr, boolean all) {
632-
List<PdfDictionary> parents = new ArrayList<>();
633-
IStructureNode firstParent = mcr.getParent();
634+
final Set<PdfDictionary> parents = new LinkedHashSet<>();
635+
final IStructureNode firstParent = mcr.getParent();
634636
PdfDictionary previous = null;
635637
PdfDictionary current = firstParent instanceof PdfStructElem ? ((PdfStructElem) firstParent).getPdfObject() : null;
636-
while (current != null && !PdfName.StructTreeRoot.equals(current.getAsName(PdfName.Type))) {
638+
639+
while (current != null
640+
&& !PdfName.StructTreeRoot.equals(current.getAsName(PdfName.Type))
641+
&& !parents.contains(current)) {
637642
if (all) {
638643
parents.add(current);
639644
}
@@ -643,7 +648,7 @@ private static List<PdfDictionary> retrieveParents(PdfMcr mcr, boolean all) {
643648
if (!all) {
644649
parents.add(previous);
645650
}
646-
return parents;
651+
return new ArrayList<>(parents);
647652
}
648653

649654
static class LastClonedAncestor {

kernel/src/test/java/com/itextpdf/kernel/utils/PdfMergerTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,22 @@ public void mergeDocumentTest02() throws IOException, InterruptedException {
162162
Assertions.assertNull(new CompareTool().compareByContent(resultFile, sourceFolder + "cmp_mergedResult02.pdf", destinationFolder, "diff_"));
163163
}
164164

165+
@Test
166+
public void mergeDocumentWithCycleTagReferenceTest() throws IOException, InterruptedException {
167+
String filename1 = sourceFolder + "doc1.pdf";
168+
String filename2 = sourceFolder + "pdfWithCycleRefInParentTag.pdf";
169+
String resultFile = destinationFolder + "pdfWithCycleRefInParentTag.pdf";
170+
try (PdfDocument pdfDocument1 = new PdfDocument(new PdfReader(filename2));
171+
PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(filename1),
172+
CompareTool.createTestPdfWriter(resultFile).setSmartMode(true));) {
173+
PdfMerger merger = new PdfMerger(pdfDocument2);
174+
merger.merge(pdfDocument1, 1, pdfDocument1.getNumberOfPages());
175+
}
176+
Assertions.assertNull(
177+
new CompareTool().compareByContent(resultFile, sourceFolder + "cmp_pdfWithCycleRefInParentTag.pdf",
178+
destinationFolder, "diff_"));
179+
}
180+
165181
@Test
166182
@LogMessages(messages = {
167183
@LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY)

0 commit comments

Comments
 (0)