• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "time_internal.h"
28 #include "bprint.h"
29 
30 struct AVDictionary {
31     int count;
32     AVDictionaryEntry *elems;
33 };
34 
av_dict_count(const AVDictionary * m)35 int av_dict_count(const AVDictionary *m)
36 {
37     return m ? m->count : 0;
38 }
39 
av_dict_get(const AVDictionary * m,const char * key,const AVDictionaryEntry * prev,int flags)40 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
41                                const AVDictionaryEntry *prev, int flags)
42 {
43     unsigned int i, j;
44 
45     if (!m)
46         return NULL;
47 
48     if (prev)
49         i = prev - m->elems + 1;
50     else
51         i = 0;
52 
53     for (; i < m->count; i++) {
54         const char *s = m->elems[i].key;
55         if (flags & AV_DICT_MATCH_CASE)
56             for (j = 0; s[j] == key[j] && key[j]; j++)
57                 ;
58         else
59             for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
60                 ;
61         if (key[j])
62             continue;
63         if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
64             continue;
65         return &m->elems[i];
66     }
67     return NULL;
68 }
69 
av_dict_set(AVDictionary ** pm,const char * key,const char * value,int flags)70 int av_dict_set(AVDictionary **pm, const char *key, const char *value,
71                 int flags)
72 {
73     AVDictionary *m = *pm;
74     AVDictionaryEntry *tag = NULL;
75     char *oldval = NULL, *copy_key = NULL, *copy_value = NULL;
76 
77     if (!(flags & AV_DICT_MULTIKEY)) {
78         tag = av_dict_get(m, key, NULL, flags);
79     }
80     if (flags & AV_DICT_DONT_STRDUP_KEY)
81         copy_key = (void *)key;
82     else
83         copy_key = av_strdup(key);
84     if (flags & AV_DICT_DONT_STRDUP_VAL)
85         copy_value = (void *)value;
86     else if (copy_key)
87         copy_value = av_strdup(value);
88     if (!m)
89         m = *pm = av_mallocz(sizeof(*m));
90     if (!m || (key && !copy_key) || (value && !copy_value))
91         goto err_out;
92 
93     if (tag) {
94         if (flags & AV_DICT_DONT_OVERWRITE) {
95             av_free(copy_key);
96             av_free(copy_value);
97             return 0;
98         }
99         if (flags & AV_DICT_APPEND)
100             oldval = tag->value;
101         else
102             av_free(tag->value);
103         av_free(tag->key);
104         *tag = m->elems[--m->count];
105     } else if (copy_value) {
106         AVDictionaryEntry *tmp = av_realloc_array(m->elems,
107                                                   m->count + 1, sizeof(*m->elems));
108         if (!tmp)
109             goto err_out;
110         m->elems = tmp;
111     }
112     if (copy_value) {
113         m->elems[m->count].key = copy_key;
114         m->elems[m->count].value = copy_value;
115         if (oldval && flags & AV_DICT_APPEND) {
116             size_t len = strlen(oldval) + strlen(copy_value) + 1;
117             char *newval = av_mallocz(len);
118             if (!newval)
119                 goto err_out;
120             av_strlcat(newval, oldval, len);
121             av_freep(&oldval);
122             av_strlcat(newval, copy_value, len);
123             m->elems[m->count].value = newval;
124             av_freep(&copy_value);
125         }
126         m->count++;
127     } else {
128         av_freep(&copy_key);
129     }
130     if (!m->count) {
131         av_freep(&m->elems);
132         av_freep(pm);
133     }
134 
135     return 0;
136 
137 err_out:
138     if (m && !m->count) {
139         av_freep(&m->elems);
140         av_freep(pm);
141     }
142     av_free(copy_key);
143     av_free(copy_value);
144     return AVERROR(ENOMEM);
145 }
146 
av_dict_set_int(AVDictionary ** pm,const char * key,int64_t value,int flags)147 int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
148                 int flags)
149 {
150     char valuestr[22];
151     snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
152     flags &= ~AV_DICT_DONT_STRDUP_VAL;
153     return av_dict_set(pm, key, valuestr, flags);
154 }
155 
parse_key_value_pair(AVDictionary ** pm,const char ** buf,const char * key_val_sep,const char * pairs_sep,int flags)156 static int parse_key_value_pair(AVDictionary **pm, const char **buf,
157                                 const char *key_val_sep, const char *pairs_sep,
158                                 int flags)
159 {
160     char *key = av_get_token(buf, key_val_sep);
161     char *val = NULL;
162     int ret;
163 
164     if (key && *key && strspn(*buf, key_val_sep)) {
165         (*buf)++;
166         val = av_get_token(buf, pairs_sep);
167     }
168 
169     if (key && *key && val && *val)
170         ret = av_dict_set(pm, key, val, flags);
171     else
172         ret = AVERROR(EINVAL);
173 
174     av_freep(&key);
175     av_freep(&val);
176 
177     return ret;
178 }
179 
av_dict_parse_string(AVDictionary ** pm,const char * str,const char * key_val_sep,const char * pairs_sep,int flags)180 int av_dict_parse_string(AVDictionary **pm, const char *str,
181                          const char *key_val_sep, const char *pairs_sep,
182                          int flags)
183 {
184     int ret;
185 
186     if (!str)
187         return 0;
188 
189     /* ignore STRDUP flags */
190     flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
191 
192     while (*str) {
193         if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
194             return ret;
195 
196         if (*str)
197             str++;
198     }
199 
200     return 0;
201 }
202 
av_dict_free(AVDictionary ** pm)203 void av_dict_free(AVDictionary **pm)
204 {
205     AVDictionary *m = *pm;
206 
207     if (m) {
208         while (m->count--) {
209             av_freep(&m->elems[m->count].key);
210             av_freep(&m->elems[m->count].value);
211         }
212         av_freep(&m->elems);
213     }
214     av_freep(pm);
215 }
216 
av_dict_copy(AVDictionary ** dst,const AVDictionary * src,int flags)217 int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
218 {
219     AVDictionaryEntry *t = NULL;
220 
221     while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) {
222         int ret = av_dict_set(dst, t->key, t->value, flags);
223         if (ret < 0)
224             return ret;
225     }
226 
227     return 0;
228 }
229 
av_dict_get_string(const AVDictionary * m,char ** buffer,const char key_val_sep,const char pairs_sep)230 int av_dict_get_string(const AVDictionary *m, char **buffer,
231                        const char key_val_sep, const char pairs_sep)
232 {
233     AVDictionaryEntry *t = NULL;
234     AVBPrint bprint;
235     int cnt = 0;
236     char special_chars[] = {pairs_sep, key_val_sep, '\0'};
237 
238     if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
239         pairs_sep == '\\' || key_val_sep == '\\')
240         return AVERROR(EINVAL);
241 
242     if (!av_dict_count(m)) {
243         *buffer = av_strdup("");
244         return *buffer ? 0 : AVERROR(ENOMEM);
245     }
246 
247     av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
248     while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
249         if (cnt++)
250             av_bprint_append_data(&bprint, &pairs_sep, 1);
251         av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
252         av_bprint_append_data(&bprint, &key_val_sep, 1);
253         av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
254     }
255     return av_bprint_finalize(&bprint, buffer);
256 }
257 
avpriv_dict_set_timestamp(AVDictionary ** dict,const char * key,int64_t timestamp)258 int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp)
259 {
260     time_t seconds = timestamp / 1000000;
261     struct tm *ptm, tmbuf;
262     ptm = gmtime_r(&seconds, &tmbuf);
263     if (ptm) {
264         char buf[32];
265         if (!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", ptm))
266             return AVERROR_EXTERNAL;
267         av_strlcatf(buf, sizeof(buf), ".%06dZ", (int)(timestamp % 1000000));
268         return av_dict_set(dict, key, buf, 0);
269     } else {
270         return AVERROR_EXTERNAL;
271     }
272 }
273