Imported Debian version 2.5.0~trusty1.1
[deb_ffmpeg.git] / ffmpeg / libavutil / dict.c
CommitLineData
2ba45a60
DM
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 <string.h>
22
23#include "avstring.h"
24#include "dict.h"
25#include "internal.h"
26#include "mem.h"
f6fa7814 27#include "bprint.h"
2ba45a60
DM
28
29struct AVDictionary {
30 int count;
31 AVDictionaryEntry *elems;
32};
33
34int av_dict_count(const AVDictionary *m)
35{
36 return m ? m->count : 0;
37}
38
f6fa7814 39AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
2ba45a60
DM
40 const AVDictionaryEntry *prev, int flags)
41{
42 unsigned int i, j;
43
44 if (!m)
45 return NULL;
46
47 if (prev)
48 i = prev - m->elems + 1;
49 else
50 i = 0;
51
52 for (; i < m->count; i++) {
53 const char *s = m->elems[i].key;
54 if (flags & AV_DICT_MATCH_CASE)
55 for (j = 0; s[j] == key[j] && key[j]; j++)
56 ;
57 else
58 for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
59 ;
60 if (key[j])
61 continue;
62 if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
63 continue;
64 return &m->elems[i];
65 }
66 return NULL;
67}
68
69int av_dict_set(AVDictionary **pm, const char *key, const char *value,
70 int flags)
71{
72 AVDictionary *m = *pm;
73 AVDictionaryEntry *tag = av_dict_get(m, key, NULL, flags);
74 char *oldval = NULL;
75
76 if (!m)
77 m = *pm = av_mallocz(sizeof(*m));
78
79 if (tag) {
80 if (flags & AV_DICT_DONT_OVERWRITE) {
81 if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
82 if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)value);
83 return 0;
84 }
85 if (flags & AV_DICT_APPEND)
86 oldval = tag->value;
87 else
88 av_free(tag->value);
89 av_free(tag->key);
90 *tag = m->elems[--m->count];
91 } else {
92 AVDictionaryEntry *tmp = av_realloc(m->elems,
93 (m->count + 1) * sizeof(*m->elems));
94 if (!tmp)
95 goto err_out;
96 m->elems = tmp;
97 }
98 if (value) {
99 if (flags & AV_DICT_DONT_STRDUP_KEY)
100 m->elems[m->count].key = (char*)(intptr_t)key;
101 else
102 m->elems[m->count].key = av_strdup(key);
103 if (flags & AV_DICT_DONT_STRDUP_VAL) {
104 m->elems[m->count].value = (char*)(intptr_t)value;
105 } else if (oldval && flags & AV_DICT_APPEND) {
106 int len = strlen(oldval) + strlen(value) + 1;
107 char *newval = av_mallocz(len);
108 if (!newval)
109 goto err_out;
110 av_strlcat(newval, oldval, len);
111 av_freep(&oldval);
112 av_strlcat(newval, value, len);
113 m->elems[m->count].value = newval;
114 } else
115 m->elems[m->count].value = av_strdup(value);
116 m->count++;
117 }
118 if (!m->count) {
119 av_free(m->elems);
120 av_freep(pm);
121 }
122
123 return 0;
124
125err_out:
126 if (!m->count) {
127 av_free(m->elems);
128 av_freep(pm);
129 }
130 if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
131 if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)value);
132 return AVERROR(ENOMEM);
133}
134
135int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
136 int flags)
137{
138 char valuestr[22];
139 snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
140 return av_dict_set(pm, key, valuestr, flags);
141}
142
143static int parse_key_value_pair(AVDictionary **pm, const char **buf,
144 const char *key_val_sep, const char *pairs_sep,
145 int flags)
146{
147 char *key = av_get_token(buf, key_val_sep);
148 char *val = NULL;
149 int ret;
150
151 if (key && *key && strspn(*buf, key_val_sep)) {
152 (*buf)++;
153 val = av_get_token(buf, pairs_sep);
154 }
155
156 if (key && *key && val && *val)
157 ret = av_dict_set(pm, key, val, flags);
158 else
159 ret = AVERROR(EINVAL);
160
161 av_freep(&key);
162 av_freep(&val);
163
164 return ret;
165}
166
167int av_dict_parse_string(AVDictionary **pm, const char *str,
168 const char *key_val_sep, const char *pairs_sep,
169 int flags)
170{
171 int ret;
172
173 if (!str)
174 return 0;
175
176 /* ignore STRDUP flags */
177 flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
178
179 while (*str) {
180 if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
181 return ret;
182
183 if (*str)
184 str++;
185 }
186
187 return 0;
188}
189
190void av_dict_free(AVDictionary **pm)
191{
192 AVDictionary *m = *pm;
193
194 if (m) {
195 while (m->count--) {
196 av_free(m->elems[m->count].key);
197 av_free(m->elems[m->count].value);
198 }
199 av_free(m->elems);
200 }
201 av_freep(pm);
202}
203
f6fa7814 204void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
2ba45a60
DM
205{
206 AVDictionaryEntry *t = NULL;
207
208 while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX)))
209 av_dict_set(dst, t->key, t->value, flags);
210}
f6fa7814
DM
211
212int av_dict_get_string(const AVDictionary *m, char **buffer,
213 const char key_val_sep, const char pairs_sep)
214{
215 AVDictionaryEntry *t = NULL;
216 AVBPrint bprint;
217 int cnt = 0;
218 char special_chars[] = {pairs_sep, key_val_sep, '\0'};
219
220 if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
221 pairs_sep == '\\' || key_val_sep == '\\')
222 return AVERROR(EINVAL);
223
224 if (!av_dict_count(m)) {
225 *buffer = av_strdup("");
226 return *buffer ? 0 : AVERROR(ENOMEM);
227 }
228
229 av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
230 while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
231 if (cnt++)
232 av_bprint_append_data(&bprint, &pairs_sep, 1);
233 av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
234 av_bprint_append_data(&bprint, &key_val_sep, 1);
235 av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
236 }
237 return av_bprint_finalize(&bprint, buffer);
238}
239
240#ifdef TEST
241static void print_dict(const AVDictionary *m)
242{
243 AVDictionaryEntry *t = NULL;
244 while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
245 printf("%s %s ", t->key, t->value);
246 printf("\n");
247}
248
249static void test_separators(const AVDictionary *m, const char pair, const char val)
250{
251 AVDictionary *dict = NULL;
252 char pairs[] = {pair , '\0'};
253 char vals[] = {val, '\0'};
254
255 char *buffer = NULL;
256 av_dict_copy(&dict, m, 0);
257 print_dict(dict);
258 av_dict_get_string(dict, &buffer, val, pair);
259 printf("%s\n", buffer);
260 av_dict_free(&dict);
261 av_dict_parse_string(&dict, buffer, vals, pairs, 0);
262 av_freep(&buffer);
263 print_dict(dict);
264 av_dict_free(&dict);
265}
266
267int main(void)
268{
269 AVDictionary *dict = NULL;
270 char *buffer = NULL;
271
272 printf("Testing av_dict_get_string() and av_dict_parse_string()\n");
273 av_dict_get_string(dict, &buffer, '=', ',');
274 printf("%s\n", buffer);
275 av_freep(&buffer);
276 av_dict_set(&dict, "aaa", "aaa", 0);
277 av_dict_set(&dict, "b,b", "bbb", 0);
278 av_dict_set(&dict, "c=c", "ccc", 0);
279 av_dict_set(&dict, "ddd", "d,d", 0);
280 av_dict_set(&dict, "eee", "e=e", 0);
281 av_dict_set(&dict, "f,f", "f=f", 0);
282 av_dict_set(&dict, "g=g", "g,g", 0);
283 test_separators(dict, ',', '=');
284 av_dict_free(&dict);
285 av_dict_set(&dict, "aaa", "aaa", 0);
286 av_dict_set(&dict, "bbb", "bbb", 0);
287 av_dict_set(&dict, "ccc", "ccc", 0);
288 av_dict_set(&dict, "\\,=\'\"", "\\,=\'\"", 0);
289 test_separators(dict, '"', '=');
290 test_separators(dict, '\'', '=');
291 test_separators(dict, ',', '"');
292 test_separators(dict, ',', '\'');
293 test_separators(dict, '\'', '"');
294 test_separators(dict, '"', '\'');
295 av_dict_free(&dict);
296
297 return 0;
298}
299#endif