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