}
+void
+check_extension_metadata (shared_ptr<dcp::CPL> cpl, vector<VerificationNote>& notes)
+{
+ DCP_ASSERT (cpl->file());
+ cxml::Document doc ("CompositionPlaylist");
+ doc.read_file (cpl->file().get());
+
+ auto missing = false;
+ string malformed;
+
+ if (auto reel_list = doc.node_child("ReelList")) {
+ auto reels = reel_list->node_children("Reel");
+ if (!reels.empty()) {
+ if (auto asset_list = reels[0]->optional_node_child("AssetList")) {
+ if (auto metadata = asset_list->optional_node_child("CompositionMetadataAsset")) {
+ if (auto extension_list = metadata->optional_node_child("ExtensionMetadataList")) {
+ missing = true;
+ for (auto extension: extension_list->node_children("ExtensionMetadata")) {
+ if (extension->optional_string_attribute("scope").get_value_or("") != "http://isdcf.com/ns/cplmd/app") {
+ continue;
+ }
+ missing = false;
+ if (auto name = extension->optional_node_child("Name")) {
+ if (name->content() != "Application") {
+ malformed = "<Name> should be 'Application'";
+ }
+ }
+ if (auto property_list = extension->optional_node_child("PropertyList")) {
+ if (auto property = property_list->optional_node_child("Property")) {
+ if (auto name = property->optional_node_child("Name")) {
+ if (name->content() != "DCP Constraints Profile") {
+ malformed = "<Name> property should be 'DCP Constraints Profile'";
+ }
+ }
+ if (auto value = property->optional_node_child("Value")) {
+ if (value->content() != "SMPTE-RDD-52:2020-Bv2.1") {
+ malformed = "<Value> property should be 'SMPTE-RDD-52:2020-Bv2.1'";
+ }
+ }
+ }
+ }
+ }
+ } else {
+ missing = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (missing) {
+ notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_EXTENSION_METADATA});
+ } else if (!malformed.empty()) {
+ notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::INVALID_EXTENSION_METADATA, malformed});
+ }
+}
+
+
vector<VerificationNote>
dcp::verify (
vector<boost::filesystem::path> directories,
} else if (!cpl->version_number()) {
notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER});
}
+
+ check_extension_metadata (cpl, notes);
}
}
return "There should be a <CompositionMetadataAsset> tag";
case dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER:
return "The CPL metadata must contain a <VersionNumber>";
+ case dcp::VerificationNote::MISSING_EXTENSION_METADATA:
+ return "The CPL metadata must contain <ExtensionMetadata>";
+ case dcp::VerificationNote::INVALID_EXTENSION_METADATA:
+ return String::compose("The <ExtensionMetadata> is malformed in some way: %1", note.note().get());
}
return "";
BOOST_REQUIRE (_content != old_content);
}
+ void delete_lines (string from, string to)
+ {
+ vector<string> lines;
+ boost::algorithm::split (lines, _content, boost::is_any_of("\r\n"), boost::token_compress_on);
+ bool deleting = false;
+ auto old_content = _content;
+ _content = "";
+ for (auto i: lines) {
+ if (i.find(from) != string::npos) {
+ deleting = true;
+ }
+ if (!deleting) {
+ _content += i + "\n";
+ }
+ if (deleting && i.find(to) != string::npos) {
+ deleting = false;
+ }
+ }
+ BOOST_REQUIRE (_content != old_content);
+ }
+
private:
boost::filesystem::path _path;
std::string _content;
static
void
-check_verify_result (vector<boost::filesystem::path> dir, vector<std::pair<dcp::VerificationNote::Type, dcp::VerificationNote::Code>> types_and_codes)
+check_verify_result (vector<boost::filesystem::path> dir, vector<dcp::VerificationNote> test_notes)
{
auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
- BOOST_REQUIRE_EQUAL (notes.size(), types_and_codes.size());
- auto i = notes.begin();
- auto j = types_and_codes.begin();
- while (i != notes.end()) {
- BOOST_CHECK_EQUAL (i->type(), j->first);
- BOOST_CHECK_EQUAL (i->code(), j->second);
- ++i;
- ++j;
- }
+ BOOST_REQUIRE_EQUAL (notes.size(), test_notes.size());
}
verify_markers_test (
boost::filesystem::path dir,
vector<pair<dcp::Marker, dcp::Time>> markers,
- vector<std::pair<dcp::VerificationNote::Type, dcp::VerificationNote::Code>> types_and_codes
+ vector<dcp::VerificationNote> test_notes
)
{
auto dcp = make_simple (dir);
}
dcp->cpls()[0]->reels()[0]->add(markers_asset);
dcp->write_xml (dcp::SMPTE);
- check_verify_result ({dir}, types_and_codes);
+ check_verify_result ({dir}, test_notes);
}
check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER }});
}
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata1)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata1";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_EXTENSION_METADATA }
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata2)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata2";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_EXTENSION_METADATA }
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata3)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata3";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("<meta:Name>A", "<meta:NameX>A");
+ e.replace ("n</meta:Name>", "n</meta:NameX>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata4)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata4";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("Application", "Fred");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Name> property should be 'Application'") },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata5)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata5";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("DCP Constraints Profile", "Fred");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'") },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata6)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata6";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("<meta:Value>", "<meta:ValueX>");
+ e.replace ("</meta:Value>", "</meta:ValueX>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata7)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata7";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_EXTENSION_METADATA, string("<Value> property should be 'SMPTE-RDD-52:2020-Bv2.1'") },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata8)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata8";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("<meta:Property>", "<meta:PropertyX>");
+ e.replace ("</meta:Property>", "</meta:PropertyX>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata9)
+{
+ boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata9";
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ {
+ Editor e (dcp->cpls()[0]->file().get());
+ e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
+ e.replace ("</meta:PropertyList>", "</meta:PropertyListX>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ });
+}
+
+