/src/vlc/modules/demux/mkv/string_dispatcher.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * string_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_STRING_DISPATCHER_HPP_ |
23 | | #define VLC_MKV_STRING_DISPATCHER_HPP_ |
24 | | |
25 | | #include "dispatcher.hpp" |
26 | | |
27 | | #include <map> |
28 | | #include <vector> |
29 | | #include <string> |
30 | | #include <cstring> |
31 | | #include <sstream> |
32 | | |
33 | | namespace { |
34 | | namespace detail { |
35 | | struct CStringCompare { |
36 | 0 | bool operator () (char const * const& s1, char const * const& s2) const { |
37 | 0 | return std::strcmp (s1, s2) < 0; |
38 | 0 | } |
39 | | }; |
40 | | } |
41 | | |
42 | | class StringDispatcher : public Dispatcher<StringDispatcher, void(*)(char const*, void*)> { |
43 | | public: |
44 | | typedef void(*Processor)(char const*, void*); |
45 | | |
46 | | typedef std::pair<char const *, Processor> ProcessorEntry; |
47 | | typedef std::map <char const *, Processor, detail::CStringCompare> ProcessorContainer; |
48 | | |
49 | | typedef std::vector<std::string> GlobParts; |
50 | | typedef std::vector<std::pair<GlobParts, Processor> > GlobContainer; |
51 | | |
52 | | public: |
53 | 0 | void insert (ProcessorEntry const& data) { |
54 | 0 | _processors.insert (data); |
55 | 0 | } |
56 | | |
57 | 0 | void insert_glob (ProcessorEntry const& data) { |
58 | 0 | std::istringstream iss (data.first); |
59 | 0 | std::vector<std::string> parts; |
60 | |
|
61 | 0 | for (std::string s1; std::getline (iss, s1, '*'); ) |
62 | 0 | parts.push_back (s1); |
63 | |
|
64 | 0 | iss.clear (); |
65 | 0 | iss.unget (); |
66 | |
|
67 | 0 | if (iss.get () == '*') |
68 | 0 | parts.push_back (std::string ()); |
69 | |
|
70 | 0 | _glob_processors.push_back (std::make_pair (parts, data.second)); |
71 | 0 | } |
72 | | |
73 | 0 | Processor find_glob_match (char const* const& haystack) const { |
74 | 0 | GlobContainer::const_iterator glob_it = _glob_processors.begin (); |
75 | 0 | GlobContainer::const_iterator glob_it_end = _glob_processors.end (); |
76 | |
|
77 | 0 | for ( ; glob_it != glob_it_end; ++glob_it) { |
78 | 0 | Processor const& callback = glob_it->second; |
79 | 0 | GlobParts const& parts = glob_it->first; |
80 | 0 | char const* haystack_p = haystack; |
81 | | |
82 | | /* No parts? match empty haystack only */ |
83 | |
|
84 | 0 | if (parts.size() == 0) { |
85 | 0 | if (*haystack_p) continue; |
86 | 0 | else return callback; |
87 | 0 | } |
88 | | |
89 | | /* make sure first part is located at the beginning of our haystack */ |
90 | 0 | { |
91 | 0 | std::string const& first_part = parts.front (); |
92 | |
|
93 | 0 | if (strncmp( first_part.c_str(), haystack_p, first_part.size() )) |
94 | 0 | continue; |
95 | | |
96 | 0 | haystack_p += first_part.size(); |
97 | 0 | } |
98 | | /* locate every remaining part in the haystack */ |
99 | 0 | { |
100 | 0 | GlobParts::const_iterator it = parts.begin() + 1; |
101 | 0 | GlobParts::const_iterator end = parts.end(); |
102 | |
|
103 | 0 | for ( ; it != end; ++it) { |
104 | 0 | haystack_p = strstr (haystack_p, it->c_str ()); |
105 | |
|
106 | 0 | if (haystack_p == NULL) |
107 | 0 | break; |
108 | | |
109 | 0 | haystack_p += it->size (); |
110 | 0 | } |
111 | |
|
112 | 0 | if ( haystack_p == NULL) continue; // last search failed |
113 | 0 | if (*haystack_p == '\0') return callback; // end of parts + end of haystack? success. |
114 | 0 | if (parts.back().size() == 0) return callback; // endof parts + glob at end? success |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | 0 | return NULL; |
119 | 0 | } |
120 | | |
121 | | bool send (char const* const& str, void* const& payload) const |
122 | 0 | { |
123 | 0 | ProcessorContainer::const_iterator cit = _processors.begin (); |
124 | 0 | ProcessorContainer::const_iterator cit_end = _processors.end (); |
125 | |
|
126 | 0 | if ((cit = _processors.find (str)) != cit_end) { |
127 | 0 | cit->second (str, payload); |
128 | 0 | return true; |
129 | 0 | } |
130 | | |
131 | 0 | if (Processor glob = find_glob_match (str)) { |
132 | 0 | glob (str, payload); |
133 | 0 | return true; |
134 | 0 | } |
135 | | |
136 | 0 | if (_default_handler != NULL) { |
137 | 0 | _default_handler (str, payload); |
138 | 0 | return true; |
139 | 0 | } |
140 | | |
141 | 0 | return false; |
142 | 0 | } |
143 | | |
144 | | private: |
145 | | ProcessorContainer _processors; |
146 | | GlobContainer _glob_processors; |
147 | | }; |
148 | | |
149 | | } /* end-of-namespace */ |
150 | | |
151 | | #define STRD_T0KENPASTE_(a, b) a ## b |
152 | | #define STRD_TOKENPASTE_(a, b) STRD_T0KENPASTE_(a, b) |
153 | | #define STRD_UNIQUE_NAME_ STRD_TOKENPASTE_(StringProcessor_, __LINE__) |
154 | | |
155 | | #define STRING_CASE_DEF(ClassName_, VariableName_, InitializationExpr_ ) \ |
156 | | MKV_SWITCH_CASE_DEFINITION(ClassName_, char const*, char const*, VariableName_, vars, InitializationExpr_, data) |
157 | | |
158 | | #define S_CASE(Str_) \ |
159 | | STRING_CASE_DEF(STRD_UNIQUE_NAME_, /* ignored */, \ |
160 | | (dispatcher.insert( StringDispatcher::ProcessorEntry(Str_, STRD_TOKENPASTE_(STRD_UNIQUE_NAME_, _callback) ) )) \ |
161 | | ) |
162 | | |
163 | | #define S_CASE_GLOB(Str_) \ |
164 | | STRING_CASE_DEF(STRD_UNIQUE_NAME_, /* ignored */, \ |
165 | | (dispatcher.insert_glob( StringDispatcher::ProcessorEntry(Str_, STRD_TOKENPASTE_(STRD_UNIQUE_NAME_, _callback) ) )) \ |
166 | | ) |
167 | | |
168 | | #define S_CASE_DEFAULT(VariableName_) \ |
169 | | STRING_CASE_DEF(default_handler, VariableName_, \ |
170 | | dispatcher.set_default_handler (&default_handler_callback) \ |
171 | | ) |
172 | | |
173 | | #endif |