id3v2: skip encrypted/compressed frames
[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
28 int ff_id3v2_match(const uint8_t *buf, const char * magic)
29 {
30     return  buf[0]         == magic[0] &&
31             buf[1]         == magic[1] &&
32             buf[2]         == magic[2] &&
33             buf[3]         != 0xff &&
34             buf[4]         != 0xff &&
35            (buf[6] & 0x80) ==    0 &&
36            (buf[7] & 0x80) ==    0 &&
37            (buf[8] & 0x80) ==    0 &&
38            (buf[9] & 0x80) ==    0;
39 }
40
41 int ff_id3v2_tag_len(const uint8_t * buf)
42 {
43     int len = ((buf[6] & 0x7f) << 21) +
44               ((buf[7] & 0x7f) << 14) +
45               ((buf[8] & 0x7f) << 7) +
46                (buf[9] & 0x7f) +
47               ID3v2_HEADER_SIZE;
48     if (buf[5] & 0x10)
49         len += ID3v2_HEADER_SIZE;
50     return len;
51 }
52
53 void ff_id3v2_read(AVFormatContext *s, const char *magic)
54 {
55     int len, ret;
56     uint8_t buf[ID3v2_HEADER_SIZE];
57     int     found_header;
58     int64_t off;
59
60     do {
61         /* save the current offset in case there's nothing to read/skip */
62         off = url_ftell(s->pb);
63         ret = get_buffer(s->pb, buf, ID3v2_HEADER_SIZE);
64         if (ret != ID3v2_HEADER_SIZE)
65             return;
66             found_header = ff_id3v2_match(buf, magic);
67             if (found_header) {
68             /* parse ID3v2 header */
69             len = ((buf[6] & 0x7f) << 21) |
70                   ((buf[7] & 0x7f) << 14) |
71                   ((buf[8] & 0x7f) << 7) |
72                    (buf[9] & 0x7f);
73             ff_id3v2_parse(s, len, buf[3], buf[5]);
74         } else {
75             url_fseek(s->pb, off, SEEK_SET);
76         }
77     } while (found_header);
78 }
79
80 static unsigned int get_size(ByteIOContext *s, int len)
81 {
82     int v = 0;
83     while (len--)
84         v = (v << 7) + (get_byte(s) & 0x7F);
85     return v;
86 }
87
88 static void read_ttag(AVFormatContext *s, ByteIOContext *pb, int taglen, const char *key)
89 {
90     char *q, dst[512];
91     const char *val = NULL;
92     int len, dstlen = sizeof(dst) - 1;
93     unsigned genre;
94     unsigned int (*get)(ByteIOContext*) = get_be16;
95
96     dst[0] = 0;
97     if (taglen < 1)
98         return;
99
100     taglen--; /* account for encoding type byte */
101
102     switch (get_byte(pb)) { /* encoding type */
103
104     case 0:  /* ISO-8859-1 (0 - 255 maps directly into unicode) */
105         q = dst;
106         while (taglen-- && q - dst < dstlen - 7) {
107             uint8_t tmp;
108             PUT_UTF8(get_byte(pb), tmp, *q++ = tmp;)
109         }
110         *q = 0;
111         break;
112
113     case 1:  /* UTF-16 with BOM */
114         taglen -= 2;
115         switch (get_be16(pb)) {
116         case 0xfffe:
117             get = get_le16;
118         case 0xfeff:
119             break;
120         default:
121             av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
122             return;
123         }
124         // fall-through
125
126     case 2:  /* UTF-16BE without BOM */
127         q = dst;
128         while (taglen > 1 && q - dst < dstlen - 7) {
129             uint32_t ch;
130             uint8_t tmp;
131
132             GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
133             PUT_UTF8(ch, tmp, *q++ = tmp;)
134         }
135         *q = 0;
136         break;
137
138     case 3:  /* UTF-8 */
139         len = FFMIN(taglen, dstlen);
140         get_buffer(pb, dst, len);
141         dst[len] = 0;
142         break;
143     default:
144         av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
145     }
146
147     if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
148         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
149         && genre <= ID3v1_GENRE_MAX)
150         val = ff_id3v1_genre_str[genre];
151     else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
152         /* dst now contains two 0-terminated strings */
153         dst[dstlen] = 0;
154         len = strlen(dst);
155         key = dst;
156         val = dst + FFMIN(len + 1, dstlen);
157     }
158     else if (*dst)
159         val = dst;
160
161     if (val)
162         av_metadata_set2(&s->metadata, key, val, 0);
163 }
164
165 void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
166 {
167     int isv34, tlen, unsync;
168     char tag[5];
169     int64_t next;
170     int taghdrlen;
171     const char *reason;
172     ByteIOContext pb;
173     unsigned char *buffer = NULL;
174     int buffer_size = 0;
175
176     switch (version) {
177     case 2:
178         if (flags & 0x40) {
179             reason = "compression";
180             goto error;
181         }
182         isv34 = 0;
183         taghdrlen = 6;
184         break;
185
186     case 3:
187     case 4:
188         isv34 = 1;
189         taghdrlen = 10;
190         break;
191
192     default:
193         reason = "version";
194         goto error;
195     }
196
197     unsync = flags & 0x80;
198
199     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
200         url_fskip(s->pb, get_size(s->pb, 4));
201
202     while (len >= taghdrlen) {
203         unsigned int tflags;
204         int tunsync = 0;
205
206         if (isv34) {
207             get_buffer(s->pb, tag, 4);
208             tag[4] = 0;
209             if(version==3){
210                 tlen = get_be32(s->pb);
211             }else
212                 tlen = get_size(s->pb, 4);
213             tflags = get_be16(s->pb);
214             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
215         } else {
216             get_buffer(s->pb, tag, 3);
217             tag[3] = 0;
218             tlen = get_be24(s->pb);
219         }
220         len -= taghdrlen + tlen;
221
222         if (len < 0)
223             break;
224
225         next = url_ftell(s->pb) + tlen;
226
227         if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
228             av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
229             url_fskip(s->pb, tlen);
230         } else if (tag[0] == 'T') {
231             if (unsync || tunsync) {
232                 int i, j;
233                 av_fast_malloc(&buffer, &buffer_size, tlen);
234                 for (i = 0, j = 0; i < tlen; i++, j++) {
235                     buffer[j] = get_byte(s->pb);
236                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
237                         /* Unsynchronised byte, skip it */
238                         j--;
239                     }
240                 }
241                 init_put_byte(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
242                 read_ttag(s, &pb, j, tag);
243             } else {
244                 read_ttag(s, s->pb, tlen, tag);
245             }
246         }
247         else if (!tag[0]) {
248             if (tag[1])
249                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
250             url_fskip(s->pb, tlen);
251             break;
252         }
253         /* Skip to end of tag */
254         url_fseek(s->pb, next, SEEK_SET);
255     }
256     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_metadata_conv);
257
258     if (len > 0) {
259         /* Skip padding */
260         url_fskip(s->pb, len);
261     }
262     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
263         url_fskip(s->pb, 10);
264
265     av_free(buffer);
266     return;
267
268   error:
269     av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
270     url_fskip(s->pb, len);
271     av_free(buffer);
272 }
273
274 const AVMetadataConv ff_id3v2_metadata_conv[] = {
275     { "TALB", "album"},
276     { "TAL",  "album"},
277     { "TCOM", "composer"},
278     { "TCON", "genre"},
279     { "TCO",  "genre"},
280     { "TCOP", "copyright"},
281     { "TDRL", "date"},
282     { "TDRC", "date"},
283     { "TDEN", "creation_time"},
284     { "TENC", "encoded_by"},
285     { "TEN",  "encoded_by"},
286     { "TIT2", "title"},
287     { "TT2",  "title"},
288     { "TLAN", "language"},
289     { "TPE1", "artist"},
290     { "TP1",  "artist"},
291     { "TPE2", "album_artist"},
292     { "TP2",  "album_artist"},
293     { "TPE3", "performer"},
294     { "TP3",  "performer"},
295     { "TPOS", "disc"},
296     { "TPUB", "publisher"},
297     { "TRCK", "track"},
298     { "TRK",  "track"},
299     { "TSOA", "album-sort"},
300     { "TSOP", "artist-sort"},
301     { "TSOT", "title-sort"},
302     { "TSSE", "encoder"},
303     { 0 }
304 };
305
306 const char ff_id3v2_tags[][4] = {
307    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
308    "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
309    "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
310    "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
311    "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
312    { 0 },
313 };