summaryrefslogtreecommitdiffstats
path: root/sub/filter_regex.c
blob: a5aa03a849db079af36cf1e60dbf60e0140467c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <regex.h>
#include <sys/types.h>

#include "common/common.h"
#include "common/msg.h"
#include "misc/bstr.h"
#include "options/options.h"
#include "sd.h"

struct priv {
    int offset;
    regex_t *regexes;
    int num_regexes;
};

static bool rf_init(struct sd_filter *ft)
{
    if (strcmp(ft->codec, "ass") != 0)
        return false;

    if (!ft->opts->rf_enable)
        return false;

    struct priv *p = talloc_zero(ft, struct priv);
    ft->priv = p;

    for (int n = 0; ft->opts->rf_items && ft->opts->rf_items[n]; n++) {
        char *item = ft->opts->rf_items[n];

        MP_TARRAY_GROW(p, p->regexes, p->num_regexes);
        regex_t *preg = &p->regexes[p->num_regexes];

        int err = regcomp(preg, item, REG_ICASE | REG_EXTENDED | REG_NOSUB);
        if (err) {
            char errbuf[512];
            regerror(err, preg, errbuf, sizeof(errbuf));
            MP_ERR(ft, "Regular expression error: '%s'\n", errbuf);
            continue;
        }

        p->num_regexes += 1;
    }

    if (!p->num_regexes)
        return false;

    char *headers = ft->event_format;
    while (headers && headers[0]) {
        p->offset += 1;
        headers = strchr(headers, ',');
        if (headers)
            headers += 1;
    }
    p->offset -= 1; // removes Start/End, adds ReadOrder

    return true;
}

static void rf_uninit(struct sd_filter *ft)
{
    struct priv *p = ft->priv;

    for (int n = 0; n < p->num_regexes; n++)
        regfree(&p->regexes[n]);
}

static struct demux_packet *rf_filter(struct sd_filter *ft,
                                      struct demux_packet *pkt)
{
    struct priv *p = ft->priv;
    char *line = bstrto0(NULL, (bstr){(char *)pkt->buffer, pkt->len});
    bool drop = false;

    char *text = line;
    for (int n = 0; n < p->offset - 1; n++) {
        text = strchr(text, ',');
        if (!text) {
            MP_WARN(ft, "Malformed event: '%s'\n", line);
            text = line; // shouldn't happen; random fallback
            break;
        }
        text = text + 1;
    }

    for (int n = 0; n < p->num_regexes; n++) {
        int err = regexec(&p->regexes[n], text, 0, NULL, 0);
        if (err == 0) {
            int level = ft->opts->rf_warn ? MSGL_WARN : MSGL_V;
            MP_MSG(ft, level, "Matching regex %d => drop: '%s'\n", n, text);
            drop = true;
            break;
        } else if (err != REG_NOMATCH) {
            MP_WARN(ft, "Error on regexec() on regex %d.\n", n);
        }
    }

    talloc_free(line);
    return drop ? NULL : pkt;
}

const struct sd_filter_functions sd_filter_regex = {
    .init   = rf_init,
    .uninit = rf_uninit,
    .filter = rf_filter,
};