summaryrefslogtreecommitdiff
path: root/libavformat/id3v2.c
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2011-10-04 03:21:14 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-10-04 03:24:59 +0200
commit2f9d6ffda78725e11b351a7a5d69414a32010810 (patch)
treeb9bf0e40ad2b85a35af8b5c0b9b6d50c19ad5303 /libavformat/id3v2.c
parent98df93c9fe2dd4698cd7b4d699b248cbfd1427b4 (diff)
parent60df6b004858dcab96fc96c6dd32484780a8d7c3 (diff)
Merge remote-tracking branch 'qatar/master'
* qatar/master: id3v2: remove pointless casts id3v2: read TXXX frames with two calls to decode_str() instead of one. id3v2: don't discard the whole tag when encountering empty frames. libvpx: fix build with older libvpx versions. ARM: check for inline asm 'y' operand modifier support Conflicts: libavcodec/libvpxenc.c libavformat/id3v2.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/id3v2.c')
-rw-r--r--libavformat/id3v2.c72
1 files changed, 37 insertions, 35 deletions
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 9d7ceef5a4..48124cee84 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -81,23 +81,20 @@ static void free_geobtag(void *obj)
/**
* 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;
@@ -112,7 +109,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--;
@@ -122,7 +119,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
case ID3v2_ENCODING_UTF16BOM:
if ((left -= 2) < 0) {
av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
- avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
+ avio_close_dyn_buf(dynbuf, dst);
av_freep(dst);
return AVERROR_INVALIDDATA;
}
@@ -133,7 +130,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
break;
default:
av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
- avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
+ avio_close_dyn_buf(dynbuf, dst);
av_freep(dst);
*maxread = left;
return AVERROR_INVALIDDATA;
@@ -141,7 +138,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);)
}
@@ -150,7 +147,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--;
@@ -163,10 +160,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, dst);
*maxread = left;
return 0;
@@ -178,38 +172,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;
+ dict_flags |= AV_DICT_DONT_STRDUP_VAL;
- if (val)
- av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
-
- av_free(dst);
+ if (dst)
+ av_dict_set(&s->metadata, key, dst, dict_flags);
}
/**
@@ -242,17 +238,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;
@@ -410,7 +406,7 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
tag[3] = 0;
tlen = avio_rb24(s->pb);
}
- if (tlen > (1<<28) || !tlen)
+ if (tlen > (1<<28))
break;
len -= taghdrlen + tlen;
@@ -419,6 +415,12 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
next = avio_tell(s->pb) + tlen;
+ if (!tlen) {
+ if (tag[0])
+ av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", tag);
+ continue;
+ }
+
if (tflags & ID3v2_FLAG_DATALEN) {
if (tlen < 4)
break;