From f0bb1a599ce51d69f5c149ae32c682e63663a5bd Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Sat, 7 Apr 2012 16:19:13 +0200 Subject: ffprobe: use avbprint API Simplify, increase robustness. --- ffprobe.c | 265 +++++++++++++++++++------------------------------------------- 1 file changed, 81 insertions(+), 184 deletions(-) (limited to 'ffprobe.c') diff --git a/ffprobe.c b/ffprobe.c index 80eace96dd..8a76a0bacd 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("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("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, -- cgit v1.2.3