/*
* Copyright 2015-2016 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.ttml;
import java.io.Serializable;
import java.util.Collection;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Locator;
import com.skynav.ttv.model.Model;
import com.skynav.ttv.model.ttml.TTML2;
import com.skynav.ttv.model.ttml2.tt.Body;
import com.skynav.ttv.model.ttml2.tt.Break;
import com.skynav.ttv.model.ttml2.tt.Chunk;
import com.skynav.ttv.model.ttml2.tt.Data;
import com.skynav.ttv.model.ttml2.tt.Division;
import com.skynav.ttv.model.ttml2.tt.Head;
import com.skynav.ttv.model.ttml2.tt.Image;
import com.skynav.ttv.model.ttml2.tt.Initial;
import com.skynav.ttv.model.ttml2.tt.Layout;
import com.skynav.ttv.model.ttml2.tt.Metadata;
import com.skynav.ttv.model.ttml2.tt.Paragraph;
import com.skynav.ttv.model.ttml2.tt.Region;
import com.skynav.ttv.model.ttml2.tt.Set;
import com.skynav.ttv.model.ttml2.tt.Source;
import com.skynav.ttv.model.ttml2.tt.Span;
import com.skynav.ttv.model.ttml2.tt.Styling;
import com.skynav.ttv.model.ttml2.tt.TimedText;
import com.skynav.ttv.model.ttml2.ttm.Actor;
import com.skynav.ttv.model.ttml2.ttm.Agent;
import com.skynav.ttv.model.ttml2.ttm.Copyright;
import com.skynav.ttv.model.ttml2.ttm.Description;
import com.skynav.ttv.model.ttml2.ttm.Item;
import com.skynav.ttv.model.ttml2.ttm.Name;
import com.skynav.ttv.model.ttml2.ttm.Title;
import com.skynav.ttv.model.ttml2.ttp.Extensions;
import com.skynav.ttv.model.ttml2.ttp.Features;
import com.skynav.ttv.model.ttml2.ttp.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;
import com.skynav.ttv.verifier.util.Images;
import com.skynav.ttv.verifier.util.ResourceFormats;
import com.skynav.ttv.verifier.util.ResourceTypes;
public class TTML2SemanticsVerifier extends TTML1SemanticsVerifier {
public static final String NAMESPACE = TTML2.Constants.NAMESPACE_TT;
public static final QName formatAttributeName = new QName("", "format");
public static final QName sourceAttributeName = new QName("", "src");
public static final QName typeAttributeName = new QName("", "type");
public static final QName imageElementName = new QName(NAMESPACE, "image");
public static final QName sourceElementName = new QName(NAMESPACE, "source");
public TTML2SemanticsVerifier(Model model) {
super(model);
}
// verifier overrides
@Override
protected boolean verifyRoot(Object root) {
if (root instanceof TimedText)
return verifyTimedText(root);
else if (root instanceof Profile)
return verifyProfile(root);
else
return unexpectedContent(root);
}
@Override
protected boolean verifyStyling(Object styling) {
boolean failed = false;
if (super.verifyStyling(styling)) {
for (Object i : getStylingInitials(styling)) {
if (i instanceof Initial) {
Initial initial = (Initial) i;
if (verifyInitial(initial))
addInitialOverrides(initial);
else
failed = true;
}
}
} else
failed = true;
return !failed;
}
protected Collection<? extends Object> getStylingInitials(Object styling) {
assert styling instanceof Styling;
return ((Styling) styling).getInitial();
}
protected boolean verifyInitial(Initial initial) {
boolean failed = false;
if (!verifyStyleAttributes(initial))
failed = true;
if (!verifyOtherAttributes(initial))
failed = true;
return !failed;
}
private void addInitialOverrides(Object initial) {
this.styleVerifier.addInitialOverrides(initial, getContext());
}
@Override
protected boolean verifyMetadataItem(Object metadata) {
if (metadata instanceof JAXBElement<?>)
return verifyMetadata(((JAXBElement<?>)metadata).getValue());
else if (metadata instanceof Actor)
return verifyActor(metadata);
else if (metadata instanceof Agent)
return verifyAgent(metadata);
else if (metadata instanceof Copyright)
return verifyCopyright(metadata);
else if (metadata instanceof Description)
return verifyDescription(metadata);
else if (metadata instanceof Item)
return verifyItem(metadata);
else if (metadata instanceof Metadata)
return verifyMetadata(metadata);
else if (metadata instanceof Name)
return verifyName(metadata);
else if (metadata instanceof Title)
return verifyTitle(metadata);
else if (metadata instanceof Element)
return verifyForeignMetadata((Element)metadata);
else
return unexpectedContent(metadata);
}
@Override
protected boolean verifyAnimation(Object animation) {
if (animation instanceof Set)
return verifySet(animation);
else
return unexpectedContent(animation);
}
@Override
protected boolean verifyBlock(Object block) {
if (block instanceof Division)
return verifyDivision(block);
else if (block instanceof Paragraph)
return verifyParagraph(block);
else if (block instanceof Image)
return verifyImage(block);
else
return unexpectedContent(block);
}
@Override
protected boolean verifyContent(Serializable content) {
if (content instanceof JAXBElement<?>) {
Object element = ((JAXBElement<?>)content).getValue();
if (isMetadataItem(element))
return verifyMetadata(element);
else if (element instanceof Set)
return verifySet(element);
else if (element instanceof Span)
return verifySpan(element);
else if (element instanceof Break)
return verifyBreak(element);
else if (element instanceof Image)
return verifyImage(element);
else
return unexpectedContent(element);
} else if (content instanceof String) {
return true;
} else
return unexpectedContent(content);
}
@Override
protected Object findBlockBindingElement(Object block, Node node) {
if (getContext().getXMLNode(block) == node)
return block;
else if (block instanceof Image)
return findBindingElement((Image) block, node);
else
return super.findBlockBindingElement(block, node);
}
@Override
protected Object findContentBindingElement(Serializable content, Node node) {
if (content instanceof JAXBElement<?>) {
Object element = ((JAXBElement<?>)content).getValue();
if (getContext().getXMLNode(element) == node)
return element;
else if (element instanceof Image)
return findBindingElement((Image) element, node);
}
return super.findContentBindingElement(content, node);
}
// metadata overrides
@Override
protected boolean isMetadataItem(Object element) {
if (element instanceof Agent)
return true;
else if (element instanceof Copyright)
return true;
else if (element instanceof Description)
return true;
else if (element instanceof Metadata)
return true;
else if (element instanceof Title)
return true;
else
return false;
}
@Override
protected Object findMetadataItemBindingElement(Object metadata, Node node) {
if (metadata instanceof JAXBElement<?>)
return findMetadataItemBindingElement(((JAXBElement<?>)metadata).getValue(), node);
else if (getContext().getXMLNode(metadata) == node)
return metadata;
else if (metadata instanceof Actor)
return findActorBindingElement(metadata, node);
else if (metadata instanceof Agent)
return findAgentBindingElement(metadata, node);
else if (metadata instanceof Copyright)
return findCopyrightBindingElement(metadata, node);
else if (metadata instanceof Description)
return findDescriptionBindingElement(metadata, node);
else if (metadata instanceof Metadata)
return findMetadataBindingElement(metadata, node);
else if (metadata instanceof Name)
return findNameBindingElement(metadata, node);
else if (metadata instanceof Title)
return findTitleBindingElement(metadata, node);
else if (metadata instanceof Element)
return findForeignMetadataBindingElement((Element)metadata, node);
else
return null;
}
@Override
protected Object findAnimationBindingElement(Object animation, Node node) {
if (animation instanceof Set)
return findSetBindingElement(animation, node);
else
return null;
}
// accessor overrides
@Override
protected Object getTimedTextHead(Object tt) {
assert tt instanceof TimedText;
return ((TimedText) tt).getHead();
}
@Override
protected Object getTimedTextBody(Object tt) {
assert tt instanceof TimedText;
return ((TimedText) tt).getBody();
}
@Override
protected Collection<? extends Object> getHeadMetadata(Object head) {
assert head instanceof Head;
return ((Head) head).getMetadataClass();
}
@Override
protected Collection<? extends Object> getHeadParameters(Object head) {
assert head instanceof Head;
return ((Head) head).getParametersClass();
}
@Override
protected Object getHeadStyling(Object head) {
assert head instanceof Head;
return ((Head) head).getStyling();
}
@Override
protected Object getHeadLayout(Object head) {
assert head instanceof Head;
return ((Head) head).getLayout();
}
@Override
protected Collection<? extends Object> getStylingMetadata(Object styling) {
assert styling instanceof Styling;
return ((Styling) styling).getMetadataClass();
}
@Override
protected Collection<? extends Object> getStylingStyles(Object styling) {
assert styling instanceof Styling;
return ((Styling) styling).getStyle();
}
@Override
protected Collection<? extends Object> getLayoutMetadata(Object layout) {
assert layout instanceof Layout;
return ((Layout) layout).getMetadataClass();
}
@Override
protected Collection<? extends Object> getLayoutRegions(Object layout) {
assert layout instanceof Layout;
return ((Layout) layout).getRegion();
}
@Override
protected Collection<? extends Object> getRegionMetadata(Object region) {
assert region instanceof Region;
return ((Region) region).getMetadataClass();
}
@Override
protected Collection<? extends Object> getRegionAnimations(Object region) {
assert region instanceof Region;
return ((Region) region).getAnimationClass();
}
@Override
protected Collection<? extends Object> getRegionStyles(Object region) {
assert region instanceof Region;
return ((Region) region).getStyle();
}
@Override
protected Collection<? extends Object> getBodyMetadata(Object body) {
assert body instanceof Body;
return ((Body) body).getMetadataClass();
}
@Override
protected Collection<? extends Object> getBodyAnimations(Object body) {
assert body instanceof Body;
return ((Body) body).getAnimationClass();
}
@Override
protected Collection<? extends Object> getBodyDivisions(Object body) {
assert body instanceof Body;
return ((Body) body).getDiv();
}
@Override
protected Collection<? extends Object> getDivisionMetadata(Object division) {
assert division instanceof Division;
return ((Division) division).getMetadataClass();
}
@Override
protected Collection<? extends Object> getDivisionAnimations(Object division) {
assert division instanceof Division;
return ((Division) division).getAnimationClass();
}
@Override
protected Collection<? extends Object> getDivisionBlocks(Object division) {
assert division instanceof Division;
return ((Division) division).getBlockOrEmbeddedClass();
}
@Override
protected Collection<Serializable> getParagraphContent(Object paragraph) {
assert paragraph instanceof Paragraph;
return ((Paragraph) paragraph).getContent();
}
@Override
protected Collection<Serializable> getSpanContent(Object span) {
assert span instanceof Span;
return ((Span) span).getContent();
}
@Override
protected Collection<? extends Object> getBreakMetadata(Object br) {
assert br instanceof Break;
return ((Break) br).getMetadataClass();
}
@Override
protected Collection<? extends Object> getBreakAnimations(Object br) {
assert br instanceof Break;
return ((Break) br).getAnimationClass();
}
@Override
protected Collection<? extends Object> getSetMetadata(Object set) {
assert set instanceof Set;
return ((Set) set).getMetadataClass();
}
@Override
protected Collection<? extends Object> getProfileMetadata(Object profile) {
assert profile instanceof Profile;
return ((Profile) profile).getMetadataClass();
}
@Override
protected Collection<? extends Object> getProfileFeatures(Object profile) {
assert profile instanceof Profile;
return ((Profile) profile).getFeatures();
}
@Override
protected Collection<? extends Object> getProfileExtensions(Object profile) {
assert profile instanceof Profile;
return ((Profile) profile).getExtensions();
}
@Override
protected Collection<? extends Object> getFeaturesMetadata(Object features) {
assert features instanceof Features;
return ((Features) features).getMetadataClass();
}
@Override
protected Collection<? extends Object> getFeaturesFeatures(Object features) {
assert features instanceof Features;
return ((Features) features).getFeature();
}
@Override
protected Collection<? extends Object> getExtensionsMetadata(Object extensions) {
assert extensions instanceof Extensions;
return ((Extensions) extensions).getMetadataClass();
}
@Override
protected Collection<? extends Object> getExtensionsExtensions(Object extensions) {
assert extensions instanceof Extensions;
return ((Extensions) extensions).getExtension();
}
@Override
protected Collection<? extends Object> getAgentNames(Object agent) {
assert agent instanceof Agent;
return ((Agent) agent).getName();
}
@Override
protected Object getAgentActor(Object agent) {
assert agent instanceof Agent;
return ((Agent) agent).getActor();
}
@Override
protected Collection<? extends Object> getMetadataAny(Object metadata) {
assert metadata instanceof Metadata;
return ((Metadata) metadata).getAny();
}
// new elements
protected boolean verifyImage(Object image) {
boolean failed = false;
if (!verifyStyleAttributes(image))
failed = true;
if (!verifyImageAttributes(image))
failed = true;
if (!verifyOtherAttributes(image))
failed = true;
for (Object m : getImageMetadata(image)) {
if (!verifyMetadataItem(m))
failed = true;
}
for (Object s : getImageSources(image)) {
if (!verifySource(s))
failed = true;
}
if (!verifyStyledItem(image))
failed = true;
if (!failed && !verifyImageResources(image))
failed = true;
return !failed;
}
protected boolean verifyImageAttributes(Object image) {
boolean failed = false;
VerifierContext context = getContext();
Reporter reporter = context.getReporter();
Location location = getLocation(image);
Locator locator = location.getLocator();
// @src
String s = getImageSourceAttribute(image);
int numSources = getImageSources(image).size();
com.skynav.ttv.model.value.Image[] outputImage = new com.skynav.ttv.model.value.Image[1];
com.skynav.ttv.model.value.Image i = null;
if (s != null) {
if (!Images.isImage(s, location, context, false, outputImage)) {
Images.badImage(s, location, context);
failed = true;
} else if (numSources > 0) {
reporter.logError(reporter.message(locator, "*KEY*",
"No ''{0}'' child permitted when ''{1}'' attribute is specified.", sourceElementName, sourceAttributeName));
failed = true;
} else {
i = outputImage[0];
}
} else if (numSources == 0) {
reporter.logError(reporter.message(locator, "*KEY*",
"At least one ''{0}'' child is required when ''{1}'' attribute is not specified.", sourceElementName, sourceAttributeName));
failed = true;
}
// @type
String t = getImageTypeAttribute(image);
if (t != null) {
if (!ResourceTypes.isType(t, location, context, null)) {
ResourceTypes.badType(t, location, context);
failed = true;
} else {
if (!i.isExternal()) {
reporter.logError(reporter.message(locator, "*KEY*",
"A ''{0}'' attribute must not specified for internal image sources.", typeAttributeName));
failed = true;
}
}
} else {
if (i.isExternal()) {
if (reporter.isWarningEnabled("missing-type-for-external-source")) {
Message message = reporter.message(locator, "*KEY*",
"A ''{0}'' attribute should specified for external image sources.", typeAttributeName);
if (reporter.logWarning(message)) {
reporter.logError(message);
failed = true;
}
}
}
}
// @format
String f = getImageFormatAttribute(image);
if (f != null) {
if (!ResourceFormats.isFormat(f, location, context, null)) {
ResourceFormats.badFormat(f, location, context);
failed = true;
}
}
return !failed;
}
protected String getImageFormatAttribute(Object image) {
assert image instanceof Image;
return ((Image) image).getFormat();
}
protected String getImageSourceAttribute(Object image) {
assert image instanceof Image;
return ((Image) image).getSrc();
}
protected String getImageTypeAttribute(Object image) {
assert image instanceof Image;
return ((Image) image).getType();
}
protected Collection<? extends Object> getImageMetadata(Object image) {
assert image instanceof Image;
return ((Image) image).getMetadataClass();
}
protected Collection<? extends Object> getImageSources(Object image) {
assert image instanceof Image;
return ((Image) image).getSource();
}
protected boolean verifyImageResources(Object image) {
boolean failed = false;
VerifierContext context = getContext();
Location location = getLocation(image);
// @src
String s = getImageSourceAttribute(image);
if ((s != null) && !Images.isImage(s, location, context, true, null))
failed = true;
// [TBD] verify resources referenced by tt:source children
return !failed;
}
protected boolean verifySource(Object source) {
boolean failed = false;
if (!verifySourceAttributes(source))
failed = true;
if (!verifyOtherAttributes(source))
failed = true;
for (Object m : getSourceMetadata(source)) {
if (!verifyMetadataItem(m))
failed = true;
}
Object data = getSourceData(source);
if (data != null) {
if (!verifyData(data))
failed = true;
}
return !failed;
}
protected boolean verifySourceAttributes(Object source) {
// [TBD] - src
// [TBD] - type
// [TBD] - format
return true;
}
protected Collection<? extends Object> getSourceMetadata(Object source) {
assert source instanceof Source;
return ((Source) source).getMetadataClass();
}
protected Data getSourceData(Object source) {
assert source instanceof Source;
return ((Source) source).getData();
}
protected boolean verifyData(Object data) {
boolean failed = false;
if (!verifyDataAttributes(data))
failed = true;
if (!verifyOtherAttributes(data))
failed = true;
for (Serializable s : getDataContent(data)) {
if (!verifyDataContent(s))
failed = true;
}
return !failed;
}
protected boolean verifyDataAttributes(Object data) {
// [TBD] - src
// [TBD] - type
// [TBD] - format
// [TBD] - length
// [TBD] - encoding
return true;
}
protected Collection<Serializable> getDataContent(Object data) {
assert data instanceof Data;
return ((Data) data).getContent();
}
protected boolean verifyDataContent(Serializable content) {
if (content instanceof JAXBElement<?>) {
Object element = ((JAXBElement<?>)content).getValue();
if (isMetadataItem(element))
return verifyMetadata(element);
else if (element instanceof Chunk)
return verifyChunk(element);
else if (element instanceof Source)
return verifySource(element);
else
return unexpectedContent(element);
} else if (content instanceof String) {
return true;
} else
return unexpectedContent(content);
}
protected boolean verifyChunk(Object chunk) {
boolean failed = false;
if (!verifyChunkAttributes(chunk))
failed = true;
if (!verifyOtherAttributes(chunk))
failed = true;
return !failed;
}
protected boolean verifyChunkAttributes(Object chunk) {
// [TBD] - length
// [TBD] - encoding
return true;
}
protected boolean verifyItem(Object item) {
boolean failed = false;
if (!verifyOtherAttributes(item))
failed = true;
if (!verifyMetadataItem(metadataVerifier, item))
failed = true;
return !failed;
}
}