Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavutil/dict.c
Line
Count
Source
1
/*
2
 * copyright (c) 2009 Michael Niedermayer
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include <inttypes.h>
22
#include <stdio.h>
23
#include <string.h>
24
25
#include "avassert.h"
26
#include "avstring.h"
27
#include "dict.h"
28
#include "error.h"
29
#include "mem.h"
30
#include "bprint.h"
31
32
struct AVDictionary {
33
    int count;
34
    AVDictionaryEntry *elems;
35
};
36
37
int av_dict_count(const AVDictionary *m)
38
0
{
39
0
    return m ? m->count : 0;
40
0
}
41
42
const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m,
43
                                         const AVDictionaryEntry *prev)
44
1.36k
{
45
1.36k
    int i = 0;
46
47
1.36k
    if (!m)
48
1.36k
        return NULL;
49
50
0
    if (prev)
51
0
        i = prev - m->elems + 1;
52
53
0
    av_assert2(i >= 0);
54
0
    if (i >= m->count)
55
0
        return NULL;
56
57
0
    return &m->elems[i];
58
0
}
59
60
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
61
                               const AVDictionaryEntry *prev, int flags)
62
0
{
63
0
    const AVDictionaryEntry *entry = prev;
64
0
    unsigned int j;
65
66
0
    if (!key)
67
0
        return NULL;
68
69
0
    while ((entry = av_dict_iterate(m, entry))) {
70
0
        const char *s = entry->key;
71
0
        if (flags & AV_DICT_MATCH_CASE)
72
0
            for (j = 0; s[j] == key[j] && key[j]; j++)
73
0
                ;
74
0
        else
75
0
            for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
76
0
                ;
77
0
        if (key[j])
78
0
            continue;
79
0
        if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
80
0
            continue;
81
0
        return (AVDictionaryEntry *)entry;
82
0
    }
83
0
    return NULL;
84
0
}
85
86
int av_dict_set(AVDictionary **pm, const char *key, const char *value,
87
                int flags)
88
0
{
89
0
    AVDictionary *m = *pm;
90
0
    AVDictionaryEntry *tag = NULL;
91
0
    char *copy_key = NULL, *copy_value = NULL;
92
0
    int err;
93
94
0
    if (flags & AV_DICT_DONT_STRDUP_VAL)
95
0
        copy_value = (void *)value;
96
0
    else if (value)
97
0
        copy_value = av_strdup(value);
98
0
    if (!key) {
99
0
        err = AVERROR(EINVAL);
100
0
        goto err_out;
101
0
    }
102
0
    if (flags & AV_DICT_DONT_STRDUP_KEY)
103
0
        copy_key = (void *)key;
104
0
    else
105
0
        copy_key = av_strdup(key);
106
0
    if (!copy_key || (value && !copy_value))
107
0
        goto enomem;
108
109
0
    if (!(flags & AV_DICT_MULTIKEY)) {
110
0
        tag = av_dict_get(m, key, NULL, flags);
111
0
    } else if (flags & AV_DICT_DEDUP) {
112
0
        while ((tag = av_dict_get(m, key, tag, flags))) {
113
0
            if ((!value && !tag->value) ||
114
0
                (value && tag->value && !strcmp(value, tag->value))) {
115
0
                av_free(copy_key);
116
0
                av_free(copy_value);
117
0
                return 0;
118
0
            }
119
0
        }
120
0
    }
121
0
    if (!m)
122
0
        m = *pm = av_mallocz(sizeof(*m));
123
0
    if (!m)
124
0
        goto enomem;
125
126
0
    if (tag) {
127
0
        if (flags & AV_DICT_DONT_OVERWRITE) {
128
0
            av_free(copy_key);
129
0
            av_free(copy_value);
130
0
            return 0;
131
0
        }
132
0
        if (copy_value && flags & AV_DICT_APPEND) {
133
0
            size_t oldlen = strlen(tag->value);
134
0
            size_t new_part_len = strlen(copy_value);
135
0
            size_t len = oldlen + new_part_len + 1;
136
0
            char *newval = av_realloc(tag->value, len);
137
0
            if (!newval)
138
0
                goto enomem;
139
0
            memcpy(newval + oldlen, copy_value, new_part_len + 1);
140
0
            av_freep(&copy_value);
141
0
            copy_value = newval;
142
0
        } else
143
0
            av_free(tag->value);
144
0
        av_free(tag->key);
145
0
        *tag = m->elems[--m->count];
146
0
    } else if (copy_value) {
147
0
        AVDictionaryEntry *tmp = av_realloc_array(m->elems,
148
0
                                                  m->count + 1, sizeof(*m->elems));
149
0
        if (!tmp)
150
0
            goto enomem;
151
0
        m->elems = tmp;
152
0
    }
153
0
    if (copy_value) {
154
0
        m->elems[m->count].key = copy_key;
155
0
        m->elems[m->count].value = copy_value;
156
0
        m->count++;
157
0
    } else {
158
0
        err = 0;
159
0
        goto end;
160
0
    }
161
162
0
    return 0;
163
164
0
enomem:
165
0
    err = AVERROR(ENOMEM);
166
0
err_out:
167
0
    av_free(copy_value);
168
0
end:
169
0
    if (m && !m->count) {
170
0
        av_freep(&m->elems);
171
0
        av_freep(pm);
172
0
    }
173
0
    av_free(copy_key);
174
0
    return err;
175
0
}
176
177
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
178
                int flags)
179
0
{
180
0
    char valuestr[22];
181
0
    snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
182
0
    flags &= ~AV_DICT_DONT_STRDUP_VAL;
183
0
    return av_dict_set(pm, key, valuestr, flags);
184
0
}
185
186
static int parse_key_value_pair(AVDictionary **pm, const char **buf,
187
                                const char *key_val_sep, const char *pairs_sep,
188
                                int flags)
189
0
{
190
0
    char *key = av_get_token(buf, key_val_sep);
191
0
    char *val = NULL;
192
0
    int ret;
193
194
0
    if (key && *key && strspn(*buf, key_val_sep)) {
195
0
        (*buf)++;
196
0
        val = av_get_token(buf, pairs_sep);
197
0
    }
198
199
0
    if (key && *key && val && *val)
200
0
        ret = av_dict_set(pm, key, val, flags);
201
0
    else
202
0
        ret = AVERROR(EINVAL);
203
204
0
    av_freep(&key);
205
0
    av_freep(&val);
206
207
0
    return ret;
208
0
}
209
210
int av_dict_parse_string(AVDictionary **pm, const char *str,
211
                         const char *key_val_sep, const char *pairs_sep,
212
                         int flags)
213
0
{
214
0
    int ret;
215
216
0
    if (!str)
217
0
        return 0;
218
219
    /* ignore STRDUP flags */
220
0
    flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
221
222
0
    while (*str) {
223
0
        if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
224
0
            return ret;
225
226
0
        if (*str)
227
0
            str++;
228
0
    }
229
230
0
    return 0;
231
0
}
232
233
void av_dict_free(AVDictionary **pm)
234
5.45k
{
235
5.45k
    AVDictionary *m = *pm;
236
237
5.45k
    if (m) {
238
0
        while (m->count--) {
239
0
            av_freep(&m->elems[m->count].key);
240
0
            av_freep(&m->elems[m->count].value);
241
0
        }
242
0
        av_freep(&m->elems);
243
0
    }
244
5.45k
    av_freep(pm);
245
5.45k
}
246
247
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
248
0
{
249
0
    const AVDictionaryEntry *t = NULL;
250
251
0
    while ((t = av_dict_iterate(src, t))) {
252
0
        int ret = av_dict_set(dst, t->key, t->value, flags);
253
0
        if (ret < 0)
254
0
            return ret;
255
0
    }
256
257
0
    return 0;
258
0
}
259
260
int av_dict_get_string(const AVDictionary *m, char **buffer,
261
                       const char key_val_sep, const char pairs_sep)
262
0
{
263
0
    const AVDictionaryEntry *t = NULL;
264
0
    AVBPrint bprint;
265
0
    int cnt = 0;
266
0
    char special_chars[] = {pairs_sep, key_val_sep, '\0'};
267
268
0
    if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
269
0
        pairs_sep == '\\' || key_val_sep == '\\')
270
0
        return AVERROR(EINVAL);
271
272
0
    if (!av_dict_count(m)) {
273
0
        *buffer = av_strdup("");
274
0
        return *buffer ? 0 : AVERROR(ENOMEM);
275
0
    }
276
277
0
    av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
278
0
    while ((t = av_dict_iterate(m, t))) {
279
0
        if (cnt++)
280
0
            av_bprint_append_data(&bprint, &pairs_sep, 1);
281
0
        av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
282
0
        av_bprint_append_data(&bprint, &key_val_sep, 1);
283
0
        av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
284
0
    }
285
0
    return av_bprint_finalize(&bprint, buffer);
286
0
}