des: add possibility to calculate DES-CBC-MAC with small buffer
[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
22#include "id3v2.h"
75411182
PD
23#include "id3v1.h"
24#include "libavutil/avstring.h"
3a1350e8 25#include "libavutil/intreadwrite.h"
d2d67e42 26#include "libavutil/dict.h"
e731b8d8 27#include "avio_internal.h"
2ea512a6 28
3a1350e8 29int ff_id3v2_match(const uint8_t *buf, const char * magic)
2ea512a6 30{
3a1350e8
MK
31 return buf[0] == magic[0] &&
32 buf[1] == magic[1] &&
33 buf[2] == magic[2] &&
7d7b8c32
DB
34 buf[3] != 0xff &&
35 buf[4] != 0xff &&
36 (buf[6] & 0x80) == 0 &&
37 (buf[7] & 0x80) == 0 &&
38 (buf[8] & 0x80) == 0 &&
1d4b1bf2 39 (buf[9] & 0x80) == 0;
2ea512a6 40}
ac3ef4a4
AC
41
42int ff_id3v2_tag_len(const uint8_t * buf)
43{
44 int len = ((buf[6] & 0x7f) << 21) +
7d7b8c32
DB
45 ((buf[7] & 0x7f) << 14) +
46 ((buf[8] & 0x7f) << 7) +
47 (buf[9] & 0x7f) +
48 ID3v2_HEADER_SIZE;
ac3ef4a4
AC
49 if (buf[5] & 0x10)
50 len += ID3v2_HEADER_SIZE;
51 return len;
52}
75411182 53
ae628ec1 54static unsigned int get_size(AVIOContext *s, int len)
75411182 55{
7d7b8c32
DB
56 int v = 0;
57 while (len--)
b7effd4e 58 v = (v << 7) + (avio_r8(s) & 0x7F);
75411182
PD
59 return v;
60}
61
ae628ec1 62static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
75411182
PD
63{
64 char *q, dst[512];
41770abf 65 const char *val = NULL;
75411182
PD
66 int len, dstlen = sizeof(dst) - 1;
67 unsigned genre;
b7effd4e 68 unsigned int (*get)(AVIOContext*) = avio_rb16;
75411182 69
7d7b8c32
DB
70 dst[0] = 0;
71 if (taglen < 1)
75411182
PD
72 return;
73
74 taglen--; /* account for encoding type byte */
75
b7effd4e 76 switch (avio_r8(pb)) { /* encoding type */
75411182 77
d66eff36 78 case ID3v2_ENCODING_ISO8859:
75411182 79 q = dst;
787f8fad 80 while (taglen-- && q - dst < dstlen - 7) {
75411182 81 uint8_t tmp;
b7effd4e 82 PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
75411182 83 }
9aa1bcce 84 *q = 0;
75411182
PD
85 break;
86
d66eff36 87 case ID3v2_ENCODING_UTF16BOM:
20c68378 88 taglen -= 2;
b7effd4e 89 switch (avio_rb16(pb)) {
20c68378 90 case 0xfffe:
b7effd4e 91 get = avio_rl16;
20c68378
AK
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
d66eff36 100 case ID3v2_ENCODING_UTF16BE:
20c68378
AK
101 q = dst;
102 while (taglen > 1 && q - dst < dstlen - 7) {
103 uint32_t ch;
104 uint8_t tmp;
105
18bbe9df 106 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
20c68378
AK
107 PUT_UTF8(ch, tmp, *q++ = tmp;)
108 }
109 *q = 0;
110 break;
111
d66eff36 112 case ID3v2_ENCODING_UTF8:
037e9afd 113 len = FFMIN(taglen, dstlen);
b7effd4e 114 avio_read(pb, dst, len);
75411182
PD
115 dst[len] = 0;
116 break;
20c68378 117 default:
fb61a7c5 118 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s.\n", key);
75411182
PD
119 }
120
41770abf 121 if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
75411182
PD
122 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
123 && genre <= ID3v1_GENRE_MAX)
41770abf
AK
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;
75411182 134
41770abf 135 if (val)
d2d67e42 136 av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
75411182
PD
137}
138
56e2ac6b
AK
139static int is_number(const char *str)
140{
141 while (*str >= '0' && *str <= '9') str++;
142 return !*str;
143}
144
d2d67e42 145static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
56e2ac6b 146{
d2d67e42
AK
147 AVDictionaryEntry *t;
148 if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
56e2ac6b
AK
149 strlen(t->value) == 4 && is_number(t->value))
150 return t;
151 return NULL;
152}
153
d2d67e42 154static void merge_date(AVDictionary **m)
56e2ac6b 155{
d2d67e42 156 AVDictionaryEntry *t;
56e2ac6b
AK
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);
d2d67e42
AK
163 av_dict_set(m, "TYER", NULL, 0);
164 av_dict_set(m, "TYE", NULL, 0);
56e2ac6b
AK
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);
d2d67e42
AK
170 av_dict_set(m, "TDAT", NULL, 0);
171 av_dict_set(m, "TDA", NULL, 0);
56e2ac6b
AK
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);
d2d67e42
AK
177 av_dict_set(m, "TIME", NULL, 0);
178 av_dict_set(m, "TIM", NULL, 0);
56e2ac6b
AK
179
180finish:
181 if (date[0])
d2d67e42 182 av_dict_set(m, "date", date, 0);
56e2ac6b
AK
183}
184
46a2da76 185static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
75411182 186{
18bbe9df 187 int isv34, tlen, unsync;
41770abf 188 char tag[5];
bca6dee3 189 int64_t next, end = avio_tell(s->pb) + len;
75411182 190 int taghdrlen;
eb1e7f78 191 const char *reason = NULL;
ae628ec1 192 AVIOContext pb;
18bbe9df
AK
193 unsigned char *buffer = NULL;
194 int buffer_size = 0;
75411182 195
7d7b8c32 196 switch (version) {
75411182 197 case 2:
7d7b8c32 198 if (flags & 0x40) {
75411182
PD
199 reason = "compression";
200 goto error;
201 }
202 isv34 = 0;
203 taghdrlen = 6;
204 break;
205
206 case 3:
207 case 4:
208 isv34 = 1;
209 taghdrlen = 10;
210 break;
211
212 default:
213 reason = "version";
214 goto error;
215 }
216
18bbe9df 217 unsync = flags & 0x80;
75411182 218
7d7b8c32 219 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
45a8a02a 220 avio_skip(s->pb, get_size(s->pb, 4));
75411182 221
7d7b8c32 222 while (len >= taghdrlen) {
40a5dd2f 223 unsigned int tflags = 0;
18bbe9df
AK
224 int tunsync = 0;
225
7d7b8c32 226 if (isv34) {
b7effd4e 227 avio_read(s->pb, tag, 4);
41770abf 228 tag[4] = 0;
3fd5a75b 229 if(version==3){
b7effd4e 230 tlen = avio_rb32(s->pb);
3fd5a75b
MN
231 }else
232 tlen = get_size(s->pb, 4);
b7effd4e 233 tflags = avio_rb16(s->pb);
7a07d158 234 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
75411182 235 } else {
b7effd4e 236 avio_read(s->pb, tag, 3);
41770abf 237 tag[3] = 0;
b7effd4e 238 tlen = avio_rb24(s->pb);
75411182 239 }
86f86877 240 if (tlen <= 0 || tlen > len - taghdrlen) {
c5f4c0fd 241 av_log(s, AV_LOG_WARNING, "Invalid size in frame %s, skipping the rest of tag.\n", tag);
75411182 242 break;
c5f4c0fd
AK
243 }
244 len -= taghdrlen + tlen;
a2704c97 245 next = avio_tell(s->pb) + tlen;
75411182 246
a152c77f 247 if (tflags & ID3v2_FLAG_DATALEN) {
b7effd4e 248 avio_rb32(s->pb);
a152c77f
AK
249 tlen -= 4;
250 }
251
407d3d5a
AK
252 if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
253 av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
45a8a02a 254 avio_skip(s->pb, tlen);
407d3d5a 255 } else if (tag[0] == 'T') {
18bbe9df
AK
256 if (unsync || tunsync) {
257 int i, j;
258 av_fast_malloc(&buffer, &buffer_size, tlen);
86f86877
AC
259 if (!buffer) {
260 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
261 goto seek;
262 }
18bbe9df 263 for (i = 0, j = 0; i < tlen; i++, j++) {
b7effd4e 264 buffer[j] = avio_r8(s->pb);
18bbe9df
AK
265 if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
266 /* Unsynchronised byte, skip it */
267 j--;
268 }
269 }
e731b8d8 270 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
18bbe9df
AK
271 read_ttag(s, &pb, j, tag);
272 } else {
273 read_ttag(s, s->pb, tlen, tag);
274 }
275 }
2e3ca1ff
JM
276 else if (!tag[0]) {
277 if (tag[1])
278 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
45a8a02a 279 avio_skip(s->pb, tlen);
2e3ca1ff
JM
280 break;
281 }
75411182 282 /* Skip to end of tag */
86f86877 283seek:
6b4aa5da 284 avio_seek(s->pb, next, SEEK_SET);
75411182
PD
285 }
286
7d7b8c32 287 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
bca6dee3 288 end += 10;
18bbe9df 289
eb1e7f78
AK
290 error:
291 if (reason)
292 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
bca6dee3 293 avio_seek(s->pb, end, SEEK_SET);
18bbe9df 294 av_free(buffer);
75411182 295 return;
75411182 296}
6378b062 297
46a2da76
AK
298void ff_id3v2_read(AVFormatContext *s, const char *magic)
299{
300 int len, ret;
301 uint8_t buf[ID3v2_HEADER_SIZE];
302 int found_header;
303 int64_t off;
304
305 do {
306 /* save the current offset in case there's nothing to read/skip */
a2704c97 307 off = avio_tell(s->pb);
b7effd4e 308 ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
46a2da76 309 if (ret != ID3v2_HEADER_SIZE)
f7fcd6a2 310 break;
46a2da76
AK
311 found_header = ff_id3v2_match(buf, magic);
312 if (found_header) {
313 /* parse ID3v2 header */
314 len = ((buf[6] & 0x7f) << 21) |
315 ((buf[7] & 0x7f) << 14) |
316 ((buf[8] & 0x7f) << 7) |
317 (buf[9] & 0x7f);
318 ff_id3v2_parse(s, len, buf[3], buf[5]);
319 } else {
6b4aa5da 320 avio_seek(s->pb, off, SEEK_SET);
46a2da76
AK
321 }
322 } while (found_header);
cb6bc576
AK
323 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
324 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
325 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
56e2ac6b 326 merge_date(&s->metadata);
46a2da76
AK
327}
328
cb6bc576 329const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
6378b062
AK
330 { "TALB", "album"},
331 { "TCOM", "composer"},
332 { "TCON", "genre"},
333 { "TCOP", "copyright"},
ca76a119 334 { "TENC", "encoded_by"},
6378b062
AK
335 { "TIT2", "title"},
336 { "TLAN", "language"},
8a98be1a 337 { "TPE1", "artist"},
ca76a119 338 { "TPE2", "album_artist"},
ca76a119 339 { "TPE3", "performer"},
6378b062
AK
340 { "TPOS", "disc"},
341 { "TPUB", "publisher"},
342 { "TRCK", "track"},
cb6bc576
AK
343 { "TSSE", "encoder"},
344 { 0 }
345};
346
347const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
348 { "TDRL", "date"},
349 { "TDRC", "date"},
350 { "TDEN", "creation_time"},
ca76a119
AK
351 { "TSOA", "album-sort"},
352 { "TSOP", "artist-sort"},
353 { "TSOT", "title-sort"},
6378b062
AK
354 { 0 }
355};
078d89a2 356
cb6bc576
AK
357const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
358 { "TAL", "album"},
359 { "TCO", "genre"},
360 { "TT2", "title"},
361 { "TEN", "encoded_by"},
362 { "TP1", "artist"},
363 { "TP2", "album_artist"},
364 { "TP3", "performer"},
365 { "TRK", "track"},
366 { 0 }
367};
368
369
078d89a2 370const char ff_id3v2_tags[][4] = {
cb6bc576
AK
371 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
372 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
373 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
374 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
375 { 0 },
376};
377
378const char ff_id3v2_4_tags[][4] = {
379 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
380 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
381 { 0 },
382};
383
384const char ff_id3v2_3_tags[][4] = {
385 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
078d89a2
AK
386 { 0 },
387};