diff options
| author | Carl Hetherington <cth@carlh.net> | 2024-01-12 23:43:23 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2024-01-12 23:43:23 +0100 |
| commit | 7036fb00620a03934e6008df420d19de1a90adbf (patch) | |
| tree | 0475423098e32af6ee8dd5a4422c7f8b628009ec | |
| parent | 75d6411bb1f04a1375b00f361a0c1358d6e8d7ab (diff) | |
Note correct/incorrect hashes when the verifier raises related errors.
| -rw-r--r-- | src/verify.cc | 74 | ||||
| -rw-r--r-- | src/verify.h | 28 | ||||
| -rw-r--r-- | test/verify_test.cc | 173 |
3 files changed, 225 insertions, 50 deletions
diff --git a/src/verify.cc b/src/verify.cc index 58eaa9af..0ef4ada5 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -385,15 +385,24 @@ enum class VerifyAssetResult { static VerifyAssetResult -verify_asset (shared_ptr<const DCP> dcp, shared_ptr<const ReelFileAsset> reel_file_asset, function<void (float)> progress) +verify_asset( + shared_ptr<const DCP> dcp, + shared_ptr<const ReelFileAsset> reel_file_asset, + function<void (float)> progress, + string* reference_hash, + string* calculated_hash + ) { + DCP_ASSERT(reference_hash); + DCP_ASSERT(calculated_hash); + /* When reading the DCP the hash will have been set to the one from the PKL/CPL. * We want to calculate the hash of the actual file contents here, so that we * can check it. unset_hash() means that this calculation will happen on the * call to hash(). */ reel_file_asset->asset_ref()->unset_hash(); - auto const actual_hash = reel_file_asset->asset_ref()->hash([progress](int64_t done, int64_t total) { + *calculated_hash = reel_file_asset->asset_ref()->hash([progress](int64_t done, int64_t total) { progress(float(done) / total); }); @@ -403,22 +412,23 @@ verify_asset (shared_ptr<const DCP> dcp, shared_ptr<const ReelFileAsset> reel_fi auto asset = reel_file_asset->asset_ref().asset(); - optional<string> pkl_hash; + optional<string> maybe_pkl_hash; for (auto i: pkls) { - pkl_hash = i->hash (reel_file_asset->asset_ref()->id()); - if (pkl_hash) { + maybe_pkl_hash = i->hash (reel_file_asset->asset_ref()->id()); + if (maybe_pkl_hash) { break; } } - DCP_ASSERT (pkl_hash); + DCP_ASSERT(maybe_pkl_hash); + *reference_hash = *maybe_pkl_hash; auto cpl_hash = reel_file_asset->hash(); - if (cpl_hash && *cpl_hash != *pkl_hash) { + if (cpl_hash && *cpl_hash != *reference_hash) { return VerifyAssetResult::CPL_PKL_DIFFER; } - if (actual_hash != *pkl_hash) { + if (*calculated_hash != *reference_hash) { return VerifyAssetResult::BAD; } @@ -517,12 +527,18 @@ verify_main_picture_asset ( if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { stage ("Checking picture asset hash", file); - auto const r = verify_asset (dcp, reel_asset, progress); + string reference_hash; + string calculated_hash; + auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash); switch (r) { case VerifyAssetResult::BAD: - notes.push_back ({ - VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_PICTURE_HASH, file - }); + notes.push_back( + dcp::VerificationNote( + VerificationNote::Type::ERROR, + VerificationNote::Code::INCORRECT_PICTURE_HASH, + file + ).set_reference_hash(reference_hash).set_calculated_hash(calculated_hash) + ); break; case VerifyAssetResult::CPL_PKL_DIFFER: notes.push_back ({ @@ -613,10 +629,18 @@ verify_main_sound_asset ( if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { stage("Checking sound asset hash", file); - auto const r = verify_asset (dcp, reel_asset, progress); + string reference_hash; + string calculated_hash; + auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash); switch (r) { case VerifyAssetResult::BAD: - notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_SOUND_HASH, file}); + notes.push_back( + dcp::VerificationNote( + VerificationNote::Type::ERROR, + VerificationNote::Code::INCORRECT_SOUND_HASH, + file + ).set_reference_hash(reference_hash).set_calculated_hash(calculated_hash) + ); break; case VerifyAssetResult::CPL_PKL_DIFFER: notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_HASHES, file}); @@ -1585,8 +1609,16 @@ verify_cpl( for (auto i: dcp->pkls()) { /* Check that the CPL's hash corresponds to the PKL */ optional<string> h = i->hash(cpl->id()); - if (h && make_digest(ArrayData(*cpl->file())) != *h) { - notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get()}); + auto calculated_cpl_hash = make_digest(ArrayData(*cpl->file())); + if (h && calculated_cpl_hash != *h) { + notes.push_back( + dcp::VerificationNote( + VerificationNote::Type::ERROR, + VerificationNote::Code::MISMATCHED_CPL_HASHES, + cpl->id(), + cpl->file().get() + ).set_calculated_hash(calculated_cpl_hash).set_reference_hash(*h) + ); } /* Check that any PKL with a single CPL has its AnnotationText the same as the CPL's ContentTitleText */ @@ -1918,15 +1950,15 @@ dcp::note_to_string (VerificationNote note) case VerificationNote::Code::FAILED_READ: return *note.note(); case VerificationNote::Code::MISMATCHED_CPL_HASHES: - return String::compose("The hash of the CPL %1 in the PKL does not agree with the CPL file.", note.note().get()); + return String::compose("The hash (%1) of the CPL (%2) in the PKL does not agree with the CPL file (%3).", note.reference_hash().get(), note.note().get(), note.calculated_hash().get()); case VerificationNote::Code::INVALID_PICTURE_FRAME_RATE: return String::compose("The picture in a reel has an invalid frame rate %1.", note.note().get()); case VerificationNote::Code::INCORRECT_PICTURE_HASH: - return String::compose("The hash of the picture asset %1 does not agree with the PKL file.", note.file()->filename()); + return String::compose("The hash (%1) of the picture asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), note.file()->filename(), note.reference_hash().get()); case VerificationNote::Code::MISMATCHED_PICTURE_HASHES: return String::compose("The PKL and CPL hashes differ for the picture asset %1.", note.file()->filename()); case VerificationNote::Code::INCORRECT_SOUND_HASH: - return String::compose("The hash of the sound asset %1 does not agree with the PKL file.", note.file()->filename()); + return String::compose("The hash (%1) of the sound asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), note.file()->filename(), note.reference_hash().get()); case VerificationNote::Code::MISMATCHED_SOUND_HASHES: return String::compose("The PKL and CPL hashes differ for the sound asset %1.", note.file()->filename()); case VerificationNote::Code::EMPTY_ASSET_PATH: @@ -2161,7 +2193,9 @@ dcp::operator== (dcp::VerificationNote const& a, dcp::VerificationNote const& b) a.size() == b.size() && a.id() == b.id() && a.other_id() == b.other_id() && - a.frame_rate() == b.frame_rate(); + a.frame_rate() == b.frame_rate() && + a.reference_hash() == b.reference_hash() && + a.calculated_hash() == b.calculated_hash(); } diff --git a/src/verify.h b/src/verify.h index 7bfe4217..4ca3297a 100644 --- a/src/verify.h +++ b/src/verify.h @@ -101,6 +101,8 @@ public: /** The hash of the CPL in the PKL does not agree with the CPL file * note contains CPL ID * file contains CPL filename + * calculated_hash contains current hash of the CPL + * reference_hash contains the hash written in the PKL */ MISMATCHED_CPL_HASHES, /** The frame rate given in a reel for the main picture is not 24, 25, 30, 48, 50 or 60 @@ -109,6 +111,8 @@ public: INVALID_PICTURE_FRAME_RATE, /** The hash of a main picture asset does not agree with the PKL file * file contains the picture asset filename + * calculated_hash contains the current hash of the picture MXF + * reference_hash contains the hash from the PKL */ INCORRECT_PICTURE_HASH, /** The hash of a main picture is different in the CPL and PKL @@ -117,6 +121,8 @@ public: MISMATCHED_PICTURE_HASHES, /** The hash of a main sound asset does not agree with the PKL file * file contains the sound asset filename + * calculated_hash contains the current hash of the picture MXF + * reference_hash contains the hash from the PKL */ INCORRECT_SOUND_HASH, /** The hash of a main sound is different in the CPL and PKL @@ -525,7 +531,9 @@ private: SIZE, ID, OTHER_ID, - FRAME_RATE + FRAME_RATE, + CALCULATED_HASH, + REFERENCE_HASH }; template <class T> @@ -605,6 +613,24 @@ public: return data<int>(Data::FRAME_RATE); } + VerificationNote& set_calculated_hash(std::string hash) { + _data[Data::CALCULATED_HASH] = hash; + return *this; + } + + boost::optional<std::string> calculated_hash() const { + return data<std::string>(Data::CALCULATED_HASH); + } + + VerificationNote& set_reference_hash(std::string hash) { + _data[Data::REFERENCE_HASH] = hash; + return *this; + } + + boost::optional<std::string> reference_hash() const { + return data<std::string>(Data::REFERENCE_HASH); + } + private: Type _type; Code _code; diff --git a/test/verify_test.cc b/test/verify_test.cc index 0e15624d..e55e0b6e 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -207,24 +207,28 @@ check_verify_result(vector<path> dir, vector<dcp::DecryptedKDM> kdm, vector<dcp: for (auto i: notes) { message += " " + note_to_string(i) + "\n"; message += dcp::String::compose( - " [%1 %2 %3 %4 %5]\n", + " [%1 %2 %3 %4 %5 %6 %7]\n", static_cast<int>(i.type()), static_cast<int>(i.code()), i.note().get_value_or("<none>"), i.file().get_value_or("<none>"), - i.line().get_value_or(0) + i.line().get_value_or(0), + i.reference_hash().get_value_or("<none>"), + i.calculated_hash().get_value_or("<none>") ); } message += "Expected:\n"; for (auto i: test_notes) { message += " " + note_to_string(i) + "\n"; message += dcp::String::compose( - " [%1 %2 %3 %4 %5]\n", + " [%1 %2 %3 %4 %5 %6 %7]\n", static_cast<int>(i.type()), static_cast<int>(i.code()), i.note().get_value_or("<none>"), i.file().get_value_or("<none>"), - i.line().get_value_or(0) + i.line().get_value_or(0), + i.reference_hash().get_value_or("<none>"), + i.calculated_hash().get_value_or("<none>") ); } @@ -269,6 +273,28 @@ add_font(shared_ptr<dcp::SubtitleAsset> asset) } +class HashCalculator +{ +public: + HashCalculator(boost::filesystem::path path) + : _path(path) + , _old_hash(dcp::make_digest(path, [](int64_t, int64_t) {})) + {} + + std::string old_hash() const { + return _old_hash; + } + + std::string new_hash() const { + return dcp::make_digest(_path, [](int64_t, int64_t) {}); + } + +private: + boost::filesystem::path _path; + std::string _old_hash; +}; + + BOOST_AUTO_TEST_CASE (verify_no_error) { stages.clear (); @@ -310,8 +336,7 @@ BOOST_AUTO_TEST_CASE (verify_no_error) BOOST_CHECK_EQUAL (st->first, "Checking PKL"); BOOST_REQUIRE (st->second); BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file)); - ++st; - BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP"); + ++st; BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP"); BOOST_REQUIRE (st->second); BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file)); ++st; @@ -328,6 +353,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash) auto dir = setup (1, "incorrect_picture_sound_hash"); auto video_path = path(dir / "video.mxf"); + HashCalculator video_calc(video_path); auto mod = fopen(video_path.string().c_str(), "r+b"); BOOST_REQUIRE (mod); fseek (mod, 4096, SEEK_SET); @@ -336,6 +362,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash) fclose (mod); auto audio_path = path(dir / "audio.mxf"); + HashCalculator audio_calc(audio_path); mod = fopen(audio_path.string().c_str(), "r+b"); BOOST_REQUIRE (mod); BOOST_REQUIRE_EQUAL (fseek(mod, -64, SEEK_END), 0); @@ -347,8 +374,12 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path) + ).set_reference_hash(video_calc.old_hash()).set_calculated_hash(video_calc.new_hash()), + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path) + ).set_reference_hash(audio_calc.old_hash()).set_calculated_hash(audio_calc.new_hash()), }); } @@ -359,6 +390,8 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes) auto dir = setup (1, "mismatched_picture_sound_hashes"); + HashCalculator calc(dir / dcp_test1_cpl()); + { Editor e (dir / dcp_test1_pkl()); e.replace ("<Hash>", "<Hash>x"); @@ -368,7 +401,9 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) + ).set_reference_hash("x" + calc.old_hash()).set_calculated_hash(calc.old_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xKcJb7S2K5cNm8RG4kfQD5FTeS0A=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 28 }, @@ -382,6 +417,8 @@ BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind) { auto dir = setup (1, "failed_read_content_kind"); + HashCalculator calc(dir / dcp_test1_cpl()); + { Editor e (dir / dcp_test1_cpl()); e.replace ("<ContentKind>", "<ContentKind>x"); @@ -391,7 +428,9 @@ BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash("4v/mVjs1Rw0NELxgyHa5rSpoBPA="), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer") } }); } @@ -1065,6 +1104,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag) dcp.set_annotation_text("hello"); dcp.write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e (find_cpl(dir)); e.replace ("MainSound", "MainSoundX"); @@ -1088,7 +1129,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag) canonical(cpl->file().get()), 71 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -2287,6 +2330,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2298,7 +2343,9 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text) {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, cpl->id(), canonical(cpl->file().get()) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) } + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -2312,6 +2359,8 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text) BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U); auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2323,7 +2372,9 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text) {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, cpl->id(), canonical(cpl->file().get()) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) } + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -2623,6 +2674,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash) BOOST_REQUIRE (cpl->reels()[0]->main_picture()); auto asset_id = cpl->reels()[0]->main_picture()->id(); + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2633,7 +2686,9 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id } }); } @@ -2765,6 +2820,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1) BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U); auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>"); @@ -2774,7 +2831,9 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->id(), cpl->file().get() } }); } @@ -2788,6 +2847,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>"); @@ -2797,7 +2858,9 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->id(), cpl->file().get() } }); } @@ -2811,6 +2874,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("<meta:Name>A", "<meta:NameX>A"); @@ -2823,7 +2888,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3) { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:NameX'"), cpl->file().get(), 70 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:NameX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2836,6 +2903,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("Application", "Fred"); @@ -2845,7 +2914,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> should be 'Application'"), cpl->file().get() }, }); } @@ -2859,6 +2930,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("DCP Constraints Profile", "Fred"); @@ -2868,7 +2941,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Name> property should be 'DCP Constraints Profile'"), cpl->file().get() }, }); } @@ -2882,6 +2957,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("<meta:Value>", "<meta:ValueX>"); @@ -2894,7 +2971,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6) { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:ValueX'"), cpl->file().get(), 74 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:ValueX' is not allowed for content model '(Name,Value)'"), cpl->file().get(), 75 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2907,6 +2986,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred"); @@ -2916,7 +2997,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string("<Value> property should be 'SMPTE-RDD-52:2020-Bv2.1'"), cpl->file().get() }, }); } @@ -2930,6 +3013,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("<meta:Property>", "<meta:PropertyX>"); @@ -2942,7 +3027,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8) { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyX'"), cpl->file().get(), 72 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyX' is not allowed for content model '(Property+)'"), cpl->file().get(), 76 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2955,6 +3042,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("<meta:PropertyList>", "<meta:PropertyListX>"); @@ -2967,7 +3056,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9) { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyListX'"), cpl->file().get(), 71 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyListX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2984,6 +3075,8 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content) path const pkl = dir / ( "pkl_" + encryption_test_pkl_id() + ".xml" ); path const cpl = dir / ( "cpl_" + encryption_test_cpl_id() + ".xml"); + HashCalculator calc(cpl); + { Editor e (cpl); e.delete_lines ("<dsig:Signature", "</dsig:Signature>"); @@ -2993,7 +3086,9 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content) {dir}, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, encryption_test_cpl_id(), canonical(cpl) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, encryption_test_cpl_id(), canonical(cpl) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl), }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }, @@ -3317,6 +3412,8 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e (find_cpl(dir)); e.insert( @@ -3331,7 +3428,9 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_ENTRY_POINT }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_DURATION }, }); @@ -3345,6 +3444,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_content_kind) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.replace("trailer", "trip"); @@ -3356,7 +3457,9 @@ BOOST_AUTO_TEST_CASE(verify_invalid_content_kind) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip") } }); @@ -3370,6 +3473,8 @@ BOOST_AUTO_TEST_CASE(verify_valid_content_kind) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.replace("<ContentKind>trailer</ContentKind>", "<ContentKind scope=\"http://bobs.contents/\">trip</ContentKind>"); @@ -3381,7 +3486,9 @@ BOOST_AUTO_TEST_CASE(verify_valid_content_kind) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -3396,6 +3503,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1) auto constexpr area = "<meta:MainPictureActiveArea>"; + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.delete_lines_after(area, 2); @@ -3410,7 +3519,9 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 1997 is not a multiple of 2", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 4080 is bigger than the asset height 1080", canonical(find_cpl(dir)) }, }); @@ -3426,6 +3537,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2) auto constexpr area = "<meta:MainPictureActiveArea>"; + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.delete_lines_after(area, 2); @@ -3440,7 +3553,9 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2) { dir }, {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is not a multiple of 2", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 9900 is bigger than the asset width 1998", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is bigger than the asset height 1080", canonical(find_cpl(dir)) }, |
