summaryrefslogtreecommitdiff
path: root/src/ST2052_TextParser.cpp
diff options
context:
space:
mode:
authorjhurst <jhurst@cinecert.com>2015-05-21 00:10:39 +0000
committerjhurst <>2015-05-21 00:10:39 +0000
commit282deda913e656d38df6bb04c685d1e2346cd29b (patch)
tree3a93fb5272cf9d6fb19a6f1c2f6c1cb9876103af /src/ST2052_TextParser.cpp
parent887003223e52b4fb2b9ca135dcb8a23e1f133cd4 (diff)
compile fixes
Diffstat (limited to 'src/ST2052_TextParser.cpp')
-rw-r--r--src/ST2052_TextParser.cpp252
1 files changed, 246 insertions, 6 deletions
diff --git a/src/ST2052_TextParser.cpp b/src/ST2052_TextParser.cpp
index 9a8dd2a..b00ebe6 100644
--- a/src/ST2052_TextParser.cpp
+++ b/src/ST2052_TextParser.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2013-2014, John Hurst
+Copyright (c) 2013-2015, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AS_02_internal.h"
#include "KM_xml.h"
+#include <openssl/sha.h>
using namespace Kumu;
using namespace ASDCP;
@@ -40,6 +41,133 @@ using Kumu::DefaultLogSink;
const char* c_tt_namespace_name = "http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt";
+
+//------------------------------------------------------------------------------------------
+
+//
+//
+static byte_t s_id_prefix[16] = {
+ // RFC 4122 type 5
+ // 2067-2 5.4.5
+ 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+};
+
+//
+void
+gen_png_name_id(const std::string& image_name, UUID& asset_id)
+{
+ SHA_CTX ctx;
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, s_id_prefix, 16);
+ SHA1_Update(&ctx, (byte_t*)image_name.c_str(), image_name.length());
+
+ const ui32_t sha_len = 20;
+ byte_t bin_buf[sha_len];
+ SHA1_Final(bin_buf, &ctx);
+
+ // Derive the asset ID from the digest. Make it a type-5 UUID
+ byte_t buf[UUID_Length];
+ memcpy(buf, bin_buf, UUID_Length);
+ buf[6] &= 0x0f; // clear bits 4-7
+ buf[6] |= 0x50; // set UUID version 'digest'
+ buf[8] &= 0x3f; // clear bits 6&7
+ buf[8] |= 0x80; // set bit 7
+ asset_id.Set(buf);
+}
+
+//------------------------------------------------------------------------------------------
+
+
+AS_02::TimedText::Type5UUIDFilenameResolver::Type5UUIDFilenameResolver() {}
+AS_02::TimedText::Type5UUIDFilenameResolver::~Type5UUIDFilenameResolver() {}
+
+const byte_t PNGMagic[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
+const byte_t OpenTypeMagic[5] = { 0x4f, 0x54, 0x54, 0x4f, 0x00 };
+const byte_t TrueTypeMagic[5] = { 0x00, 0x01, 0x00, 0x00, 0x00 };
+
+//
+Result_t
+AS_02::TimedText::Type5UUIDFilenameResolver::OpenRead(const std::string& dirname)
+{
+ DirScannerEx dir_reader;
+ DirectoryEntryType_t ft;
+ std::string next_item;
+ std::string abs_dirname = PathMakeCanonical(dirname);
+ byte_t read_buffer[16];
+
+ if ( abs_dirname.empty() )
+ {
+ abs_dirname = ".";
+ }
+
+ if ( KM_SUCCESS(dir_reader.Open(abs_dirname.c_str())) )
+ {
+ while ( KM_SUCCESS(dir_reader.GetNext(next_item, ft)) )
+ {
+ if ( next_item[0] == '.' ) continue; // no hidden files
+ std::string tmp_path = PathJoin(abs_dirname, next_item);
+
+ if ( ft == DET_FILE )
+ {
+ FileReader reader;
+ Result_t result = reader.OpenRead(tmp_path);
+
+ if ( KM_SUCCESS(result) )
+ {
+ result = reader.Read(read_buffer, 16);
+ }
+
+ if ( KM_SUCCESS(result) )
+ {
+ // is it PNG?
+ if ( memcmp(read_buffer, PNGMagic, sizeof(PNGMagic)) == 0 )
+ {
+ UUID asset_id;
+ gen_png_name_id(next_item, asset_id);
+ m_ResourceMap.insert(ResourceMap::value_type(asset_id, next_item));
+ }
+ }
+ }
+ }
+ }
+}
+
+//
+Result_t
+AS_02::TimedText::Type5UUIDFilenameResolver::ResolveRID(const byte_t* uuid, ASDCP::TimedText::FrameBuffer& FrameBuf) const
+{
+ Kumu::UUID tmp_id(uuid);
+ char buf[64];
+
+ ResourceMap::const_iterator i = m_ResourceMap.find(tmp_id);
+
+ if ( i == m_ResourceMap.end() )
+ {
+ return RESULT_NOT_FOUND;
+ }
+
+ FileReader Reader;
+
+ DefaultLogSink().Debug("Retrieving resource %s from file %s\n", tmp_id.EncodeHex(buf, 64), i->second.c_str());
+
+ Result_t result = Reader.OpenRead(i->second.c_str());
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count, read_size = Reader.Size();
+ result = FrameBuf.Capacity(read_size);
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(FrameBuf.Data(), read_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ FrameBuf.Size(read_count);
+ }
+
+ return result;
+}
+
//------------------------------------------------------------------------------------------
typedef std::map<Kumu::UUID, ASDCP::TimedText::MIMEType_t> ResourceTypeMap_t;
@@ -56,7 +184,7 @@ public:
std::string m_Filename;
std::string m_XMLDoc;
TimedTextDescriptor m_TDesc;
- ASDCP::mem_ptr<ASDCP::TimedText::LocalFilenameResolver> m_DefaultResolver;
+ ASDCP::mem_ptr<ASDCP::TimedText::IResourceResolver> m_DefaultResolver;
h__TextParser() : m_Root("**ParserRoot**")
{
@@ -69,7 +197,7 @@ public:
{
if ( m_DefaultResolver.empty() )
{
- ASDCP::TimedText::LocalFilenameResolver *resolver = new ASDCP::TimedText::LocalFilenameResolver;
+ AS_02::TimedText::Type5UUIDFilenameResolver *resolver = new AS_02::TimedText::Type5UUIDFilenameResolver;
resolver->OpenRead(PathDirname(m_Filename));
m_DefaultResolver = resolver;
}
@@ -79,7 +207,7 @@ public:
Result_t OpenRead(const std::string& filename);
Result_t OpenRead(const std::string& xml_doc, const std::string& filename);
- Result_t ReadAncillaryResource(const UUID& uuid, ASDCP::TimedText::FrameBuffer& FrameBuf,
+ Result_t ReadAncillaryResource(const byte_t *uuid, ASDCP::TimedText::FrameBuffer& FrameBuf,
const ASDCP::TimedText::IResourceResolver& Resolver) const;
};
@@ -108,11 +236,63 @@ AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead(const std::string&
}
//
+template <class VisitorType>
+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<std::string> 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;
+ }
+};
+
+//
Result_t
AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead()
{
if ( ! m_Root.ParseString(m_XMLDoc.c_str()) )
- return RESULT_FORMAT;
+ {
+ return RESULT_FORMAT;
+ }
m_TDesc.EncodingName = "UTF-8"; // the XML parser demands UTF-8
m_TDesc.ResourceList.clear();
@@ -129,9 +309,63 @@ AS_02::TimedText::ST2052_TextParser::h__TextParser::OpenRead()
m_TDesc.NamespaceName = ns->Name();
}
+ AttributeVisitor png_visitor("backgroundImage");
+ apply_visitor(m_Root, png_visitor);
+ std::set<std::string>::const_iterator i;
+
+ for ( i = png_visitor.value_list.begin(); i != png_visitor.value_list.end(); ++i )
+ {
+ UUID asset_id;
+ gen_png_name_id(*i, asset_id);
+ TimedTextResourceDescriptor TmpResource;
+ memcpy(TmpResource.ResourceID, asset_id.Value(), UUIDlen);
+ TmpResource.Type = ASDCP::TimedText::MT_PNG;
+ m_TDesc.ResourceList.push_back(TmpResource);
+ m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(TmpResource.ResourceID), ASDCP::TimedText::MT_PNG));
+ }
+
return RESULT_OK;
}
+//
+Result_t
+AS_02::TimedText::ST2052_TextParser::h__TextParser::ReadAncillaryResource(const byte_t* uuid, ASDCP::TimedText::FrameBuffer& FrameBuf,
+ const ASDCP::TimedText::IResourceResolver& Resolver) const
+{
+ FrameBuf.AssetID(uuid);
+ UUID TmpID(uuid);
+ char buf[64];
+
+ ResourceTypeMap_t::const_iterator rmi = m_ResourceTypes.find(TmpID);
+
+ if ( rmi == m_ResourceTypes.end() )
+ {
+ DefaultLogSink().Error("Unknown ancillary resource id: %s\n", TmpID.EncodeHex(buf, 64));
+ return RESULT_RANGE;
+ }
+
+ Result_t result = Resolver.ResolveRID(uuid, FrameBuf);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( (*rmi).second == ASDCP::TimedText::MT_PNG )
+ {
+ FrameBuf.MIMEType("image/png");
+ }
+ else if ( (*rmi).second == ASDCP::TimedText::MT_OPENTYPE )
+ {
+ FrameBuf.MIMEType("application/x-font-opentype");
+ }
+ else
+ {
+ FrameBuf.MIMEType("application/octet-stream");
+ }
+ }
+
+ return result;
+}
+
+
//------------------------------------------------------------------------------------------
@@ -199,7 +433,13 @@ ASDCP::Result_t
AS_02::TimedText::ST2052_TextParser::ReadAncillaryResource(const Kumu::UUID& uuid, ASDCP::TimedText::FrameBuffer& FrameBuf,
const ASDCP::TimedText::IResourceResolver* Resolver) const
{
- return RESULT_NOTIMPL;
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ if ( Resolver == 0 )
+ Resolver = m_Parser->GetDefaultResolver();
+
+ return m_Parser->ReadAncillaryResource(uuid.Value(), FrameBuf, *Resolver);
}