diff options
| -rw-r--r-- | cscript | 6 | ||||
| -rw-r--r-- | src/dcp.cc | 2 | ||||
| -rw-r--r-- | src/encrypted_kdm.cc | 11 | ||||
| -rw-r--r-- | src/encrypted_kdm.h | 1 | ||||
| -rw-r--r-- | src/smpte_text_asset.h | 1 | ||||
| -rw-r--r-- | src/util.cc | 21 | ||||
| -rw-r--r-- | src/util.h | 2 | ||||
| -rw-r--r-- | src/verify.cc | 6 | ||||
| -rw-r--r-- | src/verify.h | 70 | ||||
| -rw-r--r-- | test/util_test.cc | 9 | ||||
| -rw-r--r-- | test/verify_test.cc | 30 |
11 files changed, 122 insertions, 37 deletions
@@ -47,7 +47,7 @@ def build_with_cpp17(target): def dependencies(target, options, for_package): deps = [ - ('libcxml', 'v0.17.16', { 'c++17': build_with_cpp17(target) }), + ('libcxml', 'v0.17.17', { 'c++17': build_with_cpp17(target) }), ('asdcplib', 'v1.0.9') ] @@ -59,7 +59,7 @@ def dependencies(target, options, for_package): if target.platform != 'linux' or target.distro != 'arch' or not for_package: # Use distro-provided FFmpeg and openjpeg on Arch (except when packaging), otherwise our own if options['mpeg2']: - deps.append(('ffmpeg', '2889a7bb300f5014cf5142ef8dcdad8faf33e417', ffmpeg_options)) + deps.append(('ffmpeg', '6a0411c388767c0040748d8e448fc0197c6df1ea', ffmpeg_options)) deps.append(('openjpeg', 'ad8edaacd54a862940d0a77c41ecda5858b54d6e')) return deps @@ -79,7 +79,7 @@ def build(target, options, for_package, version): cmd += ' --static' if target.distro == 'debian' or (target.distro == 'centos' and target.version != 'stream10') or (target.distro == 'rocky' and target.version != '10') or target.distro == 'mageia': cmd += ' --disable-tests' - if target.distro == 'ubuntu' and target.version == '16.04': + if (target.distro, target.version) in [('rocky', '8'), ('ubuntu', '18.04'), ('ubuntu', '16.04')]: cmd += ' --static-boost' elif target.platform == 'windows': cmd += f' --target-windows-{target.bits}' @@ -274,7 +274,7 @@ DCP::read (vector<dcp::VerificationNote>* notes, bool ignore_incorrect_picture_m } other_assets.push_back(asset); if (found_threed_marked_as_twod && notes) { - notes->push_back({VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, path}); + notes->push_back(dcp::VerificationNote(VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, path).set_asset_id(id)); } } else if (*pkl_type == remove_parameters(FontAsset::static_pkl_type(standard))) { other_assets.push_back(make_shared<FontAsset>(id, path)); diff --git a/src/encrypted_kdm.cc b/src/encrypted_kdm.cc index d1089c0b..23cbb0b5 100644 --- a/src/encrypted_kdm.cc +++ b/src/encrypted_kdm.cc @@ -646,6 +646,10 @@ EncryptedKDM::EncryptedKDM ( kre.recipient.x509_subject_name = recipient.subject (); kre.composition_playlist_id = cpl_id; if (formulation == Formulation::DCI_ANY || formulation == Formulation::DCI_SPECIFIC) { + /* XXX: this should be the thumbprint of one of the CPL signer certificates, + * which might not necessarily be the case if we're using a CPL from somebody + * else. + */ kre.content_authenticator = signer->leaf().thumbprint (); } kre.content_title_text = content_title_text; @@ -835,3 +839,10 @@ dcp::operator== (EncryptedKDM const & a, EncryptedKDM const & b) /* Not exactly efficient... */ return a.as_xml() == b.as_xml(); } + + +vector<string> +EncryptedKDM::trusted_devices() const +{ + return _data->authenticated_public.required_extensions.kdm_required_extensions.authorized_device_info->certificate_thumbprints; +} diff --git a/src/encrypted_kdm.h b/src/encrypted_kdm.h index e74dde69..1f54cc05 100644 --- a/src/encrypted_kdm.h +++ b/src/encrypted_kdm.h @@ -103,6 +103,7 @@ public: LocalTime not_valid_after () const; std::string recipient_x509_subject_name () const; CertificateChain signer_certificate_chain () const; + std::vector<std::string> trusted_devices() const; private: diff --git a/src/smpte_text_asset.h b/src/smpte_text_asset.h index 9b7f09a6..13771833 100644 --- a/src/smpte_text_asset.h +++ b/src/smpte_text_asset.h @@ -216,7 +216,6 @@ private: friend struct ::write_subtitles_in_vertical_order_with_top_alignment; friend struct ::write_subtitles_in_vertical_order_with_bottom_alignment; - void read_fonts (std::shared_ptr<ASDCP::TimedText::MXFReader>); void parse_xml (std::shared_ptr<cxml::Document> xml); void read_mxf_descriptor (std::shared_ptr<ASDCP::TimedText::MXFReader> reader); void read_mxf_resources (std::shared_ptr<ASDCP::TimedText::MXFReader> reader, std::shared_ptr<DecryptionContext> dec); diff --git a/src/util.cc b/src/util.cc index 1984595d..61b9ba66 100644 --- a/src/util.cc +++ b/src/util.cc @@ -471,3 +471,24 @@ dcp::maybe_throw_from_asdcplib(Kumu::Result_t result, boost::filesystem::path pa } } + +size_t +dcp::utf8_strlen(string s) +{ + size_t const len = s.length(); + int N = 0; + for (size_t i = 0; i < len; ++i) { + unsigned char c = s[i]; + if ((c & 0xe0) == 0xc0) { + ++i; + } else if ((c & 0xf0) == 0xe0) { + i += 2; + } else if ((c & 0xf8) == 0xf0) { + i += 3; + } + ++N; + } + return N; +} + + @@ -171,6 +171,8 @@ void throw_from_asdcplib(Kumu::Result_t result, boost::filesystem::path path, T boost::throw_exception(general); } +extern size_t utf8_strlen(std::string s); + } diff --git a/src/verify.cc b/src/verify.cc index ac12800b..887ac166 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -1211,7 +1211,7 @@ dcp::verify_text_lines_and_characters( /* Make a list of "subtitle starts" and "subtitle ends" events */ for (auto j: asset->texts()) { if (auto text = dynamic_pointer_cast<const TextString>(j)) { - auto in = make_shared<Event>(text->in(), position(text), text->text().length()); + auto in = make_shared<Event>(text->in(), position(text), utf8_strlen(text->text())); events.push_back(in); events.push_back(make_shared<Event>(text->out(), in)); } @@ -2243,7 +2243,6 @@ dcp::VerificationNote::type() const case Code::INCORRECT_TIMED_TEXT_ASSET_ID: case Code::INVALID_CLOSED_CAPTION_LINE_COUNT: case Code::INVALID_CLOSED_CAPTION_LINE_LENGTH: - case Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES: case Code::INVALID_EXTENSION_METADATA: case Code::INVALID_PICTURE_SIZE_IN_PIXELS: case Code::INVALID_LANGUAGE: @@ -2288,7 +2287,6 @@ dcp::VerificationNote::type() const case Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_2K: case Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_4K: case Code::MISSING_JPEG2000_TLM_MARKER: - case Code::INVALID_SUBTITLE_DURATION_BV21: return Type::BV21_ERROR; case Code::DUPLICATE_ASSET_ID_IN_ASSETMAP: case Code::DUPLICATE_ASSET_ID_IN_PKL: @@ -2349,6 +2347,8 @@ dcp::VerificationNote::type() const case Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES: case Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH: case Code::THREED_ASSET_MARKED_AS_TWOD: + case Code::INVALID_SUBTITLE_DURATION_BV21: + case Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES: return Type::WARNING; }; diff --git a/src/verify.h b/src/verify.h index cb9801ef..c697c8c9 100644 --- a/src/verify.h +++ b/src/verify.h @@ -606,14 +606,14 @@ public: VerificationNote(Code code, boost::filesystem::path file) : _code(code) { - _data[Data::FILE] = file; + _location[Location::FILE] = file; } VerificationNote(Code code, boost::filesystem::path file, uint64_t line) : _code (code) { - _data[Data::FILE] = file; - _data[Data::LINE] = line; + _location[Location::FILE] = file; + _location[Location::LINE] = line; } Type type() const; @@ -625,34 +625,25 @@ public: private: enum class Data { ANNOTATION_TEXT, - ASSET_ID, - ASSET_MAP_ID, BIT_DEPTH, CALCULATED_HASH, CAPABILITIES, CODE_BLOCK_HEIGHT, CODE_BLOCK_WIDTH, - COMPONENT, CONTENT_KIND, CONTENT_VERSION, - CPL_ID, DURATION, ERROR, - FILE, ///< path of file containing the error - FRAME, FRAME_RATE, GUARD_BITS, ISSUE_DATE, LANGUAGE, - LINE, ///< error line number within the FILE LOAD_FONT_ID, MAIN_PICTURE_ACTIVE_AREA, OTHER_ASSET_ID, OTHER_DURATION, - PKL_ID, POC_MARKER, POC_MARKERS, - REEL_INDEX, ///< reel index, counting from 0 REFERENCE_HASH, SIZE_IN_BYTES, SIZE_IN_PIXELS, @@ -662,6 +653,18 @@ private: XML_NAMESPACE, }; + enum class Location { + ASSET_ID, + ASSET_MAP_ID, + COMPONENT, + CPL_ID, + FILE, ///< path of file containing the error + FRAME, + LINE, ///< error line number within the FILE + PKL_ID, + REEL_INDEX, ///< reel index, counting from 0 + }; + template <class T> boost::optional<T> data(Data key) const { @@ -672,31 +675,41 @@ private: return boost::any_cast<T>(iter->second); } + template <class T> + boost::optional<T> location(Location key) const + { + auto iter = _location.find(key); + if (iter == _location.end()) { + return {}; + } + return boost::any_cast<T>(iter->second); + } + public: boost::optional<boost::filesystem::path> file () const { - return data<boost::filesystem::path>(Data::FILE); + return location<boost::filesystem::path>(Location::FILE); } boost::optional<uint64_t> line () const { - return data<uint64_t>(Data::LINE); + return location<uint64_t>(Location::LINE); } VerificationNote& set_frame(int frame) { - _data[Data::FRAME] = frame; + _location[Location::FRAME] = frame; return *this; } boost::optional<int> frame() const { - return data<int>(Data::FRAME); + return location<int>(Location::FRAME); } VerificationNote& set_component(int component) { - _data[Data::COMPONENT] = component; + _location[Location::COMPONENT] = component; return *this; } boost::optional<int> component() const { - return data<int>(Data::COMPONENT); + return location<int>(Location::COMPONENT); } VerificationNote& set_size_in_bytes(uint64_t size) { @@ -718,12 +731,12 @@ public: } VerificationNote& set_asset_id(std::string id) { - _data[Data::ASSET_ID] = id; + _location[Location::ASSET_ID] = id; return *this; } boost::optional<std::string> asset_id() const { - return data<std::string>(Data::ASSET_ID); + return location<std::string>(Location::ASSET_ID); } VerificationNote& set_other_asset_id(std::string other_id) { @@ -763,39 +776,39 @@ public: } VerificationNote& set_cpl_id(std::string id) { - _data[Data::CPL_ID] = id; + _location[Location::CPL_ID] = id; return *this; } boost::optional<std::string> cpl_id() const { - return data<std::string>(Data::CPL_ID); + return location<std::string>(Location::CPL_ID); } VerificationNote& set_pkl_id(std::string id) { - _data[Data::PKL_ID] = id; + _location[Location::PKL_ID] = id; return *this; } boost::optional<std::string> pkl_id() const { - return data<std::string>(Data::PKL_ID); + return location<std::string>(Location::PKL_ID); } VerificationNote& set_asset_map_id(std::string id) { - _data[Data::ASSET_MAP_ID] = id; + _location[Location::ASSET_MAP_ID] = id; return *this; } boost::optional<std::string> asset_map_id() const { - return data<std::string>(Data::ASSET_MAP_ID); + return location<std::string>(Location::ASSET_MAP_ID); } VerificationNote& set_reel_index(int index) { - _data[Data::REEL_INDEX] = index; + _location[Location::REEL_INDEX] = index; return *this; } boost::optional<int> reel_index() const { - return data<int>(Data::REEL_INDEX); + return location<int>(Location::REEL_INDEX); } VerificationNote& set_error(std::string error) { @@ -990,6 +1003,7 @@ public: private: Code _code; std::map<Data, boost::any> _data; + std::map<Location, boost::any> _location; }; diff --git a/test/util_test.cc b/test/util_test.cc index 5780f898..69f4c891 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -276,3 +276,12 @@ BOOST_AUTO_TEST_CASE (unique_string_test) existing.push_back (s); } } + + +BOOST_AUTO_TEST_CASE(utf8_strlen_test) +{ + BOOST_CHECK_EQUAL(dcp::utf8_strlen("hello world"), 11U); + BOOST_CHECK_EQUAL(dcp::utf8_strlen("hëllo world"), 11U); + BOOST_CHECK_EQUAL(dcp::utf8_strlen("hëłlo wørld"), 11U); +} + diff --git a/test/verify_test.cc b/test/verify_test.cc index e3cff85a..88e6681b 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -3167,6 +3167,34 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length) } +BOOST_AUTO_TEST_CASE(verify_invalid_closed_caption_line_length_with_utf8) +{ + auto const dir = path("build/test/verify_invalid_closed_caption_line_length_with_utf8"); + auto cpl = dcp_with_text<dcp::ReelSMPTETextAsset> ( + dcp::TextType::CLOSED_CAPTION, + dir, + { + { 96, 300, 0.0, dcp::VAlign::CENTER, "0123456789012345678901234567890…" } + }); + + using VN = dcp::VerificationNote; + using VC = VN::Code; + + check_verify_result ( + {dir}, + {}, + { + note(VC::NONE_ENCRYPTED, cpl), + note(VC::MATCHING_CPL_HASHES, cpl), + VN(VC::VALID_CPL_ANNOTATION_TEXT).set_cpl_id(cpl->id()).set_annotation_text("hello"), + note(VC::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl), + note(VC::VALID_CONTENT_KIND, cpl).set_content_kind("trailer"), + note(VC::VALID_CONTENT_VERSION_LABEL_TEXT, cpl).set_content_version(cpl->content_version()->label_text), + VN(VC::MISSING_CPL_METADATA, cpl->file().get()).set_cpl_id(cpl->id()) + }); +} + + BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign1) { auto const dir = path ("build/test/verify_mismatched_closed_caption_valign1"); @@ -4881,7 +4909,7 @@ BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod) note(VC::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL, cpl), note(VC::MATCHING_CPL_HASHES, cpl), note(VC::VALID_CONTENT_KIND, cpl).set_content_kind("trailer"), - VN(VC::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(path, "j2c"))), + VN(VC::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(path, "j2c"))).set_asset_id("0d6f57e6-adac-4e1d-bfbe-d162bf13e2cd"), VN(VC::INVALID_STANDARD) }); |
