diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-05-09 00:33:51 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-05-09 00:33:51 +0200 |
| commit | 1b7394d83f64a8655787d82189c3170a2128c16b (patch) | |
| tree | 7d4a3970623956b215d9e258e5dcf658c218254b | |
| parent | f3e78c300efbf7519eda8252e7f71db0e3f1caa9 (diff) | |
Verify the XML of subtitle files.
| -rw-r--r-- | src/verify.cc | 53 | ||||
| -rw-r--r-- | test/data/broken_smpte.mxf | bin | 0 -> 62955 bytes | |||
| -rw-r--r-- | test/verify_test.cc | 111 | ||||
| -rw-r--r-- | xsd/DCDMSubtitle-2010.xsd | 417 | ||||
| -rw-r--r-- | xsd/DCSubtitle.v1.mattsson.xsd | 254 |
5 files changed, 831 insertions, 4 deletions
diff --git a/src/verify.cc b/src/verify.cc index c06b7ff9..11eb75d2 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -37,6 +37,8 @@ #include "reel.h" #include "reel_picture_asset.h" #include "reel_sound_asset.h" +#include "reel_subtitle_asset.h" +#include "interop_subtitle_asset.h" #include "mono_picture_asset.h" #include "mono_picture_frame.h" #include "stereo_picture_asset.h" @@ -61,6 +63,7 @@ #include <xercesc/dom/DOMAttr.hpp> #include <xercesc/dom/DOMErrorHandler.hpp> #include <xercesc/framework/LocalFileInputSource.hpp> +#include <xercesc/framework/MemBufInputSource.hpp> #include <boost/noncopyable.hpp> #include <boost/foreach.hpp> #include <boost/algorithm/string.hpp> @@ -200,6 +203,8 @@ public: add("http://www.digicine.com/PROTO-ASDCP-CPL-20040511.xsd", "PROTO-ASDCP-CPL-20040511.xsd"); add("http://www.digicine.com/PROTO-ASDCP-PKL-20040311.xsd", "PROTO-ASDCP-PKL-20040311.xsd"); add("http://www.digicine.com/PROTO-ASDCP-AM-20040311.xsd", "PROTO-ASDCP-AM-20040311.xsd"); + add("interop-subs", "DCSubtitle.v1.mattsson.xsd"); + add("http://www.smpte-ra.org/schemas/428-7/2010/DCST.xsd", "SMPTE-428-7-2010-DCST.xsd"); } InputSource* resolveEntity(XMLCh const *, XMLCh const * system_id) @@ -224,9 +229,25 @@ private: boost::filesystem::path _xsd_dtd_directory; }; -static + +static void +parse (XercesDOMParser& parser, boost::filesystem::path xml) +{ + parser.parse(xml.string().c_str()); +} + + +static void +parse (XercesDOMParser& parser, std::string xml) +{ + xercesc::MemBufInputSource buf(reinterpret_cast<unsigned char const*>(xml.c_str()), xml.size(), ""); + parser.parse(buf); +} + + +template <class T> void -validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_directory, list<VerificationNote>& notes) +validate_xml (T xml, boost::filesystem::path xsd_dtd_directory, list<VerificationNote>& notes) { try { XMLPlatformUtils::Initialize (); @@ -253,6 +274,8 @@ validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_ schema["http://www.digicine.com/PROTO-ASDCP-CPL-20040511#"] = "PROTO-ASDCP-CPL-20040511.xsd"; schema["http://www.digicine.com/PROTO-ASDCP-PKL-20040311#"] = "PROTO-ASDCP-PKL-20040311.xsd"; schema["http://www.digicine.com/PROTO-ASDCP-AM-20040311#"] = "PROTO-ASDCP-AM-20040311.xsd"; + schema["interop-subs"] = "DCSubtitle.v1.mattsson.xsd"; + schema["http://www.smpte-ra.org/schemas/428-7/2010/DCST.xsd"] = "DCDMSubtitle-2010.xsd"; string locations; for (map<string, string>::const_iterator i = schema.begin(); i != schema.end(); ++i) { @@ -271,7 +294,7 @@ validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_ try { parser.resetDocumentPool(); - parser.parse(xml_file.string().c_str()); + parse(parser, xml); } catch (XMLException& e) { throw MiscError(xml_ch_to_string(e.getMessage())); } catch (DOMException& e) { @@ -289,7 +312,7 @@ validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_ VerificationNote::VERIFY_ERROR, VerificationNote::XML_VALIDATION_ERROR, i.message(), - xml_file, + xml, i.line() ) ); @@ -487,6 +510,23 @@ verify_main_sound_asset ( } +static void +verify_main_subtitle_asset ( + shared_ptr<const Reel> reel, + function<void (string, optional<boost::filesystem::path>)> stage, + boost::filesystem::path xsd_dtd_directory, + list<VerificationNote>& notes + ) +{ + shared_ptr<ReelSubtitleAsset> reel_asset = reel->main_subtitle (); + stage ("Checking subtitle XML", reel->main_subtitle()->asset()->file()); + /* Note: we must not use SubtitleAsset::xml_as_string() here as that will mean the data on disk + * gets passed through libdcp which may clean up and therefore hide errors. + */ + validate_xml (reel->main_subtitle()->asset()->raw_xml(), xsd_dtd_directory, notes); +} + + list<VerificationNote> dcp::verify ( vector<boost::filesystem::path> directories, @@ -556,9 +596,14 @@ dcp::verify ( verify_main_picture_asset (dcp, reel, stage, progress, notes); } } + if (reel->main_sound() && reel->main_sound()->asset_ref().resolved()) { verify_main_sound_asset (dcp, reel, stage, progress, notes); } + + if (reel->main_subtitle() && reel->main_subtitle()->asset_ref().resolved()) { + verify_main_subtitle_asset (reel, stage, xsd_dtd_directory, notes); + } } } diff --git a/test/data/broken_smpte.mxf b/test/data/broken_smpte.mxf Binary files differnew file mode 100644 index 00000000..f647349d --- /dev/null +++ b/test/data/broken_smpte.mxf diff --git a/test/verify_test.cc b/test/verify_test.cc index b8a354ad..d744eff6 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -41,6 +41,9 @@ #include "openjpeg_image.h" #include "mono_picture_asset.h" #include "mono_picture_asset_writer.h" +#include "interop_subtitle_asset.h" +#include "smpte_subtitle_asset.h" +#include "reel_subtitle_asset.h" #include "compose.hpp" #include <boost/test/unit_test.hpp> #include <boost/foreach.hpp> @@ -624,3 +627,111 @@ BOOST_AUTO_TEST_CASE (verify_test17) BOOST_REQUIRE_EQUAL (notes.size(), 0); } + +/* DCP with valid Interop subtitles */ +BOOST_AUTO_TEST_CASE (verify_test18) +{ + boost::filesystem::path const dir("build/test/verify_test18"); + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml"); + shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml")); + shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0)); + shared_ptr<dcp::Reel> reel(new dcp::Reel()); + reel->add (reel_asset); + shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE)); + cpl->add (reel); + shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir)); + dcp->add (cpl); + dcp->write_xml (dcp::INTEROP); + + vector<boost::filesystem::path> dirs; + dirs.push_back (dir); + list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd"); + BOOST_REQUIRE_EQUAL (notes.size(), 0); +} + + +/* DCP with broken Interop subtitles */ +BOOST_AUTO_TEST_CASE (verify_test19) +{ + boost::filesystem::path const dir("build/test/verify_test19"); + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml"); + shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml")); + shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0)); + shared_ptr<dcp::Reel> reel(new dcp::Reel()); + reel->add (reel_asset); + shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE)); + cpl->add (reel); + shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir)); + dcp->add (cpl); + dcp->write_xml (dcp::INTEROP); + + { + Editor e (dir / "subs.xml"); + e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>"); + } + + vector<boost::filesystem::path> dirs; + dirs.push_back (dir); + list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd"); + dump_notes(notes); + BOOST_REQUIRE_EQUAL (notes.size(), 2); + BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR); + BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR); +} + + +/* DCP with valid SMPTE subtitles */ +BOOST_AUTO_TEST_CASE (verify_test20) +{ + boost::filesystem::path const dir("build/test/verify_test20"); + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf"); + shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf")); + shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0)); + shared_ptr<dcp::Reel> reel(new dcp::Reel()); + reel->add (reel_asset); + shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE)); + cpl->add (reel); + shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir)); + dcp->add (cpl); + dcp->write_xml (dcp::SMPTE); + + vector<boost::filesystem::path> dirs; + dirs.push_back (dir); + list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd"); + dump_notes (notes); + BOOST_REQUIRE_EQUAL (notes.size(), 0); +} + + +/* DCP with broken SMPTE subtitles */ +BOOST_AUTO_TEST_CASE (verify_test21) +{ + boost::filesystem::path const dir("build/test/verify_test21"); + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf"); + shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf")); + shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0)); + shared_ptr<dcp::Reel> reel(new dcp::Reel()); + reel->add (reel_asset); + shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE)); + cpl->add (reel); + shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir)); + dcp->add (cpl); + dcp->write_xml (dcp::SMPTE); + + vector<boost::filesystem::path> dirs; + dirs.push_back (dir); + list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd"); + dump_notes (notes); + BOOST_REQUIRE_EQUAL (notes.size(), 2); + BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR); + BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR); +} + diff --git a/xsd/DCDMSubtitle-2010.xsd b/xsd/DCDMSubtitle-2010.xsd new file mode 100644 index 00000000..1b4abfa5 --- /dev/null +++ b/xsd/DCDMSubtitle-2010.xsd @@ -0,0 +1,417 @@ +<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Copyright (c), Society of Motion Pictures and Television Engineers. 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. 3. Neither the
+name of the copyright holder nor the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER OR 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.
+-->
+
+<!--
+This document is an element of SMPTE ST 2067-100:2014, which is available at http://standards.smpte.org.
+To ensure interoperability, users are encouraged to: (a) retain this notice; (b) retrieve the recent versions
+of this document and its companion defining engineering document. In particular, this document alone might not
+be sufficient to ensure interoperability; (c) highlight and explain any modification they make to this document;
+and (d) report issues to the Director of Standards at https://www.smpte.org/about/staff.
+-->
+
+<xs:schema
+ targetNamespace="http://www.smpte-ra.org/schemas/428-7/2010/DCST"
+ xmlns:dcst="http://www.smpte-ra.org/schemas/428-7/2010/DCST"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+<!-- This version of the schema was produced for publication with ST 428-7:2014. It has been corrected from its original 2010 published version. Refer to ST 428-7:2014 Section 8 for additional details. -->
+
+
+ <!-- SubtitleReel -->
+ <xs:element name="SubtitleReel" type="dcst:SubtitleReelType"/>
+ <xs:complexType name="SubtitleReelType">
+ <xs:sequence>
+ <xs:element name="Id" type="dcst:UUID"/>
+ <xs:element name="ContentTitleText" type="dcst:UserText"/>
+ <xs:element name="AnnotationText" type="dcst:UserText" minOccurs="0"/>
+ <xs:element name="IssueDate" type="xs:dateTime"/>
+ <xs:element name="ReelNumber" type="xs:positiveInteger" minOccurs="0"/>
+ <xs:element name="Language" type="xs:language" minOccurs="0" default="en"/>
+ <xs:element name="EditRate" type="dcst:RationalType"/>
+ <xs:element name="TimeCodeRate" type="xs:positiveInteger"/>
+ <xs:element name="StartTime" type="dcst:TimeCodeType" minOccurs="0"/>
+ <xs:element name="DisplayType" type="dcst:scopedTokenType" minOccurs="0"/>
+ <xs:element name="LoadFont" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute name="ID" type="xs:string" use="optional"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="SubtitleList">
+ <xs:complexType>
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="Subtitle" type="dcst:SubtitleType"/>
+ <xs:element name="Font">
+ <xs:complexType mixed="true">
+ <xs:complexContent mixed="true">
+ <xs:extension base="dcst:FontType">
+ <xs:sequence>
+ <xs:element name="Subtitle" type="dcst:SubtitleType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Subtitle -->
+ <xs:complexType name="SubtitleType">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="Text" type="dcst:TextType"/>
+ <xs:element name="Image" type="dcst:ImageType"/>
+ <xs:element name="Font">
+ <xs:complexType mixed="true">
+ <xs:complexContent mixed="true">
+ <xs:extension base="dcst:FontType">
+ <xs:sequence>
+ <xs:element name="Text" type="dcst:TextType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="SpotNumber" type="xs:string" use="optional"/>
+ <xs:attribute name="TimeIn" type="dcst:TimeCodeType" use="required"/>
+ <xs:attribute name="TimeOut" type="dcst:TimeCodeType" use="required"/>
+ <xs:attribute name="FadeUpTime" type="dcst:TimeCodeType" use="optional"/>
+ <xs:attribute name="FadeDownTime" type="dcst:TimeCodeType" use="optional"/>
+ </xs:complexType>
+
+ <!-- Image -->
+ <xs:complexType name="ImageType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute name="Halign" use="optional" default="center">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="center"/>
+ <xs:enumeration value="left"/>
+ <xs:enumeration value="right"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Hposition" use="optional" default="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-100"/>
+ <xs:maxInclusive value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Valign" use="optional" default="center">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="center"/>
+ <xs:enumeration value="bottom"/>
+ <xs:enumeration value="top"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Vposition" use="optional" default="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-100"/>
+ <xs:maxInclusive value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- Font -->
+ <xs:complexType name="FontType" mixed="true">
+ <xs:attribute name="Script" use="optional" default="normal">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="normal"/>
+ <xs:enumeration value="super"/>
+ <xs:enumeration value="sub"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Effect" use="optional" default="shadow">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="none"/>
+ <xs:enumeration value="border"/>
+ <xs:enumeration value="shadow"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Italic" use="optional" default="no">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="yes"/>
+ <xs:enumeration value="no"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Underline" use="optional" default="no">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="yes"/>
+ <xs:enumeration value="no"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Weight" use="optional" default="normal">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="bold"/>
+ <xs:enumeration value="normal"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="ID" type="xs:string" use="optional"/>
+ <xs:attribute name="Color" use="optional" default="FFFFFFFF">
+ <xs:simpleType>
+ <xs:restriction base="xs:hexBinary">
+ <xs:length value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="EffectColor" use="optional" default="FF000000">
+ <xs:simpleType>
+ <xs:restriction base="xs:hexBinary">
+ <xs:length value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Size" use="optional" default="42">
+ <xs:simpleType>
+ <xs:restriction base="xs:positiveInteger"/>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="AspectAdjust" use="optional" default="1.0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="0.25"/>
+ <xs:maxInclusive value="4.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Spacing" use="optional" default="0.0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- Text -->
+ <xs:complexType name="TextType" mixed="true">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="Font" type="dcst:FontType"/>
+ <xs:element name="Ruby" type="dcst:RubyType"/>
+ <xs:element name="Space" type="dcst:SpaceType"/>
+ <xs:element name="HGroup" type="xs:string"/>
+ <xs:element name="Rotate" type="dcst:RotateType"/>
+ </xs:choice>
+ <xs:attribute name="Halign" use="optional" default="center">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="center"/>
+ <xs:enumeration value="left"/>
+ <xs:enumeration value="right"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Hposition" use="optional" default="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-100"/>
+ <xs:maxInclusive value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Valign" use="optional" default="center">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="center"/>
+ <xs:enumeration value="bottom"/>
+ <xs:enumeration value="top"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Vposition" use="optional" default="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-100"/>
+ <xs:maxInclusive value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Direction" use="optional" default="ltr">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="ltr"/>
+ <xs:enumeration value="rtl"/>
+ <xs:enumeration value="ttb"/>
+ <xs:enumeration value="btt"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- Rational Type -->
+ <xs:simpleType name="RationalType">
+ <xs:restriction>
+ <xs:simpleType>
+ <xs:list itemType="xs:long"/>
+ </xs:simpleType>
+ <xs:length value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- TimeCode Type -->
+ <xs:simpleType name="TimeCodeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-2][0-9]:[0-5][0-9]:[0-5][0-9]:[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- Ruby Type -->
+ <xs:complexType name="RubyType">
+ <xs:sequence>
+ <xs:element name="Rb" type="xs:string"/>
+ <xs:element name="Rt">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="Size" use="optional" default="0.5">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minExclusive value="0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Position" use="optional" default="before">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="before"/>
+ <xs:enumeration value="after"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Offset" use="optional" default="0.0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="Spacing" use="optional" default="0.0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="AspectAdjust" use="optional" default="1.0">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="0.25"/>
+ <xs:maxInclusive value="4.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Rotate Type -->
+ <xs:complexType name="RotateType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="Direction" use="optional" default="none">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="none"/>
+ <xs:enumeration value="left"/>
+ <xs:enumeration value="right"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- Space Type -->
+ <xs:complexType name="SpaceType">
+ <xs:simpleContent>
+ <xs:extension base="dcst:EmptyElement">
+ <xs:attribute name="Size" use="optional" default="0.5">
+ <xs:simpleType>
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="-1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- UUID Type -->
+ <xs:simpleType name="UUID">
+ <xs:restriction base="xs:anyURI">
+ <xs:pattern value="urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- UserText Type -->
+ <xs:complexType name="UserText">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="language" type="xs:language" use="optional" default="en"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- Scoped Token Type -->
+ <xs:complexType name="scopedTokenType">
+ <xs:simpleContent>
+ <xs:extension base="xs:token">
+ <xs:attribute name="scope" type="xs:anyURI" use="optional"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- EmptyElement Type -->
+ <xs:simpleType name="EmptyElement">
+ <xs:restriction base="xs:string">
+ <xs:length value="0"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/xsd/DCSubtitle.v1.mattsson.xsd b/xsd/DCSubtitle.v1.mattsson.xsd new file mode 100644 index 00000000..acdfcd84 --- /dev/null +++ b/xsd/DCSubtitle.v1.mattsson.xsd @@ -0,0 +1,254 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xs:element name="DCSubtitle"> + <xs:complexType> + <xs:sequence> + <xs:element name="SubtitleID" type="UUIDType"/> + <xs:element name="MovieTitle" type="xs:string"/> + <xs:element name="ReelNumber" type="xs:string"/> + <xs:element name="Language" type="xs:string"/> + <xs:element ref="LoadFont" minOccurs="0" maxOccurs="unbounded"/> + <xs:element ref="Font" minOccurs="0" maxOccurs="unbounded"/> + <xs:element ref="Subtitle" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="Version" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="1.0"/> + <xs:enumeration value="1.1"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + </xs:element> + <xs:element name="LoadFont"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="spaceType"> + <xs:attribute name="Id" use="required" type="xs:string"/> + <xs:attribute name="URI" use="required" type="xs:anyURI"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element name="Font"> + <xs:complexType mixed="true"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element ref="Font"/> + <xs:element ref="Subtitle"/> + <xs:element ref="Text"/> + <xs:element ref="Image"/> + </xs:choice> + <xs:attribute name="Id" type="xs:string"/> + <xs:attribute name="Color" type="fontColorType"/> + <xs:attribute name="Effect"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="none"/> + <xs:enumeration value="border"/> + <xs:enumeration value="shadow"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="EffectColor" type="fontColorType"/> + <xs:attribute name="Italic" type="yesNoType"/> + <xs:attribute name="Script"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal"/> + <xs:enumeration value="super"/> + <xs:enumeration value="sub"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="Size" type="xs:positiveInteger"/> + <xs:attribute name="AspectAdjust"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.25"/> + <xs:maxInclusive value="4.0"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="Underlined" type="yesNoType"/> + <xs:attribute name="Weight"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="bold"/> + <xs:enumeration value="normal"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="Spacing" type="spacingType"/> + </xs:complexType> + </xs:element> + <xs:element name="Subtitle"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element ref="Font"/> + <xs:element ref="Text"/> + <xs:element ref="Image"/> + </xs:choice> + <xs:attribute name="SpotNumber" use="required" type="xs:string"/> + <xs:attribute name="TimeIn" use="required" type="timeType"/> + <xs:attribute name="TimeOut" use="required" type="timeType"/> + <xs:attribute name="FadeUpTime" type="fadeTimeType"/> + <xs:attribute name="FadeDownTime" type="fadeTimeType"/> + </xs:complexType> + </xs:element> + <xs:element name="Text"> + <xs:complexType mixed="true"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element ref="Font"/> + <xs:element minOccurs="0" maxOccurs="unbounded" ref="Ruby"/> + <xs:element minOccurs="0" maxOccurs="unbounded" ref="Space"/> + <xs:element minOccurs="0" maxOccurs="unbounded" ref="HGroup"/> + <xs:element minOccurs="0" maxOccurs="unbounded" ref="Rotate"/> + </xs:choice> + <xs:attribute name="Direction"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="horizontal"/> + <xs:enumeration value="vertical"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="HAlign" type="hAlignType"/> + <xs:attribute name="HPosition" type="positionType"/> + <xs:attribute name="VAlign" type="vAlignType" /> + <xs:attribute name="VPosition" type="positionType"/> + </xs:complexType> + </xs:element> + <xs:element name="Ruby"> + <xs:complexType> + <xs:sequence> + <xs:element ref="Rb"/> + <xs:element ref="Rt"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Rb" type="xs:string"/> + <xs:element name="Rt"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="Size" type="sizeType"/> + <xs:attribute name="Position"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="before"/> + <xs:enumeration value="after"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="Offset" type="spacingType"/> + <xs:attribute name="Spacing" type="spacingType"/> + <xs:attribute name="AspectAdjust"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.25"/> + <xs:maxInclusive value="4.0"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element name="Space"> + <xs:complexType> + <xs:attribute name="Size" type="sizeType"/> + </xs:complexType> + </xs:element> + <xs:element name="HGroup" type="xs:string"/> + <xs:element name="Rotate"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="Direction"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="none"/> + <xs:enumeration value="right"/> + <xs:enumeration value="left"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element name="Image"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:anyURI"> + <xs:attribute name="HAlign" type="hAlignType"/> + <xs:attribute name="HPosition" type="positionType"/> + <xs:attribute name="VAlign" type="vAlignType"/> + <xs:attribute name="VPosition" type="positionType"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:simpleType name="spaceType"> + <xs:restriction base="xs:string"> + <xs:pattern value="\s*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="UUIDType"> + <xs:restriction base="xs:string"> + <xs:pattern value="\s*[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\s*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="yesNoType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="yes"/> + <xs:enumeration value="no"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="hAlignType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="left"/> + <xs:enumeration value="right"/> + <xs:enumeration value="center"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="vAlignType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="top"/> + <xs:enumeration value="bottom"/> + <xs:enumeration value="center"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="spacingType"> + <xs:restriction base="xs:string"> + <xs:pattern value="-?(\d+|\d+\.\d+)em"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="sizeType"> + <xs:restriction base="xs:string"> + <xs:pattern value="(\d+|\d+\.\d+)em"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="timeType"> + <xs:restriction base="xs:string"> + <xs:pattern value="\d\d:\d\d:\d\d(:(([0-1][0-9][0-9])|([2][0-4][0-9]))|(\.\d{1,3}))"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="fadeTimeType"> + <xs:restriction base="xs:string"> + <xs:pattern value="(\d\d:\d\d:\d\d(:|\.)(\d){1,3})|(\d){1,3}"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="fontColorType"> + <xs:restriction base="xs:string"> + <xs:pattern value="[0-9A-Fa-f]{8}"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="positionType"> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="-100"/> + <xs:maxInclusive value="100"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> |
