1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-04 22:03:09 +02:00

fftools/textformat: Apply quality improvements

Perform multiple improvements to increase code robustness.
In particular:
- favor unsigned counters for loops
- add missing checks
- avoid possible leaks
- move variable declarations to inner scopes when feasible
- provide explicit type-casting when needed

Signed-off-by: softworkz <softworkz@hotmail.com>
This commit is contained in:
softworkz
2025-04-29 02:07:30 +02:00
parent 8f42d90413
commit 5f90eea8a8
7 changed files with 82 additions and 45 deletions

View File

@ -93,9 +93,8 @@ static const AVClass textcontext_class = {
static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
{ {
int i;
av_bprintf(bp, "0X"); av_bprintf(bp, "0X");
for (i = 0; i < ubuf_size; i++) for (unsigned i = 0; i < ubuf_size; i++)
av_bprintf(bp, "%02X", ubuf[i]); av_bprintf(bp, "%02X", ubuf[i]);
} }
@ -137,6 +136,8 @@ int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
AVTextFormatContext *tctx; AVTextFormatContext *tctx;
int i, ret = 0; int i, ret = 0;
av_assert0(ptctx && formatter);
if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) { if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail; goto fail;
@ -215,8 +216,8 @@ int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
/* validate replace string */ /* validate replace string */
{ {
const uint8_t *p = tctx->string_validation_replacement; const uint8_t *p = (uint8_t *)tctx->string_validation_replacement;
const uint8_t *endp = p + strlen(p); const uint8_t *endp = p + strlen((const char *)p);
while (*p) { while (*p) {
const uint8_t *p0 = p; const uint8_t *p0 = p;
int32_t code; int32_t code;
@ -229,6 +230,7 @@ int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
"Invalid UTF8 sequence %s found in string validation replace '%s'\n", "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
bp.str, tctx->string_validation_replacement); bp.str, tctx->string_validation_replacement);
return ret; return ret;
goto fail;
} }
} }
} }
@ -256,6 +258,11 @@ static const char unit_bit_per_second_str[] = "bit/s";
void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id) void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id)
{ {
if (section_id < 0 || section_id >= tctx->nb_sections) {
av_log(tctx, AV_LOG_ERROR, "Invalid section_id for section_header: %d\n", section_id);
return;
}
tctx->level++; tctx->level++;
av_assert0(tctx->level < SECTION_MAX_NB_LEVELS); av_assert0(tctx->level < SECTION_MAX_NB_LEVELS);
@ -269,6 +276,11 @@ void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, in
void avtext_print_section_footer(AVTextFormatContext *tctx) void avtext_print_section_footer(AVTextFormatContext *tctx)
{ {
if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) {
av_log(tctx, AV_LOG_ERROR, "Invalid level for section_footer: %d\n", tctx->level);
return;
}
int section_id = tctx->section[tctx->level]->id; int section_id = tctx->section[tctx->level]->id;
int parent_section_id = tctx->level ? int parent_section_id = tctx->level ?
tctx->section[tctx->level - 1]->id : SECTION_ID_NONE; tctx->section[tctx->level - 1]->id : SECTION_ID_NONE;
@ -285,7 +297,11 @@ void avtext_print_section_footer(AVTextFormatContext *tctx)
void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val) void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val)
{ {
const struct AVTextFormatSection *section = tctx->section[tctx->level]; const AVTextFormatSection *section;
av_assert0(key && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS);
section = tctx->section[tctx->level];
if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
tctx->formatter->print_integer(tctx, key, val); tctx->formatter->print_integer(tctx, key, val);
@ -354,17 +370,18 @@ struct unit_value {
const char *unit; const char *unit;
}; };
static char *value_string(AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv) static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv)
{ {
double vald; double vald;
int64_t vali; int64_t vali = 0;
int show_float = 0; int show_float = 0;
if (uv.unit == unit_second_str) { if (uv.unit == unit_second_str) {
vald = uv.val.d; vald = uv.val.d;
show_float = 1; show_float = 1;
} else { } else {
vald = vali = uv.val.i; vald = (double)uv.val.i;
vali = uv.val.i;
} }
if (uv.unit == unit_second_str && tctx->use_value_sexagesimal_format) { if (uv.unit == unit_second_str && tctx->use_value_sexagesimal_format) {
@ -383,17 +400,17 @@ static char *value_string(AVTextFormatContext *tctx, char *buf, int buf_size, st
int64_t index; int64_t index;
if (uv.unit == unit_byte_str && tctx->use_byte_value_binary_prefix) { if (uv.unit == unit_byte_str && tctx->use_byte_value_binary_prefix) {
index = (int64_t) (log2(vald)) / 10; index = (int64_t)(log2(vald) / 10);
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
vald /= si_prefixes[index].bin_val; vald /= si_prefixes[index].bin_val;
prefix_string = si_prefixes[index].bin_str; prefix_string = si_prefixes[index].bin_str;
} else { } else {
index = (int64_t) (log10(vald)) / 3; index = (int64_t)(log10(vald) / 3);
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
vald /= si_prefixes[index].dec_val; vald /= si_prefixes[index].dec_val;
prefix_string = si_prefixes[index].dec_str; prefix_string = si_prefixes[index].dec_str;
} }
vali = vald; vali = (int64_t)vald;
} }
if (show_float || (tctx->use_value_prefix && vald != (int64_t)vald)) if (show_float || (tctx->use_value_prefix && vald != (int64_t)vald))
@ -421,9 +438,13 @@ void avtext_print_unit_int(AVTextFormatContext *tctx, const char *key, int value
int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags) int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags)
{ {
const struct AVTextFormatSection *section = tctx->section[tctx->level]; const AVTextFormatSection *section;
int ret = 0; int ret = 0;
av_assert0(key && val && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS);
section = tctx->section[tctx->level];
if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER || if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER ||
(tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO
&& (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) && (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL)
@ -465,12 +486,11 @@ void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRationa
void avtext_print_time(AVTextFormatContext *tctx, const char *key, void avtext_print_time(AVTextFormatContext *tctx, const char *key,
int64_t ts, const AVRational *time_base, int is_duration) int64_t ts, const AVRational *time_base, int is_duration)
{ {
char buf[128];
if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL); avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL);
} else { } else {
double d = ts * av_q2d(*time_base); char buf[128];
double d = av_q2d(*time_base) * ts;
struct unit_value uv; struct unit_value uv;
uv.val.d = d; uv.val.d = d;
uv.unit = unit_second_str; uv.unit = unit_second_str;
@ -491,7 +511,8 @@ void avtext_print_data(AVTextFormatContext *tctx, const char *name,
const uint8_t *data, int size) const uint8_t *data, int size)
{ {
AVBPrint bp; AVBPrint bp;
int offset = 0, l, i; unsigned offset = 0;
int l, i;
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
av_bprintf(&bp, "\n"); av_bprintf(&bp, "\n");
@ -518,25 +539,29 @@ void avtext_print_data(AVTextFormatContext *tctx, const char *name,
void avtext_print_data_hash(AVTextFormatContext *tctx, const char *name, void avtext_print_data_hash(AVTextFormatContext *tctx, const char *name,
const uint8_t *data, int size) const uint8_t *data, int size)
{ {
char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; char buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
int len;
if (!tctx->hash) if (!tctx->hash)
return; return;
av_hash_init(tctx->hash); av_hash_init(tctx->hash);
av_hash_update(tctx->hash, data, size); av_hash_update(tctx->hash, data, size);
snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(tctx->hash)); len = snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(tctx->hash));
p = buf + strlen(buf); av_hash_final_hex(tctx->hash, (uint8_t *)&buf[len], (int)sizeof(buf) - len);
av_hash_final_hex(tctx->hash, p, buf + sizeof(buf) - p);
avtext_print_string(tctx, name, buf, 0); avtext_print_string(tctx, name, buf, 0);
} }
void avtext_print_integers(AVTextFormatContext *tctx, const char *name, void avtext_print_integers(AVTextFormatContext *tctx, const char *name,
uint8_t *data, int size, const char *format, uint8_t *data, int size, const char *format,
int columns, int bytes, int offset_add) int columns, int bytes, int offset_add)
{ {
AVBPrint bp; AVBPrint bp;
int offset = 0, l, i; unsigned offset = 0;
int l, i;
if (!name || !data || !format || columns <= 0 || bytes <= 0)
return;
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
av_bprintf(&bp, "\n"); av_bprintf(&bp, "\n");
@ -602,12 +627,15 @@ int avtextwriter_context_open(AVTextWriterContext **pwctx, const AVTextWriter *w
AVTextWriterContext *wctx; AVTextWriterContext *wctx;
int ret = 0; int ret = 0;
if (!(wctx = av_mallocz(sizeof(AVTextWriterContext)))) { if (!pwctx || !writer)
return AVERROR(EINVAL);
if (!((wctx = av_mallocz(sizeof(AVTextWriterContext))))) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail; goto fail;
} }
if (!(wctx->priv = av_mallocz(writer->priv_size))) { if (writer->priv_size && !((wctx->priv = av_mallocz(writer->priv_size)))) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail; goto fail;
} }

View File

@ -21,9 +21,7 @@
#ifndef FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H #ifndef FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H
#define FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H #define FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "libavutil/attributes.h"
#include "libavutil/dict.h" #include "libavutil/dict.h"
#include "libavformat/avio.h" #include "libavformat/avio.h"
#include "libavutil/bprint.h" #include "libavutil/bprint.h"
@ -103,7 +101,7 @@ struct AVTextFormatContext {
unsigned int nb_item_type[SECTION_MAX_NB_LEVELS][SECTION_MAX_NB_SECTIONS]; unsigned int nb_item_type[SECTION_MAX_NB_LEVELS][SECTION_MAX_NB_SECTIONS];
/** section per each level */ /** section per each level */
const struct AVTextFormatSection *section[SECTION_MAX_NB_LEVELS]; const AVTextFormatSection *section[SECTION_MAX_NB_LEVELS];
AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
/// used by various formatters /// used by various formatters
@ -124,7 +122,7 @@ struct AVTextFormatContext {
#define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2 #define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2
int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args,
const struct AVTextFormatSection *sections, int nb_sections, const AVTextFormatSection *sections, int nb_sections,
int show_value_unit, int show_value_unit,
int use_value_prefix, int use_value_prefix,
int use_byte_value_binary_prefix, int use_byte_value_binary_prefix,

View File

@ -68,9 +68,10 @@ DEFINE_FORMATTER_CLASS(default);
/* lame uppercasing routine, assumes the string is lower case ASCII */ /* lame uppercasing routine, assumes the string is lower case ASCII */
static inline char *upcase_string(char *dst, size_t dst_size, const char *src) static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
{ {
int i; unsigned i;
for (i = 0; src[i] && i < dst_size - 1; i++) for (i = 0; src[i] && i < dst_size - 1; i++)
dst[i] = av_toupper(src[i]); dst[i] = (char)av_toupper(src[i]);
dst[i] = 0; dst[i] = 0;
return dst; return dst;
} }
@ -106,6 +107,9 @@ static void default_print_section_footer(AVTextFormatContext *wctx)
const struct AVTextFormatSection *section = wctx->section[wctx->level]; const struct AVTextFormatSection *section = wctx->section[wctx->level];
char buf[32]; char buf[32];
if (!section)
return;
if (def->noprint_wrappers || def->nested_section[wctx->level]) if (def->noprint_wrappers || def->nested_section[wctx->level])
return; return;

View File

@ -91,7 +91,7 @@ static char *ini_escape_str(AVBPrint *dst, const char *src)
/* fallthrough */ /* fallthrough */
default: default:
if ((unsigned char)c < 32) if ((unsigned char)c < 32)
av_bprintf(dst, "\\x00%02x", c & 0xff); av_bprintf(dst, "\\x00%02x", (unsigned char)c);
else else
av_bprint_chars(dst, c, 1); av_bprint_chars(dst, c, 1);
break; break;

View File

@ -80,13 +80,18 @@ static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx
static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 }; static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 };
const char *p; const char *p;
if (!src) {
av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n");
return NULL;
}
for (p = src; *p; p++) { for (p = src; *p; p++) {
char *s = strchr(json_escape, *p); char *s = strchr(json_escape, *p);
if (s) { if (s) {
av_bprint_chars(dst, '\\', 1); av_bprint_chars(dst, '\\', 1);
av_bprint_chars(dst, json_subst[s - json_escape], 1); av_bprint_chars(dst, json_subst[s - json_escape], 1);
} else if ((unsigned char)*p < 32) { } else if ((unsigned char)*p < 32) {
av_bprintf(dst, "\\u00%02x", *p & 0xff); av_bprintf(dst, "\\u00%02x", (unsigned char)*p);
} else { } else {
av_bprint_chars(dst, *p, 1); av_bprint_chars(dst, *p, 1);
} }
@ -100,11 +105,10 @@ static void json_print_section_header(AVTextFormatContext *wctx, const void *dat
{ {
JSONContext *json = wctx->priv; JSONContext *json = wctx->priv;
AVBPrint buf; AVBPrint buf;
const struct AVTextFormatSection *section = wctx->section[wctx->level]; const AVTextFormatSection *section = wctx->section[wctx->level];
const struct AVTextFormatSection *parent_section = wctx->level ? const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL;
wctx->section[wctx->level-1] : NULL;
if (wctx->level && wctx->nb_item[wctx->level-1]) if (wctx->level && wctx->nb_item[wctx->level - 1])
writer_put_str(wctx, ",\n"); writer_put_str(wctx, ",\n");
if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) { if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) {
@ -185,8 +189,7 @@ static void json_print_str(AVTextFormatContext *wctx, const char *key, const cha
static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
{ {
JSONContext *json = wctx->priv; JSONContext *json = wctx->priv;
const struct AVTextFormatSection *parent_section = wctx->level ? const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL;
wctx->section[wctx->level-1] : NULL;
AVBPrint buf; AVBPrint buf;
if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))

View File

@ -18,10 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <limits.h>
#include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "avtextformat.h" #include "avtextformat.h"

View File

@ -23,6 +23,7 @@
#include <string.h> #include <string.h>
#include "avtextwriters.h" #include "avtextwriters.h"
#include "libavutil/avassert.h"
#include "libavutil/error.h" #include "libavutil/error.h"
@ -53,7 +54,7 @@ static void io_w8(AVTextWriterContext *wctx, int b)
static void io_put_str(AVTextWriterContext *wctx, const char *str) static void io_put_str(AVTextWriterContext *wctx, const char *str)
{ {
IOWriterContext *ctx = wctx->priv; IOWriterContext *ctx = wctx->priv;
avio_write(ctx->avio_context, str, strlen(str)); avio_write(ctx->avio_context, (const unsigned char *)str, (int)strlen(str));
} }
static void io_printf(AVTextWriterContext *wctx, const char *fmt, ...) static void io_printf(AVTextWriterContext *wctx, const char *fmt, ...)
@ -81,6 +82,10 @@ int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_fil
IOWriterContext *ctx; IOWriterContext *ctx;
int ret; int ret;
if (!output_filename || !output_filename[0]) {
av_log(NULL, AV_LOG_ERROR, "The output_filename cannot be NULL or empty\n");
return AVERROR(EINVAL);
}
ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); ret = avtextwriter_context_open(pwctx, &avtextwriter_avio);
if (ret < 0) if (ret < 0)
@ -106,6 +111,8 @@ int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx,
IOWriterContext *ctx; IOWriterContext *ctx;
int ret; int ret;
av_assert0(avio_ctx);
ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); ret = avtextwriter_context_open(pwctx, &avtextwriter_avio);
if (ret < 0) if (ret < 0)
return ret; return ret;