Merge remote-tracking branch 'newdev/master'
[ffmpeg.git] / libavformat / id3v2.c
1 /*
2  * ID3v2 header parser
3  * Copyright (c) 2003 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
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  *
12  * FFmpeg is distributed in the hope that it will be useful,
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
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "id3v2.h"
23 #include "id3v1.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/intreadwrite.h"
26 #include "metadata.h"
27 #include "avio_internal.h"
28
29 int ff_id3v2_match(const uint8_t *buf, const char * magic)
30 {
31     return  buf[0]         == magic[0] &&
32             buf[1]         == magic[1] &&
33             buf[2]         == magic[2] &&
34             buf[3]         != 0xff &&
35             buf[4]         != 0xff &&
36            (buf[6] & 0x80) ==    0 &&
37            (buf[7] & 0x80) ==    0 &&
38            (buf[8] & 0x80) ==    0 &&
39            (buf[9] & 0x80) ==    0;
40 }
41
42 int ff_id3v2_tag_len(const uint8_t * buf)
43 {
44     int len = ((buf[6] & 0x7f) << 21) +
45               ((buf[7] & 0x7f) << 14) +
46               ((buf[8] & 0x7f) << 7) +
47                (buf[9] & 0x7f) +
48               ID3v2_HEADER_SIZE;
49     if (buf[5] & 0x10)
50         len += ID3v2_HEADER_SIZE;
51     return len;
52 }
53
54 static unsigned int get_size(AVIOContext *s, int len)
55 {
56     int v = 0;
57     while (len--)
58         v = (v << 7) + (avio_r8(s) & 0x7F);
59     return v;
60 }
61
62 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
63 {
64     char *q, dst[512];
65     const char *val = NULL;
66     int len, dstlen = sizeof(dst) - 1;
67     unsigned genre;
68     unsigned int (*get)(AVIOContext*) = avio_rb16;
69
70     dst[0] = 0;
71     if (taglen < 1)
72         return;
73
74     taglen--; /* account for encoding type byte */
75
76     switch (avio_r8(pb)) { /* encoding type */
77
78     case ID3v2_ENCODING_ISO8859:
79         q = dst;
80         while (taglen-- && q - dst < dstlen - 7) {
81             uint8_t tmp;
82             PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
83         }
84         *q = 0;
85         break;
86
87     case ID3v2_ENCODING_UTF16BOM:
88         taglen -= 2;
89         switch (avio_rb16(pb)) {
90         case 0xfffe:
91             get = avio_rl16;
92         case 0xfeff:
93             break;
94         default:
95             av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
96             return;
97         }
98         // fall-through
99
100     case ID3v2_ENCODING_UTF16BE:
101         q = dst;
102         while (taglen > 1 && q - dst < dstlen - 7) {
103             uint32_t ch;
104             uint8_t tmp;
105
106             GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
107             PUT_UTF8(ch, tmp, *q++ = tmp;)
108         }
109         *q = 0;
110         break;
111
112     case ID3v2_ENCODING_UTF8:
113         len = FFMIN(taglen, dstlen);
114         avio_read(pb, dst, len);
115         dst[len] = 0;
116         break;
117     default:
118         av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s.\n", key);
119     }
120
121     if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
122         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
123         && genre <= ID3v1_GENRE_MAX)
124         val = ff_id3v1_genre_str[genre];
125     else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
126         /* dst now contains two 0-terminated strings */
127         dst[dstlen] = 0;
128         len = strlen(dst);
129         key = dst;
130         val = dst + FFMIN(len + 1, dstlen);
131     }
132     else if (*dst)
133         val = dst;
134
135     if (val)
136         av_metadata_set2(&s->metadata, key, val, AV_METADATA_DONT_OVERWRITE);
137 }
138
139 static int is_number(const char *str)
140 {
141     while (*str >= '0' && *str <= '9') str++;
142     return !*str;
143 }
144
145 static AVMetadataTag* get_date_tag(AVMetadata *m, const char *tag)
146 {
147     AVMetadataTag *t;
148     if ((t = av_metadata_get(m, tag, NULL, AV_METADATA_MATCH_CASE)) &&
149         strlen(t->value) == 4 && is_number(t->value))
150         return t;
151     return NULL;
152 }
153
154 static void merge_date(AVMetadata **m)
155 {
156     AVMetadataTag *t;
157     char date[17] = {0};      // YYYY-MM-DD hh:mm
158
159     if (!(t = get_date_tag(*m, "TYER")) &&
160         !(t = get_date_tag(*m, "TYE")))
161         return;
162     av_strlcpy(date, t->value, 5);
163     av_metadata_set2(m, "TYER", NULL, 0);
164     av_metadata_set2(m, "TYE",  NULL, 0);
165
166     if (!(t = get_date_tag(*m, "TDAT")) &&
167         !(t = get_date_tag(*m, "TDA")))
168         goto finish;
169     snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
170     av_metadata_set2(m, "TDAT", NULL, 0);
171     av_metadata_set2(m, "TDA",  NULL, 0);
172
173     if (!(t = get_date_tag(*m, "TIME")) &&
174         !(t = get_date_tag(*m, "TIM")))
175         goto finish;
176     snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
177     av_metadata_set2(m, "TIME", NULL, 0);
178     av_metadata_set2(m, "TIM",  NULL, 0);
179
180 finish:
181     if (date[0])
182         av_metadata_set2(m, "date", date, 0);
183 }
184
185 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
186 {
187     int isv34, unsync;
188     unsigned tlen;
189     char tag[5];
190     int64_t next;
191     int taghdrlen;
192     const char *reason;
193     AVIOContext pb;
194     unsigned char *buffer = NULL;
195     int buffer_size = 0;
196
197     switch (version) {
198     case 2:
199         if (flags & 0x40) {
200             reason = "compression";
201             goto error;
202         }
203         isv34 = 0;
204         taghdrlen = 6;
205         break;
206
207     case 3:
208     case 4:
209         isv34 = 1;
210         taghdrlen = 10;
211         break;
212
213     default:
214         reason = "version";
215         goto error;
216     }
217
218     unsync = flags & 0x80;
219
220     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
221         avio_skip(s->pb, get_size(s->pb, 4));
222
223     while (len >= taghdrlen) {
224         unsigned int tflags;
225         int tunsync = 0;
226
227         if (isv34) {
228             avio_read(s->pb, tag, 4);
229             tag[4] = 0;
230             if(version==3){
231                 tlen = avio_rb32(s->pb);
232             }else
233                 tlen = get_size(s->pb, 4);
234             tflags = avio_rb16(s->pb);
235             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
236         } else {
237             avio_read(s->pb, tag, 3);
238             tag[3] = 0;
239             tlen = avio_rb24(s->pb);
240         }
241         if (tlen > (1<<28))
242             break;
243         len -= taghdrlen + tlen;
244
245         if (len < 0)
246             break;
247
248         next = avio_tell(s->pb) + tlen;
249
250         if (tflags & ID3v2_FLAG_DATALEN) {
251             avio_rb32(s->pb);
252             tlen -= 4;
253         }
254
255         if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
256             av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
257             avio_skip(s->pb, tlen);
258         } else if (tag[0] == 'T') {
259             if (unsync || tunsync) {
260                 int i, j;
261                 av_fast_malloc(&buffer, &buffer_size, tlen);
262                 for (i = 0, j = 0; i < tlen; i++, j++) {
263                     buffer[j] = avio_r8(s->pb);
264                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
265                         /* Unsynchronised byte, skip it */
266                         j--;
267                     }
268                 }
269                 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
270                 read_ttag(s, &pb, j, tag);
271             } else {
272                 read_ttag(s, s->pb, tlen, tag);
273             }
274         }
275         else if (!tag[0]) {
276             if (tag[1])
277                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
278             avio_skip(s->pb, tlen);
279             break;
280         }
281         /* Skip to end of tag */
282         avio_seek(s->pb, next, SEEK_SET);
283     }
284
285     if (len > 0) {
286         /* Skip padding */
287         avio_skip(s->pb, len);
288     }
289     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
290         avio_skip(s->pb, 10);
291
292     av_free(buffer);
293     return;
294
295   error:
296     av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
297     avio_seek(s->pb, len, SEEK_CUR);
298     av_free(buffer);
299 }
300
301 void ff_id3v2_read(AVFormatContext *s, const char *magic)
302 {
303     int len, ret;
304     uint8_t buf[ID3v2_HEADER_SIZE];
305     int     found_header;
306     int64_t off;
307
308     do {
309         /* save the current offset in case there's nothing to read/skip */
310         off = avio_tell(s->pb);
311         ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
312         if (ret != ID3v2_HEADER_SIZE)
313             break;
314             found_header = ff_id3v2_match(buf, magic);
315             if (found_header) {
316             /* parse ID3v2 header */
317             len = ((buf[6] & 0x7f) << 21) |
318                   ((buf[7] & 0x7f) << 14) |
319                   ((buf[8] & 0x7f) << 7) |
320                    (buf[9] & 0x7f);
321             ff_id3v2_parse(s, len, buf[3], buf[5]);
322         } else {
323             avio_seek(s->pb, off, SEEK_SET);
324         }
325     } while (found_header);
326     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
327     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
328     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
329     merge_date(&s->metadata);
330 }
331
332 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
333     { "TALB", "album"},
334     { "TCOM", "composer"},
335     { "TCON", "genre"},
336     { "TCOP", "copyright"},
337     { "TENC", "encoded_by"},
338     { "TIT2", "title"},
339     { "TLAN", "language"},
340     { "TPE1", "artist"},
341     { "TPE2", "album_artist"},
342     { "TPE3", "performer"},
343     { "TPOS", "disc"},
344     { "TPUB", "publisher"},
345     { "TRCK", "track"},
346     { "TSSE", "encoder"},
347     { 0 }
348 };
349
350 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
351     { "TDRL", "date"},
352     { "TDRC", "date"},
353     { "TDEN", "creation_time"},
354     { "TSOA", "album-sort"},
355     { "TSOP", "artist-sort"},
356     { "TSOT", "title-sort"},
357     { 0 }
358 };
359
360 const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
361     { "TAL",  "album"},
362     { "TCO",  "genre"},
363     { "TT2",  "title"},
364     { "TEN",  "encoded_by"},
365     { "TP1",  "artist"},
366     { "TP2",  "album_artist"},
367     { "TP3",  "performer"},
368     { "TRK",  "track"},
369     { 0 }
370 };
371
372
373 const char ff_id3v2_tags[][4] = {
374    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
375    "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
376    "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
377    "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
378    { 0 },
379 };
380
381 const char ff_id3v2_4_tags[][4] = {
382    "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
383    "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
384    { 0 },
385 };
386
387 const char ff_id3v2_3_tags[][4] = {
388    "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
389    { 0 },
390 };