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