[FFmpeg-devel] [PATCH] ffprobe: use avbprint API
Stefano Sabatini
stefasab at gmail.com
Sat Apr 7 17:03:21 CEST 2012
Simplify, increase robustness.
---
ffprobe.c | 265 +++++++++++++++++++------------------------------------------
1 files changed, 81 insertions(+), 184 deletions(-)
diff --git a/ffprobe.c b/ffprobe.c
index 80eace9..8a76a0b 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -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);
+ quote = 1;
- 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;
- 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, key, wctx));
+ av_bprint_finalize(&buf, NULL);
+
+ 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,
--
1.7.5.4
More information about the ffmpeg-devel
mailing list