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 | * according to encoding (only UTF-8 or UTF-16+BOM supported). | 45 | * according to encoding (only UTF-8 or UTF-16+BOM supported). |
| 46 | * @return number of bytes written or a negative error code. | 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 | uint32_t tag, enum ID3v2Encoding enc) | 49 | uint32_t tag, enum ID3v2Encoding enc) |
| 50 | { | 50 | { |
| 51 | int len; | 51 | int len; |
| @@ -73,17 +73,21 @@ static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2 · 21 unmodified lines | |||
| 73 | put(dyn_buf, str2); | 73 | put(dyn_buf, str2); |
| 74 | len = avio_close_dyn_buf(dyn_buf, &pb); | 74 | len = avio_close_dyn_buf(dyn_buf, &pb); |
| 75 | 75 | ||
| 76 | avio_wb32(s->pb, tag); | 76 | avio_wb32(avioc, tag); |
| 77 | id3v2_put_size(s->pb, len); | 77 | /* ID3v2.3 frame size is not synchsafe */ |
| 78 | avio_wb16(s->pb, 0); | 78 | if (id3->version == 3) |
| 79 | avio_write(s->pb, pb, len); | 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 | av_freep(&pb); | 85 | av_freep(&pb); |
| 82 | return len + ID3v2_HEADER_SIZE; | 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], | 89 | static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t, |
| 86 | enum ID3v2Encoding enc) | 90 | const char table[][4], enum ID3v2Encoding enc) |
| 87 | { | 91 | { |
| 88 | uint32_t tag; | 92 | uint32_t tag; |
| 89 | int i; | 93 | int i; |
| @@ -93,7 +97,7 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const · 3 unmodified lines | |||
| 93 | tag = AV_RB32(t->key); | 97 | tag = AV_RB32(t->key); |
| 94 | for (i = 0; *table[i]; i++) | 98 | for (i = 0; *table[i]; i++) |
| 95 | if (tag == AV_RB32(table[i])) | 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 | return -1; | 101 | return -1; |
| 98 | } | 102 | } |
| 99 | 103 | ||
| @@ -124,18 +128,18 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) · 24 unmodified lines | |||
| 124 | while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { | 128 | while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { |
| 125 | int ret; | 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 | id3->len += ret; | 132 | id3->len += ret; |
| 129 | continue; | 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 | ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { | 136 | ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { |
| 133 | id3->len += ret; | 137 | id3->len += ret; |
| 134 | continue; | 138 | continue; |
| 135 | } | 139 | } |
| 136 | 140 | ||
| 137 | /* unknown tag, write as TXXX frame */ | 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 | return ret; | 143 | return ret; |
| 140 | id3->len += ret; | 144 | id3->len += ret; |
| 141 | } | 145 | } |