|
|
|
@ -29,6 +29,7 @@ |
|
|
|
|
#include "libavformat/avformat.h" |
|
|
|
|
#include "libavcodec/avcodec.h" |
|
|
|
|
#include "libavutil/avstring.h" |
|
|
|
|
#include "libavutil/bprint.h" |
|
|
|
|
#include "libavutil/opt.h" |
|
|
|
|
#include "libavutil/pixdesc.h" |
|
|
|
|
#include "libavutil/dict.h" |
|
|
|
@ -384,31 +385,6 @@ fail: |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define ESCAPE_INIT_BUF_SIZE 256 |
|
|
|
|
|
|
|
|
|
#define ESCAPE_CHECK_SIZE(src, size, max_size) \ |
|
|
|
|
if (size > max_size) { \
|
|
|
|
|
char buf[64]; \
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s", src); \
|
|
|
|
|
av_log(log_ctx, AV_LOG_WARNING, \
|
|
|
|
|
"String '%s...' is too big\n", buf); \
|
|
|
|
|
return "FFPROBE_TOO_BIG_STRING"; \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define ESCAPE_REALLOC_BUF(dst_size_p, dst_p, src, size) \ |
|
|
|
|
if (*dst_size_p < size) { \
|
|
|
|
|
char *q = av_realloc(*dst_p, size); \
|
|
|
|
|
if (!q) { \
|
|
|
|
|
char buf[64]; \
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s", src); \
|
|
|
|
|
av_log(log_ctx, AV_LOG_WARNING, \
|
|
|
|
|
"String '%s...' could not be escaped\n", buf); \
|
|
|
|
|
return "FFPROBE_THIS_STRING_COULD_NOT_BE_ESCAPED"; \
|
|
|
|
|
} \
|
|
|
|
|
*dst_size_p = size; \
|
|
|
|
|
*dst = q; \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* WRITERS */ |
|
|
|
|
|
|
|
|
|
/* Default output */ |
|
|
|
@ -487,81 +463,51 @@ static const Writer default_writer = { |
|
|
|
|
* Escape \n, \r, \\ and sep characters contained in s, and print the |
|
|
|
|
* resulting string. |
|
|
|
|
*/ |
|
|
|
|
static const char *c_escape_str(char **dst, size_t *dst_size, |
|
|
|
|
const char *src, const char sep, void *log_ctx) |
|
|
|
|
static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
|
|
|
|
{ |
|
|
|
|
const char *p; |
|
|
|
|
char *q; |
|
|
|
|
size_t size = 1; |
|
|
|
|
|
|
|
|
|
/* precompute size */ |
|
|
|
|
for (p = src; *p; p++, size++) { |
|
|
|
|
ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-2); |
|
|
|
|
if (*p == '\n' || *p == '\r' || *p == '\\') |
|
|
|
|
size++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ESCAPE_REALLOC_BUF(dst_size, dst, src, size); |
|
|
|
|
|
|
|
|
|
q = *dst; |
|
|
|
|
for (p = src; *p; p++) { |
|
|
|
|
switch (*src) { |
|
|
|
|
case '\n': *q++ = '\\'; *q++ = 'n'; break; |
|
|
|
|
case '\r': *q++ = '\\'; *q++ = 'r'; break; |
|
|
|
|
case '\\': *q++ = '\\'; *q++ = '\\'; break; |
|
|
|
|
case '\n': av_bprintf(dst, "%s", "\\n"); break; |
|
|
|
|
case '\r': av_bprintf(dst, "%s", "\\r"); break; |
|
|
|
|
case '\\': av_bprintf(dst, "%s", "\\\\"); break; |
|
|
|
|
default: |
|
|
|
|
if (*p == sep) |
|
|
|
|
*q++ = '\\'; |
|
|
|
|
*q++ = *p; |
|
|
|
|
av_bprint_chars(dst, '\\', 1); |
|
|
|
|
av_bprint_chars(dst, *p, 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*q = 0; |
|
|
|
|
return *dst; |
|
|
|
|
return dst->str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Quote fields containing special characters, check RFC4180. |
|
|
|
|
*/ |
|
|
|
|
static const char *csv_escape_str(char **dst, size_t *dst_size, |
|
|
|
|
const char *src, const char sep, void *log_ctx) |
|
|
|
|
static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
|
|
|
|
{ |
|
|
|
|
const char *p; |
|
|
|
|
char *q; |
|
|
|
|
size_t size = 1; |
|
|
|
|
int quote = 0; |
|
|
|
|
|
|
|
|
|
/* precompute size */ |
|
|
|
|
for (p = src; *p; p++, size++) { |
|
|
|
|
ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-4); |
|
|
|
|
/* check if input needs quoting */ |
|
|
|
|
for (p = src; *p; p++) |
|
|
|
|
if (*p == '"' || *p == sep || *p == '\n' || *p == '\r') |
|
|
|
|
if (!quote) { |
|
|
|
|
quote = 1; |
|
|
|
|
size += 2; |
|
|
|
|
} |
|
|
|
|
if (*p == '"') |
|
|
|
|
size++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ESCAPE_REALLOC_BUF(dst_size, dst, src, size); |
|
|
|
|
|
|
|
|
|
q = *dst; |
|
|
|
|
p = src; |
|
|
|
|
if (quote) |
|
|
|
|
*q++ = '\"'; |
|
|
|
|
while (*p) { |
|
|
|
|
av_bprint_chars(dst, '\"', 1); |
|
|
|
|
|
|
|
|
|
for (p = src; *p; p++) { |
|
|
|
|
if (*p == '"') |
|
|
|
|
*q++ = '\"'; |
|
|
|
|
*q++ = *p++; |
|
|
|
|
av_bprint_chars(dst, '\"', 1); |
|
|
|
|
av_bprint_chars(dst, *p, 1); |
|
|
|
|
} |
|
|
|
|
if (quote) |
|
|
|
|
*q++ = '\"'; |
|
|
|
|
*q = 0; |
|
|
|
|
|
|
|
|
|
return *dst; |
|
|
|
|
av_bprint_chars(dst, '\"', 1); |
|
|
|
|
return dst->str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char *none_escape_str(char **dst, size_t *dst_size, |
|
|
|
|
const char *src, const char sep, void *log_ctx) |
|
|
|
|
static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
|
|
|
|
{ |
|
|
|
|
return src; |
|
|
|
|
} |
|
|
|
@ -571,11 +517,8 @@ typedef struct CompactContext { |
|
|
|
|
char *item_sep_str; |
|
|
|
|
char item_sep; |
|
|
|
|
int nokey; |
|
|
|
|
char *buf; |
|
|
|
|
size_t buf_size; |
|
|
|
|
char *escape_mode_str; |
|
|
|
|
const char * (*escape_str)(char **dst, size_t *dst_size, |
|
|
|
|
const char *src, const char sep, void *log_ctx); |
|
|
|
|
const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); |
|
|
|
|
} CompactContext; |
|
|
|
|
|
|
|
|
|
#define OFFSET(x) offsetof(CompactContext, x) |
|
|
|
@ -621,10 +564,6 @@ static av_cold int compact_init(WriterContext *wctx, const char *args, void *opa |
|
|
|
|
} |
|
|
|
|
compact->item_sep = compact->item_sep_str[0]; |
|
|
|
|
|
|
|
|
|
compact->buf_size = ESCAPE_INIT_BUF_SIZE; |
|
|
|
|
if (!(compact->buf = av_malloc(compact->buf_size))) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str; |
|
|
|
|
else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str; |
|
|
|
|
else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str; |
|
|
|
@ -641,7 +580,6 @@ static av_cold void compact_uninit(WriterContext *wctx) |
|
|
|
|
CompactContext *compact = wctx->priv; |
|
|
|
|
|
|
|
|
|
av_freep(&compact->item_sep_str); |
|
|
|
|
av_freep(&compact->buf); |
|
|
|
|
av_freep(&compact->escape_mode_str); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -660,12 +598,14 @@ static void compact_print_section_footer(WriterContext *wctx, const char *sectio |
|
|
|
|
static void compact_print_str(WriterContext *wctx, const char *key, const char *value) |
|
|
|
|
{ |
|
|
|
|
CompactContext *compact = wctx->priv; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
if (wctx->nb_item) printf("%c", compact->item_sep); |
|
|
|
|
if (!compact->nokey) |
|
|
|
|
printf("%s=", key); |
|
|
|
|
printf("%s", compact->escape_str(&compact->buf, &compact->buf_size, |
|
|
|
|
value, compact->item_sep, wctx)); |
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void compact_print_int(WriterContext *wctx, const char *key, long long int value) |
|
|
|
@ -682,14 +622,20 @@ static void compact_show_tags(WriterContext *wctx, AVDictionary *dict) |
|
|
|
|
{ |
|
|
|
|
CompactContext *compact = wctx->priv; |
|
|
|
|
AVDictionaryEntry *tag = NULL; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
|
if (wctx->nb_item) printf("%c", compact->item_sep); |
|
|
|
|
if (!compact->nokey) |
|
|
|
|
printf("tag:%s=", compact->escape_str(&compact->buf, &compact->buf_size, |
|
|
|
|
tag->key, compact->item_sep, wctx)); |
|
|
|
|
printf("%s", compact->escape_str(&compact->buf, &compact->buf_size, |
|
|
|
|
tag->value, compact->item_sep, wctx)); |
|
|
|
|
|
|
|
|
|
if (!compact->nokey) { |
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("tag:%s=", compact->escape_str(&buf, tag->key, compact->item_sep, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("%s", compact->escape_str(&buf, tag->value, compact->item_sep, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -731,8 +677,6 @@ static const Writer csv_writer = { |
|
|
|
|
typedef struct { |
|
|
|
|
const AVClass *class; |
|
|
|
|
int multiple_entries; ///< tells if the given chapter requires multiple entries
|
|
|
|
|
char *buf; |
|
|
|
|
size_t buf_size; |
|
|
|
|
int print_packets_and_frames; |
|
|
|
|
int indent_level; |
|
|
|
|
int compact; |
|
|
|
@ -776,52 +720,27 @@ static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque |
|
|
|
|
json->item_sep = json->compact ? ", " : ",\n"; |
|
|
|
|
json->item_start_end = json->compact ? " " : "\n"; |
|
|
|
|
|
|
|
|
|
json->buf_size = ESCAPE_INIT_BUF_SIZE; |
|
|
|
|
if (!(json->buf = av_malloc(json->buf_size))) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static av_cold void json_uninit(WriterContext *wctx) |
|
|
|
|
{ |
|
|
|
|
JSONContext *json = wctx->priv; |
|
|
|
|
av_freep(&json->buf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char *json_escape_str(char **dst, size_t *dst_size, const char *src, |
|
|
|
|
void *log_ctx) |
|
|
|
|
static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) |
|
|
|
|
{ |
|
|
|
|
static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0}; |
|
|
|
|
static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0}; |
|
|
|
|
const char *p; |
|
|
|
|
char *q; |
|
|
|
|
size_t size = 1; |
|
|
|
|
|
|
|
|
|
// compute the length of the escaped string
|
|
|
|
|
for (p = src; *p; p++) { |
|
|
|
|
ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-6); |
|
|
|
|
if (strchr(json_escape, *p)) size += 2; // simple escape
|
|
|
|
|
else if ((unsigned char)*p < 32) size += 6; // handle non-printable chars
|
|
|
|
|
else size += 1; // char copy
|
|
|
|
|
} |
|
|
|
|
ESCAPE_REALLOC_BUF(dst_size, dst, src, size); |
|
|
|
|
|
|
|
|
|
q = *dst; |
|
|
|
|
for (p = src; *p; p++) { |
|
|
|
|
char *s = strchr(json_escape, *p); |
|
|
|
|
if (s) { |
|
|
|
|
*q++ = '\\'; |
|
|
|
|
*q++ = json_subst[s - json_escape]; |
|
|
|
|
av_bprint_chars(dst, '\\', 1); |
|
|
|
|
av_bprint_chars(dst, json_subst[s - json_escape], 1); |
|
|
|
|
} else if ((unsigned char)*p < 32) { |
|
|
|
|
snprintf(q, 7, "\\u00%02x", *p & 0xff); |
|
|
|
|
q += 6; |
|
|
|
|
av_bprintf(dst, "\\u00%02x", *p & 0xff); |
|
|
|
|
} else { |
|
|
|
|
*q++ = *p; |
|
|
|
|
av_bprint_chars(dst, *p, 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*q = 0; |
|
|
|
|
return *dst; |
|
|
|
|
return dst->str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void json_print_header(WriterContext *wctx) |
|
|
|
@ -843,6 +762,7 @@ static void json_print_footer(WriterContext *wctx) |
|
|
|
|
static void json_print_chapter_header(WriterContext *wctx, const char *chapter) |
|
|
|
|
{ |
|
|
|
|
JSONContext *json = wctx->priv; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
if (wctx->nb_chapter) |
|
|
|
|
printf(","); |
|
|
|
@ -852,7 +772,9 @@ static void json_print_chapter_header(WriterContext *wctx, const char *chapter) |
|
|
|
|
!strcmp(chapter, "streams") || !strcmp(chapter, "library_versions"); |
|
|
|
|
if (json->multiple_entries) { |
|
|
|
|
JSON_INDENT(); |
|
|
|
|
printf("\"%s\": [\n", json_escape_str(&json->buf, &json->buf_size, chapter, wctx)); |
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("\"%s\": [\n", json_escape_str(&buf, chapter, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
json->print_packets_and_frames = !strcmp(chapter, "packets_and_frames"); |
|
|
|
|
json->indent_level++; |
|
|
|
|
} |
|
|
|
@ -903,10 +825,15 @@ static void json_print_section_footer(WriterContext *wctx, const char *section) |
|
|
|
|
static inline void json_print_item_str(WriterContext *wctx, |
|
|
|
|
const char *key, const char *value) |
|
|
|
|
{ |
|
|
|
|
JSONContext *json = wctx->priv; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("\"%s\":", json_escape_str(&buf, key, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
|
|
|
|
|
printf("\"%s\":", json_escape_str(&json->buf, &json->buf_size, key, wctx)); |
|
|
|
|
printf(" \"%s\"", json_escape_str(&json->buf, &json->buf_size, value, wctx)); |
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf(" \"%s\"", json_escape_str(&buf, value, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void json_print_str(WriterContext *wctx, const char *key, const char *value) |
|
|
|
@ -922,12 +849,15 @@ static void json_print_str(WriterContext *wctx, const char *key, const char *val |
|
|
|
|
static void json_print_int(WriterContext *wctx, const char *key, long long int value) |
|
|
|
|
{ |
|
|
|
|
JSONContext *json = wctx->priv; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
if (wctx->nb_item) printf("%s", json->item_sep); |
|
|
|
|
if (!json->compact) |
|
|
|
|
JSON_INDENT(); |
|
|
|
|
printf("\"%s\": %lld", |
|
|
|
|
json_escape_str(&json->buf, &json->buf_size, key, wctx), value); |
|
|
|
|
|
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void json_show_tags(WriterContext *wctx, AVDictionary *dict) |
|
|
|
@ -960,7 +890,6 @@ static const Writer json_writer = { |
|
|
|
|
.name = "json", |
|
|
|
|
.priv_size = sizeof(JSONContext), |
|
|
|
|
.init = json_init, |
|
|
|
|
.uninit = json_uninit, |
|
|
|
|
.print_header = json_print_header, |
|
|
|
|
.print_footer = json_print_footer, |
|
|
|
|
.print_chapter_header = json_print_chapter_header, |
|
|
|
@ -982,8 +911,6 @@ typedef struct { |
|
|
|
|
int indent_level; |
|
|
|
|
int fully_qualified; |
|
|
|
|
int xsd_strict; |
|
|
|
|
char *buf; |
|
|
|
|
size_t buf_size; |
|
|
|
|
} XMLContext; |
|
|
|
|
|
|
|
|
|
#undef OFFSET |
|
|
|
@ -1043,61 +970,25 @@ static av_cold int xml_init(WriterContext *wctx, const char *args, void *opaque) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
xml->buf_size = ESCAPE_INIT_BUF_SIZE; |
|
|
|
|
if (!(xml->buf = av_malloc(xml->buf_size))) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static av_cold void xml_uninit(WriterContext *wctx) |
|
|
|
|
{ |
|
|
|
|
XMLContext *xml = wctx->priv; |
|
|
|
|
av_freep(&xml->buf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char *xml_escape_str(char **dst, size_t *dst_size, const char *src, |
|
|
|
|
void *log_ctx) |
|
|
|
|
static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx) |
|
|
|
|
{ |
|
|
|
|
const char *p; |
|
|
|
|
char *q; |
|
|
|
|
size_t size = 1; |
|
|
|
|
|
|
|
|
|
/* precompute size */ |
|
|
|
|
for (p = src; *p; p++, size++) { |
|
|
|
|
ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-10); |
|
|
|
|
switch (*p) { |
|
|
|
|
case '&' : size += strlen("&"); break; |
|
|
|
|
case '<' : size += strlen("<"); break; |
|
|
|
|
case '>' : size += strlen(">"); break; |
|
|
|
|
case '\"': size += strlen("""); break; |
|
|
|
|
case '\'': size += strlen("'"); break; |
|
|
|
|
default: size++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ESCAPE_REALLOC_BUF(dst_size, dst, src, size); |
|
|
|
|
|
|
|
|
|
#define COPY_STR(str) { \ |
|
|
|
|
const char *s = str; \
|
|
|
|
|
while (*s) \
|
|
|
|
|
*q++ = *s++; \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
p = src; |
|
|
|
|
q = *dst; |
|
|
|
|
while (*p) { |
|
|
|
|
for (p = src; *p; p++) { |
|
|
|
|
switch (*p) { |
|
|
|
|
case '&' : COPY_STR("&"); break; |
|
|
|
|
case '<' : COPY_STR("<"); break; |
|
|
|
|
case '>' : COPY_STR(">"); break; |
|
|
|
|
case '\"': COPY_STR("""); break; |
|
|
|
|
case '\'': COPY_STR("'"); break; |
|
|
|
|
default: *q++ = *p; |
|
|
|
|
case '&' : av_bprintf(dst, "%s", "&"); break; |
|
|
|
|
case '<' : av_bprintf(dst, "%s", "<"); break; |
|
|
|
|
case '>' : av_bprintf(dst, "%s", ">"); break; |
|
|
|
|
case '\"': av_bprintf(dst, "%s", """); break; |
|
|
|
|
case '\'': av_bprintf(dst, "%s", "'"); break; |
|
|
|
|
default: av_bprint_chars(dst, *p, 1); |
|
|
|
|
} |
|
|
|
|
p++; |
|
|
|
|
} |
|
|
|
|
*q = 0; |
|
|
|
|
|
|
|
|
|
return *dst; |
|
|
|
|
return dst->str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void xml_print_header(WriterContext *wctx) |
|
|
|
@ -1172,11 +1063,13 @@ static void xml_print_section_footer(WriterContext *wctx, const char *section) |
|
|
|
|
|
|
|
|
|
static void xml_print_str(WriterContext *wctx, const char *key, const char *value) |
|
|
|
|
{ |
|
|
|
|
XMLContext *xml = wctx->priv; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
if (wctx->nb_item) |
|
|
|
|
printf(" "); |
|
|
|
|
printf("%s=\"%s\"", key, xml_escape_str(&xml->buf, &xml->buf_size, value, wctx)); |
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void xml_print_int(WriterContext *wctx, const char *key, long long int value) |
|
|
|
@ -1191,6 +1084,7 @@ static void xml_show_tags(WriterContext *wctx, AVDictionary *dict) |
|
|
|
|
XMLContext *xml = wctx->priv; |
|
|
|
|
AVDictionaryEntry *tag = NULL; |
|
|
|
|
int is_first = 1; |
|
|
|
|
AVBPrint buf; |
|
|
|
|
|
|
|
|
|
xml->indent_level++; |
|
|
|
|
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
@ -1201,10 +1095,14 @@ static void xml_show_tags(WriterContext *wctx, AVDictionary *dict) |
|
|
|
|
is_first = 0; |
|
|
|
|
} |
|
|
|
|
XML_INDENT(); |
|
|
|
|
printf("<tag key=\"%s\"", |
|
|
|
|
xml_escape_str(&xml->buf, &xml->buf_size, tag->key, wctx)); |
|
|
|
|
printf(" value=\"%s\"/>\n", |
|
|
|
|
xml_escape_str(&xml->buf, &xml->buf_size, tag->value, wctx)); |
|
|
|
|
|
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf("<tag key=\"%s\"", xml_escape_str(&buf, tag->key, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
|
|
|
|
|
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
printf(" value=\"%s\"/>\n", xml_escape_str(&buf, tag->value, wctx)); |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
xml->indent_level--; |
|
|
|
|
} |
|
|
|
@ -1213,7 +1111,6 @@ static Writer xml_writer = { |
|
|
|
|
.name = "xml", |
|
|
|
|
.priv_size = sizeof(XMLContext), |
|
|
|
|
.init = xml_init, |
|
|
|
|
.uninit = xml_uninit, |
|
|
|
|
.print_header = xml_print_header, |
|
|
|
|
.print_footer = xml_print_footer, |
|
|
|
|
.print_chapter_header = xml_print_chapter_header, |
|
|
|
|