Commit 89d49acb authored by Stefano Sabatini's avatar Stefano Sabatini

ffprobe: add INI writer

Liberally based on the work of Luca Barbato <lu_zero@gentoo.org>, done
for libav/avprobe.
parent 908c045f
......@@ -2,6 +2,8 @@ Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version next:
- INI output in ffprobe
version 0.11:
Fixes:CVE-2012-2772, CVE-2012-2774, CVE-2012-2775, CVE-2012-2776, CVE-2012-2777,
......
......@@ -269,6 +269,45 @@ CSV format.
This writer is equivalent to
@code{compact=item_sep=,:nokey=1:escape=csv}.
@section ini
INI format output.
Print output in an INI based format.
The following conventions are adopted:
@itemize
@item
all key and values are UTF-8
@item
'.' is the subgroup separator
@item
newline, '\t', '\f', '\b' and the following characters are escaped
@item
'\' is the escape character
@item
'#' is the comment indicator
@item
'=' is the key/value separator
@item
':' is not used but usually parsed as key/value separator
@end itemize
This writer accepts options as a list of @var{key}=@var{value} pairs,
separated by ":".
The description of the accepted options follows.
@table @option
@item hierarchical, h
Specify if the section name specification should be hierarchical. If
set to 1, and if there is more than one section in the current
chapter, the section name will be prefixed by the name of the
chapter. A value of 0 will disable this behavior.
Default value is 1.
@end table
@section json
JSON based format.
......
......@@ -713,6 +713,174 @@ static const Writer csv_writer = {
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
};
/* INI format output */
typedef struct {
const AVClass *class;
AVBPrint chapter_name, section_name;
int print_packets_and_frames;
int nb_frame;
int nb_packet;
int hierarchical;
} INIContext;
#undef OFFSET
#define OFFSET(x) offsetof(INIContext, x)
static const AVOption ini_options[] = {
{"hierachical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
{"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
{NULL},
};
static const char *ini_get_name(void *ctx)
{
return "ini";
}
static const AVClass ini_class = {
"INIContext",
ini_get_name,
ini_options
};
static av_cold int ini_init(WriterContext *wctx, const char *args, void *opaque)
{
INIContext *ini = wctx->priv;
int err;
av_bprint_init(&ini->chapter_name, 1, AV_BPRINT_SIZE_UNLIMITED);
av_bprint_init(&ini->section_name, 1, AV_BPRINT_SIZE_UNLIMITED);
ini->nb_frame = ini->nb_packet = 0;
ini->class = &ini_class;
av_opt_set_defaults(ini);
if (args && (err = av_set_options_string(ini, args, "=", ":")) < 0) {
av_log(wctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
return err;
}
return 0;
}
static av_cold void ini_uninit(WriterContext *wctx)
{
INIContext *ini = wctx->priv;
av_bprint_finalize(&ini->chapter_name, NULL);
av_bprint_finalize(&ini->section_name, NULL);
}
static void ini_print_header(WriterContext *wctx)
{
printf("# ffprobe output\n\n");
}
static char *ini_escape_str(AVBPrint *dst, const char *src)
{
int i = 0;
char c = 0;
while (c = src[i++]) {
switch (c) {
case '\b': av_bprintf(dst, "%s", "\\b"); break;
case '\f': av_bprintf(dst, "%s", "\\f"); break;
case '\n': av_bprintf(dst, "%s", "\\n"); break;
case '\r': av_bprintf(dst, "%s", "\\r"); break;
case '\t': av_bprintf(dst, "%s", "\\t"); break;
case '\\':
case '#' :
case '=' :
case ':' : av_bprint_chars(dst, '\\', 1);
default:
if ((unsigned char)c < 32)
av_bprintf(dst, "\\x00%02x", c & 0xff);
else
av_bprint_chars(dst, c, 1);
break;
}
}
return dst->str;
}
static void ini_print_chapter_header(WriterContext *wctx, const char *chapter)
{
INIContext *ini = wctx->priv;
av_bprint_clear(&ini->chapter_name);
av_bprintf(&ini->chapter_name, "%s", chapter);
if (wctx->nb_chapter)
printf("\n");
ini->print_packets_and_frames = !strcmp("packets_and_frames", chapter);
}
static void ini_print_section_header(WriterContext *wctx, const char *section)
{
INIContext *ini = wctx->priv;
int n;
if (wctx->nb_section)
printf("\n");
av_bprint_clear(&ini->section_name);
if (ini->hierarchical && wctx->multiple_sections)
av_bprintf(&ini->section_name, "%s.", ini->chapter_name.str);
av_bprintf(&ini->section_name, "%s", section);
if (ini->print_packets_and_frames)
n = !strcmp(section, "packet") ? ini->nb_packet++ : ini->nb_frame++;
else
n = wctx->nb_section;
if (wctx->multiple_sections)
av_bprintf(&ini->section_name, ".%d", n);
printf("[%s]\n", ini->section_name.str);
}
static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
{
AVBPrint buf;
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("%s=", ini_escape_str(&buf, key));
av_bprint_clear(&buf);
printf("%s\n", ini_escape_str(&buf, value));
av_bprint_finalize(&buf, NULL);
}
static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
{
printf("%s=%lld\n", key, value);
}
static void ini_show_tags(WriterContext *wctx, AVDictionary *dict)
{
INIContext *ini = wctx->priv;
AVDictionaryEntry *tag = NULL;
int is_first = 1;
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (is_first) {
printf("\n[%s.tags]\n", ini->section_name.str);
is_first = 0;
}
writer_print_string(wctx, tag->key, tag->value, 0);
}
}
static const Writer ini_writer = {
.name = "ini",
.priv_size = sizeof(INIContext),
.init = ini_init,
.uninit = ini_uninit,
.print_header = ini_print_header,
.print_chapter_header = ini_print_chapter_header,
.print_section_header = ini_print_section_header,
.print_integer = ini_print_int,
.print_string = ini_print_str,
.show_tags = ini_show_tags,
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
};
/* JSON output */
typedef struct {
......@@ -1168,6 +1336,7 @@ static void writer_register_all(void)
writer_register(&default_writer);
writer_register(&compact_writer);
writer_register(&csv_writer);
writer_register(&ini_writer);
writer_register(&json_writer);
writer_register(&xml_writer);
}
......@@ -1734,7 +1903,7 @@ static const OptionDef options[] = {
{ "pretty", 0, {(void*)&opt_pretty},
"prettify the format of displayed values, make it more human readable" },
{ "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
"set the output printing format (available formats are: default, compact, csv, json, xml)", "format" },
"set the output printing format (available formats are: default, compact, csv, ini, json, xml)", "format" },
{ "show_error", OPT_BOOL, {(void*)&do_show_error} , "show probing error" },
{ "show_format", OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
{ "show_frames", OPT_BOOL, {(void*)&do_show_frames} , "show frames info" },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment