FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dict.c
Go to the documentation of this file.
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"
27 #include "bprint.h"
28 
29 struct AVDictionary {
30  int count;
32 };
33 
35 {
36  return m ? m->count : 0;
37 }
38 
39 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
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 
69 int 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  if (!m)
79  goto err_out;
80 
81  if (tag) {
82  if (flags & AV_DICT_DONT_OVERWRITE) {
83  if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
84  if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)value);
85  return 0;
86  }
87  if (flags & AV_DICT_APPEND)
88  oldval = tag->value;
89  else
90  av_free(tag->value);
91  av_free(tag->key);
92  *tag = m->elems[--m->count];
93  } else {
95  (m->count + 1) * sizeof(*m->elems));
96  if (!tmp)
97  goto err_out;
98  m->elems = tmp;
99  }
100  if (value) {
101  if (flags & AV_DICT_DONT_STRDUP_KEY)
102  m->elems[m->count].key = (char*)(intptr_t)key;
103  else
104  m->elems[m->count].key = av_strdup(key);
105  if (!m->elems[m->count].key)
106  goto err_out;
107  if (flags & AV_DICT_DONT_STRDUP_VAL) {
108  m->elems[m->count].value = (char*)(intptr_t)value;
109  } else if (oldval && flags & AV_DICT_APPEND) {
110  int len = strlen(oldval) + strlen(value) + 1;
111  char *newval = av_mallocz(len);
112  if (!newval)
113  goto err_out;
114  av_strlcat(newval, oldval, len);
115  av_freep(&oldval);
116  av_strlcat(newval, value, len);
117  m->elems[m->count].value = newval;
118  } else
119  m->elems[m->count].value = av_strdup(value);
120  m->count++;
121  }
122  if (!m->count) {
123  av_freep(&m->elems);
124  av_freep(pm);
125  }
126 
127  return 0;
128 
129 err_out:
130  if (m && !m->count) {
131  av_freep(&m->elems);
132  av_freep(pm);
133  }
134  if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
135  if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)value);
136  return AVERROR(ENOMEM);
137 }
138 
139 int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
140  int flags)
141 {
142  char valuestr[22];
143  snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
144  return av_dict_set(pm, key, valuestr, flags);
145 }
146 
147 static int parse_key_value_pair(AVDictionary **pm, const char **buf,
148  const char *key_val_sep, const char *pairs_sep,
149  int flags)
150 {
151  char *key = av_get_token(buf, key_val_sep);
152  char *val = NULL;
153  int ret;
154 
155  if (key && *key && strspn(*buf, key_val_sep)) {
156  (*buf)++;
157  val = av_get_token(buf, pairs_sep);
158  }
159 
160  if (key && *key && val && *val)
161  ret = av_dict_set(pm, key, val, flags);
162  else
163  ret = AVERROR(EINVAL);
164 
165  av_freep(&key);
166  av_freep(&val);
167 
168  return ret;
169 }
170 
171 int av_dict_parse_string(AVDictionary **pm, const char *str,
172  const char *key_val_sep, const char *pairs_sep,
173  int flags)
174 {
175  int ret;
176 
177  if (!str)
178  return 0;
179 
180  /* ignore STRDUP flags */
182 
183  while (*str) {
184  if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
185  return ret;
186 
187  if (*str)
188  str++;
189  }
190 
191  return 0;
192 }
193 
195 {
196  AVDictionary *m = *pm;
197 
198  if (m) {
199  while (m->count--) {
200  av_freep(&m->elems[m->count].key);
201  av_freep(&m->elems[m->count].value);
202  }
203  av_freep(&m->elems);
204  }
205  av_freep(pm);
206 }
207 
209 {
210  AVDictionaryEntry *t = NULL;
211 
212  while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX)))
213  av_dict_set(dst, t->key, t->value, flags);
214 }
215 
217  const char key_val_sep, const char pairs_sep)
218 {
219  AVDictionaryEntry *t = NULL;
220  AVBPrint bprint;
221  int cnt = 0;
222  char special_chars[] = {pairs_sep, key_val_sep, '\0'};
223 
224  if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
225  pairs_sep == '\\' || key_val_sep == '\\')
226  return AVERROR(EINVAL);
227 
228  if (!av_dict_count(m)) {
229  *buffer = av_strdup("");
230  return *buffer ? 0 : AVERROR(ENOMEM);
231  }
232 
234  while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
235  if (cnt++)
236  av_bprint_append_data(&bprint, &pairs_sep, 1);
237  av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
238  av_bprint_append_data(&bprint, &key_val_sep, 1);
239  av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
240  }
241  return av_bprint_finalize(&bprint, buffer);
242 }
243 
244 #ifdef TEST
245 static void print_dict(const AVDictionary *m)
246 {
247  AVDictionaryEntry *t = NULL;
248  while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
249  printf("%s %s ", t->key, t->value);
250  printf("\n");
251 }
252 
253 static void test_separators(const AVDictionary *m, const char pair, const char val)
254 {
255  AVDictionary *dict = NULL;
256  char pairs[] = {pair , '\0'};
257  char vals[] = {val, '\0'};
258 
259  char *buffer = NULL;
260  av_dict_copy(&dict, m, 0);
261  print_dict(dict);
262  av_dict_get_string(dict, &buffer, val, pair);
263  printf("%s\n", buffer);
264  av_dict_free(&dict);
265  av_dict_parse_string(&dict, buffer, vals, pairs, 0);
266  av_freep(&buffer);
267  print_dict(dict);
268  av_dict_free(&dict);
269 }
270 
271 int main(void)
272 {
273  AVDictionary *dict = NULL;
274  char *buffer = NULL;
275 
276  printf("Testing av_dict_get_string() and av_dict_parse_string()\n");
277  av_dict_get_string(dict, &buffer, '=', ',');
278  printf("%s\n", buffer);
279  av_freep(&buffer);
280  av_dict_set(&dict, "aaa", "aaa", 0);
281  av_dict_set(&dict, "b,b", "bbb", 0);
282  av_dict_set(&dict, "c=c", "ccc", 0);
283  av_dict_set(&dict, "ddd", "d,d", 0);
284  av_dict_set(&dict, "eee", "e=e", 0);
285  av_dict_set(&dict, "f,f", "f=f", 0);
286  av_dict_set(&dict, "g=g", "g,g", 0);
287  test_separators(dict, ',', '=');
288  av_dict_free(&dict);
289  av_dict_set(&dict, "aaa", "aaa", 0);
290  av_dict_set(&dict, "bbb", "bbb", 0);
291  av_dict_set(&dict, "ccc", "ccc", 0);
292  av_dict_set(&dict, "\\,=\'\"", "\\,=\'\"", 0);
293  test_separators(dict, '"', '=');
294  test_separators(dict, '\'', '=');
295  test_separators(dict, ',', '"');
296  test_separators(dict, ',', '\'');
297  test_separators(dict, '\'', '"');
298  test_separators(dict, '"', '\'');
299  av_dict_free(&dict);
300 
301  return 0;
302 }
303 #endif