@@ -64,17 +64,188 @@ static bool str_key_val_prefix(const str * p, const char * q,
64
64
return true;
65
65
}
66
66
67
- static bool dummy_is_list (parser_arg a ) {
68
- return false;
67
+ static inline bool skip_char (str * s , char c ) {
68
+ if (s -> len == 0 || s -> s [0 ] != c )
69
+ return false;
70
+ str_shift (s , 1 );
71
+ return true;
72
+ }
73
+ static inline void skip_chars (str * s , char c ) {
74
+ while (skip_char (s , c ));
75
+ }
76
+
77
+ static int rtpp_is_dict_list (str * a ) {
78
+ str list = * a ;
79
+ if (!skip_char (& list , '[' ))
80
+ return 0 ;
81
+ // check contents
82
+ if (list .len == 0 )
83
+ return 0 ; // unexpected end of string
84
+ if (list .s [0 ] == '[' )
85
+ return 1 ; // contains sub-list, must be a list
86
+ // inspect first element for 'key='
87
+ str key , val ;
88
+ if (!get_key_val (& key , & val , & list ))
89
+ return 0 ; // nothing to read
90
+ if (val .len )
91
+ return 2 ; // is a dict
92
+ return 1 ; // is a list
93
+ }
94
+
95
+ static bool rtpp_is_list (rtpp_pos * a ) {
96
+ return rtpp_is_dict_list (& a -> cur ) == 1 ;
69
97
}
70
- static str * dummy_get_str (parser_arg a , str * b ) {
71
- * b = * a .str ;
98
+ static bool rtpp_is_dict (rtpp_pos * a ) {
99
+ return rtpp_is_dict_list (& a -> cur ) == 2 ;
100
+ }
101
+ static str * rtpp_get_str (rtpp_pos * a , str * b ) {
102
+ if (rtpp_is_dict_list (& a -> cur ) != 0 )
103
+ return NULL ;
104
+ if (a -> cur .len == 0 )
105
+ return NULL ;
106
+ * b = a -> cur ;
72
107
return b ;
73
108
}
109
+ static long long rtpp_get_int_str (rtpp_pos * a , long long def ) {
110
+ str s ;
111
+ if (!rtpp_get_str (a , & s ))
112
+ return def ;
113
+ return str_to_i (& s , def );
114
+ }
115
+ static bool rtpp_dict_list_end_rewind (rtpp_pos * pos ) {
116
+ // check for dict/list end, which is only valid if it doesn't also start one
117
+ if (pos -> cur .len == 0 || pos -> cur .s [0 ] == '[' || pos -> cur .s [pos -> cur .len - 1 ] != ']' )
118
+ return false;
119
+
120
+ pos -> cur .len -- ;
121
+ // remove any extra closing bracket, and return them to the remainder for
122
+ // the upper level function to parse
123
+ while (pos -> cur .len && pos -> cur .s [pos -> cur .len - 1 ] == ']' ) {
124
+ pos -> cur .len -- ;
125
+ pos -> remainder .s -- ;
126
+ pos -> remainder .len ++ ;
127
+ // we might be on a space or something - go to the actual bracket, which must
128
+ // be there somewhere
129
+ while (pos -> remainder .s [0 ] != ']' ) {
130
+ pos -> remainder .s -- ;
131
+ pos -> remainder .len ++ ;
132
+ }
133
+ }
134
+
135
+ return true;
136
+ }
137
+ static bool rtpp_dict_list_closing (rtpp_pos * pos ) {
138
+ if (pos -> cur .s [0 ] != ']' )
139
+ return false;
140
+
141
+ str_shift (& pos -> cur , 1 );
142
+ // anything left in the string, return it to the remainder
143
+ pos -> remainder .len += pos -> remainder .s - pos -> cur .s ;
144
+ pos -> remainder .s = pos -> cur .s ;
145
+
146
+ return true;
147
+ }
148
+ static void rtpp_list_iter (const ng_parser_t * parser , rtpp_pos * pos ,
149
+ void (* str_callback )(str * key , unsigned int , helper_arg ),
150
+ void (* item_callback )(const ng_parser_t * , parser_arg , helper_arg ), helper_arg arg )
151
+ {
152
+ // list opener
153
+ if (!skip_char (& pos -> cur , '[' ))
154
+ return ;
155
+
156
+ unsigned int idx = 0 ;
157
+
158
+ while (true) {
159
+ skip_chars (& pos -> cur , ' ' );
160
+ if (!pos -> cur .len )
161
+ goto next ; // empty token?
162
+
163
+ // list closing?
164
+ if (rtpp_dict_list_closing (pos ))
165
+ break ;
166
+
167
+ // does it start another list or dict?
168
+ if (pos -> cur .s [0 ] == '[' ) {
169
+ if (item_callback )
170
+ item_callback (parser , pos , arg );
171
+ goto next ;
172
+ }
173
+
174
+ // guess it's a string token
175
+ // does it end the list?
176
+ bool end = rtpp_dict_list_end_rewind (pos );
177
+
178
+ if (pos -> cur .len == 0 )
179
+ break ; // nothing left
180
+
181
+ if (str_callback )
182
+ str_callback (& pos -> cur , idx ++ , arg );
183
+ if (end )
184
+ break ;
185
+ goto next ;
186
+
187
+ next :
188
+ // find next token in remainder, put in `cur`
189
+ if (!str_token_sep (& pos -> cur , & pos -> remainder , ' ' ))
190
+ break ;
191
+ }
192
+ }
193
+ static bool rtpp_dict_iter (const ng_parser_t * parser , rtpp_pos * pos ,
194
+ void (* callback )(const ng_parser_t * , str * , parser_arg , helper_arg ),
195
+ helper_arg arg )
196
+ {
197
+ // list opener
198
+ if (!skip_char (& pos -> cur , '[' ))
199
+ return false;
200
+
201
+ while (true) {
202
+ skip_chars (& pos -> cur , ' ' );
203
+ if (!pos -> cur .len )
204
+ goto next ; // empty token?
205
+
206
+ // dict closing?
207
+ if (rtpp_dict_list_closing (pos ))
208
+ break ;
209
+
210
+ str key ;
211
+ if (!str_token (& key , & pos -> cur , '=' )) {
212
+ ilog (LOG_ERR , "Entry in dictionary without equals sign ('" STR_FORMAT "'), aborting" ,
213
+ STR_FMT (& pos -> cur ));
214
+ break ;
215
+ }
216
+
217
+ // guess it's a string token
218
+ // does it end the dict?
219
+ bool end = rtpp_dict_list_end_rewind (pos );
220
+
221
+ if (pos -> cur .len == 0 )
222
+ break ; // nothing left
223
+
224
+ callback (parser , & key , pos , arg );
225
+ if (end )
226
+ break ;
227
+ goto next ;
228
+
229
+ next :
230
+ // find next token in remainder, put in `cur`
231
+ if (!str_token_sep (& pos -> cur , & pos -> remainder , ' ' ))
232
+ break ;
233
+ }
234
+
235
+ return true;
236
+ }
237
+ static bool rtpp_is_int (rtpp_pos * pos ) {
238
+ return false;
239
+ }
74
240
75
241
const ng_parser_t dummy_parser = {
76
- .is_list = dummy_is_list ,
77
- .get_str = dummy_get_str ,
242
+ .is_list = rtpp_is_list ,
243
+ .is_dict = rtpp_is_dict ,
244
+ .is_int = rtpp_is_int ,
245
+ .list_iter = rtpp_list_iter ,
246
+ .dict_iter = rtpp_dict_iter ,
247
+ .get_str = rtpp_get_str ,
248
+ .get_int_str = rtpp_get_int_str ,
78
249
};
79
250
80
251
static bool parse_codec_to_dict (str * key , str * val , const char * cmp1 , const char * cmp2 ,
@@ -158,8 +329,7 @@ void parse_rtpp_flags(const str * rtpp_flags, sdp_ng_flags *out)
158
329
while (remainder .len )
159
330
{
160
331
/* skip spaces */
161
- while (remainder .len && remainder .s [0 ] == ' ' )
162
- str_shift (& remainder , 1 );
332
+ skip_chars (& remainder , ' ' );
163
333
164
334
/* set key and val */
165
335
if (!get_key_val (& key , & val , & remainder ))
@@ -229,7 +399,7 @@ void parse_rtpp_flags(const str * rtpp_flags, sdp_ng_flags *out)
229
399
if (!val .s && str_eq (& key , "RTP/SAVPF" ))
230
400
transport = 0x103 ;
231
401
/* direction */
232
- else if (str_eq (& key , "direction" ))
402
+ else if (str_eq (& key , "direction" ) && rtpp_is_dict_list ( & val ) == 0 )
233
403
rtpp_direction_flag (out , & direction_flag , & val );
234
404
else
235
405
goto generic ;
@@ -258,8 +428,11 @@ void parse_rtpp_flags(const str * rtpp_flags, sdp_ng_flags *out)
258
428
if (!val .len )
259
429
call_ng_flags_flags (& key , 0 , out );
260
430
/* generic flags with value, but no particular processing */
261
- else
262
- call_ng_main_flags (& dummy_parser , & key , & val , out );
431
+ else {
432
+ rtpp_pos pos = { .cur = val , .remainder = remainder };
433
+ call_ng_main_flags (& dummy_parser , & key , & pos , out );
434
+ remainder = pos .remainder ;
435
+ }
263
436
264
437
next :;
265
438
}
0 commit comments