Skip to content

Commit

Permalink
fix: remove recursion in reading order checks
Browse files Browse the repository at this point in the history
Unnecessary recursion was causing StackOverflowError with large package documents.

Fix #1358, Close #1356.

Co-Authored-By: Daniel Persson <kalaspuffar@users.noreply.github.com>
  • Loading branch information
rdeltour and kalaspuffar committed Nov 27, 2022
1 parent 5903626 commit 6cbbefa
Showing 1 changed file with 55 additions and 49 deletions.
104 changes: 55 additions & 49 deletions src/main/java/com/adobe/epubcheck/opf/XRefChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ public void checkReferences()
break;
}
}
checkReadingOrder(tocLinks, -1, -1);
checkReadingOrder(overlayLinks, -1, -1);
checkReadingOrder(tocLinks);
checkReadingOrder(overlayLinks);
}

private void checkReference(URLReference reference)
Expand Down Expand Up @@ -665,58 +665,30 @@ private void checkRegionBasedNav(URLReference ref)
}
}

private void checkReadingOrder(Queue<URLReference> references, int lastSpinePosition,
int lastAnchorPosition)
private void checkReadingOrder(Queue<URLReference> references)
{
// de-queue
URLReference ref = references.poll();
if (ref == null) return;

Preconditions.checkArgument(ref.type == Type.NAV_PAGELIST_LINK || ref.type == Type.NAV_TOC_LINK
|| ref.type == Type.OVERLAY_TEXT_LINK);
Resource res = resources.get(ref.targetDoc);

// abort early if the link target is not a spine item (checked elsewhere)
if (res == null || !res.hasItem() || !res.getItem().isInSpine()) return;

// check that the link is in spine order
int targetSpinePosition = res.getItem().getSpinePosition();
if (targetSpinePosition < lastSpinePosition)
int lastSpinePosition = -1;
int lastAnchorPosition = -1;
while (!references.isEmpty())
{
String orderContext = LocalizedMessages.getInstance(locale).getSuggestion(MessageId.NAV_011,
"spine");

if (ref.type == Type.OVERLAY_TEXT_LINK)
{
report.message(MessageId.MED_015, ref.location, container.relativize(ref.url),
orderContext);
}
else
{
report.message(MessageId.NAV_011, ref.location,
(ref.type == Type.NAV_TOC_LINK) ? "toc" : "page-list", container.relativize(ref.url),
orderContext);
}
lastSpinePosition = targetSpinePosition;
lastAnchorPosition = -1;
}
else
{

// if new spine item, reset last positions
if (targetSpinePosition > lastSpinePosition)
URLReference ref = references.poll();
Preconditions
.checkArgument(ref.type == Type.NAV_PAGELIST_LINK || ref.type == Type.NAV_TOC_LINK
|| ref.type == Type.OVERLAY_TEXT_LINK);
Resource res = resources.get(ref.targetDoc);
// abort early if the link target is not a spine item (checked elsewhere)
if (res == null || !res.hasItem() || !res.getItem().isInSpine())
{
lastSpinePosition = targetSpinePosition;
lastAnchorPosition = -1;
continue;
}

// check that the fragment is in document order
URLFragment fragment = URLFragment.parse(ref.url, res.getMimeType());
int targetAnchorPosition = res.getIDPosition(fragment.getId());
if (targetAnchorPosition < lastAnchorPosition)
// check that the link is in spine order
int targetSpinePosition = res.getItem().getSpinePosition();
if (targetSpinePosition < lastSpinePosition)
{
String orderContext = LocalizedMessages.getInstance(locale).getSuggestion(MessageId.NAV_011,
"document");
"spine");

if (ref.type == Type.OVERLAY_TEXT_LINK)
{
report.message(MessageId.MED_015, ref.location, container.relativize(ref.url),
Expand All @@ -728,9 +700,43 @@ private void checkReadingOrder(Queue<URLReference> references, int lastSpinePosi
(ref.type == Type.NAV_TOC_LINK) ? "toc" : "page-list", container.relativize(ref.url),
orderContext);
}
lastSpinePosition = targetSpinePosition;
lastAnchorPosition = -1;
}
else
{

// if new spine item, reset last positions
if (targetSpinePosition > lastSpinePosition)
{
lastSpinePosition = targetSpinePosition;
lastAnchorPosition = -1;
}

// check that the fragment is in document order
URLFragment fragment = URLFragment.parse(ref.url, res.getMimeType());
int targetAnchorPosition = res.getIDPosition(fragment.getId());
if (targetAnchorPosition < lastAnchorPosition)
{
String orderContext = LocalizedMessages.getInstance(locale).getSuggestion(
MessageId.NAV_011,
"document");
if (ref.type == Type.OVERLAY_TEXT_LINK)
{
report.message(MessageId.MED_015, ref.location, container.relativize(ref.url),
orderContext);
}
else
{
report.message(MessageId.NAV_011, ref.location,
(ref.type == Type.NAV_TOC_LINK) ? "toc" : "page-list",
container.relativize(ref.url),
orderContext);
}
}
lastAnchorPosition = targetAnchorPosition;
}
lastAnchorPosition = targetAnchorPosition;
}
checkReadingOrder(references, lastSpinePosition, lastAnchorPosition);

}
}

0 comments on commit 6cbbefa

Please sign in to comment.