d9f80ea2 |
/*
* copyright (c) 2009 Michael Niedermayer
* |
6a137dde |
* This file is part of FFmpeg. |
d9f80ea2 |
* |
6a137dde |
* FFmpeg is free software; you can redistribute it and/or |
d9f80ea2 |
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* |
6a137dde |
* FFmpeg is distributed in the hope that it will be useful, |
d9f80ea2 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public |
6a137dde |
* License along with FFmpeg; if not, write to the Free Software |
d9f80ea2 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
|
1d9c2dc8 |
#include <string.h>
|
1b9b37b8 |
#include "avstring.h" |
d9f80ea2 |
#include "dict.h"
#include "internal.h"
#include "mem.h" |
b72a7b96 |
#include "time_internal.h" |
ab922f9e |
#include "bprint.h" |
d9f80ea2 |
|
33de86db |
struct AVDictionary {
int count;
AVDictionaryEntry *elems;
};
|
987170cb |
int av_dict_count(const AVDictionary *m)
{
return m ? m->count : 0;
}
|
5182a2a2 |
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, |
93d216d3 |
const AVDictionaryEntry *prev, int flags) |
d9f80ea2 |
{
unsigned int i, j;
|
93d216d3 |
if (!m) |
d9f80ea2 |
return NULL;
|
93d216d3 |
if (prev)
i = prev - m->elems + 1;
else
i = 0; |
d9f80ea2 |
|
93d216d3 |
for (; i < m->count; i++) {
const char *s = m->elems[i].key;
if (flags & AV_DICT_MATCH_CASE)
for (j = 0; s[j] == key[j] && key[j]; j++)
;
else
for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
;
if (key[j]) |
d9f80ea2 |
continue; |
93d216d3 |
if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX)) |
d9f80ea2 |
continue;
return &m->elems[i];
}
return NULL;
}
|
93d216d3 |
int av_dict_set(AVDictionary **pm, const char *key, const char *value,
int flags) |
d9f80ea2 |
{ |
93d216d3 |
AVDictionary *m = *pm; |
4ebf0b10 |
AVDictionaryEntry *tag = NULL; |
a8c5b455 |
char *oldval = NULL, *copy_key = NULL, *copy_value = NULL; |
d9f80ea2 |
|
4ebf0b10 |
if (!(flags & AV_DICT_MULTIKEY)) {
tag = av_dict_get(m, key, NULL, flags);
} |
a8c5b455 |
if (flags & AV_DICT_DONT_STRDUP_KEY)
copy_key = (void *)key;
else
copy_key = av_strdup(key);
if (flags & AV_DICT_DONT_STRDUP_VAL)
copy_value = (void *)value;
else if (copy_key)
copy_value = av_strdup(value); |
93d216d3 |
if (!m) |
d9f80ea2 |
m = *pm = av_mallocz(sizeof(*m)); |
a8c5b455 |
if (!m || (key && !copy_key) || (value && !copy_value)) |
a963fdb0 |
goto err_out; |
d9f80ea2 |
|
93d216d3 |
if (tag) { |
1619274f |
if (flags & AV_DICT_DONT_OVERWRITE) { |
a8c5b455 |
av_free(copy_key);
av_free(copy_value); |
d9f80ea2 |
return 0; |
1619274f |
} |
1b9b37b8 |
if (flags & AV_DICT_APPEND)
oldval = tag->value;
else
av_free(tag->value); |
d9f80ea2 |
av_free(tag->key);
*tag = m->elems[--m->count]; |
a740263d |
} else if (copy_value) { |
93d216d3 |
AVDictionaryEntry *tmp = av_realloc(m->elems,
(m->count + 1) * sizeof(*m->elems)); |
f0de0185 |
if (!tmp) |
bddc5920 |
goto err_out; |
f0de0185 |
m->elems = tmp; |
d9f80ea2 |
} |
a8c5b455 |
if (copy_value) {
m->elems[m->count].key = copy_key;
m->elems[m->count].value = copy_value;
if (oldval && flags & AV_DICT_APPEND) { |
4c128ea1 |
size_t len = strlen(oldval) + strlen(copy_value) + 1; |
1d81f744 |
char *newval = av_mallocz(len);
if (!newval) |
bddc5920 |
goto err_out; |
1d81f744 |
av_strlcat(newval, oldval, len); |
086566a5 |
av_freep(&oldval); |
a8c5b455 |
av_strlcat(newval, copy_value, len); |
1d81f744 |
m->elems[m->count].value = newval; |
a8c5b455 |
av_freep(©_value);
} |
d9f80ea2 |
m->count++; |
a8c5b455 |
} else {
av_freep(©_key); |
d9f80ea2 |
}
if (!m->count) { |
336bb3f7 |
av_freep(&m->elems); |
d9f80ea2 |
av_freep(pm);
}
return 0; |
bddc5920 |
err_out: |
a963fdb0 |
if (m && !m->count) { |
336bb3f7 |
av_freep(&m->elems); |
bddc5920 |
av_freep(pm);
} |
a8c5b455 |
av_free(copy_key);
av_free(copy_value); |
bddc5920 |
return AVERROR(ENOMEM); |
d9f80ea2 |
}
|
c2829dc9 |
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
int flags)
{
char valuestr[22];
snprintf(valuestr, sizeof(valuestr), "%"PRId64, value); |
08d0dbf2 |
flags &= ~AV_DICT_DONT_STRDUP_VAL; |
c2829dc9 |
return av_dict_set(pm, key, valuestr, flags);
}
|
38c1466c |
static int parse_key_value_pair(AVDictionary **pm, const char **buf,
const char *key_val_sep, const char *pairs_sep,
int flags)
{
char *key = av_get_token(buf, key_val_sep);
char *val = NULL;
int ret;
if (key && *key && strspn(*buf, key_val_sep)) {
(*buf)++;
val = av_get_token(buf, pairs_sep);
}
if (key && *key && val && *val)
ret = av_dict_set(pm, key, val, flags);
else
ret = AVERROR(EINVAL);
av_freep(&key);
av_freep(&val);
return ret;
}
int av_dict_parse_string(AVDictionary **pm, const char *str,
const char *key_val_sep, const char *pairs_sep,
int flags)
{
int ret;
if (!str)
return 0;
/* ignore STRDUP flags */
flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
while (*str) {
if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
return ret;
if (*str)
str++;
}
return 0;
}
|
d9f80ea2 |
void av_dict_free(AVDictionary **pm)
{
AVDictionary *m = *pm;
if (m) { |
93d216d3 |
while (m->count--) { |
336bb3f7 |
av_freep(&m->elems[m->count].key);
av_freep(&m->elems[m->count].value); |
d9f80ea2 |
} |
336bb3f7 |
av_freep(&m->elems); |
d9f80ea2 |
}
av_freep(pm);
}
|
11c5f438 |
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags) |
d9f80ea2 |
{
AVDictionaryEntry *t = NULL;
|
11c5f438 |
while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) {
int ret = av_dict_set(dst, t->key, t->value, flags);
if (ret < 0)
return ret;
}
return 0; |
d9f80ea2 |
} |
ab922f9e |
int av_dict_get_string(const AVDictionary *m, char **buffer,
const char key_val_sep, const char pairs_sep)
{
AVDictionaryEntry *t = NULL;
AVBPrint bprint;
int cnt = 0;
char special_chars[] = {pairs_sep, key_val_sep, '\0'};
if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
pairs_sep == '\\' || key_val_sep == '\\')
return AVERROR(EINVAL);
if (!av_dict_count(m)) {
*buffer = av_strdup("");
return *buffer ? 0 : AVERROR(ENOMEM);
}
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
if (cnt++)
av_bprint_append_data(&bprint, &pairs_sep, 1);
av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
av_bprint_append_data(&bprint, &key_val_sep, 1);
av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
}
return av_bprint_finalize(&bprint, buffer);
} |
b72a7b96 |
int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp)
{
time_t seconds = timestamp / 1000000;
struct tm *ptm, tmbuf;
ptm = gmtime_r(&seconds, &tmbuf);
if (ptm) {
char buf[32];
if (!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", ptm))
return AVERROR_EXTERNAL;
av_strlcatf(buf, sizeof(buf), ".%06dZ", (int)(timestamp % 1000000));
return av_dict_set(dict, key, buf, 0);
} else {
return AVERROR_EXTERNAL;
}
} |