FFmpeg
Loading...
Searching...
No Matches
tf_xml.c
Go to the documentation of this file.
1/*
2 * Copyright (c) The FFmpeg developers
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 <inttypes.h>
22#include <stddef.h>
23
24#include "avtextformat.h"
25#include "libavutil/bprint.h"
26#include "libavutil/error.h"
27#include "libavutil/opt.h"
28#include "tf_internal.h"
29
30/* XML output */
31
32typedef struct XMLContext {
33 const AVClass *class;
39
40#undef OFFSET
41#define OFFSET(x) offsetof(XMLContext, x)
42
43static const AVOption xml_options[] = {
44 { "fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
45 { "q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
46 { "xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
47 { "x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
48 { NULL },
49};
50
52
54{
55 XMLContext *xml = wctx->priv;
56
57 if (xml->xsd_strict) {
58 xml->fully_qualified = 1;
59#define CHECK_COMPLIANCE(opt, opt_name) \
60 if (opt) { \
61 av_log(wctx, AV_LOG_ERROR, \
62 "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
63 "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
64 return AVERROR(EINVAL); \
65 }
66 ////CHECK_COMPLIANCE(show_private_data, "private");
68 CHECK_COMPLIANCE(wctx->opts.use_value_prefix, "prefix");
69 }
70
71 return 0;
72}
73
74#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ')
75
76static void xml_print_section_header(AVTextFormatContext *wctx, const void *data)
77{
78 XMLContext *xml = wctx->priv;
79 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
80 const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
81
82 if (!section)
83 return;
84
85 if (wctx->level == 0) {
86 const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
87 "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" "
88 "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\"";
89
90 writer_put_str(wctx, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
91 writer_printf(wctx, "<%sffprobe%s>\n",
92 xml->fully_qualified ? "ffprobe:" : "",
93 xml->fully_qualified ? qual : "");
94 return;
95 }
96
97 if (xml->within_tag) {
98 xml->within_tag = 0;
99 writer_put_str(wctx, ">\n");
100 }
101
102 if (parent_section && (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) &&
103 wctx->level && wctx->nb_item[wctx->level - 1])
104 writer_w8(wctx, '\n');
105 xml->indent_level++;
106
108 XML_INDENT();
109 writer_printf(wctx, "<%s", section->name);
110
112 AVBPrint buf;
114 av_bprint_escape(&buf, section->get_type(data), NULL,
116 writer_printf(wctx, " type=\"%s\"", buf.str);
117 }
118 writer_printf(wctx, ">\n", section->name);
119 } else {
120 XML_INDENT();
121 writer_printf(wctx, "<%s ", section->name);
122 xml->within_tag = 1;
123 }
124}
125
127{
128 XMLContext *xml = wctx->priv;
129 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
130
131 if (!section)
132 return;
133
134 if (wctx->level == 0) {
135 writer_printf(wctx, "</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
136 } else if (xml->within_tag) {
137 xml->within_tag = 0;
138 writer_put_str(wctx, "/>\n");
139 xml->indent_level--;
140 } else {
141 XML_INDENT();
142 writer_printf(wctx, "</%s>\n", section->name);
143 xml->indent_level--;
144 }
145}
146
147static void xml_print_value(AVTextFormatContext *wctx, const char *key,
148 const char *str, int64_t num, const int is_int)
149{
150 AVBPrint buf;
151 XMLContext *xml = wctx->priv;
152 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
153
154 if (!section)
155 return;
156
158
160 xml->indent_level++;
161 XML_INDENT();
164 writer_printf(wctx, "<%s key=\"%s\"",
165 section->element_name, buf.str);
166 av_bprint_clear(&buf);
167
168 if (is_int) {
169 writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num);
170 } else {
171 av_bprint_escape(&buf, str, NULL,
173 writer_printf(wctx, " value=\"%s\"/>\n", buf.str);
174 }
175 xml->indent_level--;
176 } else {
177 if (wctx->nb_item[wctx->level])
178 writer_w8(wctx, ' ');
179
180 if (is_int) {
181 writer_printf(wctx, "%s=\"%"PRId64"\"", key, num);
182 } else {
183 av_bprint_escape(&buf, str, NULL,
185 writer_printf(wctx, "%s=\"%s\"", key, buf.str);
186 }
187 }
188
190}
191
192static inline void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
193{
194 xml_print_value(wctx, key, value, 0, 0);
195}
196
197static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
198{
199 xml_print_value(wctx, key, NULL, value, 1);
200}
201
203 .name = "xml",
204 .priv_size = sizeof(XMLContext),
205 .init = xml_init,
206 .print_section_header = xml_print_section_header,
207 .print_section_footer = xml_print_section_footer,
208 .print_integer = xml_print_int,
209 .print_string = xml_print_str,
211 .priv_class = &xml_class,
212};
#define AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE
For these sections the element_name field is mandatory.
#define AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER
the section only contains other sections, but has no data at its own level
#define AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS
the section may contain a variable number of fields with variable keys.
#define AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY
the section contains an array of elements of the same type
#define AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT
const AVTextFormatter avtextformatter_xml
Definition tf_xml.c:202
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_UNLIMITED
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
error code definitions
double value
Definition eval.c:102
const char * key
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition bprint.c:263
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition bprint.c:227
#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double quoted attributes.
Definition avstring.h:348
@ AV_ESCAPE_MODE_XML
Use XML non-markup character data escaping.
Definition avstring.h:318
#define av_cold
Definition attributes.h:117
const char data[16]
Definition mxf.c:149
AVOptions.
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
void * priv
private data for use by the filter
AVTextFormatOptions opts
int level
current level, starting from 0
unsigned int nb_item[SECTION_MAX_NB_LEVELS]
number of the item printed in the given section, starting from 0
const char * element_name
name of the contained element, if provided
const char * name
const char *(* get_type)(const void *data)
function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
int xsd_strict
Definition tf_xml.c:37
int fully_qualified
Definition tf_xml.c:36
int indent_level
Definition tf_xml.c:35
int within_tag
Definition tf_xml.c:34
Internal utilities for text formatters.
static const AVTextFormatSection * tf_get_section(AVTextFormatContext *tfc, int level)
Safely validate and access a section at a given level.
Definition tf_internal.h:42
static const AVTextFormatSection * tf_get_parent_section(AVTextFormatContext *tfc, int level)
Safely access the parent section.
Definition tf_internal.h:55
#define DEFINE_FORMATTER_CLASS(name)
Definition tf_internal.h:31
static void writer_w8(AVTextFormatContext *wctx, int b)
Definition tf_internal.h:63
static void writer_printf(AVTextFormatContext *wctx, const char *fmt,...)
Definition tf_internal.h:73
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition tf_internal.h:68
static void xml_print_value(AVTextFormatContext *wctx, const char *key, const char *str, int64_t num, const int is_int)
Definition tf_xml.c:147
#define CHECK_COMPLIANCE(opt, opt_name)
static void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition tf_xml.c:192
static void xml_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition tf_xml.c:76
static const AVOption xml_options[]
Definition tf_xml.c:43
#define XML_INDENT()
Definition tf_xml.c:74
static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition tf_xml.c:197
static av_cold int xml_init(AVTextFormatContext *wctx)
Definition tf_xml.c:53
#define OFFSET(x)
Definition tf_xml.c:41
static void xml_print_section_footer(AVTextFormatContext *wctx)
Definition tf_xml.c:126