Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/tvbparse.c
Line
Count
Source
1
/* tvbparse.c
2
 *
3
 * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <stdlib.h>
15
#include <string.h>
16
#include <glib.h>
17
18
#include <epan/wmem_scopes.h>
19
#include <epan/proto.h>
20
#include <epan/packet_info.h>
21
#include <epan/tvbparse.h>
22
#include <wsutil/ws_assert.h>
23
24
25
#define TVBPARSE_DEBUG_ALL 0xffffffff
26
27
#if 0
28
#define TVBPARSE_DEBUG_ 0x80000000
29
#define TVBPARSE_DEBUG_ 0x40000000
30
#define TVBPARSE_DEBUG_ 0x20000000
31
#define TVBPARSE_DEBUG_ 0x10000000
32
#endif
33
34
#define TVBPARSE_DEBUG_CHAR 0x08000000
35
#define TVBPARSE_DEBUG_CHARS 0x04000000
36
#define TVBPARSE_DEBUG_NOT_CHAR 0x02000000
37
#define TVBPARSE_DEBUG_NOT_CHARS 0x01000000
38
#define TVBPARSE_DEBUG_STRING 0x00800000
39
#define TVBPARSE_DEBUG_CASESTRING 0x00400000
40
#define TVBPARSE_DEBUG_ONEOF 0x00200000
41
#define TVBPARSE_DEBUG_HASH 0x00100000
42
#define TVBPARSE_DEBUG_SEQ 0x00080000
43
#define TVBPARSE_DEBUG_SOME 0x00040000
44
#define TVBPARSE_DEBUG_UNTIL 0x00020000
45
#if 0
46
#define TVBPARSE_DEBUG_ 0x00010000
47
#define TVBPARSE_DEBUG_ 0x00008000
48
#define TVBPARSE_DEBUG_ 0x00004000
49
#define TVBPARSE_DEBUG_ 0x00002000
50
#define TVBPARSE_DEBUG_ 0x00001000
51
#endif
52
#define TVBPARSE_DEBUG_TT 0x00000800
53
#define TVBPARSE_DEBUG_CB 0x00000400
54
#define TVBPARSE_DEBUG_GET 0x00000200
55
#define TVBPARSE_DEBUG_FIND 0x00000100
56
#define TVBPARSE_DEBUG_NEWTOK 0x00000080
57
#define TVBPARSE_DEBUG_IGNORE 0x00000040
58
#define TVBPARSE_DEBUG_PEEK 0x00000020
59
#if 0
60
#define TVBPARSE_DEBUG_ 0x00000010
61
#define TVBPARSE_DEBUG_ 0x00000008
62
#define TVBPARSE_DEBUG_ 0x00000004
63
#define TVBPARSE_DEBUG_ 0x00000002
64
#define TVBPARSE_DEBUG_ 0x00000001
65
#endif
66
67
/*
68
#define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
69
*/
70
71
442k
#define TVBPARSE_MAX_RECURSION_DEPTH 100 // Arbitrary. Matches DAAP and PNIO.
72
73
static tvbparse_elem_t* new_tok(tvbparse_t* tt,
74
                                int id,
75
                                int offset,
76
                                int len,
77
374k
                                const tvbparse_wanted_t* wanted) {
78
374k
    tvbparse_elem_t* tok;
79
80
#ifdef TVBPARSE_DEBUG
81
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) ws_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
82
#endif
83
84
374k
    tok = wmem_new(tt->scope, tvbparse_elem_t);
85
86
374k
    tok->parser = tt;
87
374k
    tok->tvb = tt->tvb;
88
374k
    tok->id = id;
89
374k
    tok->offset = offset;
90
374k
    tok->len = len;
91
374k
    tok->data = NULL;
92
374k
    tok->sub = NULL;
93
374k
    tok->next = NULL;
94
374k
    tok->wanted = wanted;
95
374k
    tok->last = tok;
96
97
374k
    return tok;
98
374k
}
99
100
209k
static int ignore_fcn(tvbparse_t* tt, int offset) {
101
209k
    int len = 0;
102
209k
    int consumed;
103
209k
    tvbparse_elem_t* ignored = NULL;
104
105
209k
    if (!tt->ignore) return 0;
106
107
#ifdef TVBPARSE_DEBUG
108
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: enter");
109
#endif
110
111
239k
    while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) {
112
29.7k
        len += consumed;
113
29.7k
        offset += consumed;
114
#ifdef TVBPARSE_DEBUG
115
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: consumed=%i",consumed);
116
#endif
117
118
29.7k
    }
119
120
#ifdef TVBPARSE_DEBUG
121
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: len=%i",len);
122
#endif
123
124
209k
    return len;
125
209k
}
126
127
128
348k
static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
129
348k
    char c,t;
130
348k
    unsigned i;
131
132
#ifdef TVBPARSE_DEBUG
133
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: control='%s'",wanted->control.str);
134
#endif
135
136
348k
    if ( offset + 1 > tt->end_offset )
137
0
        return -1;
138
139
348k
    t = (char) tvb_get_uint8(tt->tvb,offset);
140
141
600k
    for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) {
142
352k
        if ( c == t ) {
143
101k
            *tok =  new_tok(tt,wanted->id,offset,1,wanted);
144
#ifdef TVBPARSE_DEBUG
145
            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: GOT: '%c'",c);
146
#endif
147
101k
            return 1;
148
101k
        }
149
352k
    }
150
151
247k
    return -1;
152
348k
}
153
154
tvbparse_wanted_t* tvbparse_char(const int id,
155
                                 const char* chr,
156
                                 const void* data,
157
                                 tvbparse_action_t before_cb,
158
504
                                 tvbparse_action_t after_cb) {
159
504
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
160
161
504
    w->condition = cond_char;
162
504
    w->id = id;
163
504
    w->control.str = chr;
164
504
    w->len = 1;
165
504
    w->data = data;
166
504
    w->before = before_cb;
167
504
    w->after = after_cb;
168
169
504
    return w;
170
504
}
171
172
327k
static int cond_chars_common(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
173
327k
    unsigned length = 0;
174
327k
    int start = offset;
175
327k
    int left = tt->end_offset - offset;
176
177
#ifdef TVBPARSE_DEBUG
178
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: control='%s'",wanted->control.str);
179
#endif
180
181
327k
    if ( offset + (int)wanted->min > tt->end_offset )
182
8.65k
        return -1;
183
184
319k
    left = left < (int) wanted->max ? left :  (int) wanted->max;
185
186
654k
    while( left > 0 ) {
187
647k
        uint8_t t = tvb_get_uint8(tt->tvb,offset++);
188
189
647k
        if (!wanted->control.str[t])
190
312k
            break;
191
192
335k
        length++;
193
335k
        left--;
194
335k
    };
195
196
319k
    if (length < wanted->min) {
197
249k
        return  -1;
198
249k
    } else {
199
69.3k
        *tok = new_tok(tt,wanted->id,start,length,wanted);
200
#ifdef TVBPARSE_DEBUG
201
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: GOT len=%i",length);
202
#endif
203
69.3k
        return length;
204
69.3k
    }
205
319k
}
206
207
tvbparse_wanted_t* tvbparse_chars(const int id,
208
                                  const unsigned min_len,
209
                                  const unsigned max_len,
210
                                  const char* chr,
211
                                  const void* data,
212
                                  tvbparse_action_t before_cb,
213
                                  tvbparse_action_t after_cb)
214
322
{
215
322
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
216
322
    char *accept_str;
217
322
    size_t i;
218
219
322
    accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
220
322
    memset(accept_str, 0x00, 256);
221
6.77k
    for (i = 0; chr[i]; i++)
222
6.45k
        accept_str[(unsigned)chr[i]] = (char)0xFF;
223
224
322
    w->condition = cond_chars_common;
225
322
    w->id = id;
226
322
    w->control.str = accept_str;
227
322
    w->min = min_len ? min_len : 1;
228
322
    w->max = max_len ? max_len : INT_MAX/2;
229
322
    w->data = data;
230
322
    w->before = before_cb;
231
322
    w->after = after_cb;
232
233
322
    return w;
234
322
}
235
236
237
0
static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
238
0
    char c, t;
239
0
    unsigned i;
240
0
    bool not_matched = false;
241
242
#ifdef TVBPARSE_DEBUG
243
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: control='%s'",wanted->control.str);
244
#endif
245
246
0
    if ( offset >= tt->end_offset ) {
247
0
        return -1;
248
0
    }
249
250
0
    t = (char) tvb_get_uint8(tt->tvb,offset);
251
252
0
    for(i = 0; (c = wanted->control.str[i]); i++) {
253
0
        if ( c == t ) {
254
0
            not_matched = true;
255
0
        }
256
0
    }
257
258
0
    if (not_matched) {
259
0
        return -1;
260
0
    } else {
261
0
        *tok =  new_tok(tt,wanted->id,offset,1,wanted);
262
#ifdef TVBPARSE_DEBUG
263
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: GOT='%c'",t);
264
#endif
265
0
        return 1;
266
0
    }
267
0
}
268
269
tvbparse_wanted_t* tvbparse_not_char(const int id,
270
                                     const char* chr,
271
                                     const void* data,
272
                                     tvbparse_action_t before_cb,
273
0
                                     tvbparse_action_t after_cb) {
274
0
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
275
276
0
    w->condition = cond_not_char;
277
0
    w->id = id;
278
0
    w->control.str = chr;
279
0
    w->data = data;
280
0
    w->before = before_cb;
281
0
    w->after = after_cb;
282
283
0
    return w;
284
0
}
285
286
tvbparse_wanted_t* tvbparse_not_chars(const int id,
287
                                      const unsigned min_len,
288
                                      const unsigned max_len,
289
                                      const char* chr,
290
                                      const void* data,
291
                                      tvbparse_action_t before_cb,
292
                                      tvbparse_action_t after_cb)
293
112
{
294
112
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
295
112
    char *accept_str;
296
112
    size_t i;
297
298
    /* cond_chars_common() use accept string, so mark all elements with, and later unset from reject */
299
112
    accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
300
112
    memset(accept_str, 0xFF, 256);
301
294
    for (i = 0; chr[i]; i++)
302
182
        accept_str[(unsigned) chr[i]] = '\0';
303
304
112
    w->condition = cond_chars_common;
305
112
    w->id = id;
306
112
    w->control.str = accept_str;
307
112
    w->len = 0;
308
112
    w->min = min_len ? min_len : 1;
309
112
    w->max = max_len ? max_len : INT_MAX/2;
310
112
    w->data = data;
311
112
    w->before = before_cb;
312
112
    w->after = after_cb;
313
314
112
    return w;
315
112
}
316
317
318
199k
static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
319
199k
    int len = wanted->len;
320
#ifdef TVBPARSE_DEBUG
321
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: control='%s'",wanted->control.str);
322
#endif
323
324
199k
    if ( offset + wanted->len > tt->end_offset )
325
426
        return -1;
326
327
199k
    if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
328
5.31k
        *tok = new_tok(tt,wanted->id,offset,len,wanted);
329
#ifdef TVBPARSE_DEBUG
330
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: GOT len=%i",len);
331
#endif
332
5.31k
        return len;
333
193k
    } else {
334
193k
        return -1;
335
193k
    }
336
199k
}
337
338
tvbparse_wanted_t* tvbparse_string(const int id,
339
                                   const char* str,
340
                                   const void* data,
341
                                   tvbparse_action_t before_cb,
342
364
                                   tvbparse_action_t after_cb) {
343
364
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
344
345
364
    w->condition = cond_string;
346
364
    w->id = id;
347
364
    w->control.str = str;
348
364
    w->len = (int) strlen(str);
349
364
    w->data = data;
350
364
    w->before = before_cb;
351
364
    w->after = after_cb;
352
353
364
    return w;
354
364
}
355
356
1.47k
static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
357
1.47k
    int len = wanted->len;
358
#ifdef TVBPARSE_DEBUG
359
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: control='%s'",wanted->control.str);
360
#endif
361
362
1.47k
    if ( offset + len > tt->end_offset )
363
0
        return -1;
364
365
1.47k
    if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
366
369
        *tok = new_tok(tt,wanted->id,offset,len,wanted);
367
#ifdef TVBPARSE_DEBUG
368
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: GOT len=%i",len);
369
#endif
370
369
        return len;
371
1.10k
    } else {
372
1.10k
        *tok = NULL;
373
1.10k
        return -1;
374
1.10k
    }
375
1.47k
}
376
377
tvbparse_wanted_t* tvbparse_casestring(const int id,
378
                                       const char* str,
379
                                       const void* data,
380
                                       tvbparse_action_t before_cb,
381
42
                                       tvbparse_action_t after_cb) {
382
42
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
383
384
42
    w->condition = cond_casestring;
385
42
    w->id = id;
386
42
    w->control.str = str;
387
42
    w->len = (int) strlen(str);
388
42
    w->data = data;
389
42
    w->before = before_cb;
390
42
    w->after = after_cb;
391
392
42
    return w;
393
42
}
394
395
92.5k
static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
396
92.5k
    unsigned i;
397
#ifdef TVBPARSE_DEBUG
398
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: START");
399
#endif
400
401
92.5k
    if ( offset > tt->end_offset )
402
0
        return -1;
403
404
92.5k
    if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
405
70
        return -1;
406
407
413k
    for(i=0; i < wanted->control.elems->len; i++) {
408
387k
        tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
409
387k
        tvbparse_elem_t* new_elem = NULL;
410
387k
        int curr_len;
411
412
387k
        if ( offset + w->len > tt->end_offset )
413
2.94k
            continue;
414
415
384k
        curr_len = w->condition(tt, offset, w,  &new_elem);
416
417
384k
        if (curr_len >= 0) {
418
66.9k
            *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
419
66.9k
            (*tok)->sub = new_elem;
420
#ifdef TVBPARSE_DEBUG
421
            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: GOT len=%i",curr_len);
422
#endif
423
66.9k
            tt->recursion_depth--;
424
66.9k
            return curr_len;
425
66.9k
        }
426
384k
    }
427
428
25.5k
    tt->recursion_depth--;
429
25.5k
    return -1;
430
92.4k
}
431
432
static bool
433
tvbparse_wanted_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
434
0
{
435
0
    tvbparse_wanted_t* w = (tvbparse_wanted_t *)user_data;
436
0
    g_ptr_array_free(w->control.elems, true);
437
0
    return false;
438
0
}
439
440
tvbparse_wanted_t* tvbparse_set_oneof(const int id,
441
                                      const void* data,
442
                                      tvbparse_action_t before_cb,
443
                                      tvbparse_action_t after_cb,
444
364
                                      ...) {
445
364
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
446
364
    tvbparse_t* el;
447
364
    va_list ap;
448
449
364
    w->condition = cond_one_of;
450
364
    w->id = id;
451
364
    w->data = data;
452
364
    w->before = before_cb;
453
364
    w->after = after_cb;
454
364
    w->control.elems = g_ptr_array_new();
455
364
    wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
456
457
364
    va_start(ap,after_cb);
458
459
1.49k
    while(( el = va_arg(ap,tvbparse_t*) )) {
460
1.13k
        g_ptr_array_add(w->control.elems,el);
461
1.13k
    };
462
463
364
    va_end(ap);
464
465
364
    return w;
466
364
}
467
468
0
static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) {
469
0
    int key_len;
470
0
    uint8_t* key = NULL;
471
0
    tvbparse_elem_t* key_elem = NULL;
472
0
    tvbparse_wanted_t* value_wanted = NULL;
473
0
    int value_len;
474
0
    tvbparse_elem_t* value_elem = NULL;
475
0
    int tot_len;
476
0
    tvbparse_elem_t* ret_tok;
477
478
#ifdef TVBPARSE_DEBUG
479
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: START");
480
#endif
481
482
0
    if ( offset > tt->end_offset )
483
0
        return -1;
484
485
0
    if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
486
0
        return -1;
487
488
0
    key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key,  &key_elem);
489
490
0
    if (key_len < 0) {
491
0
        tt->recursion_depth--;
492
0
        return -1;
493
0
    }
494
495
0
    key = tvb_get_string_enc(tt->scope,key_elem->parser->tvb,key_elem->offset,key_elem->len, ENC_ASCII);
496
#ifdef TVBPARSE_DEBUG
497
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: got key='%s'",key);
498
#endif
499
500
0
    if ((value_wanted = (tvbparse_wanted_t *)wmem_map_lookup(wanted->control.hash.table,key))) {
501
0
        value_len = value_wanted->condition(tt, offset + key_len, value_wanted,  &value_elem);
502
0
    } else if (wanted->control.hash.other) {
503
0
        value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other,  &value_elem);
504
0
        if (value_len < 0) {
505
0
            tt->recursion_depth--;
506
0
            return -1;
507
0
        }
508
0
    } else {
509
0
        tt->recursion_depth--;
510
0
        return -1;
511
0
    }
512
513
0
    tt->recursion_depth--;
514
515
0
    tot_len = key_len + value_len;
516
517
0
    ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted);
518
0
    ret_tok->sub = key_elem;
519
0
    ret_tok->sub->last->next = value_elem;
520
521
0
    *tok = ret_tok;
522
#ifdef TVBPARSE_DEBUG
523
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: GOT len=%i",tot_len);
524
#endif
525
526
0
    return tot_len;
527
0
}
528
529
tvbparse_wanted_t* tvbparse_hashed(const int id,
530
                                   const void* data,
531
                                   tvbparse_action_t before_cb,
532
                                   tvbparse_action_t after_cb,
533
                                   tvbparse_wanted_t* key,
534
                                   tvbparse_wanted_t* other,
535
0
                                   ...) {
536
0
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
537
0
    char* name;
538
0
    tvbparse_wanted_t* el;
539
0
    va_list ap;
540
541
0
    w->condition = cond_hash;
542
0
    w->id = id;
543
0
    w->data = data;
544
0
    w->before = before_cb;
545
0
    w->after = after_cb;
546
0
    w->control.hash.table = wmem_map_new(wmem_epan_scope(), g_str_hash,g_str_equal);
547
0
    w->control.hash.key = key;
548
0
    w->control.hash.other = other;
549
550
0
    va_start(ap,other);
551
552
0
    while(( name = va_arg(ap,char*) )) {
553
0
        el = va_arg(ap,tvbparse_wanted_t*);
554
0
        wmem_map_insert(w->control.hash.table,name,el);
555
0
    }
556
557
0
    va_end(ap);
558
559
0
    return w;
560
0
}
561
562
0
void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) {
563
0
    tvbparse_wanted_t* el;
564
0
    va_list ap;
565
0
    char* name;
566
567
0
    va_start(ap,w);
568
569
0
    while (( name = va_arg(ap,char*) )) {
570
0
        el = va_arg(ap,tvbparse_wanted_t*);
571
0
        wmem_map_insert(w->control.hash.table,name,el);
572
0
    }
573
574
0
    va_end(ap);
575
0
}
576
577
312k
static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
578
312k
    unsigned i;
579
312k
    int len = 0;
580
312k
    int start = offset;
581
312k
    tvbparse_elem_t* ret_tok = NULL;
582
583
#ifdef TVBPARSE_DEBUG
584
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: START");
585
#endif
586
587
312k
    if ( offset > tt->end_offset )
588
0
        return -1;
589
590
312k
    if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
591
228
        return -1;
592
593
488k
    for(i=0; i < wanted->control.elems->len; i++) {
594
445k
        tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
595
445k
        tvbparse_elem_t* new_elem = NULL;
596
597
445k
        if ( offset + w->len > tt->end_offset ) {
598
17.8k
            tt->recursion_depth--;
599
17.8k
            return -1;
600
17.8k
        }
601
602
428k
        len = w->condition(tt, offset, w, &new_elem);
603
604
428k
        if (len >= 0) {
605
175k
            if (ret_tok) {
606
73.9k
                if (new_elem->len)
607
56.9k
                    ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
608
73.9k
                ret_tok->sub->last->next = new_elem;
609
73.9k
                ret_tok->sub->last = new_elem;
610
101k
            } else {
611
101k
                ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
612
101k
                ret_tok->sub = new_elem;
613
101k
                new_elem->last = new_elem;
614
101k
            }
615
252k
        } else {
616
252k
            tt->recursion_depth--;
617
252k
            return -1;
618
252k
        }
619
620
175k
        offset += len;
621
175k
        offset += ignore_fcn(tt,offset);
622
175k
    }
623
624
42.3k
    tt->recursion_depth--;
625
626
42.3k
    *tok = ret_tok;
627
628
#ifdef TVBPARSE_DEBUG
629
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: GOT len=%i",offset - start);
630
#endif
631
632
42.3k
    return offset - start;
633
312k
}
634
635
636
tvbparse_wanted_t* tvbparse_set_seq(const int id,
637
                                    const void* data,
638
                                    tvbparse_action_t before_cb,
639
                                    tvbparse_action_t after_cb,
640
630
                                    ...) {
641
630
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
642
630
    tvbparse_wanted_t*  el = NULL;
643
630
    va_list ap;
644
645
630
    w->condition = cond_seq;
646
630
    w->id = id;
647
630
    w->data = data;
648
630
    w->before = before_cb;
649
630
    w->after = after_cb;
650
630
    w->control.elems = g_ptr_array_new();
651
630
    wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
652
653
630
    va_start(ap,after_cb);
654
655
2.22k
    while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
656
1.59k
        g_ptr_array_add(w->control.elems,el);
657
1.59k
    };
658
659
630
    va_end(ap);
660
630
    return w;
661
630
}
662
663
35.5k
static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
664
35.5k
    unsigned got_so_far = 0;
665
35.5k
    int start = offset;
666
35.5k
    tvbparse_elem_t* ret_tok = NULL;
667
#ifdef TVBPARSE_DEBUG
668
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: START");
669
#endif
670
671
35.5k
    if ( offset > tt->end_offset )
672
0
        return -1;
673
674
35.5k
    if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
675
87
        return -1;
676
677
35.4k
    if ( wanted->min == 0 ) {
678
28.6k
        ret_tok = new_tok(tt,wanted->id,offset,0,wanted);
679
28.6k
    }
680
681
48.6k
    while (got_so_far < wanted->max) {
682
45.6k
        tvbparse_elem_t* new_elem = NULL;
683
45.6k
        int consumed;
684
685
45.6k
        if ( offset > tt->end_offset ) {
686
0
            tt->recursion_depth--;
687
0
            return -1;
688
0
        }
689
690
45.6k
        consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem);
691
692
45.6k
        if(consumed >= 0) {
693
13.2k
            if (ret_tok) {
694
12.4k
                if (new_elem->len)
695
12.4k
                    ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
696
697
12.4k
                if (ret_tok->sub) {
698
8.09k
                    ret_tok->sub->last->next = new_elem;
699
8.09k
                    ret_tok->sub->last = new_elem;
700
8.09k
                } else {
701
4.39k
                    ret_tok->sub = new_elem;
702
4.39k
                }
703
12.4k
            } else {
704
781
                ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
705
781
                ret_tok->sub = new_elem;
706
781
            }
707
32.3k
        } else {
708
32.3k
            break;
709
32.3k
        }
710
711
13.2k
        offset += consumed;
712
13.2k
        got_so_far++;
713
13.2k
    }
714
715
35.4k
    tt->recursion_depth--;
716
717
#ifdef TVBPARSE_DEBUG
718
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: got num=%u",got_so_far);
719
#endif
720
721
35.4k
    if(got_so_far < wanted->min) {
722
5.99k
        return -1;
723
5.99k
    }
724
725
29.4k
    *tok = ret_tok;
726
#ifdef TVBPARSE_DEBUG
727
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: GOT len=%i",offset - start);
728
#endif
729
29.4k
    return offset - start;
730
35.4k
}
731
732
tvbparse_wanted_t* tvbparse_some(const int id,
733
                                 const unsigned min,
734
                                 const unsigned max,
735
                                 const void* data,
736
                                 tvbparse_action_t before_cb,
737
                                 tvbparse_action_t after_cb,
738
210
                                 const tvbparse_wanted_t* wanted) {
739
740
210
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
741
742
210
    ws_assert(min <= max);
743
744
210
    w->condition = cond_some;
745
210
    w->id = id;
746
210
    w->min = min;
747
210
    w->max = max;
748
210
    w->data = data;
749
210
    w->before = before_cb;
750
210
    w->after = after_cb;
751
210
    w->control.subelem = wanted;
752
753
210
    return w;
754
210
}
755
756
757
1.88k
static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
758
1.88k
    tvbparse_elem_t* new_elem = NULL;
759
1.88k
    int len = 0;
760
1.88k
    int target_offset = offset;
761
#ifdef TVBPARSE_DEBUG
762
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: START");
763
#endif
764
765
1.88k
    if ( offset + wanted->control.until.subelem->len > tt->end_offset )
766
14
        return -1;
767
768
1.87k
    if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
769
0
        return -1;
770
771
188k
    do {
772
188k
        len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem,  &new_elem);
773
188k
    } while(len < 0  && target_offset+1 < tt->end_offset);
774
775
1.87k
    tt->recursion_depth--;
776
777
1.87k
    if (len >= 0) {
778
779
859
        new_elem->id = wanted->id;
780
859
        new_elem->next = NULL;
781
859
        new_elem->last = NULL;
782
859
        new_elem->wanted = wanted;
783
859
        new_elem->offset = offset;
784
785
859
        (*tok) = new_elem;
786
787
859
        switch (wanted->control.until.mode) {
788
706
            case TP_UNTIL_INCLUDE:
789
706
                new_elem->len = target_offset - offset - 1 + len;
790
#ifdef TVBPARSE_DEBUG
791
                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
792
#endif
793
706
                return target_offset - offset -1 + len;
794
153
            case TP_UNTIL_SPEND:
795
153
                new_elem->len = target_offset - offset - 1;
796
#ifdef TVBPARSE_DEBUG
797
                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
798
#endif
799
153
                return target_offset - offset - 1 + len;
800
0
            case TP_UNTIL_LEAVE:
801
0
                new_elem->len = target_offset - offset - 1;
802
#ifdef TVBPARSE_DEBUG
803
                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1);
804
#endif
805
0
                return target_offset - offset -1;
806
0
            default:
807
0
                DISSECTOR_ASSERT_NOT_REACHED();
808
0
                return -1;
809
859
        }
810
811
1.01k
    } else {
812
1.01k
        return -1;
813
1.01k
    }
814
1.87k
}
815
816
tvbparse_wanted_t* tvbparse_until(const int id,
817
                                  const void* data,
818
                                  tvbparse_action_t before_cb,
819
                                  tvbparse_action_t after_cb,
820
                                  const tvbparse_wanted_t* el,
821
70
                                  until_mode_t until_mode) {
822
70
    tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
823
824
70
    w->condition = cond_until;
825
70
    w->control.until.mode = until_mode;
826
70
    w->control.until.subelem = el;
827
70
    w->id = id;
828
70
    w->data = data;
829
70
    w->before = before_cb;
830
70
    w->after = after_cb;
831
832
70
    return w;
833
70
}
834
835
tvbparse_wanted_t* tvbparse_quoted(const int id,
836
                                   const void* data,
837
                                   tvbparse_action_t before_cb,
838
                                   tvbparse_action_t after_cb,
839
                                   const char quote,
840
56
                                   const char esc) {
841
842
56
    char* esc_quot = wmem_strdup_printf(wmem_epan_scope(), "%c%c",esc,quote);
843
56
    char* quot = wmem_strdup_printf(wmem_epan_scope(), "%c",quote);
844
56
    tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
845
846
56
    return tvbparse_set_oneof(id, data, before_cb, after_cb,
847
56
                              tvbparse_set_seq(-1, NULL, NULL, NULL,
848
56
                                               want_quot,
849
56
                                               tvbparse_set_seq(-1,NULL,NULL,NULL,
850
56
                                                                tvbparse_set_oneof(-1, NULL, NULL, NULL,
851
56
                                                                                   tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
852
56
                                                                                   tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
853
56
                                                                                   NULL),
854
56
                                                                NULL),
855
56
                                               want_quot,
856
56
                                               NULL),
857
56
                              tvbparse_set_seq(-1, NULL, NULL, NULL,
858
56
                                               want_quot,
859
56
                                               want_quot,
860
56
                                               NULL),
861
56
                              NULL);
862
56
}
863
864
void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
865
                              const void* wanted_data _U_,
866
318
                              tvbparse_elem_t* tok) {
867
318
    tok->offset += 1;
868
318
    tok->len -= 2;
869
318
}
870
871
tvbparse_t* tvbparse_init(wmem_allocator_t *scope,
872
                          tvbuff_t* tvb,
873
                          const int offset,
874
                          int len,
875
                          void* data,
876
4.37k
                          const tvbparse_wanted_t* ignore) {
877
4.37k
    tvbparse_t* tt = wmem_new(scope, tvbparse_t);
878
879
#ifdef TVBPARSE_DEBUG
880
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
881
#endif
882
883
4.37k
    tt->scope = scope;
884
4.37k
    tt->tvb = tvb;
885
4.37k
    tt->offset = offset;
886
4.37k
    len = (len == -1) ? (int) tvb_captured_length(tvb) : len;
887
4.37k
    tt->end_offset = offset + len;
888
4.37k
    tt->data = data;
889
4.37k
    tt->ignore = ignore;
890
4.37k
    tt->recursion_depth = 0;
891
4.37k
    return tt;
892
4.37k
}
893
894
bool tvbparse_reset(tvbparse_t* tt,
895
                        const unsigned offset,
896
0
                        unsigned len) {
897
898
#ifdef TVBPARSE_DEBUG
899
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
900
#endif
901
902
0
    if( tvb_captured_length_remaining(tt->tvb, offset) >= len) {
903
0
        tt->offset = offset;
904
0
        tt->end_offset = offset + len;
905
0
        return true;
906
0
    } else {
907
0
        return false;
908
0
    }
909
0
}
910
911
2.66k
unsigned tvbparse_curr_offset(tvbparse_t* tt) {
912
2.66k
    return tt->offset;
913
2.66k
}
914
915
29.6k
static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
916
29.6k
    wmem_stack_t *stack = wmem_stack_new(tt->scope);
917
918
228k
    while (curr) {
919
198k
        if(curr->wanted->before) {
920
#ifdef TVBPARSE_DEBUG
921
            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
922
#endif
923
11.3k
            curr->wanted->before(tt->data, curr->wanted->data, curr);
924
11.3k
        }
925
926
198k
        if(curr->sub) {
927
101k
            wmem_stack_push(stack, curr);
928
101k
            curr = curr->sub;
929
101k
            continue;
930
101k
        } else {
931
#ifdef TVBPARSE_DEBUG
932
            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
933
#endif
934
97.1k
            if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
935
97.1k
        }
936
937
97.1k
        curr = curr->next;
938
939
198k
        while( !curr && wmem_stack_count(stack) > 0 ) {
940
101k
            curr = (tvbparse_elem_t *)wmem_stack_pop(stack);
941
#ifdef TVBPARSE_DEBUG
942
            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
943
#endif
944
101k
            if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
945
101k
            curr = curr->next;
946
101k
        }
947
97.1k
    }
948
949
29.6k
}
950
951
bool tvbparse_peek(tvbparse_t* tt,
952
0
                       const tvbparse_wanted_t* wanted) {
953
0
    tvbparse_elem_t* tok = NULL;
954
0
    int consumed;
955
0
    int offset = tt->offset;
956
957
#ifdef TVBPARSE_DEBUG
958
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: ENTER offset=%i",offset);
959
#endif
960
961
0
    offset += ignore_fcn(tt,offset);
962
963
#ifdef TVBPARSE_DEBUG
964
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: after ignore offset=%i",offset);
965
#endif
966
967
0
    consumed = wanted->condition(tt,offset,wanted,&tok);
968
969
0
    if (consumed >= 0) {
970
#ifdef TVBPARSE_DEBUG
971
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: GOT len=%i",consumed);
972
#endif
973
0
        return true;
974
0
    } else {
975
#ifdef TVBPARSE_DEBUG
976
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: NOT GOT");
977
#endif
978
0
        return false;
979
0
    }
980
981
0
}
982
983
tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
984
34.0k
                              const tvbparse_wanted_t* wanted) {
985
34.0k
    tvbparse_elem_t* tok = NULL;
986
34.0k
    int consumed;
987
34.0k
    int offset = tt->offset;
988
989
#ifdef TVBPARSE_DEBUG
990
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: ENTER offset=%i",offset);
991
#endif
992
993
34.0k
    offset += ignore_fcn(tt,offset);
994
995
#ifdef TVBPARSE_DEBUG
996
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: after ignore offset=%i",offset);
997
#endif
998
999
34.0k
    consumed = wanted->condition(tt,offset,wanted,&tok);
1000
1001
34.0k
    if (consumed >= 0) {
1002
#ifdef TVBPARSE_DEBUG
1003
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: GOT len=%i",consumed);
1004
#endif
1005
29.6k
        execute_callbacks(tt,tok);
1006
29.6k
        tt->offset = offset + consumed;
1007
#ifdef TVBPARSE_DEBUG
1008
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1009
#endif
1010
29.6k
        return tok;
1011
29.6k
    } else {
1012
4.37k
        return NULL;
1013
4.37k
    }
1014
1015
34.0k
}
1016
1017
1018
0
tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
1019
0
    tvbparse_elem_t* tok = NULL;
1020
0
    int len = 0;
1021
0
    int offset = tt->offset;
1022
0
    int target_offset = offset -1;
1023
1024
#ifdef TVBPARSE_DEBUG
1025
    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: ENTER offset=%i", tt->offset);
1026
#endif
1027
1028
0
    do {
1029
0
        len = wanted->condition(tt, target_offset+1, wanted,  &tok);
1030
0
    } while(len < 0  && ++target_offset < tt->end_offset);
1031
1032
0
    if (len >= 0) {
1033
#ifdef TVBPARSE_DEBUG
1034
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len);
1035
#endif
1036
0
        execute_callbacks(tt,tok);
1037
0
        tt->offset = target_offset + len;
1038
1039
#ifdef TVBPARSE_DEBUG
1040
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1041
#endif
1042
0
        return tok;
1043
0
    } else {
1044
#ifdef TVBPARSE_DEBUG
1045
        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: NOT FOUND");
1046
#endif
1047
0
        return NULL;
1048
0
    }
1049
0
}
1050
1051
struct _elem_tree_stack_frame {
1052
    proto_tree* tree;
1053
    tvbparse_elem_t* elem;
1054
};
1055
1056
154
void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
1057
154
    wmem_stack_t *stack = wmem_stack_new(curr->parser->scope);
1058
154
    struct _elem_tree_stack_frame* frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1059
154
    proto_item* pi;
1060
154
    frame->tree = tree;
1061
154
    frame->elem = curr;
1062
1063
1.01k
    while (curr) {
1064
859
        pi = proto_tree_add_format_text(frame->tree,curr->parser->tvb,curr->offset,curr->len);
1065
1066
859
        if(curr->sub) {
1067
505
            frame->elem = curr;
1068
505
            wmem_stack_push(stack, frame);
1069
505
            frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1070
505
            frame->tree = proto_item_add_subtree(pi,0);
1071
505
            curr = curr->sub;
1072
505
            continue;
1073
505
        }
1074
1075
354
        curr = curr->next;
1076
1077
859
        while( !curr && wmem_stack_count(stack) > 0 ) {
1078
505
            frame = (struct _elem_tree_stack_frame *)wmem_stack_pop(stack);
1079
505
            curr = frame->elem->next;
1080
505
        }
1081
1082
354
    }
1083
154
}
1084
1085
/*
1086
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1087
 *
1088
 * Local variables:
1089
 * c-basic-offset: 4
1090
 * tab-width: 8
1091
 * indent-tabs-mode: nil
1092
 * End:
1093
 *
1094
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1095
 * :indentSize=4:tabSize=8:noTabs=true:
1096
 */