cosmetics: Reformat to K&R and prettyprint newly created files.
[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
26 int ff_id3v2_match(const uint8_t *buf)
27 {
28     return  buf[0]         ==  'I' &&
29             buf[1]         ==  'D' &&
30             buf[2]         ==  '3' &&
31             buf[3]         != 0xff &&
32             buf[4]         != 0xff &&
33            (buf[6] & 0x80) ==    0 &&
34            (buf[7] & 0x80) ==    0 &&
35            (buf[8] & 0x80) ==    0 &&
36            (buf[9] & 0x80) == 0;
37 }
38
39 int ff_id3v2_tag_len(const uint8_t * buf)
40 {
41     int len = ((buf[6] & 0x7f) << 21) +
42               ((buf[7] & 0x7f) << 14) +
43               ((buf[8] & 0x7f) << 7) +
44                (buf[9] & 0x7f) +
45               ID3v2_HEADER_SIZE;
46     if (buf[5] & 0x10)
47         len += ID3v2_HEADER_SIZE;
48     return len;
49 }
50
51 static unsigned int get_size(ByteIOContext *s, int len)
52 {
53     int v = 0;
54     while (len--)
55         v = (v << 7) + (get_byte(s) & 0x7F);
56     return v;
57 }
58
59 static void read_ttag(AVFormatContext *s, int taglen, const char *key)
60 {
61     char *q, dst[512];
62     int len, dstlen = sizeof(dst) - 1;
63     unsigned genre;
64
65     dst[0] = 0;
66     if (taglen < 1)
67         return;
68
69     taglen--; /* account for encoding type byte */
70
71     switch (get_byte(s->pb)) { /* encoding type */
72
73     case 0:  /* ISO-8859-1 (0 - 255 maps directly into unicode) */
74         q = dst;
75         while (taglen--) {
76             uint8_t tmp;
77             PUT_UTF8(get_byte(s->pb), tmp, if (q - dst < dstlen - 1) *q++ = tmp;)
78         }
79         *q = '\0';
80         break;
81
82     case 3:  /* UTF-8 */
83         len = FFMIN(taglen, dstlen - 1);
84         get_buffer(s->pb, dst, len);
85         dst[len] = 0;
86         break;
87     }
88
89     if (!strcmp(key, "genre")
90         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
91         && genre <= ID3v1_GENRE_MAX)
92         av_strlcpy(dst, ff_id3v1_genre_str[genre], sizeof(dst));
93
94     if (*dst)
95         av_metadata_set(&s->metadata, key, dst);
96 }
97
98 void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
99 {
100     int isv34, tlen;
101     uint32_t tag;
102     int64_t next;
103     int taghdrlen;
104     const char *reason;
105
106     switch (version) {
107     case 2:
108         if (flags & 0x40) {
109             reason = "compression";
110             goto error;
111         }
112         isv34 = 0;
113         taghdrlen = 6;
114         break;
115
116     case 3:
117     case 4:
118         isv34 = 1;
119         taghdrlen = 10;
120         break;
121
122     default:
123         reason = "version";
124         goto error;
125     }
126
127     if (flags & 0x80) {
128         reason = "unsynchronization";
129         goto error;
130     }
131
132     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
133         url_fskip(s->pb, get_size(s->pb, 4));
134
135     while (len >= taghdrlen) {
136         if (isv34) {
137             tag  = get_be32(s->pb);
138             tlen = get_size(s->pb, 4);
139             get_be16(s->pb); /* flags */
140         } else {
141             tag  = get_be24(s->pb);
142             tlen = get_size(s->pb, 3);
143         }
144         len -= taghdrlen + tlen;
145
146         if (len < 0)
147             break;
148
149         next = url_ftell(s->pb) + tlen;
150
151         switch (tag) {
152         case MKBETAG('T', 'I', 'T', '2'):
153         case MKBETAG(0,   'T', 'T', '2'):
154             read_ttag(s, tlen, "title");
155             break;
156         case MKBETAG('T', 'P', 'E', '1'):
157         case MKBETAG(0,   'T', 'P', '1'):
158             read_ttag(s, tlen, "author");
159             break;
160         case MKBETAG('T', 'A', 'L', 'B'):
161         case MKBETAG(0,   'T', 'A', 'L'):
162             read_ttag(s, tlen, "album");
163             break;
164         case MKBETAG('T', 'C', 'O', 'N'):
165         case MKBETAG(0,   'T', 'C', 'O'):
166             read_ttag(s, tlen, "genre");
167             break;
168         case MKBETAG('T', 'C', 'O', 'P'):
169         case MKBETAG(0,   'T', 'C', 'R'):
170             read_ttag(s, tlen, "copyright");
171             break;
172         case MKBETAG('T', 'R', 'C', 'K'):
173         case MKBETAG(0,   'T', 'R', 'K'):
174             read_ttag(s, tlen, "track");
175             break;
176         case 0:
177             /* padding, skip to end */
178             url_fskip(s->pb, len);
179             len = 0;
180             continue;
181         }
182         /* Skip to end of tag */
183         url_fseek(s->pb, next, SEEK_SET);
184     }
185
186     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
187         url_fskip(s->pb, 10);
188     return;
189
190   error:
191     av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
192     url_fskip(s->pb, len);
193 }