From d2961e4ebfbb78af0f066760eb0ffb8a8567e529 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 2 Oct 2011 09:06:34 +0200 Subject: id3v2: read TXXX frames with two calls to decode_str() instead of one. Read the key in the first, value in the second. This allows to avoid pointless strdups and simplify decode_str() by dropping two of its parameters. --- libavformat/id3v2.c | 60 +++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'libavformat') diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index a3d7ae6c5f..48443e1865 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -73,23 +73,20 @@ static void free_geobtag(ID3v2ExtraMetaGEOB *geob) /** * Decode characters to UTF-8 according to encoding type. The decoded buffer is - * always null terminated. + * always null terminated. Stop reading when either *maxread bytes are read from + * pb or U+0000 character is found. * * @param dst Pointer where the address of the buffer with the decoded bytes is * stored. Buffer must be freed by caller. - * @param dstlen Pointer to an int where the length of the decoded string - * is stored (in bytes, incl. null termination) * @param maxread Pointer to maximum number of characters to read from the * AVIOContext. After execution the value is decremented by the number of bytes * actually read. - * @seeknull If true, decoding stops after the first U+0000 character found, if - * there is any before maxread is reached * @returns 0 if no error occured, dst is uninitialized on error */ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, - uint8_t **dst, int *dstlen, int *maxread, const int seeknull) + uint8_t **dst, int *maxread) { - int len, ret; + int ret; uint8_t tmp; uint32_t ch = 1; int left = *maxread; @@ -104,7 +101,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, switch (encoding) { case ID3v2_ENCODING_ISO8859: - while (left && (!seeknull || ch)) { + while (left && ch) { ch = avio_r8(pb); PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);) left--; @@ -133,7 +130,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, // fall-through case ID3v2_ENCODING_UTF16BE: - while ((left > 1) && (!seeknull || ch)) { + while ((left > 1) && ch) { GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;) PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);) } @@ -142,7 +139,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, break; case ID3v2_ENCODING_UTF8: - while (left && (!seeknull || ch)) { + while (left && ch) { ch = avio_r8(pb); avio_w8(dynbuf, ch); left--; @@ -155,10 +152,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, if (ch) avio_w8(dynbuf, 0); - len = avio_close_dyn_buf(dynbuf, (uint8_t **)dst); - if (dstlen) - *dstlen = len; - + avio_close_dyn_buf(dynbuf, (uint8_t **)dst); *maxread = left; return 0; @@ -170,38 +164,40 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key) { uint8_t *dst; - const char *val = NULL; - int len, dstlen; + int encoding, dict_flags = AV_DICT_DONT_OVERWRITE; unsigned genre; if (taglen < 1) return; + encoding = avio_r8(pb); taglen--; /* account for encoding type byte */ - if (decode_str(s, pb, avio_r8(pb), &dst, &dstlen, &taglen, 0) < 0) { + if (decode_str(s, pb, encoding, &dst, &taglen) < 0) { av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key); return; } if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) - && genre <= ID3v1_GENRE_MAX) - val = ff_id3v1_genre_str[genre]; - else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) { - /* dst now contains two 0-terminated strings */ - dst[dstlen] = 0; - len = strlen(dst); + && genre <= ID3v1_GENRE_MAX) { + av_freep(&dst); + dst = ff_id3v1_genre_str[genre]; + } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) { + /* dst now contains the key, need to get value */ key = dst; - val = dst + FFMIN(len + 1, dstlen); + if (decode_str(s, pb, encoding, &dst, &taglen) < 0) { + av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key); + av_freep(&key); + return; + } + dict_flags |= AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_STRDUP_KEY; } else if (*dst) - val = dst; - - if (val) - av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE); + dict_flags |= AV_DICT_DONT_STRDUP_VAL; - av_free(dst); + if (dst) + av_dict_set(&s->metadata, key, dst, dict_flags); } /** @@ -234,17 +230,17 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char * taglen--; /* read MIME type (always ISO-8859) */ - if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, NULL, &taglen, 1) < 0 + if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, &taglen) < 0 || taglen <= 0) goto fail; /* read file name */ - if (decode_str(s, pb, encoding, &geob_data->file_name, NULL, &taglen, 1) < 0 + if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 || taglen <= 0) goto fail; /* read content description */ - if (decode_str(s, pb, encoding, &geob_data->description, NULL, &taglen, 1) < 0 + if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 || taglen < 0) goto fail; -- cgit v1.2.3