if ((i->intrinsic_duration() * i->edit_rate().denominator / i->edit_rate().numerator) < 1) {
notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::INTRINSIC_DURATION_TOO_SMALL, i->id()));
}
+ auto mxf = dynamic_pointer_cast<ReelMXF>(i);
+ if (mxf && !mxf->hash()) {
+ notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_HASH, i->id()});
+ }
}
if (dcp->standard() == dcp::SMPTE) {
return "Closed caption assets must have an <EntryPoint> tag.";
case dcp::VerificationNote::CLOSED_CAPTION_ENTRY_POINT_NON_ZERO:
return "Closed caption assets must have an <EntryPoint> of 0.";
+ case dcp::VerificationNote::MISSING_HASH:
+ return String::compose("An asset is missing a <Hash> tag: %1", note.note().get());
}
return "";
MISSING_CLOSED_CAPTION_ENTRY_POINT,
/** Closed caption MainSubtitle <EntryPoint> must be zero Bv2.1_8.3.2 */
CLOSED_CAPTION_ENTRY_POINT_NON_ZERO,
+ /** <Hash> must be present for assets in CPLs */
+ MISSING_HASH,
};
VerificationNote (Type type, Code code)
}
);
}
+
+
+BOOST_AUTO_TEST_CASE (verify_assets_must_have_hashes)
+{
+ RNGFixer fix;
+
+ boost::filesystem::path const dir("build/test/verify_assets_must_have_hashes");
+ auto dcp = make_simple (dir);
+ dcp->write_xml (dcp::SMPTE);
+ BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
+
+ {
+ BOOST_REQUIRE (dcp->cpls()[0]->file());
+ Editor e(dcp->cpls()[0]->file().get());
+ e.replace("<Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>", "");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_HASH }
+ });
+}
+