]> git.sesse.net Git - ffmpeg/blob - libavformat/id3v2.c
Check for out of bounds reads in the Delphine Software International CIN decoder.
[ffmpeg] / libavformat / id3v2.c
1 /*
2  * Copyright (c) 2003 Fabrice Bellard
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 /**
22  * @file
23  * ID3v2 header parser
24  *
25  * Specifications available at:
26  * http://id3.org/Developer_Information
27  */
28
29 #include "id3v2.h"
30 #include "id3v1.h"
31 #include "libavutil/avstring.h"
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/dict.h"
34 #include "avio_internal.h"
35
36 int ff_id3v2_match(const uint8_t *buf, const char * magic)
37 {
38     return  buf[0]         == magic[0] &&
39             buf[1]         == magic[1] &&
40             buf[2]         == magic[2] &&
41             buf[3]         != 0xff &&
42             buf[4]         != 0xff &&
43            (buf[6] & 0x80) ==    0 &&
44            (buf[7] & 0x80) ==    0 &&
45            (buf[8] & 0x80) ==    0 &&
46            (buf[9] & 0x80) ==    0;
47 }
48
49 int ff_id3v2_tag_len(const uint8_t * buf)
50 {
51     int len = ((buf[6] & 0x7f) << 21) +
52               ((buf[7] & 0x7f) << 14) +
53               ((buf[8] & 0x7f) << 7) +
54                (buf[9] & 0x7f) +
55               ID3v2_HEADER_SIZE;
56     if (buf[5] & 0x10)
57         len += ID3v2_HEADER_SIZE;
58     return len;
59 }
60
61 static unsigned int get_size(AVIOContext *s, int len)
62 {
63     int v = 0;
64     while (len--)
65         v = (v << 7) + (avio_r8(s) & 0x7F);
66     return v;
67 }
68
69 /**
70  * Free GEOB type extra metadata.
71  */
72 static void free_geobtag(void *obj)
73 {
74     ID3v2ExtraMetaGEOB *geob = obj;
75     av_free(geob->mime_type);
76     av_free(geob->file_name);
77     av_free(geob->description);
78     av_free(geob->data);
79     av_free(geob);
80 }
81
82 /**
83  * Decode characters to UTF-8 according to encoding type. The decoded buffer is
84  * always null terminated.
85  *
86  * @param dst Pointer where the address of the buffer with the decoded bytes is
87  * stored. Buffer must be freed by caller.
88  * @param dstlen Pointer to an int where the length of the decoded string
89  * is stored (in bytes, incl. null termination)
90  * @param maxread Pointer to maximum number of characters to read from the
91  * AVIOContext. After execution the value is decremented by the number of bytes
92  * actually read.
93  * @seeknull If true, decoding stops after the first U+0000 character found, if
94  * there is any before maxread is reached
95  * @returns 0 if no error occured, dst is uninitialized on error
96  */
97 static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
98                       uint8_t **dst, int *dstlen, int *maxread, const int seeknull)
99 {
100     int len, ret;
101     uint8_t tmp;
102     uint32_t ch = 1;
103     int left = *maxread;
104     unsigned int (*get)(AVIOContext*) = avio_rb16;
105     AVIOContext *dynbuf;
106
107     if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
108         av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
109         return ret;
110     }
111
112     switch (encoding) {
113
114     case ID3v2_ENCODING_ISO8859:
115         while (left && (!seeknull || ch)) {
116             ch = avio_r8(pb);
117             PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
118             left--;
119         }
120         break;
121
122     case ID3v2_ENCODING_UTF16BOM:
123         if ((left -= 2) < 0) {
124             av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
125             avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
126             av_freep(dst);
127             return AVERROR_INVALIDDATA;
128         }
129         switch (avio_rb16(pb)) {
130         case 0xfffe:
131             get = avio_rl16;
132         case 0xfeff:
133             break;
134         default:
135             av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
136             avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
137             av_freep(dst);
138             *maxread = left;
139             return AVERROR_INVALIDDATA;
140         }
141         // fall-through
142
143     case ID3v2_ENCODING_UTF16BE:
144         while ((left > 1) && (!seeknull || ch)) {
145             GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
146             PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
147         }
148         if (left < 0)
149             left += 2; /* did not read last char from pb */
150         break;
151
152     case ID3v2_ENCODING_UTF8:
153         while (left && (!seeknull || ch)) {
154             ch = avio_r8(pb);
155             avio_w8(dynbuf, ch);
156             left--;
157         }
158         break;
159     default:
160         av_log(s, AV_LOG_WARNING, "Unknown encoding\n");
161     }
162
163     if (ch)
164         avio_w8(dynbuf, 0);
165
166     len = avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
167     if (dstlen)
168         *dstlen = len;
169
170     *maxread = left;
171
172     return 0;
173 }
174
175 /**
176  * Parse a text tag.
177  */
178 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
179 {
180     uint8_t *dst;
181     const char *val = NULL;
182     int len, dstlen;
183     unsigned genre;
184
185     if (taglen < 1)
186         return;
187
188     taglen--; /* account for encoding type byte */
189
190     if (decode_str(s, pb, avio_r8(pb), &dst, &dstlen, &taglen, 0) < 0) {
191         av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
192         return;
193     }
194
195     if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
196         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
197         && genre <= ID3v1_GENRE_MAX)
198         val = ff_id3v1_genre_str[genre];
199     else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
200         /* dst now contains two 0-terminated strings */
201         dst[dstlen] = 0;
202         len = strlen(dst);
203         key = dst;
204         val = dst + FFMIN(len + 1, dstlen);
205     }
206     else if (*dst)
207         val = dst;
208
209     if (val)
210         av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
211
212     av_free(dst);
213 }
214
215 /**
216  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
217  */
218 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
219 {
220     ID3v2ExtraMetaGEOB *geob_data = NULL;
221     ID3v2ExtraMeta *new_extra = NULL;
222     char encoding;
223     unsigned int len;
224
225     if (taglen < 1)
226         return;
227
228     geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
229     if (!geob_data) {
230         av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB));
231         return;
232     }
233
234     new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
235     if (!new_extra) {
236         av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta));
237         goto fail;
238     }
239
240     /* read encoding type byte */
241     encoding = avio_r8(pb);
242     taglen--;
243
244     /* read MIME type (always ISO-8859) */
245     if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, NULL, &taglen, 1) < 0
246         || taglen <= 0)
247         goto fail;
248
249     /* read file name */
250     if (decode_str(s, pb, encoding, &geob_data->file_name, NULL, &taglen, 1) < 0
251         || taglen <= 0)
252         goto fail;
253
254     /* read content description */
255     if (decode_str(s, pb, encoding, &geob_data->description, NULL, &taglen, 1) < 0
256         || taglen < 0)
257         goto fail;
258
259     if (taglen) {
260         /* save encapsulated binary data */
261         geob_data->data = av_malloc(taglen);
262         if (!geob_data->data) {
263             av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
264             goto fail;
265         }
266         if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
267             av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n");
268         geob_data->datasize = len;
269     } else {
270         geob_data->data = NULL;
271         geob_data->datasize = 0;
272     }
273
274     /* add data to the list */
275     new_extra->tag = "GEOB";
276     new_extra->data = geob_data;
277     new_extra->next = *extra_meta;
278     *extra_meta = new_extra;
279
280     return;
281
282 fail:
283     av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
284     free_geobtag(geob_data);
285     av_free(new_extra);
286     return;
287 }
288
289 static int is_number(const char *str)
290 {
291     while (*str >= '0' && *str <= '9') str++;
292     return !*str;
293 }
294
295 static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
296 {
297     AVDictionaryEntry *t;
298     if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
299         strlen(t->value) == 4 && is_number(t->value))
300         return t;
301     return NULL;
302 }
303
304 static void merge_date(AVDictionary **m)
305 {
306     AVDictionaryEntry *t;
307     char date[17] = {0};      // YYYY-MM-DD hh:mm
308
309     if (!(t = get_date_tag(*m, "TYER")) &&
310         !(t = get_date_tag(*m, "TYE")))
311         return;
312     av_strlcpy(date, t->value, 5);
313     av_dict_set(m, "TYER", NULL, 0);
314     av_dict_set(m, "TYE",  NULL, 0);
315
316     if (!(t = get_date_tag(*m, "TDAT")) &&
317         !(t = get_date_tag(*m, "TDA")))
318         goto finish;
319     snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
320     av_dict_set(m, "TDAT", NULL, 0);
321     av_dict_set(m, "TDA",  NULL, 0);
322
323     if (!(t = get_date_tag(*m, "TIME")) &&
324         !(t = get_date_tag(*m, "TIM")))
325         goto finish;
326     snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
327     av_dict_set(m, "TIME", NULL, 0);
328     av_dict_set(m, "TIM",  NULL, 0);
329
330 finish:
331     if (date[0])
332         av_dict_set(m, "date", date, 0);
333 }
334
335 /**
336  * Get the corresponding ID3v2EMFunc struct for a tag.
337  * @param isv34 Determines if v2.2 or v2.3/4 strings are used
338  * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
339  */
340 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
341 {
342     int i = 0;
343     while (ff_id3v2_extra_meta_funcs[i].tag3) {
344         if (!memcmp(tag,
345                     (isv34 ?
346                         ff_id3v2_extra_meta_funcs[i].tag4 :
347                         ff_id3v2_extra_meta_funcs[i].tag3),
348                     (isv34 ? 4 : 3)))
349             return &ff_id3v2_extra_meta_funcs[i];
350         i++;
351     }
352     return &ff_id3v2_extra_meta_funcs[i];
353 }
354
355 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
356 {
357     int isv34, unsync;
358     unsigned tlen;
359     char tag[5];
360     int64_t next, end = avio_tell(s->pb) + len;
361     int taghdrlen;
362     const char *reason = NULL;
363     AVIOContext pb;
364     AVIOContext *pbx;
365     unsigned char *buffer = NULL;
366     int buffer_size = 0;
367     void (*extra_func)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta**) = NULL;
368
369     switch (version) {
370     case 2:
371         if (flags & 0x40) {
372             reason = "compression";
373             goto error;
374         }
375         isv34 = 0;
376         taghdrlen = 6;
377         break;
378
379     case 3:
380     case 4:
381         isv34 = 1;
382         taghdrlen = 10;
383         break;
384
385     default:
386         reason = "version";
387         goto error;
388     }
389
390     unsync = flags & 0x80;
391
392     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
393         avio_skip(s->pb, get_size(s->pb, 4));
394
395     while (len >= taghdrlen) {
396         unsigned int tflags = 0;
397         int tunsync = 0;
398
399         if (isv34) {
400             avio_read(s->pb, tag, 4);
401             tag[4] = 0;
402             if(version==3){
403                 tlen = avio_rb32(s->pb);
404             }else
405                 tlen = get_size(s->pb, 4);
406             tflags = avio_rb16(s->pb);
407             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
408         } else {
409             avio_read(s->pb, tag, 3);
410             tag[3] = 0;
411             tlen = avio_rb24(s->pb);
412         }
413         if (tlen > (1<<28) || !tlen)
414             break;
415         len -= taghdrlen + tlen;
416
417         if (len < 0)
418             break;
419
420         next = avio_tell(s->pb) + tlen;
421
422         if (tflags & ID3v2_FLAG_DATALEN) {
423             if (tlen < 4)
424                 break;
425             avio_rb32(s->pb);
426             tlen -= 4;
427         }
428
429         if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
430             av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
431             avio_skip(s->pb, tlen);
432         /* check for text tag or supported special meta tag */
433         } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)->read))) {
434             if (unsync || tunsync) {
435                 int i, j;
436                 av_fast_malloc(&buffer, &buffer_size, tlen);
437                 if (!buffer) {
438                     av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
439                     goto seek;
440                 }
441                 for (i = 0, j = 0; i < tlen; i++, j++) {
442                     buffer[j] = avio_r8(s->pb);
443                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
444                         /* Unsynchronised byte, skip it */
445                         j--;
446                     }
447                 }
448                 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
449                 tlen = j;
450                 pbx = &pb; // read from sync buffer
451             } else {
452                 pbx = s->pb; // read straight from input
453             }
454             if (tag[0] == 'T')
455                 /* parse text tag */
456                 read_ttag(s, pbx, tlen, tag);
457             else
458                 /* parse special meta tag */
459                 extra_func(s, pbx, tlen, tag, extra_meta);
460         }
461         else if (!tag[0]) {
462             if (tag[1])
463                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
464             avio_skip(s->pb, tlen);
465             break;
466         }
467         /* Skip to end of tag */
468 seek:
469         avio_seek(s->pb, next, SEEK_SET);
470     }
471
472     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
473         end += 10;
474
475   error:
476     if (reason)
477         av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
478     avio_seek(s->pb, end, SEEK_SET);
479     av_free(buffer);
480     return;
481 }
482
483 void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
484 {
485     int len, ret;
486     uint8_t buf[ID3v2_HEADER_SIZE];
487     int     found_header;
488     int64_t off;
489
490     do {
491         /* save the current offset in case there's nothing to read/skip */
492         off = avio_tell(s->pb);
493         ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
494         if (ret != ID3v2_HEADER_SIZE)
495             break;
496             found_header = ff_id3v2_match(buf, magic);
497             if (found_header) {
498             /* parse ID3v2 header */
499             len = ((buf[6] & 0x7f) << 21) |
500                   ((buf[7] & 0x7f) << 14) |
501                   ((buf[8] & 0x7f) << 7) |
502                    (buf[9] & 0x7f);
503             ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
504         } else {
505             avio_seek(s->pb, off, SEEK_SET);
506         }
507     } while (found_header);
508     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
509     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
510     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
511     merge_date(&s->metadata);
512 }
513
514 void ff_id3v2_read(AVFormatContext *s, const char *magic)
515 {
516     ff_id3v2_read_all(s, magic, NULL);
517 }
518
519 void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
520 {
521     ID3v2ExtraMeta *current = *extra_meta, *next;
522     void (*free_func)(void *);
523
524     while (current) {
525         if ((free_func = get_extra_meta_func(current->tag, 1)->free))
526             free_func(current->data);
527         next = current->next;
528         av_freep(&current);
529         current = next;
530     }
531 }
532
533 const ID3v2EMFunc ff_id3v2_extra_meta_funcs[] = {
534     { "GEO", "GEOB", read_geobtag, free_geobtag },
535     { NULL,  NULL,   NULL,         NULL }
536 };
537
538 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
539     { "TALB", "album"},
540     { "TCOM", "composer"},
541     { "TCON", "genre"},
542     { "TCOP", "copyright"},
543     { "TENC", "encoded_by"},
544     { "TIT2", "title"},
545     { "TLAN", "language"},
546     { "TPE1", "artist"},
547     { "TPE2", "album_artist"},
548     { "TPE3", "performer"},
549     { "TPOS", "disc"},
550     { "TPUB", "publisher"},
551     { "TRCK", "track"},
552     { "TSSE", "encoder"},
553     { 0 }
554 };
555
556 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
557     { "TDRL", "date"},
558     { "TDRC", "date"},
559     { "TDEN", "creation_time"},
560     { "TSOA", "album-sort"},
561     { "TSOP", "artist-sort"},
562     { "TSOT", "title-sort"},
563     { 0 }
564 };
565
566 const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
567     { "TAL",  "album"},
568     { "TCO",  "genre"},
569     { "TT2",  "title"},
570     { "TEN",  "encoded_by"},
571     { "TP1",  "artist"},
572     { "TP2",  "album_artist"},
573     { "TP3",  "performer"},
574     { "TRK",  "track"},
575     { 0 }
576 };
577
578
579 const char ff_id3v2_tags[][4] = {
580    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
581    "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
582    "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
583    "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
584    { 0 },
585 };
586
587 const char ff_id3v2_4_tags[][4] = {
588    "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
589    "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
590    { 0 },
591 };
592
593 const char ff_id3v2_3_tags[][4] = {
594    "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
595    { 0 },
596 };