diff options
| -rw-r--r-- | src/dcp.cc | 2 | ||||
| -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 |
7 files changed, 107 insertions, 33 deletions
@@ -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/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) }); |
