libavcodec minor version is > 99 so fix the formating
[libav.git] / libavformat / id3v2.c
CommitLineData
2ea512a6
AC
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"
75411182
PD
23#include "id3v1.h"
24#include "libavutil/avstring.h"
3a1350e8 25#include "libavutil/intreadwrite.h"
03700d39 26#include "metadata.h"
2ea512a6 27
3a1350e8 28int ff_id3v2_match(const uint8_t *buf, const char * magic)
2ea512a6 29{
3a1350e8
MK
30 return buf[0] == magic[0] &&
31 buf[1] == magic[1] &&
32 buf[2] == magic[2] &&
7d7b8c32
DB
33 buf[3] != 0xff &&
34 buf[4] != 0xff &&
35 (buf[6] & 0x80) == 0 &&
36 (buf[7] & 0x80) == 0 &&
37 (buf[8] & 0x80) == 0 &&
1d4b1bf2 38 (buf[9] & 0x80) == 0;
2ea512a6 39}
ac3ef4a4
AC
40
41int ff_id3v2_tag_len(const uint8_t * buf)
42{
43 int len = ((buf[6] & 0x7f) << 21) +
7d7b8c32
DB
44 ((buf[7] & 0x7f) << 14) +
45 ((buf[8] & 0x7f) << 7) +
46 (buf[9] & 0x7f) +
47 ID3v2_HEADER_SIZE;
ac3ef4a4
AC
48 if (buf[5] & 0x10)
49 len += ID3v2_HEADER_SIZE;
50 return len;
51}
75411182 52
3a1350e8 53void ff_id3v2_read(AVFormatContext *s, const char *magic)
50fcd5be
PD
54{
55 int len, ret;
56 uint8_t buf[ID3v2_HEADER_SIZE];
0c41d554
DB
57 int found_header;
58 int64_t off;
50fcd5be 59
0c41d554
DB
60 do {
61 /* save the current offset in case there's nothing to read/skip */
62 off = url_ftell(s->pb);
27af8902
RD
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 }
0c41d554 77 } while (found_header);
50fcd5be
PD
78}
79
75411182
PD
80static unsigned int get_size(ByteIOContext *s, int len)
81{
7d7b8c32
DB
82 int v = 0;
83 while (len--)
84 v = (v << 7) + (get_byte(s) & 0x7F);
75411182
PD
85 return v;
86}
87
18bbe9df 88static void read_ttag(AVFormatContext *s, ByteIOContext *pb, int taglen, const char *key)
75411182
PD
89{
90 char *q, dst[512];
41770abf 91 const char *val = NULL;
75411182
PD
92 int len, dstlen = sizeof(dst) - 1;
93 unsigned genre;
20c68378 94 unsigned int (*get)(ByteIOContext*) = get_be16;
75411182 95
7d7b8c32
DB
96 dst[0] = 0;
97 if (taglen < 1)
75411182
PD
98 return;
99
100 taglen--; /* account for encoding type byte */
101
18bbe9df 102 switch (get_byte(pb)) { /* encoding type */
75411182
PD
103
104 case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */
105 q = dst;
787f8fad 106 while (taglen-- && q - dst < dstlen - 7) {
75411182 107 uint8_t tmp;
18bbe9df 108 PUT_UTF8(get_byte(pb), tmp, *q++ = tmp;)
75411182 109 }
9aa1bcce 110 *q = 0;
75411182
PD
111 break;
112
20c68378
AK
113 case 1: /* UTF-16 with BOM */
114 taglen -= 2;
18bbe9df 115 switch (get_be16(pb)) {
20c68378
AK
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
18bbe9df 132 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
20c68378
AK
133 PUT_UTF8(ch, tmp, *q++ = tmp;)
134 }
135 *q = 0;
136 break;
137
75411182 138 case 3: /* UTF-8 */
037e9afd 139 len = FFMIN(taglen, dstlen);
18bbe9df 140 get_buffer(pb, dst, len);
75411182
PD
141 dst[len] = 0;
142 break;
20c68378
AK
143 default:
144 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
75411182
PD
145 }
146
41770abf 147 if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
75411182
PD
148 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
149 && genre <= ID3v1_GENRE_MAX)
41770abf
AK
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;
75411182 160
41770abf 161 if (val)
2ef6c124 162 av_metadata_set2(&s->metadata, key, val, 0);
75411182
PD
163}
164
165void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
166{
18bbe9df 167 int isv34, tlen, unsync;
41770abf 168 char tag[5];
75411182
PD
169 int64_t next;
170 int taghdrlen;
171 const char *reason;
18bbe9df
AK
172 ByteIOContext pb;
173 unsigned char *buffer = NULL;
174 int buffer_size = 0;
75411182 175
7d7b8c32 176 switch (version) {
75411182 177 case 2:
7d7b8c32 178 if (flags & 0x40) {
75411182
PD
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
18bbe9df 197 unsync = flags & 0x80;
75411182 198
7d7b8c32 199 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
75411182
PD
200 url_fskip(s->pb, get_size(s->pb, 4));
201
7d7b8c32 202 while (len >= taghdrlen) {
18bbe9df
AK
203 unsigned int tflags;
204 int tunsync = 0;
205
7d7b8c32 206 if (isv34) {
41770abf
AK
207 get_buffer(s->pb, tag, 4);
208 tag[4] = 0;
3fd5a75b 209 if(version==3){
d004179e 210 tlen = get_be32(s->pb);
3fd5a75b
MN
211 }else
212 tlen = get_size(s->pb, 4);
18bbe9df 213 tflags = get_be16(s->pb);
7a07d158 214 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
75411182 215 } else {
41770abf
AK
216 get_buffer(s->pb, tag, 3);
217 tag[3] = 0;
1cd44221 218 tlen = get_be24(s->pb);
75411182
PD
219 }
220 len -= taghdrlen + tlen;
221
7d7b8c32 222 if (len < 0)
75411182
PD
223 break;
224
225 next = url_ftell(s->pb) + tlen;
226
a152c77f
AK
227 if (tflags & ID3v2_FLAG_DATALEN) {
228 get_be32(s->pb);
229 tlen -= 4;
230 }
231
407d3d5a
AK
232 if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
233 av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
234 url_fskip(s->pb, tlen);
235 } else if (tag[0] == 'T') {
18bbe9df
AK
236 if (unsync || tunsync) {
237 int i, j;
238 av_fast_malloc(&buffer, &buffer_size, tlen);
239 for (i = 0, j = 0; i < tlen; i++, j++) {
240 buffer[j] = get_byte(s->pb);
241 if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
242 /* Unsynchronised byte, skip it */
243 j--;
244 }
245 }
246 init_put_byte(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
247 read_ttag(s, &pb, j, tag);
248 } else {
249 read_ttag(s, s->pb, tlen, tag);
250 }
251 }
2e3ca1ff
JM
252 else if (!tag[0]) {
253 if (tag[1])
254 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
ff58de29 255 url_fskip(s->pb, tlen);
2e3ca1ff
JM
256 break;
257 }
75411182
PD
258 /* Skip to end of tag */
259 url_fseek(s->pb, next, SEEK_SET);
260 }
ad7768f4 261 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_metadata_conv);
75411182 262
ff58de29
AK
263 if (len > 0) {
264 /* Skip padding */
265 url_fskip(s->pb, len);
266 }
7d7b8c32 267 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
75411182 268 url_fskip(s->pb, 10);
18bbe9df
AK
269
270 av_free(buffer);
75411182
PD
271 return;
272
273 error:
274 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
275 url_fskip(s->pb, len);
18bbe9df 276 av_free(buffer);
75411182 277}
6378b062
AK
278
279const AVMetadataConv ff_id3v2_metadata_conv[] = {
280 { "TALB", "album"},
dfe9ee6b 281 { "TAL", "album"},
6378b062
AK
282 { "TCOM", "composer"},
283 { "TCON", "genre"},
dfe9ee6b 284 { "TCO", "genre"},
6378b062
AK
285 { "TCOP", "copyright"},
286 { "TDRL", "date"},
ca76a119 287 { "TDRC", "date"},
bcb5d217 288 { "TDEN", "creation_time"},
ca76a119
AK
289 { "TENC", "encoded_by"},
290 { "TEN", "encoded_by"},
6378b062 291 { "TIT2", "title"},
dfe9ee6b 292 { "TT2", "title"},
6378b062 293 { "TLAN", "language"},
8a98be1a 294 { "TPE1", "artist"},
dfe9ee6b 295 { "TP1", "artist"},
ca76a119
AK
296 { "TPE2", "album_artist"},
297 { "TP2", "album_artist"},
298 { "TPE3", "performer"},
299 { "TP3", "performer"},
6378b062
AK
300 { "TPOS", "disc"},
301 { "TPUB", "publisher"},
302 { "TRCK", "track"},
dfe9ee6b 303 { "TRK", "track"},
ca76a119
AK
304 { "TSOA", "album-sort"},
305 { "TSOP", "artist-sort"},
306 { "TSOT", "title-sort"},
307 { "TSSE", "encoder"},
6378b062
AK
308 { 0 }
309};
078d89a2
AK
310
311const char ff_id3v2_tags[][4] = {
312 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
313 "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
314 "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
315 "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
316 "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
317 { 0 },
318};