Frame sizes in ID3v2.3 are not synchsafe, they are simply 32be numbers. In practice this bug is not noticeable unless the frame size takes more than 7 bits (which is almost never for text frames).
Unified · Split
| @@ -45,7 +45,7 @@ static int string_is_ascii(const uint8_t *str) · 44 unmodified lines | ||
| 45 | 45 | * according to encoding (only UTF-8 or UTF-16+BOM supported). |
| 46 | 46 | * @return number of bytes written or a negative error code. |
| 47 | 47 | */ |
| 48 | −static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2, | |
| 48 | +static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char *str1, const char *str2, | |
| 49 | 49 | uint32_t tag, enum ID3v2Encoding enc) |
| 50 | 50 | { |
| 51 | 51 | int len; |
| @@ -73,17 +73,21 @@ static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2 · 21 unmodified lines | ||
| 73 | 73 | put(dyn_buf, str2); |
| 74 | 74 | len = avio_close_dyn_buf(dyn_buf, &pb); |
| 75 | 75 | |
| 76 | − avio_wb32(s->pb, tag); | |
| 77 | − id3v2_put_size(s->pb, len); | |
| 78 | − avio_wb16(s->pb, 0); | |
| 79 | − avio_write(s->pb, pb, len); | |
| 76 | + avio_wb32(avioc, tag); | |
| 77 | + /* ID3v2.3 frame size is not synchsafe */ | |
| 78 | + if (id3->version == 3) | |
| 79 | + avio_wb32(avioc, len); | |
| 80 | + else | |
| 81 | + id3v2_put_size(avioc, len); | |
| 82 | + avio_wb16(avioc, 0); | |
| 83 | + avio_write(avioc, pb, len); | |
| 80 | 84 | |
| 81 | 85 | av_freep(&pb); |
| 82 | 86 | return len + ID3v2_HEADER_SIZE; |
| 83 | 87 | } |
| 84 | 88 | |
| 85 | −static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const char table[][4], | |
| 86 | − enum ID3v2Encoding enc) | |
| 89 | +static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t, | |
| 90 | + const char table[][4], enum ID3v2Encoding enc) | |
| 87 | 91 | { |
| 88 | 92 | uint32_t tag; |
| 89 | 93 | int i; |
| @@ -93,7 +97,7 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const · 3 unmodified lines | ||
| 93 | 97 | tag = AV_RB32(t->key); |
| 94 | 98 | for (i = 0; *table[i]; i++) |
| 95 | 99 | if (tag == AV_RB32(table[i])) |
| 96 | − return id3v2_put_ttag(s, t->value, NULL, tag, enc); | |
| 100 | + return id3v2_put_ttag(id3, pb, t->value, NULL, tag, enc); | |
| 97 | 101 | return -1; |
| 98 | 102 | } |
| 99 | 103 | |
| @@ -124,18 +128,18 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) · 24 unmodified lines | ||
| 124 | 128 | while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { |
| 125 | 129 | int ret; |
| 126 | 130 | |
| 127 | − if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) { | |
| 131 | + if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) { | |
| 128 | 132 | id3->len += ret; |
| 129 | 133 | continue; |
| 130 | 134 | } |
| 131 | − if ((ret = id3v2_check_write_tag(s, t, id3->version == 3 ? | |
| 135 | + if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ? | |
| 132 | 136 | ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { |
| 133 | 137 | id3->len += ret; |
| 134 | 138 | continue; |
| 135 | 139 | } |
| 136 | 140 | |
| 137 | 141 | /* unknown tag, write as TXXX frame */ |
| 138 | − if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) | |
| 142 | + if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) | |
| 139 | 143 | return ret; |
| 140 | 144 | id3->len += ret; |
| 141 | 145 | } |