FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/textformat/tf_flat.c
Date: 2025-04-25 22:50:00
Exec Total Coverage
Lines: 48 57 84.2%
Functions: 6 7 85.7%
Branches: 25 37 67.6%

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