private void processBinding(XMLElement e) { String mimeType = e.getAttribute("media-type"); String handlerId = e.getAttribute("handler"); if ((mimeType != null) && (handlerId != null)) { if (OPFChecker30.isCoreMediaType(mimeType)) { report.message( MessageId.OPF_008, new MessageLocation(path, parser.getLineNumber(), parser.getColumnNumber()), mimeType); return; } if (xrefChecker != null && xrefChecker.getBindingHandlerSrc(mimeType) != null) { report.message( MessageId.OPF_009, new MessageLocation(path, parser.getLineNumber(), parser.getColumnNumber()), mimeType, xrefChecker.getBindingHandlerSrc(mimeType)); return; } OPFItem handler = itemMapById.get(handlerId); if (handler != null && xrefChecker != null) { xrefChecker.registerBinding(mimeType, handler.path); } } }
protected void checkLink(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); String rel = e.getAttributeNS(attrNS, "rel"); if (xrefChecker.isPresent() && href != null && rel != null && rel.toLowerCase().contains("stylesheet")) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker .get() .registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.STYLESHEET); // Check the mimetype to record possible non-standard stylesheets // with no fallback String mimetype = xrefChecker.get().getMimeType(href); if (mimetype != null) { if (OPFChecker.isBlessedStyleType(mimetype) || OPFChecker.isDeprecatedBlessedStyleType(mimetype)) { hasCss = true; } else { nonStandardStylesheetLink = Optional.of( EPUBLocation.create( path, parser.getLineNumber(), parser.getColumnNumber(), href)); } } } }
public void startElement() { if (!checkedUnsupportedXMLVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXMLVersion = true; } XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (name.equals("smil")) { vocabs = VocabUtil.parsePrefixDeclaration( e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "prefix"), RESERVED_VOCABS, KNOWN_VOCAB_URIS, DEFAULT_VOCAB_URIS, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } else if (name.equals("seq")) { processSeq(e); } else if (name.equals("text")) { processSrc(e); } else if (name.equals("audio")) { processRef(e.getAttribute("src"), XRefChecker.Type.AUDIO); } else if (name.equals("body") || name.equals("par")) { checkType(e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type")); } }
public void endElement() { openElements--; XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); if (openElements == 0) { report.info(path, FeatureEnum.CHARS_COUNT, Long.toString(charsCount)); if (!epubTypeInUse) { if (context.version == EPUBVersion.VERSION_3) { report.message(MessageId.ACC_007, EPUBLocation.create(path)); } } else { epubTypeInUse = false; } } ElementLocation currentLocation = elementLocationStack.pop(); if (EpubConstants.HtmlNamespaceUri.equals(ns)) { if ("script".equals(name)) { String attr = e.getAttribute("type"); report.info(path, FeatureEnum.HAS_SCRIPTS, (attr == null) ? "" : attr); } else if ("style".equals(name)) { String style = textNode.toString(); if (style.length() > 0) { CSSCheckerFactory.getInstance() .newInstance(context, style, currentLocation.getLineNumber(), false) .runChecks(); } textNode = null; } else if ("head".equals(name)) { checkStylesheetFallback(); } else if ("table".equals(name)) { if (tableDepth > 0) { --tableDepth; EPUBLocation location = EPUBLocation.create( path, currentLocation.getLineNumber(), currentLocation.getColumnNumber(), "table"); checkDependentCondition(MessageId.ACC_005, tableDepth == 0, hasTh, location); checkDependentCondition(MessageId.ACC_006, tableDepth == 0, hasThead, location); checkDependentCondition(MessageId.ACC_012, tableDepth == 0, hasCaption, location); hasTh = hasThead = hasCaption = false; } } } }
public void characters(char[] chars, int start, int len) { XMLElement e = parser.getCurrentElement(); if (e.getNamespace().equals("http://purl.org/dc/elements/1.1/")) { String name = e.getName(); if (name.equals("identifier") || name.equals("date") || name.equals("title") || name.equals("language")) { String val = (String) e.getPrivateData(); String text = new String(chars, start, len); if (val == null) val = text; else val = val + text; e.setPrivateData(val); } } }
protected void checkImage(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (xrefChecker.isPresent() && href != null) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker .get() .registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.IMAGE); } }
public void startElement() { XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); String id = e.getAttribute("id"); if (ns.equals("http://www.daisy.org/z3986/2005/dtbook/")) { // link@href, a@href, img@src String uri = null; /* * This section checks to see if the references used are registered * schema-types and whether they point to external resources. The * resources are only allowed to be external if the attribute * "external" is set to true. */ if (name.equals("a")) { uri = e.getAttribute("href"); String external = e.getAttribute("external"); if (uri != null && external.equals("true")) { if (OPSHandler.isRegisteredSchemeType(uri)) uri = null; else if (uri.indexOf(':') > 0) { parser .getReport() .warning( path, parser.getLineNumber(), parser.getColumnNumber(), "use of non-registered URI schema type in href: " + uri); uri = null; } } } else if (name.equals("link")) { uri = e.getAttribute("href"); } else if (name.equals("img")) { uri = e.getAttribute("src"); } if (uri != null) { // TODO check if dtbook uses xml:base of so set third param uri = PathUtil.resolveRelativeReference(path, uri, null); xrefChecker.registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), uri, name.equals("img") ? XRefChecker.RT_IMAGE : XRefChecker.RT_HYPERLINK); if (uri.startsWith("http")) { parser.getReport().info(path, FeatureEnum.REFERENCE, uri); } } if (id != null) xrefChecker.registerAnchor( path, parser.getLineNumber(), parser.getColumnNumber(), id, XRefChecker.RT_HYPERLINK); } }
public void startElement() { XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); if (ns.equals("http://www.daisy.org/z3986/2005/ncx/")) { if (name.equals("content")) { String href = e.getAttribute("src"); if (href != null) { href = PathUtil.resolveRelativeReference(path, href, null); xrefChecker.registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.RT_HYPERLINK); } } } }
protected void checkHRef(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (href == null) { return; } href = href.trim(); if (href.isEmpty()) { // if href="" then selfreference which is valid, // but as per issue 225, issue a hint report.message( MessageId.HTM_045, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href)); return; } else if (href.contains("#epubcfi")) { return; // temp until cfi implemented } else if (".".equals(href)) { // selfreference, no need to check return; } URI uri = checkURI(href); if (uri == null) return; if ("http".equals(uri.getScheme())) { report.info(path, FeatureEnum.REFERENCE, href); } /* * mgy 20120417 adding check for base to initial if clause as part of * solution to issue 155 */ if (URISchemes.contains(uri.getScheme()) || (null != base && URISchemes.contains(base.getScheme()))) { return; } // This if statement is needed to make sure XML Fragment identifiers // are not reported as non-registered URI scheme types else if (uri.getScheme() != null) { report.message( MessageId.HTM_025, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href)); return; } try { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); } catch (IllegalArgumentException err) { report.message( MessageId.OPF_010, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href), err.getMessage()); return; } processHyperlink(href); }
public void startElement() { super.startElement(); XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (name.equals("package")) { HandlerUtil.processPrefixes( e.getAttribute("prefix"), prefixSet, report, path, parser.getLineNumber(), parser.getColumnNumber()); } else if (name.equals("meta")) { processMeta(e); } else if (name.equals("link")) { processLink(e); } else if (name.equals("item")) { processItemProperties(e.getAttribute("properties"), e.getAttribute("media-type")); } else if (name.equals("itemref")) { processItemrefProperties(e.getAttribute("properties")); } else if (name.equals("mediaType")) { processBinding(e); } }
private void processLink(XMLElement e) { processLinkRel(e.getAttribute("rel")); // needs refactor: its problematic to register // link resources as items String id = e.getAttribute("id"); String href = e.getAttribute("href"); if (href != null && !href.matches("^[^:/?#]+://.*")) { try { href = PathUtil.resolveRelativeReference(path, href, null); } catch (IllegalArgumentException ex) { report.message( MessageId.OPF_010, new MessageLocation(path, parser.getLineNumber(), parser.getColumnNumber(), href), ex.getMessage()); href = null; } } if (href != null && href.matches("^[^:/?#]+://.*")) { report.info(path, FeatureEnum.REFERENCE, href); } String mimeType = e.getAttribute("media-type"); OPFItem item = new OPFItem( id, href, mimeType, "", "", "", null, parser.getLineNumber(), parser.getColumnNumber()); if (id != null) { itemMapById.put(id, item); } // if (href != null) { // mgy: awaiting proper refactor, only add these if local if (href != null && !href.matches("^[^:/?#]+://.*")) { itemMapByPath.put(href, item); items.add(item); } }
protected void checkPaint(XMLElement e, String attr) { String paint = e.getAttribute(attr); if (xrefChecker.isPresent() && paint != null && paint.startsWith("url(") && paint.endsWith(")")) { String href = paint.substring(4, paint.length() - 1); href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker .get() .registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.SVG_PAINT); } }
public void endElement() { XMLElement e = parser.getCurrentElement(); if (e.getNamespace().equals("http://purl.org/dc/elements/1.1/")) { String name = e.getName(); if (name.equals("identifier")) { String idAttr = e.getAttribute("id"); if (idAttr != null && !idAttr.equals("") && idAttr.equals(uniqueIdent)) { // String idval = (String) e.getPrivateData(); // if (idval != null && ocf != null) // ocf.setUniqueIdentifier(idval); } } else if (name.equals("date")) { String dateval = (String) e.getPrivateData(); boolean valid = true; String detail = null; if (dateval == null || "".equals(dateval)) { valid = false; detail = "zero-length string"; } else { DateParser dateParser = new DateParser(); try { Date date = dateParser.parse(dateval.trim()); /* * mg: DateParser does not enforce four-digit years, * which http://www.w3.org/TR/NOTE-datetime seems to want */ String year = new SimpleDateFormat("yyyy").format(date); if (year.length() > 4) throw new InvalidDateException(year); } catch (InvalidDateException d) { valid = false; detail = d.getMessage(); } } if (!valid) { if (this.version == EPUBVersion.VERSION_3) { report.warning( path, parser.getLineNumber(), parser.getColumnNumber(), "date value '" + (dateval == null ? "" : dateval) + "' does not follow recommended syntax as per http://www.w3.org/TR/NOTE-datetime:" + detail); } else { report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "date value '" + (dateval == null ? "" : dateval) + "' is not valid as per http://www.w3.org/TR/NOTE-datetime:" + detail); } } } else if (name.equals("title") || name.equals("language")) { // issue 138: issue a warning if dc:title and dc:language is empty for 2.0 and 2.0.1 // note that an empty dc:identifier is checked in opf20.rng and will // therefore be reported as an error, that may or may not be a good idea. if (version == EPUBVersion.VERSION_2) { String value = (String) e.getPrivateData(); if (value == null || value.trim().length() < 1) { report.warning( path, parser.getLineNumber(), parser.getColumnNumber(), name + " element is empty"); } } } } }
public void startElement() { boolean registerEntry = true; XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); if (ns == null || ns.equals("") || ns.equals("http://openebook.org/namespaces/oeb-package/1.0/") || ns.equals("http://www.idpf.org/2007/opf")) { String name = e.getName(); if (name.equals("package")) { if (!ns.equals("http://www.idpf.org/2007/opf")) { report.warning( path, parser.getLineNumber(), parser.getColumnNumber(), "OPF file is using OEBPS 1.2 syntax allowing backwards compatibility"); opf12PackageFile = true; } /* * This section checks to see the value of the unique-identifier * attribute and stores it in the String uniqueIdent or reports * an error if the unique-identifier attribute is missing or * does not have a value */ String uniqueIdentAttr = e.getAttribute("unique-identifier"); if (uniqueIdentAttr != null && !uniqueIdentAttr.equals("")) { uniqueIdent = uniqueIdentAttr; } else { report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "unique-identifier attribute in package element must be present and have a value"); } } else if (name.equals("item")) { String id = e.getAttribute("id"); String href = e.getAttribute("href"); if (href != null && !(version == EPUBVersion.VERSION_3 && href.startsWith("http://"))) { try { href = PathUtil.resolveRelativeReference(path, href, null); } catch (IllegalArgumentException ex) { report.error(path, parser.getLineNumber(), parser.getColumnNumber(), ex.getMessage()); href = null; } } String mimeType = e.getAttribute("media-type"); String fallback = e.getAttribute("fallback"); String fallbackStyle = e.getAttribute("fallback-style"); String namespace = e.getAttribute("island-type"); String properties = e.getAttribute("properties"); if (properties != null) properties = properties.replaceAll("[\\s]+", " "); if (version == EPUBVersion.VERSION_3 && href.startsWith("http://") && !OPFChecker30.isBlessedAudioType(mimeType)) if (OPFChecker30.isCoreMediaType(mimeType)) { report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "Only audio and video remote resources are permitted"); } else { // mgy 20120414: this shouldn't even be a warning // report.warning( // path, // parser.getLineNumber(), // parser.getColumnNumber(), // "Remote resource not validated"); } OPFItem item = new OPFItem( id, href, mimeType, fallback, fallbackStyle, namespace, properties, parser.getLineNumber(), parser.getColumnNumber()); if (id != null) itemMapById.put(id, item); if (properties != null) { String propertyArray[] = properties.split(" "); for (int i = 0; i < propertyArray.length; i++) { if (propertyArray[i].equals("nav")) item.setNav(true); if (propertyArray[i].equals("scripted")) item.setScripted(true); } } if (href != null && registerEntry) { itemMapByPath.put(href, item); items.add(item); } } else if (name.equals("reference")) { String type = e.getAttribute("type"); String title = e.getAttribute("title"); String href = e.getAttribute("href"); if (href != null && xrefChecker != null) { try { href = PathUtil.resolveRelativeReference(path, href, null); xrefChecker.registerReference( path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.RT_GENERIC); } catch (IllegalArgumentException ex) { report.error(path, parser.getLineNumber(), parser.getColumnNumber(), ex.getMessage()); href = null; } } OPFReference ref = new OPFReference(type, title, href, parser.getLineNumber(), parser.getColumnNumber()); refs.add(ref); } else if (name.equals("spine")) { String idref = e.getAttribute("toc"); if (idref != null) { toc = (OPFItem) itemMapById.get(idref); if (toc == null) report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "item with id '" + idref + "' not found"); else { toc.setNcx(true); if (toc.getMimeType() != null && !toc.getMimeType().equals("application/x-dtbncx+xml")) report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "toc attribute references resource with non-NCX mime type; \"application/x-dtbncx+xml\" is expected"); } } } else if (name.equals("itemref")) { String idref = e.getAttribute("idref"); if (idref != null) { OPFItem item = getItemById(idref); if (item != null) { spine.add(item); item.setInSpine(true); String linear = e.getAttribute("linear"); if (linear != null && "no".equals(linear.trim())) { item.setSpineLinear(false); } else { item.setSpineLinear(true); } } else { report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "item with id '" + idref + "' not found"); } } } else if (name.equals("dc-metadata") || name.equals("x-metadata")) { if (!opf12PackageFile) report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "use of deprecated element '" + name + "'"); } } else if (ns.equals("http://purl.org/dc/elements/1.1/")) { // in the DC metadata, when the <identifier> element is parsed, if // it has a non-null and non-empty id attribute value that is the // same as the value of the unique-identifier attribute of the // package element, set uniqueIdentExists = true (to make sure that // the unique-identifier attribute references an existing // <identifier> id attribute String name = e.getName(); if (name.equals("identifier")) { String idAttr = e.getAttribute("id"); if (idAttr != null && !idAttr.equals("") && idAttr.equals(uniqueIdent)) uniqueIdentExists = true; } else if (name.equals("creator")) { String role = e.getAttributeNS("http://www.idpf.org/2007/opf", "role"); if (role != null && !role.equals("")) { if (!isValidRole(role)) report.error( path, parser.getLineNumber(), parser.getColumnNumber(), "role value '" + role + "' is not valid"); } } } }
private void processSrc(XMLElement e) { processRef(e.getAttribute("src"), XRefChecker.Type.HYPERLINK); }
private void processSeq(XMLElement e) { processRef( e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "textref"), XRefChecker.Type.HYPERLINK); checkType(e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type")); }
private void processMeta(XMLElement e) { processMetaProperty(e.getAttribute("property")); processMetaScheme(e.getAttribute("scheme")); }
public void startElement() { openElements++; XMLElement e = parser.getCurrentElement(); ElementLocation currentLocation = new ElementLocation(parser.getLineNumber(), parser.getColumnNumber()); elementLocationStack.push(currentLocation); if (!checkedUnsupportedXMLVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXMLVersion = true; } String id = e.getAttribute("id"); String baseTest = e.getAttributeNS(XMLConstants.XML_NS_URI, "base"); if (baseTest != null) { base = checkURI(baseTest); } if (!epubTypeInUse) { String eNS = e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type"); if (eNS != null) { epubTypeInUse = true; } } String ns = e.getNamespace(); String name = e.getName().toLowerCase(); XRefChecker.Type resourceType = XRefChecker.Type.GENERIC; if (ns != null) { if (ns.equals("http://www.w3.org/2000/svg")) { if (name.equals("lineargradient") || name.equals("radialgradient") || name.equals("pattern")) { resourceType = XRefChecker.Type.SVG_PAINT; } else if (name.equals("clippath")) { resourceType = XRefChecker.Type.SVG_CLIP_PATH; } else if (name.equals("symbol")) { resourceType = XRefChecker.Type.SVG_SYMBOL; } else if (name.equals("a")) { checkHRef(e, "http://www.w3.org/1999/xlink", "href"); } else if (name.equals("use")) { checkSymbol(e, "http://www.w3.org/1999/xlink", "href"); } else if (name.equals("image")) { checkImage(e, "http://www.w3.org/1999/xlink", "href"); } checkPaint(e, "fill"); checkPaint(e, "stroke"); } else if (ns.equals(EpubConstants.HtmlNamespaceUri)) { if (name.equals("a")) { checkHRef(e, null, "href"); } else if (name.equals("img")) { checkImage(e, null, "src"); } else if (name.equals("object")) { checkObject(e, null, "data"); } else if (name.equals("link")) { checkLink(e, null, "href"); } else if (name.equals("base")) { base = checkURI(e.getAttribute("href")); } else if (name.equals("style")) { textNode = new StringBuilder(); } else if (name.equals("iframe")) { checkIFrame(e); } else if (name.equals("table")) { ++tableDepth; } else if (name.equals("th") && tableDepth > 0) { hasTh = true; } else if (name.equals("thead") && tableDepth > 0) { hasThead = true; } else if (name.equals("caption") && tableDepth > 0) { hasCaption = true; } else if (name.equals("i") || name.equals("b") || name.equals("em") || name.equals("strong")) { checkBoldItalics(e); } resourceType = XRefChecker.Type.HYPERLINK; String style = e.getAttribute("style"); if (style != null && style.length() > 0) { CSSCheckerFactory.getInstance() .newInstance(context, style, currentLocation.getLineNumber(), true) .runChecks(); } } } if (xrefChecker.isPresent() && id != null) { xrefChecker .get() .registerAnchor( path, currentLocation.getLineNumber(), currentLocation.getColumnNumber(), id, resourceType); } }
protected void checkIFrame(XMLElement e) { report.message( MessageId.HTM_036, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), e.getName())); }