summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dcp.cc2
-rw-r--r--src/util.cc21
-rw-r--r--src/util.h2
-rw-r--r--src/verify.cc6
-rw-r--r--src/verify.h70
-rw-r--r--test/util_test.cc9
-rw-r--r--test/verify_test.cc30
7 files changed, 107 insertions, 33 deletions
diff --git a/src/dcp.cc b/src/dcp.cc
index 4d5be236..c9d1c8e7 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -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;
+}
+
+
diff --git a/src/util.h b/src/util.h
index cfed9fcb..62c0e295 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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)
});