1 /***************************************************************************** 2 * Ebml_dispatcher.hpp : matroska demuxer 3 ***************************************************************************** 4 * Copyright (C) 2016 VLC authors, VideoLAN, Videolabs SAS 5 * $Id: c58e5801ce20e111014fdfcafecfe4aec85c4c0a $ 6 * 7 * Authors: Filip Roseen <filip@videolabs.io> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU Lesser General Public License as published by 11 * the Free Software Foundation; either version 2.1 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this program; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 22 *****************************************************************************/ 23 #ifndef VLC_MKV_EBML_DISPATCHER_HPP_ 24 #define VLC_MKV_EBML_DISPATCHER_HPP_ 25 26 #include "dispatcher.hpp" 27 28 #include "ebml/EbmlElement.h" 29 #include "ebml/EbmlId.h" 30 31 #include <vlc_threads.h> 32 33 #include <algorithm> 34 #include <typeinfo> 35 #include <vector> 36 37 namespace { 38 struct EbmlProcessorEntry { 39 typedef void (*EbmlProcessor) (EbmlElement*, void*); 40 41 EbmlId const* p_ebmlid; 42 EbmlProcessor callback; 43 EbmlProcessorEntry__anonb57a10320111::EbmlProcessorEntry44 EbmlProcessorEntry (EbmlId const& id, EbmlProcessor cb) 45 : p_ebmlid (&id), callback (cb) 46 { } 47 48 }; 49 operator <(EbmlProcessorEntry const & lhs,EbmlProcessorEntry const & rhs)50 bool operator<( EbmlProcessorEntry const& lhs, EbmlProcessorEntry const& rhs ) 51 { 52 EbmlId const& lid = *lhs.p_ebmlid; 53 EbmlId const& rid = *rhs.p_ebmlid; 54 55 return lid.GetLength() < rid.GetLength() || ( 56 !( rid.GetLength() < lid.GetLength() ) && lid.GetValue() < rid.GetValue() 57 ); 58 } 59 60 class EbmlTypeDispatcher : public Dispatcher<EbmlTypeDispatcher, EbmlProcessorEntry::EbmlProcessor> { 61 protected: 62 typedef std::vector<EbmlProcessorEntry> ProcessorContainer; 63 64 public: insert(EbmlProcessorEntry const & data)65 void insert (EbmlProcessorEntry const& data) { 66 _processors.push_back (data); 67 } 68 on_create()69 void on_create () { 70 std::sort (_processors.begin(), _processors.end()); 71 } 72 send(EbmlElement * const & element,void * payload) const73 bool send (EbmlElement * const& element, void* payload) const 74 { 75 if ( element == nullptr ) 76 return false; 77 78 EbmlProcessorEntry eb = EbmlProcessorEntry ( 79 static_cast<EbmlId const&> (*element), NULL 80 ); 81 82 // -------------------------------------------------------------- 83 // Find the appropriate callback for the received EbmlElement 84 // -------------------------------------------------------------- 85 86 ProcessorContainer::const_iterator cit_end = _processors.end(); 87 ProcessorContainer::const_iterator cit = std::lower_bound ( 88 _processors.begin(), cit_end, eb 89 ); 90 91 /* Check that the processor is valid and unique. */ 92 if (cit != cit_end && 93 cit->p_ebmlid == eb.p_ebmlid && 94 (*cit->p_ebmlid == *eb.p_ebmlid)) 95 { 96 cit->callback (element, payload); 97 return true; 98 } 99 100 if (_default_handler == NULL) 101 return false; 102 103 _default_handler (element, payload); 104 return true; 105 } 106 107 public: 108 ProcessorContainer _processors; 109 }; 110 111 } /* end-of-namespace */ 112 113 #define EBML_ELEMENT_CASE_DEF(EbmlType_, ClassName_, VariableName_, InitializationExpr_) \ 114 MKV_SWITCH_CASE_DEFINITION( ClassName_, EbmlType_, EbmlElement*, VariableName_, vars, \ 115 InitializationExpr_, static_cast<EbmlType_&> (*data) \ 116 ) 117 118 #define E_CASE(EbmlType_, VariableName_) \ 119 EBML_ELEMENT_CASE_DEF(EbmlType_, EbmlType_, VariableName_, \ 120 (dispatcher.insert( EbmlProcessorEntry( EbmlType_ ::ClassInfos.ClassId(), &EbmlType_ ## _callback) ) ) \ 121 ) 122 123 #define E_CASE_DEFAULT(VariableName_) \ 124 EBML_ELEMENT_CASE_DEF(EbmlElement, ebml_default, VariableName_, \ 125 dispatcher.set_default_handler (&ebml_default_callback) \ 126 ) 127 128 #endif 129