Check ASSETMAP; add a PKL test; tidy up calls to validate_xml().
authorCarl Hetherington <cth@carlh.net>
Sun, 8 Dec 2019 23:44:07 +0000 (00:44 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 22 Dec 2019 00:21:00 +0000 (01:21 +0100)
src/dcp.cc
src/dcp.h
src/verify.cc
test/verify_test.cc
xsd/SMPTE-429-9-2007-AM.xsd [new file with mode: 0644]

index e057f25f2dad69965f5e00eface09acbb8e91822..da12e4d9742f55b65f40ef50dd8b1ba9d94f8281 100644 (file)
@@ -112,18 +112,17 @@ DCP::read (list<dcp::VerificationNote>* notes, bool ignore_incorrect_picture_mxf
 {
        /* Read the ASSETMAP and PKL */
 
-       boost::filesystem::path asset_map_file;
        if (boost::filesystem::exists (_directory / "ASSETMAP")) {
-               asset_map_file = _directory / "ASSETMAP";
+               _asset_map = _directory / "ASSETMAP";
        } else if (boost::filesystem::exists (_directory / "ASSETMAP.xml")) {
-               asset_map_file = _directory / "ASSETMAP.xml";
+               _asset_map = _directory / "ASSETMAP.xml";
        } else {
                boost::throw_exception (DCPReadError (String::compose ("could not find ASSETMAP nor ASSETMAP.xml in `%1'", _directory.string())));
        }
 
        cxml::Document asset_map ("AssetMap");
 
-       asset_map.read_file (asset_map_file);
+       asset_map.read_file (_asset_map.get());
        if (asset_map.namespace_uri() == assetmap_interop_ns) {
                _standard = INTEROP;
        } else if (asset_map.namespace_uri() == assetmap_smpte_ns) {
@@ -436,6 +435,7 @@ DCP::write_assetmap (Standard standard, string pkl_uuid, boost::filesystem::path
        }
 
        doc.write_to_file_formatted (p.string (), "UTF-8");
+       _asset_map = p;
 }
 
 /** Write all the XML files for this DCP.
index 34611fb73b70ea931f94b569724cf4b4443282d5..0ac93f49e627f0ce5bcc281793b494b25305c087 100644 (file)
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -134,6 +134,10 @@ public:
                return _pkls;
        }
 
+       boost::optional<boost::filesystem::path> asset_map_path () {
+               return _asset_map;
+       }
+
        static std::vector<boost::filesystem::path> directories_from_files (std::vector<boost::filesystem::path> files);
 
 private:
@@ -146,11 +150,14 @@ private:
         */
        void write_assetmap (Standard standard, std::string pkl_uuid, boost::filesystem::path pkl_path, XMLMetadata metadata) const;
 
-       /** the directory that we are writing to */
+       /** The directory that we are writing to */
        boost::filesystem::path _directory;
-       /** the CPLs that make up this DCP */
+       /** The CPLs that make up this DCP */
        std::list<boost::shared_ptr<CPL> > _cpls;
+       /** The PKLs that make up this DCP */
        std::list<boost::shared_ptr<PKL> > _pkls;
+       /** File that the ASSETMAP was read from or last written to */
+       mutable boost::optional<boost::filesystem::path> _asset_map;
 
        /** Standard of DCP that was read in */
        boost::optional<Standard> _standard;
index 9a2b0f7052209977759acacf37269e53bdb40b7c..cb2b12872d75a7630a9b96f56563af1906e8ddd7 100644 (file)
@@ -229,8 +229,8 @@ private:
 };
 
 static
-list<XMLValidationError>
-validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_directory)
+void
+validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_directory, list<VerificationNote>& notes)
 {
        try {
                XMLPlatformUtils::Initialize ();
@@ -252,6 +252,7 @@ validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_
                schema["http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"] = "xmldsig-core-schema.xsd";
                schema["http://www.smpte-ra.org/schemas/429-7/2006/CPL"] = "SMPTE-429-7-2006-CPL.xsd";
                schema["http://www.smpte-ra.org/schemas/429-8/2006/PKL"] = "SMPTE-429-8-2006-PKL.xsd";
+               schema["http://www.smpte-ra.org/schemas/429-9/2007/AM"] = "SMPTE-429-9-2007-AM.xsd";
                schema["http://www.w3.org/2001/03/xml.xsd"] = "xml.xsd";
 
                string locations;
@@ -283,7 +284,17 @@ validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_
 
        XMLPlatformUtils::Terminate ();
 
-       return error_handler.errors ();
+       BOOST_FOREACH (XMLValidationError i, error_handler.errors()) {
+               notes.push_back (
+                       VerificationNote(
+                               VerificationNote::VERIFY_ERROR,
+                               VerificationNote::Code::XML_VALIDATION_ERROR,
+                               i.message(),
+                               xml_file,
+                               i.line()
+                               )
+                       );
+       }
 }
 
 static Result
@@ -349,19 +360,7 @@ dcp::verify (
 
                BOOST_FOREACH (shared_ptr<CPL> cpl, dcp->cpls()) {
                        stage ("Checking CPL", cpl->file());
-
-                       list<XMLValidationError> errors = validate_xml (cpl->file().get(), xsd_dtd_directory);
-                       BOOST_FOREACH (XMLValidationError i, errors) {
-                               notes.push_back (
-                                       VerificationNote(
-                                               VerificationNote::VERIFY_ERROR,
-                                               VerificationNote::Code::XML_VALIDATION_ERROR,
-                                               i.message(),
-                                               cpl->file().get(),
-                                               i.line()
-                                               )
-                                       );
-                       }
+                       validate_xml (cpl->file().get(), xsd_dtd_directory, notes);
 
                        /* Check that the CPL's hash corresponds to the PKL */
                        BOOST_FOREACH (shared_ptr<PKL> i, dcp->pkls()) {
@@ -437,20 +436,12 @@ dcp::verify (
 
                BOOST_FOREACH (shared_ptr<PKL> pkl, dcp->pkls()) {
                        stage ("Checking PKL", pkl->file());
-
-                       list<XMLValidationError> errors = validate_xml (pkl->file().get(), xsd_dtd_directory);
-                       BOOST_FOREACH (XMLValidationError i, errors) {
-                               notes.push_back (
-                                       VerificationNote(
-                                               VerificationNote::VERIFY_ERROR,
-                                               VerificationNote::Code::XML_VALIDATION_ERROR,
-                                               i.message(),
-                                               pkl->file().get(),
-                                               i.line()
-                                               )
-                                       );
-                       }
+                       validate_xml (pkl->file().get(), xsd_dtd_directory, notes);
                }
+
+               stage ("Checking ASSETMAP", dcp->asset_map_path().get());
+               validate_xml (dcp->asset_map_path().get(), xsd_dtd_directory, notes);
+
        }
 
        return notes;
index f23e54c4ced5a4b994f53767e892b2c8840a3ff0..9ac19adabadfd034ecbcb86b459da1582af3c018 100644 (file)
@@ -120,6 +120,7 @@ BOOST_AUTO_TEST_CASE (verify_test1)
 
        boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
        boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml";
+       boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
 
        list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
        BOOST_CHECK_EQUAL (st->first, "Checking DCP");
@@ -145,6 +146,10 @@ BOOST_AUTO_TEST_CASE (verify_test1)
        BOOST_REQUIRE (st->second);
        BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
        ++st;
+       BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
+       BOOST_REQUIRE (st->second);
+       BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
+       ++st;
        BOOST_REQUIRE (st == stages.end());
 
        dump_notes (notes);
@@ -239,6 +244,20 @@ cpl (int n)
        return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
 }
 
+static
+boost::filesystem::path
+pkl (int n)
+{
+       return dcp::String::compose("build/test/verify_test%1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", n);
+}
+
+static
+boost::filesystem::path
+asset_map (int n)
+{
+       return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
+}
+
 static
 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
 {
@@ -380,3 +399,23 @@ BOOST_AUTO_TEST_CASE (verify_test10)
                        dcp::VerificationNote::Code::CPL_HASH_INCORRECT
                        );
 }
+
+/* Badly-formatted <Id> in PKL */
+BOOST_AUTO_TEST_CASE (verify_test11)
+{
+       check_after_replace (
+               11, &pkl,
+               "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
+               dcp::VerificationNote::Code::XML_VALIDATION_ERROR
+               );
+}
+
+/* Badly-formatted <Id> in ASSETMAP */
+BOOST_AUTO_TEST_CASE (verify_test12)
+{
+       check_after_replace (
+               12, &asset_map,
+               "<Id>urn:uuid:74e", "<Id>urn:uuid:x4e",
+               dcp::VerificationNote::Code::XML_VALIDATION_ERROR
+               );
+}
diff --git a/xsd/SMPTE-429-9-2007-AM.xsd b/xsd/SMPTE-429-9-2007-AM.xsd
new file mode 100644 (file)
index 0000000..a4432fe
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="http://www.smpte-ra.org/schemas/429-9/2007/AM" xmlns:am="http://www.smpte-ra.org/schemas/429-9/2007/AM" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+  <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>
+
+  <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>
+
+  <xs:complexType name="ChunkType">
+    <xs:sequence>
+      <xs:element name="Path" type="xs:anyURI"/>
+      <xs:element name="VolumeIndex" type="xs:positiveInteger" minOccurs="0"/>
+      <xs:element name="Offset" type="xs:nonNegativeInteger" minOccurs="0"/>
+      <xs:element name="Length" type="xs:positiveInteger" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="AssetType">
+    <xs:sequence>
+      <xs:element name="Id" type="am:UUID"/>
+      <xs:element name="AnnotationText" type="am:UserText" minOccurs="0"/>
+      <xs:element name="PackingList" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="ChunkList">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="Chunk" type="am:ChunkType" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="AssetMapType">
+    <xs:sequence>
+      <xs:element name="Id" type="am:UUID"/>
+      <xs:element name="AnnotationText" type="am:UserText" minOccurs="0"/>
+      <xs:element name="Creator" type="am:UserText"/>
+      <xs:element name="VolumeCount" type="xs:positiveInteger"/>
+      <xs:element name="IssueDate" type="xs:dateTime"/>
+      <xs:element name="Issuer" type="am:UserText"/>
+      <xs:element name="AssetList">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="Asset" type="am:AssetType" maxOccurs="unbounded"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="AssetMap" type="am:AssetMapType"/>
+
+  <xs:complexType name="VolumeIndexType">
+    <xs:sequence>
+      <xs:element name="Index" type="xs:positiveInteger"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="VolumeIndex" type="am:VolumeIndexType"/>
+
+</xs:schema>
+