/* * Copyright 2013-2015 Skynav, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.skynav.ttv.verifier.util; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.xml.sax.Locator; import com.skynav.ttv.model.Model; import com.skynav.ttv.model.Profile; import com.skynav.ttv.util.Location; import com.skynav.ttv.util.Message; import com.skynav.ttv.util.Reporter; import com.skynav.ttv.verifier.VerifierContext; public class Profiles { public static boolean isFeatureDesignation(String value, Location location, VerifierContext context, String base) { try { URI featureUri = new URI(base).resolve(value); String uriString = featureUri.toString(); String uriFragment = featureUri.getFragment(); String featureNamespace = (uriFragment != null) ? uriString.substring(0, uriString.indexOf("#" + uriFragment)) : uriString; String ttFeatureNamespace = context.getModel().getTTFeatureNamespaceUri().toString(); if (!featureNamespace.equals(ttFeatureNamespace)) return false; else if (uriFragment == null) return false; else if (uriFragment.length() == 0) return false; else if (!context.getModel().isStandardFeatureDesignation(featureUri)) return false; else return true; } catch (URISyntaxException e) { // Phase 3 will have already reported that value doesn't correspond with xs:anyURI. return false; } } public static void badFeatureDesignation(String value, Location location, VerifierContext context, String base) { Reporter reporter = context.getReporter(); Locator locator = location.getLocator(); Message message = null; try { URI featureUri = new URI(base).resolve(value); String uriString = featureUri.toString(); String uriFragment = featureUri.getFragment(); String featureNamespace = (uriFragment != null) ? uriString.substring(0, uriString.indexOf("#" + uriFragment)) : uriString; String ttFeatureNamespace = context.getModel().getTTFeatureNamespaceUri().toString(); if (!featureNamespace.equals(ttFeatureNamespace)) { message = reporter.message(locator, "*KEY*", "Unknown namespace in feature designation ''{0}'', expect TT Feature Namespace ''{1}''.", featureUri, ttFeatureNamespace); } else if (uriFragment == null) { message = reporter.message(locator, "*KEY*", "Missing designation in feature designation ''{0}''.", featureUri); } else if (uriFragment.length() == 0) { message =reporter.message(locator, "*KEY*", "Empty designation token in feature designation ''{0}''.", featureUri); } else if (!context.getModel().isStandardFeatureDesignation(featureUri)) { message =reporter.message(locator, "*KEY*", "Unknown designation token in feature designation ''{0}''.", featureUri); } } catch (URISyntaxException e) { // Phase 3 will have already reported that value doesn't correspond with xs:anyURI. } if (message != null) reporter.logInfo(message); } public static boolean isExtensionDesignation(String value, Location location, VerifierContext context, String base) { Reporter reporter = context.getReporter(); Locator locator = location.getLocator(); try { URI extensionUri = new URI(base).resolve(value); String uriString = extensionUri.toString(); String uriFragment = extensionUri.getFragment(); String extensionNamespace = (uriFragment != null) ? uriString.substring(0, uriString.indexOf("#" + uriFragment)) : uriString; String ttExtensionNamespace = context.getModel().getTTExtensionNamespaceUri().toString(); String modelExtensionNamespace = context.getModel().getExtensionNamespaceUri().toString(); if (uriFragment == null) return false; else if (uriFragment.length() == 0) return false; else if (extensionNamespace.equals(ttExtensionNamespace)) return context.getModel().isStandardExtensionDesignation(extensionUri); else if (extensionNamespace.equals(modelExtensionNamespace)) return context.getModel().isStandardExtensionDesignation(extensionUri); else { if (reporter.isWarningEnabled("references-other-extension-namespace")) { if (reporter.logWarning(reporter.message(locator, "*KEY*", "Other namespace in extension designation ''{0}''.", extensionUri))) return false; } if (reporter.isWarningEnabled("references-non-standard-extension")) { if (reporter.logWarning(reporter.message(locator, "*KEY*", "Non-standard extension designation ''{0}'' in an Other Extension Namespace.", extensionUri))) return false; } return true; } } catch (URISyntaxException e) { // Phase 3 will have already reported that value doesn't correspond with xs:anyURI. return false; } } public static void badExtensionDesignation(String value, Location location, VerifierContext context, String base) { Reporter reporter = context.getReporter(); Locator locator = location.getLocator(); Message message = null; try { URI extensionUri = new URI(base).resolve(value); String uriString = extensionUri.toString(); String uriFragment = extensionUri.getFragment(); String extensionNamespace = (uriFragment != null) ? uriString.substring(0, uriString.indexOf("#" + uriFragment)) : uriString; Model model = context.getModel(); String ttExtensionNamespace = model.getTTExtensionNamespaceUri().toString(); String modelExtensionNamespace = model.getExtensionNamespaceUri().toString(); String modelName = model.getName(); if (uriFragment == null) { message = reporter.message(locator, "*KEY*", "Missing designation in extension designation ''{0}''.", extensionUri); } else if (uriFragment.length() == 0) { message = reporter.message(locator, "*KEY*", "Empty designation token in extension designation ''{0}''.", extensionUri); } else if (extensionNamespace.equals(ttExtensionNamespace)) { if (!model.isStandardExtensionDesignation(extensionUri)) { message = reporter.message(locator, "*KEY*", "Unknown designation token in extension designation ''{0}'' in TT Extension Namespace.", extensionUri); } } else if (extensionNamespace.equals(modelExtensionNamespace)) { if (!model.isStandardExtensionDesignation(extensionUri)) { message = reporter.message(locator, "*KEY*", "Unknown designation token in extension designation ''{0}'' in Model ({1}) Extension Namespace.", extensionUri, modelName); } } } catch (URISyntaxException e) { // Phase 3 will have already reported that value doesn't correspond with xs:anyURI. } if (message != null) reporter.logInfo(message); } public static boolean isProfileDesignators(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators) { return isProfileDesignators(value, location, context, ttmlProfileNamespaceUri, designators, null, null); } private static final Pattern quantifiedDesignatorsPattern = Pattern.compile("(\\p{Alpha}+)\\(([^\\)]*)\\)"); public static boolean isProfileDesignators(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators, List<URI> outputDesignators, Profile.Quantifier[] outputQuantifier) { String v = value; Profile.Quantifier q; Matcher m = quantifiedDesignatorsPattern.matcher(v); if (m.matches()) { String ident = m.group(1); String arguments = m.group(2).trim(); if (ident.equals("any")) q = Profile.Quantifier.ANY; else if (ident.equals("all")) q = Profile.Quantifier.ALL; else return false; v = arguments; } else q = null; if (q == null) q = Profile.Quantifier.ALL; List<URI> uris = new java.util.ArrayList<URI>(); v = v.trim(); if (v.isEmpty()) return false; else { for (String d : v.split("\\s+")) { URI[] uri = new URI[1]; if (!isProfileDesignator(d, location, context, ttmlProfileNamespaceUri, designators, uri)) return false; else uris.add(uri[0]); } } Set<URI> uu = new java.util.HashSet<URI>(); for (URI u : uris) { if (uu.contains(u)) return false; else uu.add(u); } if (outputDesignators != null) { outputDesignators.clear(); outputDesignators.addAll(uris); } if (outputQuantifier != null) { outputQuantifier[0] = q; } return true; } public static boolean isProfileDesignator(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators) { return isProfileDesignator(value, location, context, ttmlProfileNamespaceUri, designators, null); } private static final Pattern badDelimiterSuffixPattern = Pattern.compile("[^\\,\\;\\)]+([\\,\\;\\)])"); public static boolean isProfileDesignator(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators, URI[] outputDesignator) { boolean failed = false; URI uri = null; Matcher m = badDelimiterSuffixPattern.matcher(value); if (m.matches()) failed = true; else { try { uri = new URI(value); if (!uri.isAbsolute()) { if (uri.getFragment() != null) { // [TBD] - IMPLEMENT ME throw new UnsupportedOperationException(); } uri = ttmlProfileNamespaceUri.resolve(uri); } if (!designators.contains(uri)) { String s = uri.toString(); if (s.indexOf(ttmlProfileNamespaceUri.toString()) == 0) { // error - unknown designator in TTML profile namespace failed = true; } else { Reporter reporter = context.getReporter(); if (reporter.isWarningEnabled("references-non-standard-profile")) { if (reporter.logWarning(reporter.message(location.getLocator(), "*KEY*", "Non-standard profile designator ''{0}''.", uri))) failed = true; } } } } catch (URISyntaxException e) { failed = true; } } if (!failed && (outputDesignator != null)) outputDesignator[0] = uri; return !failed; } public static void badProfileDesignators(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators) { Reporter reporter = context.getReporter(); Locator locator = location.getLocator(); String v = value; Matcher m = quantifiedDesignatorsPattern.matcher(v); if (m.matches()) { String ident = m.group(1); String arguments = m.group(2); if (!ident.equals("all") && !ident.equals("any")) { reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile quantifier syntax, unknown quantifier ''{0}''.", ident)); return; } else v = arguments; } List<URI> uris = new java.util.ArrayList<URI>(); v = v.trim(); if (v.isEmpty()) reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile quantifier syntax, empty designator list.")); else { for (String d : v.split("\\s+")) { URI[] uri = new URI[1]; if (!isProfileDesignator(d, location, context, ttmlProfileNamespaceUri, designators, uri)) badProfileDesignator(d, location, context, ttmlProfileNamespaceUri, designators); else uris.add(uri[0]); } } Set<URI> uu = new java.util.HashSet<URI>(); for (URI u : uris) { if (uu.contains(u)) reporter.logInfo(reporter.message(locator, "*KEY*", "Duplicate profile designator ''{0}''.", u.toString())); else uu.add(u); } } public static void badProfileDesignator(String value, Location location, VerifierContext context, URI ttmlProfileNamespaceUri, Set<URI> designators) { Reporter reporter = context.getReporter(); Locator locator = location.getLocator(); Matcher m = badDelimiterSuffixPattern.matcher(value); if (m.matches()) { String suffix = m.group(1); reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile designator ''{0}'' ends with unexpected delimiter suffix ''{1}''.", value, suffix)); } else { try { URI uri = new URI(value); if (!uri.isAbsolute()) uri = ttmlProfileNamespaceUri.resolve(uri); if (!designators.contains(uri)) { String s = uri.toString(); if (s.indexOf(ttmlProfileNamespaceUri.toString()) == 0) { reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile designator, unrecognized designator ''{0}'' in TT Profile Namespace.", value)); } else { reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile designator, unrecognized designator ''{0}'' in Other Profile Namespace.", value)); } } } catch (URISyntaxException e) { reporter.logInfo(reporter.message(locator, "*KEY*", "Bad profile designator ''{0}'', invalid designator syntax.", value)); } } } }