FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/textformat/tf_flat.c
Date: 2026-08-30 18:45:47
Exec Total Coverage
Lines: 48 57 84.2%
Functions: 6 6 100.0%
Branches: 24 37 64.9%

Line Branch Exec Source
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 <limits.h>
23 #include <stdarg.h>
24 #include <string.h>
25
26 #include "avtextformat.h"
27 #include "libavutil/bprint.h"
28 #include "libavutil/error.h"
29 #include "libavutil/opt.h"
30 #include "tf_internal.h"
31
32 /* Flat output */
33
34 typedef struct FlatContext {
35 const AVClass *class;
36 const char *sep_str;
37 char sep;
38 int hierarchical;
39 } FlatContext;
40
41 #undef OFFSET
42 #define OFFSET(x) offsetof(FlatContext, x)
43
44 static const AVOption flat_options[] = {
45 { "sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 },
46 { "s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 },
47 { "hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 },
48 { "h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 },
49 { NULL },
50 };
51
52 DEFINE_FORMATTER_CLASS(flat);
53
54 2 static av_cold int flat_init(AVTextFormatContext *wctx)
55 {
56 2 FlatContext *flat = wctx->priv;
57
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (strlen(flat->sep_str) != 1) {
59 av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
60 flat->sep_str);
61 return AVERROR(EINVAL);
62 }
63 2 flat->sep = flat->sep_str[0];
64
65 2 return 0;
66 }
67
68 382 static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
69 {
70 const char *p;
71
72
2/2
✓ Branch 0 taken 4011 times.
✓ Branch 1 taken 382 times.
4393 for (p = src; *p; p++) {
73
3/4
✓ Branch 0 taken 4011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4010 times.
✓ Branch 3 taken 1 times.
4011 if (!((*p >= '0' && *p <= '9') ||
74
3/4
✓ Branch 0 taken 3607 times.
✓ Branch 1 taken 403 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3607 times.
4010 (*p >= 'a' && *p <= 'z') ||
75
3/4
✓ Branch 0 taken 403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 402 times.
✓ Branch 3 taken 1 times.
403 (*p >= 'A' && *p <= 'Z')))
76 402 av_bprint_chars(dst, '_', 1);
77 else
78 3609 av_bprint_chars(dst, *p, 1);
79 }
80 382 return dst->str;
81 }
82
83 382 static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
84 {
85 const char *p;
86
87
2/2
✓ Branch 0 taken 2569 times.
✓ Branch 1 taken 382 times.
2951 for (p = src; *p; p++) {
88
2/7
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2567 times.
2569 switch (*p) {
89 case '\n': av_bprintf(dst, "%s", "\\n"); break;
90 case '\r': av_bprintf(dst, "%s", "\\r"); break;
91 case '\\': av_bprintf(dst, "%s", "\\\\"); break;
92 2 case '"': av_bprintf(dst, "%s", "\\\""); break;
93 case '`': av_bprintf(dst, "%s", "\\`"); break;
94 case '$': av_bprintf(dst, "%s", "\\$"); break;
95 2567 default: av_bprint_chars(dst, *p, 1); break;
96 }
97 }
98 382 return dst->str;
99 }
100
101 48 static void flat_print_section_header(AVTextFormatContext *wctx, const void *data)
102 {
103 48 FlatContext *flat = wctx->priv;
104 48 AVBPrint *buf = &wctx->section_pbuf[wctx->level];
105 48 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
106 48 const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
107
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (!section)
109 return;
110
111 /* build section header */
112 48 av_bprint_clear(buf);
113
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
48 if (!parent_section)
114 2 return;
115
116 46 av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level - 1].str);
117
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (flat->hierarchical ||
119 !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) {
120 46 av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
121
122
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 12 times.
46 if (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) {
123 68 int n = parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE
124 28 ? wctx->nb_item_type[wctx->level - 1][section->id]
125
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 6 times.
34 : wctx->nb_item[wctx->level - 1];
126
127 34 av_bprintf(buf, "%d%s", n, flat->sep_str);
128 }
129 }
130 }
131
132 318 static void flat_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
133 {
134 318 writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value);
135 318 }
136
137 382 static void flat_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
138 {
139 382 FlatContext *flat = wctx->priv;
140 AVBPrint buf;
141
142 382 writer_put_str(wctx, wctx->section_pbuf[wctx->level].str);
143 382 av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
144 382 writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep));
145 382 av_bprint_clear(&buf);
146 382 writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value));
147 382 av_bprint_finalize(&buf, NULL);
148 382 }
149
150 const AVTextFormatter avtextformatter_flat = {
151 .name = "flat",
152 .priv_size = sizeof(FlatContext),
153 .init = flat_init,
154 .print_section_header = flat_print_section_header,
155 .print_integer = flat_print_int,
156 .print_string = flat_print_str,
157 .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS | AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT,
158 .priv_class = &flat_class,
159 };
160