diff --git a/pom.xml b/pom.xml
index a83c5d7cb..9c1dc3135 100644
--- a/pom.xml
+++ b/pom.xml
@@ -173,7 +173,7 @@
com.ibm.icuicu4j
- 70.1
+ 72.1net.sf.saxon
diff --git a/src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java b/src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java
index 04960f4b4..7e03d3edb 100755
--- a/src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java
+++ b/src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java
@@ -287,8 +287,6 @@ private boolean checkContainerStructure(OCFCheckerState state)
List directories = new LinkedList<>();
// Loop through the entries
- OCFFilenameChecker filenameChecker = new OCFFilenameChecker(state.context().build());
- // FIXME catch IAE MALFORMED entries
for (OCFResource resource : resourcesProvider)
{
Preconditions.checkNotNull(resource.getPath());
@@ -318,7 +316,7 @@ else if (resources.containsKey(
else
{
// Check file name requirements
- filenameChecker.checkCompatiblyEscaped(resource.getPath());
+ new OCFFilenameChecker(resource.getPath(), state.context().build()).check();;
// report entry metadata
reportFeatures(resource.getProperties());
diff --git a/src/main/java/com/adobe/epubcheck/ocf/OCFFilenameChecker.java b/src/main/java/com/adobe/epubcheck/ocf/OCFFilenameChecker.java
index 8a2e4a5eb..d9bd3217e 100644
--- a/src/main/java/com/adobe/epubcheck/ocf/OCFFilenameChecker.java
+++ b/src/main/java/com/adobe/epubcheck/ocf/OCFFilenameChecker.java
@@ -1,127 +1,162 @@
package com.adobe.epubcheck.ocf;
+import java.util.LinkedHashSet;
import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.w3c.epubcheck.core.Checker;
import com.adobe.epubcheck.api.EPUBLocation;
import com.adobe.epubcheck.api.Report;
import com.adobe.epubcheck.messages.MessageId;
import com.adobe.epubcheck.opf.ValidationContext;
import com.adobe.epubcheck.util.EPUBVersion;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.text.UCharacterIterator;
+import com.ibm.icu.text.UForwardCharacterIterator;
+import com.ibm.icu.text.UnicodeSet;
-//FIXME 2022 update related PKG-* messages to contain the file name string
-public final class OCFFilenameChecker
+public final class OCFFilenameChecker implements Checker
{
- private static final Set RESTRICTED_30_CHARACTER_SET = ImmutableSet.of("PRIVATE_USE_AREA",
- "ARABIC_PRESENTATION_FORMS_A", "SPECIALS", "SUPPLEMENTARY_PRIVATE_USE_AREA_A",
- "SUPPLEMENTARY_PRIVATE_USE_AREA_B", "VARIATION_SELECTORS_SUPPLEMENT", "TAGS");
+
+ private static final UnicodeSet ASCII = new UnicodeSet("[:ascii:]").freeze();
+
+ private static final UnicodeSet DISALLOWED_EPUB2 = new UnicodeSet()
+ // .add(0x002F)// SOLIDUS '/' -- allowed as path separator
+ .add(0x0022)// QUOTATION MARK '"'
+ .add(0x002A)// ASTERISK '*'
+ // .add(0x002E)// FULL STOP '.' -- only disallowed as the last character
+ .add(0x003A)// COLON ':'
+ .add(0x003C)// LESS-THAN SIGN '<'
+ .add(0x003E)// GREATER-THAN SIGN '>'
+ .add(0x003F)// QUESTION MARK '?'
+ .add(0x005C)// REVERSE SOLIDUS '\'
+ .freeze();
+
+ private static final ImmutableMap DISALLOWED_EPUB3 = new ImmutableMap.Builder()
+ .put("ASCII", new UnicodeSet() //
+ .addAll(DISALLOWED_EPUB2)// all disallowed in EPUB 2.0.1
+ .add(0x007C) // VERTICAL LINE '|'
+ .freeze())
+ .put("NON CHARACTER", new UnicodeSet("[:Noncharacter_Code_Point=Yes:]")//
+ .freeze())
+ .put("CONTROL", new UnicodeSet().add(0x007F) // DEL
+ .addAll(0x0000, 0x001F) // C0 range
+ .addAll(0x0080, 0x009F) // C1 range
+ .freeze())
+ .put("PRIVATE USE", new UnicodeSet() //
+ .addAll(0xE000, 0xF8FF) // Private Use Area
+ .addAll(0xF0000, 0xFFFFF) // Supplementary Private Use Area-A
+ .addAll(0x100000, 0x10FFFF) // Supplementary Private Use Area-B
+ .freeze())
+ .put("SPECIALS", new UnicodeSet() //
+ .addAll(0xFFF0, 0xFFFF) // Specials Blocks
+ .freeze())
+ .put("DEPRECATED", new UnicodeSet() //
+ .add(0xE0001)// LANGUAGE TAG
+ // .add(0xE007F)// CANCEL TAG -- reinstated in Emoji tag sequences
+ .freeze())
+ .build();
+
+ private static String toString(int codepoint, String setName)
+ {
+ assert setName != null;
+ StringBuilder result = new StringBuilder().append(String.format("U+%04X ", codepoint));
+ if ("ASCII".equals(setName))
+ {
+ result.append('(').append(UCharacter.toString(codepoint)).append(')');
+ }
+ else
+ {
+ String characterName = UCharacter.getName(codepoint);
+ if (characterName != null)
+ {
+ result.append(characterName).append(' ');
+ }
+ result.append('(').append(setName).append(')');
+ }
+ return result.toString();
+ }
private final Report report;
private final EPUBVersion version;
private final EPUBLocation location;
+ private final String filename;
+
+ public OCFFilenameChecker(String filename, ValidationContext context)
+ {
+ this(filename, context, null);
+ }
- public OCFFilenameChecker(ValidationContext context)
+ public OCFFilenameChecker(String filename, ValidationContext context, EPUBLocation location)
{
+ Preconditions.checkArgument(filename != null);
+ Preconditions.checkArgument(context != null);
+ this.filename = filename;
this.report = context.report;
this.version = context.version;
- this.location = EPUBLocation.of(context);
+ this.location = (location != null) ? location : EPUBLocation.of(context);
}
- public String checkCompatiblyEscaped(final String str)
+ @Override
+ public void check()
{
- // don't check remote resources
- if (str.matches("^[^:/?#]+://.*"))
- {
- return "";
- }
-
- // the test string will be used to compare test result
- String test = checkNonAsciiFilename(str);
-
- if (str.endsWith("."))
- {
- report.message(MessageId.PKG_011, location, str);
- test += ".";
- }
-
- boolean spaces = false;
- final char[] ascciGraphic = new char[] { '<', '>', '"', '{', '}', '|', '^', '`', '*',
- '?' /* , ':','/', '\\' */ };
- String result = "";
- char[] chars = str.toCharArray();
- for (char c : chars)
+ // Iterate through the code points to search disallowed characters
+ UCharacterIterator chars = UCharacterIterator.getInstance(filename);
+ final Set disallowed = new LinkedHashSet<>();
+ boolean hasSpaces = false;
+ boolean isASCIIOnly = true;
+ int codepoint;
+ while ((codepoint = chars.nextCodePoint()) != UForwardCharacterIterator.DONE)
{
- for (char a : ascciGraphic)
+ // Check if the string has non-ASCII characters
+ isASCIIOnly = isASCIIOnly && ASCII.contains(codepoint);
+ // Check if the string has space characters
+ hasSpaces = hasSpaces || UCharacter.isUWhiteSpace(codepoint);
+ // Check for disallowed characters
+ switch (version)
{
- if (c == a)
+ case VERSION_2:
+ if (DISALLOWED_EPUB2.contains(codepoint))
{
- result += "\"" + Character.toString(c) + "\",";
- test += Character.toString(c);
+ disallowed.add(toString(codepoint, "ASCII"));
}
- }
- if (Character.isSpaceChar(c))
- {
- spaces = true;
- test += Character.toString(c);
+ break;
+ default:
+ for (String name : DISALLOWED_EPUB3.keySet())
+ {
+ if (DISALLOWED_EPUB3.get(name).contains(codepoint))
+ {
+ disallowed.add(toString(codepoint, name));
+ break;
+ }
+ }
+ break;
}
}
- if (result.length() > 1)
+ // Check that FULL STOP is not used as the last character
+ if (chars.previousCodePoint() == 0x002E)
{
- result = result.substring(0, result.length() - 1);
- report.message(MessageId.PKG_009, location, str, result);
+ report.message(MessageId.PKG_011, location, filename);
}
- if (spaces)
+ // Report if disallowed characters were found
+ if (!disallowed.isEmpty())
{
- report.message(MessageId.PKG_010, location, str);
+ report.message(MessageId.PKG_009, location, filename,
+ disallowed.stream().collect(Collectors.joining(", ")));
}
-
- if (version == EPUBVersion.VERSION_3)
+ // Report whitespace characters
+ if (hasSpaces)
{
- checkCompatiblyEscaped30(str, test);
+ report.message(MessageId.PKG_010, location, filename);
}
- return test;
- }
-
- private String checkNonAsciiFilename(final String str)
- {
- String nonAscii = str.replaceAll("[\\p{ASCII}]", "");
- if (nonAscii.length() > 0)
+ // Report non-ASCII characters as usage
+ if (!isASCIIOnly)
{
- report.message(MessageId.PKG_012, location, str, nonAscii);
+ report.message(MessageId.PKG_012, location, filename);
}
- return nonAscii;
}
- private String checkCompatiblyEscaped30(String str, String test)
- {
- String result = "";
-
- char[] chars = str.toCharArray();
- for (char c : chars)
- {
- if (Character.isISOControl(c))
- {
- result += "\"" + Character.toString(c) + "\",";
- test += Character.toString(c);
- }
-
- // DEL (U+007F)
- if (c == '\u007F')
- {
- result += "\"" + Character.toString(c) + "\",";
- test += Character.toString(c);
- }
- String unicodeType = Character.UnicodeBlock.of(c).toString();
- if (RESTRICTED_30_CHARACTER_SET.contains(unicodeType))
- {
- result += "\"" + Character.toString(c) + "\",";
- }
- }
- if (result.length() > 1)
- {
- result = result.substring(0, result.length() - 1);
- report.message(MessageId.PKG_009, location, str, result);
- }
- return test;
- }
}
diff --git a/src/main/java/com/adobe/epubcheck/opf/OPFChecker.java b/src/main/java/com/adobe/epubcheck/opf/OPFChecker.java
index e54fe3b59..f69190ffb 100755
--- a/src/main/java/com/adobe/epubcheck/opf/OPFChecker.java
+++ b/src/main/java/com/adobe/epubcheck/opf/OPFChecker.java
@@ -207,16 +207,12 @@ protected boolean checkContent()
for (OPFItem item : opfHandler.getItems())
{
- // only check Filename CompatiblyEscaped when in "-mode opf"
- // this is when 'xrefChecker' Object is null which is an indicator for
- // single file validation
- // (Had no better possibility in mind since "mode" isn't available in
- // OPFChecker.java)
- //
- // bugfix for issue 239
- if (!context.xrefChecker.isPresent())
+ // only check the filename in single-file mode
+ // (it is checked by the container checker in full-publication mode)
+ // and for local resources (i.e. computed to a file URL)
+ if (!context.container.isPresent() && !item.isRemote())
{
- new OCFFilenameChecker(context).checkCompatiblyEscaped(item.getPath());
+ new OCFFilenameChecker(item.getPath(), context, item.getLocation()).check();
}
if (!item.equals(opfHandler.getItemByURL(item.getURL()).orNull()))
{
diff --git a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties
index a09ca0378..bed87d83a 100644
--- a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties
+++ b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties
@@ -297,10 +297,10 @@ PKG_005=The mimetype file has an extra field of length %1$s. The use of the extr
PKG_006=Mimetype file entry is missing or is not the first file in the archive.
PKG_007=Mimetype file should only contain the string "application/epub+zip" and should not be compressed.
PKG_008=Unable to read file "%1$s".
-PKG_009=File name contains characters that are not allowed in OCF file names: "%1$s".
-PKG_010=Filename contains spaces, therefore URI escaping is necessary. Consider removing spaces from filename.
-PKG_011=Filename is not allowed to end with ".".
-PKG_012=File name contains the following non-ascii characters: %1$s. Consider changing the filename.
+PKG_009=The file name "%1$s" contains characters that are not allowed in OCF file names: %2$s.
+PKG_010=The file name "%1$s" contains spaces, which may create interoperability issues with older reading systems.
+PKG_011=The file name "%1$s" is not allowed to end with ".".
+PKG_012=The file name "%1$s" contains non-ASCII characters, which might create interoperability issues with older reading systems.
PKG_013=The EPUB file includes multiple OPS renditions.
PKG_014=The EPUB contains empty directory "%1$s".
PKG_015=Unable to read EPUB contents: %1$s
diff --git a/src/test/java/com/adobe/epubcheck/ocf/OCFFilenameCheckerTest.java b/src/test/java/com/adobe/epubcheck/ocf/OCFFilenameCheckerTest.java
deleted file mode 100644
index 7fa7fd726..000000000
--- a/src/test/java/com/adobe/epubcheck/ocf/OCFFilenameCheckerTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2011 Adobe Systems Incorporated
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-package com.adobe.epubcheck.ocf;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-import com.adobe.epubcheck.api.EPUBProfile;
-import com.adobe.epubcheck.api.Report;
-import com.adobe.epubcheck.opf.ValidationContext;
-import com.adobe.epubcheck.util.EPUBVersion;
-import com.adobe.epubcheck.util.Messages;
-import com.adobe.epubcheck.util.ValidationReport;
-import com.adobe.epubcheck.util.outWriter;
-
-public class OCFFilenameCheckerTest
-{
-
- private boolean verbose = false;
- private final Messages messages = Messages.getInstance();
-
- /*
- * TEST DEBUG FUNCTION
- */
- public void testValidateDocument(String fileName, String expected, EPUBVersion version,
- boolean verbose)
- {
- if (verbose)
- {
- this.verbose = verbose;
- }
- testValidateDocument(fileName, expected, version);
-
- }
-
- public void testValidateDocument(String fileName, String expected, EPUBVersion version)
- {
- Report testReport = new ValidationReport(fileName,
- String.format(messages.get("single_file"), "opf", version.toString(), EPUBProfile.DEFAULT));
-
- ValidationContext testContext = ValidationContext.test().report(testReport).version(version)
- .build();
-
- OCFFilenameChecker checker = new OCFFilenameChecker(testContext);
-
- String result = checker.checkCompatiblyEscaped(fileName);
-
- if (verbose)
- {
- verbose = false;
- outWriter.println(testReport);
- outWriter.println("Test result: " + result + " \nExpected: " + expected);
- }
-
- assertEquals(expected, result);
- }
-
- @Test
- public void testValidateDocumentTest001()
- {
- testValidateDocument("abc\u3053abc", "\u3053", EPUBVersion.VERSION_3);
- }
-
- @Test
- public void testValidateDocumentTest002()
- {
- testValidateDocument("www.google.ro.", ".", EPUBVersion.VERSION_3);
- }
-
- @Test
- public void testValidateDocumentTest003()
- {
- testValidateDocument("go gle/ro", " ", EPUBVersion.VERSION_3);
- }
-
- @Test
- public void testValidateDocumentTest004()
- {
- testValidateDocument("/foo/b>ar/quux", ">", EPUBVersion.VERSION_3);
- }
-
- @Test
- public void testValidateDocumentTest005()
- {
- testValidateDocument("/foo/b>ar/quu\uE000x", "\uE000>", EPUBVersion.VERSION_3);
- }
-
- @Test
- public void testValidateDocumentTest006()
- {
- testValidateDocument("http://www% .google.ro", "", EPUBVersion.VERSION_2);
- }
-}
diff --git a/src/test/java/org/w3c/epubcheck/container/FilenameCheckerSteps.java b/src/test/java/org/w3c/epubcheck/container/FilenameCheckerSteps.java
new file mode 100644
index 000000000..860f6fba4
--- /dev/null
+++ b/src/test/java/org/w3c/epubcheck/container/FilenameCheckerSteps.java
@@ -0,0 +1,41 @@
+package org.w3c.epubcheck.container;
+
+import org.w3c.epubcheck.test.TestConfiguration;
+
+import com.adobe.epubcheck.ocf.OCFFilenameChecker;
+import com.adobe.epubcheck.opf.ValidationContext;
+
+import io.cucumber.java.ParameterType;
+import io.cucumber.java.en.When;
+
+public class FilenameCheckerSteps
+{
+
+ private final ValidationContext context;
+
+ public FilenameCheckerSteps(TestConfiguration configuration)
+ {
+ this.context = configuration.getContextBuilder().build();
+ }
+
+ @ParameterType("U\\+[0-9a-zA-Z]{4,6}")
+ public int codepoint(String codepoint)
+ {
+ return Integer.valueOf(codepoint.substring(2), 16);
+ }
+
+ @When("checking file name {string}")
+ public void checkFilename(String string)
+ {
+ new OCFFilenameChecker(string, context).check();
+ }
+
+ @When("checking file name containing code point {codepoint}")
+ public void checkFilenameWithCodepoint(int codepoint)
+ {
+ new OCFFilenameChecker(
+ new StringBuilder().append("a").appendCodePoint(codepoint).append("name").toString(),
+ context).check();
+ }
+
+}
diff --git a/src/test/resources/epub3/04-ocf/filename-checker.feature b/src/test/resources/epub3/04-ocf/filename-checker.feature
new file mode 100644
index 000000000..e8d685f4b
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/filename-checker.feature
@@ -0,0 +1,84 @@
+Feature: File name checker
+
+ Tests the checker for disallowed characters in file names.
+
+ Note that these test cases evaluate raw Unicode file name strings.
+ Additional functional tests (based on full publications or package documents)
+ are also available in the feature file for container-relates tests.
+
+ Scenario Outline: valid file name '' is accepted
+ When checking file name ''
+ Then no error or warning is reported
+
+ Scenarios:
+ | filename |
+ | only-ascii |
+ | not-ascii-รฉ |
+ | ideograph-ไ |
+ | emoji-๐ |
+ | emoji-tag-sequence-๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ |
+
+ Scenario Outline: space () is reported as warning
+ When checking file name containing code point
+ Then warning PKG-010 is reported
+
+ Scenarios:
+ | codepoint | name |
+ | U+0009 | TAB |
+ | U+000A | LF |
+ | U+000C | FF |
+ | U+000D | CR |
+ | U+0020 | SPACE |
+ | U+2009 | THIN SPACE |
+
+ Scenario: disallow FULL STOP as the last character
+ When checking file name 'aname.'
+ Then error PKG-011 is reported
+
+ Scenario: disallowed characters are reported
+ When checking file name 'a*name'
+ Then error PKG-009 is reported
+ Then the message contains 'U+002A (*)'
+
+ Scenario: disallowed characters are all reported
+ When checking file name 'a*na"me'
+ Then error PKG-009 is reported
+ Then the message contains 'U+002A (*), U+0022 (")'
+
+ Scenario: disallowed characters are reported only once
+ When checking file name 'a*na*me'
+ Then error PKG-009 is reported
+ Then the message contains 'U+002A (*).'
+
+ Scenario Outline: disallowed character is reported
+ When checking file name containing code point
+ Then error PKG-009 is reported
+ And the message contains ''
+
+ Scenarios:
+ | codepoint | tostring |
+ | U+0022 | (") |
+ | U+002A | (*) |
+ | U+003A | (:) |
+ | U+003C | (<) |
+ | U+003E | (>) |
+ | U+003F | (?) |
+ | U+005C | (\) |
+ | U+007C | (\|) |
+ | U+007F | (CONTROL) |
+ | U+0000 | (CONTROL) |
+ | U+0080 | (CONTROL) |
+ | U+E000 | (PRIVATE USE) |
+ | U+FDD0 | (NON CHARACTER) |
+ | U+FFFD | REPLACEMENT CHARACTER (SPECIALS) |
+ | U+FFFE | (NON CHARACTER) |
+ | U+9FFFE | (NON CHARACTER) |
+ | U+E0001 | LANGUAGE TAG (DEPRECATED) |
+ #| U+E007F | CANCEL TAG | # Re-instated for ETS use
+ | U+F0001 | (PRIVATE USE) |
+ | U+100000 | (PRIVATE USE) |
+
+ Scenario: VERTICAL LINE (|) is not disallowed in EPUB 2.0.1
+ Given EPUBCheck configured to check EPUB 2 rules
+ When checking file name 'a|name'
+ Then no error or warning is reported
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/content_001.xhtml "b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/content_\360\237\217\264\363\240\201\247\363\240\201\242\363\240\201\245\363\240\201\256\363\240\201\247\363\240\201\277.xhtml"
similarity index 100%
rename from src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/content_001.xhtml
rename to "src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/content_\360\237\217\264\363\240\201\247\363\240\201\242\363\240\201\245\363\240\201\256\363\240\201\247\363\240\201\277.xhtml"
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/nav.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/nav.xhtml
new file mode 100644
index 000000000..a11ebc68d
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/nav.xhtml
@@ -0,0 +1,14 @@
+
+
+
+
+ Minimal Nav
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/package.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/EPUB/package.opf
new file mode 100644
index 000000000..77441bdac
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/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/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/META-INF/container.xml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/META-INF/container.xml
new file mode 100644
index 000000000..318782179
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/META-INF/container.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/mimetype b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/mimetype
new file mode 100644
index 000000000..57ef03f24
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-emoji-tag-sequence-valid/mimetype
@@ -0,0 +1 @@
+application/epub+zip
\ No newline at end of file
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error.opf
new file mode 100644
index 000000000..ffb6b06a0
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error.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/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/content_|.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/content_|.xhtml
new file mode 100644
index 000000000..ea29a1610
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/content_|.xhtml
@@ -0,0 +1,11 @@
+
+
+
+
+ Minimal EPUB
+
+
+
Loomings
+
Call me Ishmael.
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/nav.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/nav.xhtml
new file mode 100644
index 000000000..508931b93
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/nav.xhtml
@@ -0,0 +1,14 @@
+
+
+
+
+ Minimal Nav
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/package.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/package.opf
index 44f20ae4b..ffb6b06a0 100644
--- a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/package.opf
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/package.opf
@@ -7,8 +7,8 @@
2017-06-14T00:00:01Z
-
-
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-in-remote-URL-valid.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-in-remote-URL-valid.opf
new file mode 100644
index 000000000..ee1dd54b1
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-in-remote-URL-valid.opf
@@ -0,0 +1,17 @@
+
+
+
+ Minimal EPUB 3.0
+ en
+ NOID
+ 2017-06-14T00:00:01Z
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/content_001.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/content_001.xhtml
new file mode 100644
index 000000000..ea29a1610
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/content_001.xhtml
@@ -0,0 +1,11 @@
+
+
+
+
+ Minimal EPUB
+
+
+
Loomings
+
Call me Ishmael.
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/nav_{}.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/nav.xhtml
similarity index 100%
rename from src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-error/EPUB/nav_{}.xhtml
rename to src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/nav.xhtml
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/package.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/EPUB/package.opf
new file mode 100644
index 000000000..0d1eec6e9
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-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/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/META-INF/container.xml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/META-INF/container.xml
new file mode 100644
index 000000000..318782179
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/META-INF/container.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/META-INF/file_<>.txt b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/META-INF/file_<>.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/mimetype b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/mimetype
new file mode 100644
index 000000000..57ef03f24
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-forbidden-non-publication-resource-error/mimetype
@@ -0,0 +1 @@
+application/epub+zip
\ No newline at end of file
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-non-ascii-warning.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-non-ascii-warning.opf
new file mode 100644
index 000000000..ed2f02006
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-non-ascii-warning.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/04-ocf/files/ocf-filename-character-space-warning.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning.opf
new file mode 100644
index 000000000..8ab0fcbe4
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning.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/04-ocf/files/ocf-filename-character-space-warning/EPUB/content 001.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/content 001.xhtml
new file mode 100644
index 000000000..ea29a1610
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/content 001.xhtml
@@ -0,0 +1,11 @@
+
+
+
+
+ Minimal EPUB
+
+
+
Loomings
+
Call me Ishmael.
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/nav.xhtml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/nav.xhtml
new file mode 100644
index 000000000..83df7550b
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/nav.xhtml
@@ -0,0 +1,14 @@
+
+
+
+
+ Minimal Nav
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/package.opf b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/EPUB/package.opf
new file mode 100644
index 000000000..8ab0fcbe4
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/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/04-ocf/files/ocf-filename-character-space-warning/META-INF/container.xml b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/META-INF/container.xml
new file mode 100644
index 000000000..318782179
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/META-INF/container.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/mimetype b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/mimetype
new file mode 100644
index 000000000..57ef03f24
--- /dev/null
+++ b/src/test/resources/epub3/04-ocf/files/ocf-filename-character-space-warning/mimetype
@@ -0,0 +1 @@
+application/epub+zip
\ No newline at end of file
diff --git a/src/test/resources/epub3/04-ocf/ocf.feature b/src/test/resources/epub3/04-ocf/ocf.feature
index 001c2adbe..017e9c55a 100644
--- a/src/test/resources/epub3/04-ocf/ocf.feature
+++ b/src/test/resources/epub3/04-ocf/ocf.feature
@@ -41,15 +41,55 @@ Feature: EPUB 3 โ Open Container Format
And no other errors or warnings are reported
@spec @xref:sec-container-filenames
- Scenario: Report forbidden characters in filenames
+ Scenario: Allow Unicode emoji tag set in file name
+ When checking EPUB 'ocf-filename-character-emoji-tag-sequence-valid'
+ Then no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Report forbidden characters in file names
When checking EPUB 'ocf-filename-character-forbidden-error'
- And error PKG-009 is reported
+ Then error PKG-009 is reported
+ And no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Report forbidden characters in file names even for non-publication resources
+ When checking EPUB 'ocf-filename-character-forbidden-non-publication-resource-error'
+ Then error PKG-009 is reported
+ And no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Allow forbidden characters in remote resource URLs
+ When checking EPUB 'ocf-filename-character-forbidden-in-remote-URL-valid.opf'
+ Then no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Report forbidden characters in file names (single package doc check)
+ When checking EPUB 'ocf-filename-character-forbidden-error.opf'
+ Then error PKG-009 is reported
And no other errors or warnings are reported
- Scenario: Report non-ASCII characters in filenames
+ Scenario: Inform about non-ASCII characters in file names (full-publication check)
Given the reporting level is set to USAGE
When checking EPUB 'ocf-filename-character-non-ascii-warning'
- And usage PKG-012 is reported
+ Then usage PKG-012 is reported
+ And no other errors or warnings are reported
+
+ Scenario: Inform about non-ASCII characters in file names (single package doc check)
+ Given the reporting level is set to USAGE
+ When checking EPUB 'ocf-filename-character-non-ascii-warning.opf'
+ Then usage PKG-012 is reported
+ And no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Warn about spaces in file names (full-publication check)
+ When checking file 'ocf-filename-character-space-warning'
+ Then warning PKG-010 is reported
+ And no other errors or warnings are reported
+
+ @spec @xref:sec-container-filenames
+ Scenario: Warn about spaces in file names (single package doc check)
+ When checking file 'ocf-filename-character-space-warning.opf'
+ Then warning PKG-010 is reported
And no other errors or warnings are reported
### 4.1.5 URLs in the OCF abstract container
diff --git a/src/test/resources/epub3/05-package-document/files/item-href-contains-spaces-warning.opf b/src/test/resources/epub3/05-package-document/files/item-href-contains-spaces-warning.opf
deleted file mode 100644
index d5510d048..000000000
--- a/src/test/resources/epub3/05-package-document/files/item-href-contains-spaces-warning.opf
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- xxx
- Title
- en
- 2019-01-01T12:00:00Z
-
-
-
-
-
-
-
-
-
diff --git a/src/test/resources/epub3/05-package-document/package-document.feature b/src/test/resources/epub3/05-package-document/package-document.feature
index 8a9463379..239211170 100644
--- a/src/test/resources/epub3/05-package-document/package-document.feature
+++ b/src/test/resources/epub3/05-package-document/package-document.feature
@@ -420,17 +420,12 @@ Feature: EPUB 3 โ Package document
And the message contains 'missing required attribute "media-type"'
And no other errors or warnings are reported
- Scenario: item URLs should not contain spaces, even if properly encoded
+ Scenario: item URLs must be properly encoded
When checking file 'item-href-contains-spaces-unencoded-error.opf'
Then error RSC-020 is reported
And warning PKG-010 is reported (side effect of spaces)
And no other errors or warnings are reported
- Scenario: item URLs should not contain spaces, even if properly encoded
- When checking file 'item-href-contains-spaces-warning.opf'
- Then warning PKG-010 is reported
- And no other errors or warnings are reported
-
@spec @xref:sec-item-elem
Scenario: item URLs must not have a fragment identifier
When checking file 'item-href-with-fragment-error.opf'