diff options
| -rw-r--r-- | src/verify.cc | 23 | ||||
| -rw-r--r-- | src/verify.h | 7 | ||||
| -rw-r--r-- | test/verify_test.cc | 23 |
3 files changed, 49 insertions, 4 deletions
diff --git a/src/verify.cc b/src/verify.cc index c42a10d4..f570a41d 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -849,7 +849,7 @@ verify_closed_caption_asset ( } -/** Check the timing of the individual subtitles and make sure there are no empty <Text> nodes */ +/** Check the timing of the individual subtitles and make sure there are no empty <Text> nodes etc. */ static void verify_text_details ( @@ -870,9 +870,11 @@ verify_text_details ( auto empty_text = false; /* current reel start time (in editable units) */ int64_t reel_offset = 0; + vector<string> font_ids; + optional<string> missing_load_font_id; std::function<void (cxml::ConstNodePtr, optional<int>, optional<Time>, int, bool)> parse; - parse = [&parse, &last_out, &too_short, &too_close, &too_early, &empty_text, &reel_offset](cxml::ConstNodePtr node, optional<int> tcr, optional<Time> start_time, int er, bool first_reel) { + parse = [&parse, &last_out, &too_short, &too_close, &too_early, &empty_text, &reel_offset, &font_ids, &missing_load_font_id](cxml::ConstNodePtr node, optional<int> tcr, optional<Time> start_time, int er, bool first_reel) { if (node->name() == "Subtitle") { Time in (node->string_attribute("TimeIn"), tcr); if (start_time) { @@ -912,8 +914,17 @@ verify_text_details ( if (!node_has_content(node)) { empty_text = true; } + } else if (node->name() == "LoadFont") { + if (auto const id = node->optional_string_attribute("Id")) { + font_ids.push_back(*id); + } + } else if (node->name() == "Font") { + if (auto const font_id = node->optional_string_attribute("Id")) { + if (std::find_if(font_ids.begin(), font_ids.end(), [font_id](string const& id) { return id == font_id; }) == font_ids.end()) { + missing_load_font_id = font_id; + } + } } - for (auto i: node->node_children()) { parse(i, tcr, start_time, er, first_reel); } @@ -990,6 +1001,10 @@ verify_text_details ( VerificationNote::Type::WARNING, VerificationNote::Code::EMPTY_TEXT }); } + + if (missing_load_font_id) { + notes.push_back(dcp::VerificationNote(VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_LOAD_FONT).set_id(*missing_load_font_id)); + } } @@ -2042,6 +2057,8 @@ dcp::note_to_string (VerificationNote note) ); case VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT: return String::compose("The XML in the subtitle asset %1 has more than one namespace declaration.", note.note().get()); + case VerificationNote::Code::MISSING_LOAD_FONT: + return String::compose("A subtitle or closed caption refers to a font with ID %1 that does not have a corresponding <LoadFont> node", note.id().get()); } return ""; diff --git a/src/verify.h b/src/verify.h index 08a24227..9c98ef01 100644 --- a/src/verify.h +++ b/src/verify.h @@ -447,7 +447,12 @@ public: /** A subtitle XML root node has more than one namespace (xmlns) declaration. * note contains the asset ID */ - INCORRECT_SUBTITLE_NAMESPACE_COUNT + INCORRECT_SUBTITLE_NAMESPACE_COUNT, + /** A subtitle or closed caption file has a <Font> tag which refers to a font that is not + * first introduced with a <LoadFont>. + * id conatins the ID of the <Font> tag. + */ + MISSING_LOAD_FONT }; VerificationNote (Type type, Code code) diff --git a/test/verify_test.cc b/test/verify_test.cc index 3ac3c83c..a43e989b 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -3656,3 +3656,26 @@ BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces) { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, std::string{"315de731-1173-484c-9a35-bdacf5a9d99d"} } }); } + + +BOOST_AUTO_TEST_CASE(verify_missing_load_font) +{ + path const dir("build/test/verify_missing_load_font"); + prepare_directory (dir); + copy_file ("test/data/subs1.xml", dir / "subs.xml"); + { + Editor editor(dir / "subs.xml"); + editor.delete_first_line_containing("LoadFont"); + } + auto asset = make_shared<dcp::InteropSubtitleAsset>(dir / "subs.xml"); + auto reel_asset = make_shared<dcp::ReelInteropSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0); + write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP); + + check_verify_result ( + {dir}, { + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, + dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id("theFontId") + }); + +} + |
