aarch64: Add assembly support for -fsanitize=hwaddress tagged globals.
[libav.git] / libavformat / id3v2.c
CommitLineData
2ea512a6
AC
1/*
2 * ID3v2 header parser
3 * Copyright (c) 2003 Fabrice Bellard
4 *
2912e87a 5 * This file is part of Libav.
2ea512a6 6 *
2912e87a 7 * Libav is free software; you can redistribute it and/or
2ea512a6
AC
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
2912e87a 12 * Libav is distributed in the hope that it will be useful,
2ea512a6
AC
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
2912e87a 18 * License along with Libav; if not, write to the Free Software
2ea512a6
AC
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
75411182 22#include "libavutil/avstring.h"
d2d67e42 23#include "libavutil/dict.h"
0671adbb 24#include "libavutil/intreadwrite.h"
e731b8d8 25#include "avio_internal.h"
a93b09cb 26#include "internal.h"
0671adbb
LB
27#include "id3v1.h"
28#include "id3v2.h"
2ea512a6 29
3b78c180 30const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
0671adbb
LB
31 { "TALB", "album" },
32 { "TCOM", "composer" },
33 { "TCON", "genre" },
34 { "TCOP", "copyright" },
35 { "TENC", "encoded_by" },
36 { "TIT2", "title" },
37 { "TLAN", "language" },
38 { "TPE1", "artist" },
39 { "TPE2", "album_artist" },
40 { "TPE3", "performer" },
41 { "TPOS", "disc" },
42 { "TPUB", "publisher" },
43 { "TRCK", "track" },
44 { "TSSE", "encoder" },
3b78c180
DB
45 { 0 }
46};
47
48const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
0671adbb
LB
49 { "TDRL", "date" },
50 { "TDRC", "date" },
51 { "TDEN", "creation_time" },
52 { "TSOA", "album-sort" },
53 { "TSOP", "artist-sort" },
54 { "TSOT", "title-sort" },
3b78c180
DB
55 { 0 }
56};
57
c4a37885 58static const AVMetadataConv id3v2_2_metadata_conv[] = {
0671adbb
LB
59 { "TAL", "album" },
60 { "TCO", "genre" },
61 { "TT2", "title" },
62 { "TEN", "encoded_by" },
63 { "TP1", "artist" },
64 { "TP2", "album_artist" },
65 { "TP3", "performer" },
66 { "TRK", "track" },
3b78c180
DB
67 { 0 }
68};
69
3b78c180 70const char ff_id3v2_tags[][4] = {
0671adbb
LB
71 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
72 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
73 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
74 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
75 { 0 },
3b78c180
DB
76};
77
78const char ff_id3v2_4_tags[][4] = {
0671adbb
LB
79 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
80 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
81 { 0 },
3b78c180
DB
82};
83
84const char ff_id3v2_3_tags[][4] = {
0671adbb
LB
85 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
86 { 0 },
3b78c180
DB
87};
88
fd9212f2 89const char * const ff_id3v2_picture_types[21] = {
a93b09cb
AK
90 "Other",
91 "32x32 pixels 'file icon'",
92 "Other file icon",
93 "Cover (front)",
94 "Cover (back)",
95 "Leaflet page",
96 "Media (e.g. label side of CD)",
97 "Lead artist/lead performer/soloist",
98 "Artist/performer",
99 "Conductor",
100 "Band/Orchestra",
101 "Composer",
102 "Lyricist/text writer",
103 "Recording Location",
104 "During recording",
105 "During performance",
106 "Movie/video screen capture",
107 "A bright coloured fish",
108 "Illustration",
109 "Band/artist logotype",
110 "Publisher/Studio logotype",
111};
112
113const CodecMime ff_id3v2_mime_tags[] = {
0671adbb
LB
114 { "image/gif", AV_CODEC_ID_GIF },
115 { "image/jpeg", AV_CODEC_ID_MJPEG },
116 { "image/jpg", AV_CODEC_ID_MJPEG },
117 { "image/png", AV_CODEC_ID_PNG },
118 { "image/tiff", AV_CODEC_ID_TIFF },
119 { "image/bmp", AV_CODEC_ID_BMP },
120 { "JPG", AV_CODEC_ID_MJPEG }, /* ID3v2.2 */
121 { "PNG", AV_CODEC_ID_PNG }, /* ID3v2.2 */
122 { "", AV_CODEC_ID_NONE },
a93b09cb
AK
123};
124
0671adbb 125int ff_id3v2_match(const uint8_t *buf, const char *magic)
2ea512a6 126{
3a1350e8
MK
127 return buf[0] == magic[0] &&
128 buf[1] == magic[1] &&
129 buf[2] == magic[2] &&
0671adbb
LB
130 buf[3] != 0xff &&
131 buf[4] != 0xff &&
132 (buf[6] & 0x80) == 0 &&
133 (buf[7] & 0x80) == 0 &&
134 (buf[8] & 0x80) == 0 &&
135 (buf[9] & 0x80) == 0;
2ea512a6 136}
ac3ef4a4 137
0671adbb 138int ff_id3v2_tag_len(const uint8_t *buf)
ac3ef4a4
AC
139{
140 int len = ((buf[6] & 0x7f) << 21) +
7d7b8c32
DB
141 ((buf[7] & 0x7f) << 14) +
142 ((buf[8] & 0x7f) << 7) +
0671adbb 143 (buf[9] & 0x7f) +
7d7b8c32 144 ID3v2_HEADER_SIZE;
ac3ef4a4
AC
145 if (buf[5] & 0x10)
146 len += ID3v2_HEADER_SIZE;
147 return len;
148}
75411182 149
ae628ec1 150static unsigned int get_size(AVIOContext *s, int len)
75411182 151{
7d7b8c32
DB
152 int v = 0;
153 while (len--)
b7effd4e 154 v = (v << 7) + (avio_r8(s) & 0x7F);
75411182
PD
155 return v;
156}
157
7a019dff
DG
158/**
159 * Free GEOB type extra metadata.
160 */
ec22979a 161static void free_geobtag(void *obj)
75411182 162{
ec22979a 163 ID3v2ExtraMetaGEOB *geob = obj;
7a019dff
DG
164 av_free(geob->mime_type);
165 av_free(geob->file_name);
166 av_free(geob->description);
167 av_free(geob->data);
168 av_free(geob);
169}
75411182 170
7a019dff
DG
171/**
172 * Decode characters to UTF-8 according to encoding type. The decoded buffer is
d2961e4e
AK
173 * always null terminated. Stop reading when either *maxread bytes are read from
174 * pb or U+0000 character is found.
7a019dff
DG
175 *
176 * @param dst Pointer where the address of the buffer with the decoded bytes is
177 * stored. Buffer must be freed by caller.
7a019dff
DG
178 * @param maxread Pointer to maximum number of characters to read from the
179 * AVIOContext. After execution the value is decremented by the number of bytes
180 * actually read.
da9cea77 181 * @returns 0 if no error occurred, dst is uninitialized on error
7a019dff
DG
182 */
183static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
d2961e4e 184 uint8_t **dst, int *maxread)
7a019dff 185{
d2961e4e 186 int ret;
7a019dff
DG
187 uint8_t tmp;
188 uint32_t ch = 1;
189 int left = *maxread;
190 unsigned int (*get)(AVIOContext*) = avio_rb16;
191 AVIOContext *dynbuf;
75411182 192
7a019dff
DG
193 if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
194 av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
195 return ret;
196 }
75411182 197
7a019dff 198 switch (encoding) {
d66eff36 199 case ID3v2_ENCODING_ISO8859:
d2961e4e 200 while (left && ch) {
7a019dff
DG
201 ch = avio_r8(pb);
202 PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
203 left--;
75411182 204 }
75411182
PD
205 break;
206
d66eff36 207 case ID3v2_ENCODING_UTF16BOM:
7a019dff
DG
208 if ((left -= 2) < 0) {
209 av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
8e32b1f0
MS
210 ffio_free_dyn_buf(&dynbuf);
211 *dst = NULL;
7a019dff
DG
212 return AVERROR_INVALIDDATA;
213 }
b7effd4e 214 switch (avio_rb16(pb)) {
20c68378 215 case 0xfffe:
b7effd4e 216 get = avio_rl16;
20c68378
AK
217 case 0xfeff:
218 break;
219 default:
7a019dff 220 av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
8e32b1f0
MS
221 ffio_free_dyn_buf(&dynbuf);
222 *dst = NULL;
7a019dff
DG
223 *maxread = left;
224 return AVERROR_INVALIDDATA;
20c68378
AK
225 }
226 // fall-through
227
d66eff36 228 case ID3v2_ENCODING_UTF16BE:
d2961e4e 229 while ((left > 1) && ch) {
7a019dff
DG
230 GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
231 PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
20c68378 232 }
7a019dff 233 if (left < 0)
0671adbb 234 left += 2; /* did not read last char from pb */
20c68378
AK
235 break;
236
d66eff36 237 case ID3v2_ENCODING_UTF8:
d2961e4e 238 while (left && ch) {
7a019dff
DG
239 ch = avio_r8(pb);
240 avio_w8(dynbuf, ch);
241 left--;
242 }
75411182 243 break;
20c68378 244 default:
7a019dff
DG
245 av_log(s, AV_LOG_WARNING, "Unknown encoding\n");
246 }
247
248 if (ch)
249 avio_w8(dynbuf, 0);
250
60df6b00 251 avio_close_dyn_buf(dynbuf, dst);
7a019dff
DG
252 *maxread = left;
253
254 return 0;
255}
256
257/**
258 * Parse a text tag.
259 */
0671adbb
LB
260static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
261 const char *key)
7a019dff
DG
262{
263 uint8_t *dst;
049ce4fa 264 int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
7a019dff
DG
265 unsigned genre;
266
267 if (taglen < 1)
268 return;
269
d2961e4e 270 encoding = avio_r8(pb);
7a019dff
DG
271 taglen--; /* account for encoding type byte */
272
d2961e4e 273 if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
7a019dff
DG
274 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
275 return;
75411182
PD
276 }
277
0671adbb 278 if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
3ec6f855 279 (sscanf(dst, "(%u)", &genre) == 1 || sscanf(dst, "%u", &genre) == 1) &&
0671adbb 280 genre <= ID3v1_GENRE_MAX) {
d2961e4e 281 av_freep(&dst);
049ce4fa 282 dst = av_strdup(ff_id3v1_genre_str[genre]);
d2961e4e
AK
283 } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
284 /* dst now contains the key, need to get value */
41770abf 285 key = dst;
d2961e4e
AK
286 if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
287 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
288 av_freep(&key);
289 return;
290 }
049ce4fa
CB
291 dict_flags |= AV_DICT_DONT_STRDUP_KEY;
292 } else if (!*dst)
ffdd2e91 293 av_freep(&dst);
7a019dff 294
d2961e4e
AK
295 if (dst)
296 av_dict_set(&s->metadata, key, dst, dict_flags);
7a019dff
DG
297}
298
299/**
300 * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
301 */
0671adbb 302static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
54bc15d5
AK
303 const char *tag, ID3v2ExtraMeta **extra_meta,
304 int isv34)
7a019dff
DG
305{
306 ID3v2ExtraMetaGEOB *geob_data = NULL;
0671adbb 307 ID3v2ExtraMeta *new_extra = NULL;
7a019dff
DG
308 char encoding;
309 unsigned int len;
310
311 if (taglen < 1)
312 return;
313
314 geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
315 if (!geob_data) {
0671adbb
LB
316 av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
317 sizeof(ID3v2ExtraMetaGEOB));
7a019dff
DG
318 return;
319 }
320
321 new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
322 if (!new_extra) {
0671adbb
LB
323 av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
324 sizeof(ID3v2ExtraMeta));
7a019dff
DG
325 goto fail;
326 }
327
328 /* read encoding type byte */
329 encoding = avio_r8(pb);
330 taglen--;
331
332 /* read MIME type (always ISO-8859) */
0671adbb
LB
333 if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type,
334 &taglen) < 0 ||
335 taglen <= 0)
7a019dff
DG
336 goto fail;
337
338 /* read file name */
0671adbb
LB
339 if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 ||
340 taglen <= 0)
7a019dff
DG
341 goto fail;
342
343 /* read content description */
0671adbb
LB
344 if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 ||
345 taglen < 0)
7a019dff
DG
346 goto fail;
347
348 if (taglen) {
349 /* save encapsulated binary data */
350 geob_data->data = av_malloc(taglen);
351 if (!geob_data->data) {
352 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
353 goto fail;
354 }
355 if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
0671adbb
LB
356 av_log(s, AV_LOG_WARNING,
357 "Error reading GEOB frame, data truncated.\n");
7a019dff
DG
358 geob_data->datasize = len;
359 } else {
0671adbb 360 geob_data->data = NULL;
7a019dff
DG
361 geob_data->datasize = 0;
362 }
363
364 /* add data to the list */
0671adbb 365 new_extra->tag = "GEOB";
7a019dff
DG
366 new_extra->data = geob_data;
367 new_extra->next = *extra_meta;
0671adbb 368 *extra_meta = new_extra;
7a019dff
DG
369
370 return;
371
372fail:
373 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
374 free_geobtag(geob_data);
375 av_free(new_extra);
376 return;
75411182
PD
377}
378
56e2ac6b
AK
379static int is_number(const char *str)
380{
0671adbb
LB
381 while (*str >= '0' && *str <= '9')
382 str++;
56e2ac6b
AK
383 return !*str;
384}
385
0671adbb 386static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
56e2ac6b 387{
d2d67e42
AK
388 AVDictionaryEntry *t;
389 if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
56e2ac6b
AK
390 strlen(t->value) == 4 && is_number(t->value))
391 return t;
392 return NULL;
393}
394
d2d67e42 395static void merge_date(AVDictionary **m)
56e2ac6b 396{
d2d67e42 397 AVDictionaryEntry *t;
0671adbb 398 char date[17] = { 0 }; // YYYY-MM-DD hh:mm
56e2ac6b
AK
399
400 if (!(t = get_date_tag(*m, "TYER")) &&
401 !(t = get_date_tag(*m, "TYE")))
402 return;
403 av_strlcpy(date, t->value, 5);
d2d67e42 404 av_dict_set(m, "TYER", NULL, 0);
0671adbb 405 av_dict_set(m, "TYE", NULL, 0);
56e2ac6b
AK
406
407 if (!(t = get_date_tag(*m, "TDAT")) &&
408 !(t = get_date_tag(*m, "TDA")))
409 goto finish;
410 snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
d2d67e42 411 av_dict_set(m, "TDAT", NULL, 0);
0671adbb 412 av_dict_set(m, "TDA", NULL, 0);
56e2ac6b
AK
413
414 if (!(t = get_date_tag(*m, "TIME")) &&
415 !(t = get_date_tag(*m, "TIM")))
416 goto finish;
0671adbb
LB
417 snprintf(date + 10, sizeof(date) - 10,
418 " %.2s:%.2s", t->value, t->value + 2);
d2d67e42 419 av_dict_set(m, "TIME", NULL, 0);
0671adbb 420 av_dict_set(m, "TIM", NULL, 0);
56e2ac6b
AK
421
422finish:
423 if (date[0])
d2d67e42 424 av_dict_set(m, "date", date, 0);
56e2ac6b
AK
425}
426
a93b09cb
AK
427static void free_apic(void *obj)
428{
429 ID3v2ExtraMetaAPIC *apic = obj;
1afddbe5 430 av_buffer_unref(&apic->buf);
a93b09cb
AK
431 av_freep(&apic->description);
432 av_freep(&apic);
433}
434
0671adbb 435static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
54bc15d5
AK
436 const char *tag, ID3v2ExtraMeta **extra_meta,
437 int isv34)
a93b09cb
AK
438{
439 int enc, pic_type;
0671adbb
LB
440 char mimetype[64];
441 const CodecMime *mime = ff_id3v2_mime_tags;
442 enum AVCodecID id = AV_CODEC_ID_NONE;
443 ID3v2ExtraMetaAPIC *apic = NULL;
a93b09cb 444 ID3v2ExtraMeta *new_extra = NULL;
0671adbb 445 int64_t end = avio_tell(pb) + taglen;
a93b09cb 446
54bc15d5 447 if (taglen <= 4 || (!isv34 && taglen <= 6))
a93b09cb
AK
448 goto fail;
449
450 new_extra = av_mallocz(sizeof(*new_extra));
451 apic = av_mallocz(sizeof(*apic));
452 if (!new_extra || !apic)
453 goto fail;
454
455 enc = avio_r8(pb);
456 taglen--;
457
458 /* mimetype */
54bc15d5
AK
459 if (isv34) {
460 taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
461 } else {
462 avio_read(pb, mimetype, 3);
463 mimetype[3] = 0;
464 taglen -= 3;
465 }
466
36ef5369 467 while (mime->id != AV_CODEC_ID_NONE) {
6e9bbc65 468 if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) {
a93b09cb
AK
469 id = mime->id;
470 break;
471 }
472 mime++;
473 }
36ef5369 474 if (id == AV_CODEC_ID_NONE) {
0671adbb
LB
475 av_log(s, AV_LOG_WARNING,
476 "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
a93b09cb
AK
477 goto fail;
478 }
479 apic->id = id;
480
481 /* picture type */
482 pic_type = avio_r8(pb);
483 taglen--;
484 if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
0671adbb
LB
485 av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n",
486 pic_type);
a93b09cb
AK
487 pic_type = 0;
488 }
489 apic->type = ff_id3v2_picture_types[pic_type];
490
491 /* description and picture data */
492 if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
0671adbb
LB
493 av_log(s, AV_LOG_ERROR,
494 "Error decoding attached picture description.\n");
a93b09cb
AK
495 goto fail;
496 }
497
059a9348 498 apic->buf = av_buffer_alloc(taglen + AV_INPUT_BUFFER_PADDING_SIZE);
1afddbe5 499 if (!apic->buf || avio_read(pb, apic->buf->data, taglen) != taglen)
a93b09cb 500 goto fail;
059a9348 501 memset(apic->buf->data + taglen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
a93b09cb 502
0671adbb
LB
503 new_extra->tag = "APIC";
504 new_extra->data = apic;
505 new_extra->next = *extra_meta;
506 *extra_meta = new_extra;
a93b09cb
AK
507
508 return;
509
510fail:
511 if (apic)
512 free_apic(apic);
513 av_freep(&new_extra);
514 avio_seek(pb, end, SEEK_SET);
515}
516
c4a37885
DB
517typedef struct ID3v2EMFunc {
518 const char *tag3;
519 const char *tag4;
932788be 520 void (*read)(AVFormatContext *s, AVIOContext *pb, int taglen,
54bc15d5
AK
521 const char *tag, ID3v2ExtraMeta **extra_meta,
522 int isv34);
ec22979a 523 void (*free)(void *obj);
c4a37885
DB
524} ID3v2EMFunc;
525
526static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
3b78c180 527 { "GEO", "GEOB", read_geobtag, free_geobtag },
0671adbb 528 { "PIC", "APIC", read_apic, free_apic },
3b78c180
DB
529 { NULL }
530};
531
7a019dff
DG
532/**
533 * Get the corresponding ID3v2EMFunc struct for a tag.
534 * @param isv34 Determines if v2.2 or v2.3/4 strings are used
535 * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
536 */
537static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
538{
539 int i = 0;
c4a37885 540 while (id3v2_extra_meta_funcs[i].tag3) {
7a019dff 541 if (!memcmp(tag,
c4a37885
DB
542 (isv34 ? id3v2_extra_meta_funcs[i].tag4 :
543 id3v2_extra_meta_funcs[i].tag3),
7a019dff 544 (isv34 ? 4 : 3)))
c4a37885 545 return &id3v2_extra_meta_funcs[i];
7a019dff
DG
546 i++;
547 }
548 return NULL;
549}
550
e926b5ce
DB
551static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
552 uint8_t flags, ID3v2ExtraMeta **extra_meta)
75411182 553{
18bbe9df 554 int isv34, tlen, unsync;
41770abf 555 char tag[5];
bca6dee3 556 int64_t next, end = avio_tell(s->pb) + len;
75411182 557 int taghdrlen;
eb1e7f78 558 const char *reason = NULL;
ae628ec1 559 AVIOContext pb;
7a019dff 560 AVIOContext *pbx;
18bbe9df 561 unsigned char *buffer = NULL;
0671adbb 562 int buffer_size = 0;
c780b543 563 const ID3v2EMFunc *extra_func;
75411182 564
7d7b8c32 565 switch (version) {
75411182 566 case 2:
7d7b8c32 567 if (flags & 0x40) {
75411182
PD
568 reason = "compression";
569 goto error;
570 }
0671adbb 571 isv34 = 0;
75411182
PD
572 taghdrlen = 6;
573 break;
574
575 case 3:
576 case 4:
0671adbb 577 isv34 = 1;
75411182
PD
578 taghdrlen = 10;
579 break;
580
581 default:
582 reason = "version";
583 goto error;
584 }
585
18bbe9df 586 unsync = flags & 0x80;
75411182 587
ddb44312
AK
588 if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
589 int extlen = get_size(s->pb, 4);
590 if (version == 4)
0671adbb
LB
591 /* In v2.4 the length includes the length field we just read. */
592 extlen -= 4;
ddb44312
AK
593
594 if (extlen < 0) {
595 reason = "invalid extended header length";
596 goto error;
597 }
598 avio_skip(s->pb, extlen);
599 }
75411182 600
7d7b8c32 601 while (len >= taghdrlen) {
40a5dd2f 602 unsigned int tflags = 0;
0671adbb 603 int tunsync = 0;
18bbe9df 604
7d7b8c32 605 if (isv34) {
b7effd4e 606 avio_read(s->pb, tag, 4);
41770abf 607 tag[4] = 0;
0671adbb 608 if (version == 3) {
b7effd4e 609 tlen = avio_rb32(s->pb);
0671adbb 610 } else
3fd5a75b 611 tlen = get_size(s->pb, 4);
0671adbb 612 tflags = avio_rb16(s->pb);
7a07d158 613 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
75411182 614 } else {
b7effd4e 615 avio_read(s->pb, tag, 3);
41770abf 616 tag[3] = 0;
0671adbb 617 tlen = avio_rb24(s->pb);
75411182 618 }
1e18d32d 619 if (tlen < 0 || tlen > len - taghdrlen) {
0671adbb
LB
620 av_log(s, AV_LOG_WARNING,
621 "Invalid size in frame %s, skipping the rest of tag.\n",
622 tag);
75411182 623 break;
c5f4c0fd
AK
624 }
625 len -= taghdrlen + tlen;
a2704c97 626 next = avio_tell(s->pb) + tlen;
75411182 627
1e18d32d
AK
628 if (!tlen) {
629 if (tag[0])
0671adbb
LB
630 av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n",
631 tag);
1e18d32d
AK
632 continue;
633 }
634
a152c77f 635 if (tflags & ID3v2_FLAG_DATALEN) {
b7effd4e 636 avio_rb32(s->pb);
a152c77f
AK
637 tlen -= 4;
638 }
639
407d3d5a 640 if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
0671adbb
LB
641 av_log(s, AV_LOG_WARNING,
642 "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
45a8a02a 643 avio_skip(s->pb, tlen);
7a019dff 644 /* check for text tag or supported special meta tag */
0671adbb
LB
645 } else if (tag[0] == 'T' ||
646 (extra_meta &&
647 (extra_func = get_extra_meta_func(tag, isv34)))) {
18bbe9df 648 if (unsync || tunsync) {
9ae80e6a
AK
649 int64_t end = avio_tell(s->pb) + tlen;
650 uint8_t *b;
18bbe9df 651 av_fast_malloc(&buffer, &buffer_size, tlen);
86f86877
AC
652 if (!buffer) {
653 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
654 goto seek;
655 }
9ae80e6a 656 b = buffer;
af4cc260 657 while (avio_tell(s->pb) < end && !s->pb->eof_reached) {
9ae80e6a 658 *b++ = avio_r8(s->pb);
af4cc260
LB
659 if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 &&
660 !s->pb->eof_reached ) {
9ae80e6a
AK
661 uint8_t val = avio_r8(s->pb);
662 *b++ = val ? val : avio_r8(s->pb);
18bbe9df
AK
663 }
664 }
0671adbb
LB
665 ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL,
666 NULL);
9ae80e6a 667 tlen = b - buffer;
0671adbb 668 pbx = &pb; // read from sync buffer
18bbe9df 669 } else {
7a019dff 670 pbx = s->pb; // read straight from input
18bbe9df 671 }
7a019dff
DG
672 if (tag[0] == 'T')
673 /* parse text tag */
674 read_ttag(s, pbx, tlen, tag);
675 else
676 /* parse special meta tag */
54bc15d5 677 extra_func->read(s, pbx, tlen, tag, extra_meta, isv34);
0671adbb 678 } else if (!tag[0]) {
2e3ca1ff
JM
679 if (tag[1])
680 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
45a8a02a 681 avio_skip(s->pb, tlen);
2e3ca1ff
JM
682 break;
683 }
75411182 684 /* Skip to end of tag */
86f86877 685seek:
6b4aa5da 686 avio_seek(s->pb, next, SEEK_SET);
75411182
PD
687 }
688
0671adbb
LB
689 /* Footer preset, always 10 bytes, skip over it */
690 if (version == 4 && flags & 0x10)
bca6dee3 691 end += 10;
18bbe9df 692
0671adbb 693error:
eb1e7f78 694 if (reason)
0671adbb
LB
695 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n",
696 version, reason);
bca6dee3 697 avio_seek(s->pb, end, SEEK_SET);
18bbe9df 698 av_free(buffer);
75411182 699 return;
75411182 700}
6378b062 701
0671adbb
LB
702void ff_id3v2_read(AVFormatContext *s, const char *magic,
703 ID3v2ExtraMeta **extra_meta)
46a2da76
AK
704{
705 int len, ret;
706 uint8_t buf[ID3v2_HEADER_SIZE];
0671adbb 707 int found_header;
46a2da76
AK
708 int64_t off;
709
710 do {
711 /* save the current offset in case there's nothing to read/skip */
a2704c97 712 off = avio_tell(s->pb);
b7effd4e 713 ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
46a2da76 714 if (ret != ID3v2_HEADER_SIZE)
f7fcd6a2 715 break;
0671adbb
LB
716 found_header = ff_id3v2_match(buf, magic);
717 if (found_header) {
46a2da76
AK
718 /* parse ID3v2 header */
719 len = ((buf[6] & 0x7f) << 21) |
720 ((buf[7] & 0x7f) << 14) |
721 ((buf[8] & 0x7f) << 7) |
722 (buf[9] & 0x7f);
e926b5ce 723 id3v2_parse(s, len, buf[3], buf[5], extra_meta);
46a2da76 724 } else {
6b4aa5da 725 avio_seek(s->pb, off, SEEK_SET);
46a2da76
AK
726 }
727 } while (found_header);
cb6bc576 728 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
c4a37885 729 ff_metadata_conv(&s->metadata, NULL, id3v2_2_metadata_conv);
cb6bc576 730 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
56e2ac6b 731 merge_date(&s->metadata);
46a2da76
AK
732}
733
7a019dff
DG
734void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
735{
736 ID3v2ExtraMeta *current = *extra_meta, *next;
c780b543 737 const ID3v2EMFunc *extra_func;
7a019dff
DG
738
739 while (current) {
c780b543
AK
740 if ((extra_func = get_extra_meta_func(current->tag, 1)))
741 extra_func->free(current->data);
7a019dff
DG
742 next = current->next;
743 av_freep(&current);
744 current = next;
745 }
746}
079ea6ca
AK
747
748int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
749{
750 ID3v2ExtraMeta *cur;
751
752 for (cur = *extra_meta; cur; cur = cur->next) {
753 ID3v2ExtraMetaAPIC *apic;
754 AVStream *st;
755
756 if (strcmp(cur->tag, "APIC"))
757 continue;
758 apic = cur->data;
759
760 if (!(st = avformat_new_stream(s, NULL)))
761 return AVERROR(ENOMEM);
762
763 st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
9200514a
AK
764 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
765 st->codecpar->codec_id = apic->id;
379e5603 766
767 if (apic->description[0])
768 av_dict_set(&st->metadata, "title", apic->description, 0);
769
079ea6ca
AK
770 av_dict_set(&st->metadata, "comment", apic->type, 0);
771
772 av_init_packet(&st->attached_pic);
1afddbe5
AK
773 st->attached_pic.buf = apic->buf;
774 st->attached_pic.data = apic->buf->data;
059a9348 775 st->attached_pic.size = apic->buf->size - AV_INPUT_BUFFER_PADDING_SIZE;
079ea6ca 776 st->attached_pic.stream_index = st->index;
713f3062 777 st->attached_pic.flags |= AV_PKT_FLAG_KEY;
079ea6ca 778
1afddbe5 779 apic->buf = NULL;
079ea6ca
AK
780 }
781
782 return 0;
783}