From dec4ef68baee633aac30f4b3e0aab6553c22f967 Mon Sep 17 00:00:00 2001 From: jhurst Date: Wed, 7 Dec 2016 18:11:32 +0000 Subject: [PATCH] o Improved IMSC-1 profile detection. May not yet be perfect, experimentation encouraged! o Refactored XML element & attribute visitation to KM_xml.h o Added km_join() template to KM_util.h --- src/KM_util.h | 21 ++++++++ src/KM_xml.h | 72 ++++++++++++++++++++++++++ src/ST2052_TextParser.cpp | 106 ++++++++++++++++++++------------------ 3 files changed, 150 insertions(+), 49 deletions(-) diff --git a/src/KM_util.h b/src/KM_util.h index 4834891..e8004c1 100755 --- a/src/KM_util.h +++ b/src/KM_util.h @@ -543,6 +543,27 @@ namespace Kumu // adjacent instances of the separator. E.g., "/foo//bar/" will return ["", "foo", "", "bar", ""]. std::list km_token_split(const std::string& str, const std::string& separator); + // Join the tokens in the given list using delimiter. If prefix is defined then each token + // will be concatenated with the prefix before being added to the composite string. + template + std::string + km_join(const T& list, const std::string& delimiter, const std::string& prefix = "") + { + std::string result; + + for ( typename T::const_iterator i = list.begin(); i != list.end(); ++i ) + { + if ( i != list.begin() ) + { + result += delimiter; + } + + result += prefix + *i; + } + + return result; + } + } // namespace Kumu diff --git a/src/KM_xml.h b/src/KM_xml.h index 0c84e56..120857c 100644 --- a/src/KM_xml.h +++ b/src/KM_xml.h @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include namespace Kumu @@ -143,6 +144,77 @@ namespace Kumu void DeleteChild(const XMLElement* element); void ForgetChild(const XMLElement* element); }; + + // + template + bool + apply_visitor(const XMLElement& element, VisitorType& visitor) + { + const ElementList& l = element.GetChildren(); + ElementList::const_iterator i; + + for ( i = l.begin(); i != l.end(); ++i ) + { + if ( ! visitor.Element(**i) ) + { + return false; + } + + if ( ! apply_visitor(**i, visitor) ) + { + return false; + } + } + + return true; + } + + // + class AttributeVisitor + { + std::string attr_name; + + public: + AttributeVisitor(const std::string& n) : attr_name(n) {} + std::set value_list; + + bool Element(const XMLElement& e) + { + const AttributeList& l = e.GetAttributes(); + AttributeList::const_iterator i; + + for ( i = l.begin(); i != l.end(); ++i ) + { + if ( i->name == attr_name ) + { + value_list.insert(i->value); + } + } + + return true; + } + }; + + // + class ElementVisitor + { + std::string element_name; + + public: + ElementVisitor(const std::string& n) : element_name(n) {} + std::set value_list; + + bool Element(const XMLElement& e) + { + if ( e.GetBody() == element_name ) + { + value_list.insert(e.GetBody()); + } + + return true; + } + }; + } // namespace Kumu #endif // _KM_XML_H_ diff --git a/src/ST2052_TextParser.cpp b/src/ST2052_TextParser.cpp index f291a1b..a98b4ca 100644 --- a/src/ST2052_TextParser.cpp +++ b/src/ST2052_TextParser.cpp @@ -290,55 +290,10 @@ AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead(const std::string& return OpenRead(profile_name); } -// -template -bool -apply_visitor(const XMLElement& element, VisitorType& visitor) -{ - const ElementList& l = element.GetChildren(); - ElementList::const_iterator i; - - for ( i = l.begin(); i != l.end(); ++i ) - { - if ( ! visitor.Element(**i) ) - { - return false; - } - - if ( ! apply_visitor(**i, visitor) ) - { - return false; - } - } - - return true; -} -// -class AttributeVisitor -{ - std::string attr_name; - -public: - AttributeVisitor(const std::string& n) : attr_name(n) {} - std::set value_list; - - bool Element(const XMLElement& e) - { - const AttributeList& l = e.GetAttributes(); - AttributeList::const_iterator i; - - for ( i = l.begin(); i != l.end(); ++i ) - { - if ( i->name == attr_name ) - { - value_list.insert(i->value); - } - } - return true; - } -}; +std::string const IMSC1_imageProfile = "http://www.w3.org/ns/ttml/profile/imsc1/image"; +std::string const IMSC1_textProfile = "http://www.w3.org/ns/ttml/profile/imsc1/text"; // Result_t @@ -355,11 +310,45 @@ AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead(const std::string& m_TDesc.EncodingName = "UTF-8"; // the XML parser demands UTF-8 m_TDesc.ResourceList.clear(); m_TDesc.ContainerDuration = 0; - m_TDesc.NamespaceName = profile_name; + m_TDesc.NamespaceName = profile_name; // set the profile explicitly + std::set::const_iterator i; + + // Attempt to set the profile from + if ( m_TDesc.NamespaceName.empty() ) + { + ElementVisitor conforms_visitor("conformsToStandard"); + apply_visitor(m_Root, conforms_visitor); + + for ( i = conforms_visitor.value_list.begin(); i != conforms_visitor.value_list.end(); ++i ) + { + if ( *i == IMSC1_imageProfile || *i == IMSC1_textProfile ) + { + m_TDesc.NamespaceName = *i; + break; + } + } + } + + // Attempt to set the profile from the use of attribute "profile" + if ( m_TDesc.NamespaceName.empty() ) + { + AttributeVisitor profile_visitor("profile"); + apply_visitor(m_Root, profile_visitor); + + for ( i = profile_visitor.value_list.begin(); i != profile_visitor.value_list.end(); ++i ) + { + if ( *i == IMSC1_imageProfile || *i == IMSC1_textProfile ) + { + m_TDesc.NamespaceName = *i; + break; + } + } + } + // Find image resources for later packaging as GS partitions. + // Attempt to set the profile; infer from use of images. AttributeVisitor png_visitor("backgroundImage"); apply_visitor(m_Root, png_visitor); - std::set::const_iterator i; for ( i = png_visitor.value_list.begin(); i != png_visitor.value_list.end(); ++i ) { @@ -370,8 +359,27 @@ AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead(const std::string& m_TDesc.ResourceList.push_back(png_resource); m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(png_resource.ResourceID), ASDCP::TimedText::MT_PNG)); + + if ( m_TDesc.NamespaceName.empty() ) + { + m_TDesc.NamespaceName = IMSC1_imageProfile; + } + } + + // If images are present and profile is "text" make sure to say something. + if ( ! m_ResourceTypes.empty() && m_TDesc.NamespaceName == IMSC1_textProfile ) + { + DefaultLogSink().Warn("Unexpected IMSC-1 text profile; document contains images.\n "); + } + + // If all else fails set the profile to "text". + if ( m_TDesc.NamespaceName.empty() ) + { + DefaultLogSink().Warn("Using default IMSC-1 text profile.\n "); + m_TDesc.NamespaceName = IMSC1_textProfile; } + // Find font resources for later packaging as GS partitions. AttributeVisitor font_visitor("fontFamily"); apply_visitor(m_Root, font_visitor); char buf[64]; -- 2.30.2