From f7b5dd9412249de3cc0e2cd40ceebca0f3c7b5c4 Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Wed, 5 Jul 2023 15:15:23 +0200 Subject: [PATCH] fix: incorrect ID refs in toc nav caused a NullPointerException When the `toc` nav of the navigation document contained links pointing to non-existing IDs, checking that links are in reading order caused a NullPointerException. This commit fixes that by using a more defensive programming logic. Fix #1516 --- .../references/ResourceReferencesChecker.java | 34 ++++++++++--------- .../core/references/ResourceRegistry.java | 4 ++- .../content-document-xhtml.feature | 5 +++ .../EPUB/content_001.xhtml | 11 ++++++ .../EPUB/nav.xhtml | 15 ++++++++ .../EPUB/package.opf | 16 +++++++++ .../META-INF/container.xml | 6 ++++ .../mimetype | 1 + 8 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/content_001.xhtml create mode 100644 src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/nav.xhtml create mode 100644 src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/package.opf create mode 100644 src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/META-INF/container.xml create mode 100644 src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/mimetype diff --git a/src/main/java/org/w3c/epubcheck/core/references/ResourceReferencesChecker.java b/src/main/java/org/w3c/epubcheck/core/references/ResourceReferencesChecker.java index c4c91a9f6..21074cb60 100755 --- a/src/main/java/org/w3c/epubcheck/core/references/ResourceReferencesChecker.java +++ b/src/main/java/org/w3c/epubcheck/core/references/ResourceReferencesChecker.java @@ -456,25 +456,27 @@ private void checkReadingOrder(Queue references) // check that the fragment is in document order URLFragment fragment = URLFragment.parse(ref.url, res.getMimeType()); int targetAnchorPosition = resourceRegistry.getIDPosition(fragment.getId(), res); - if (targetAnchorPosition < lastAnchorPosition) - { - String orderContext = LocalizedMessages.getInstance(locale).getSuggestion( - MessageId.NAV_011, - "document"); - if (ref.type == Reference.Type.OVERLAY_TEXT_LINK) - { - report.message(MessageId.MED_015, ref.location, container.relativize(ref.url), - orderContext); - } - else + if (targetAnchorPosition > -1) { + if (targetAnchorPosition < lastAnchorPosition) { - report.message(MessageId.NAV_011, ref.location, - (ref.type == Reference.Type.NAV_TOC_LINK) ? "toc" : "page-list", - container.relativize(ref.url), - orderContext); + String orderContext = LocalizedMessages.getInstance(locale).getSuggestion( + MessageId.NAV_011, + "document"); + if (ref.type == Reference.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 == Reference.Type.NAV_TOC_LINK) ? "toc" : "page-list", + container.relativize(ref.url), + orderContext); + } } + lastAnchorPosition = targetAnchorPosition; } - lastAnchorPosition = targetAnchorPosition; } } diff --git a/src/main/java/org/w3c/epubcheck/core/references/ResourceRegistry.java b/src/main/java/org/w3c/epubcheck/core/references/ResourceRegistry.java index 6a3d04b0c..1061c85b1 100644 --- a/src/main/java/org/w3c/epubcheck/core/references/ResourceRegistry.java +++ b/src/main/java/org/w3c/epubcheck/core/references/ResourceRegistry.java @@ -11,6 +11,7 @@ import com.adobe.epubcheck.opf.OPFItem; import com.google.common.base.Preconditions; import com.google.common.collect.HashBasedTable; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Table; import io.mola.galimatias.URL; @@ -54,7 +55,8 @@ public int getIDPosition(String id, Resource resource) { Preconditions.checkArgument(resource != null); if (id == null || id.trim().isEmpty()) return 0; - int position = ids.get(resource.getURL()).indexOf(id); + int position = Optional.ofNullable(ids.get(resource.getURL())).orElse(ImmutableList.of()) + .indexOf(id); return (position == -1) ? -1 : position + 1; } diff --git a/src/test/resources/epub3/06-content-document/content-document-xhtml.feature b/src/test/resources/epub3/06-content-document/content-document-xhtml.feature index 3ca0c29b5..69019ed35 100644 --- a/src/test/resources/epub3/06-content-document/content-document-xhtml.feature +++ b/src/test/resources/epub3/06-content-document/content-document-xhtml.feature @@ -263,6 +263,11 @@ Feature: EPUB 3 — Content Documents — XHTML Then error RSC-012 is reported And no errors or warnings are reported + Scenario: Report a hyperlink to a missing identifier in the Nav Doc + When checking EPUB 'content-xhtml-link-to-missing-id-in-nav-doc-error' + Then error RSC-012 is reported + And no errors or warnings are reported + Scenario: Report a hyperlink to a mising identifier in another document When checking EPUB 'content-xhtml-link-to-missing-id-xref-error' Then error RSC-012 is reported diff --git a/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/content_001.xhtml b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/content_001.xhtml new file mode 100644 index 000000000..43a520ea2 --- /dev/null +++ b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/content_001.xhtml @@ -0,0 +1,11 @@ + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/nav.xhtml b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/nav.xhtml new file mode 100644 index 000000000..1b6fac727 --- /dev/null +++ b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/nav.xhtml @@ -0,0 +1,15 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/package.opf b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/package.opf new file mode 100644 index 000000000..0d1eec6e9 --- /dev/null +++ b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/EPUB/package.opf @@ -0,0 +1,16 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/META-INF/container.xml b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/mimetype b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/06-content-document/files/content-xhtml-link-to-missing-id-in-nav-doc-error/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file