blob: 1fff030e57a6da3d3c6e1b8fe8b381b2ce978321 [file] [log] [blame]
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "id3.h"
29#include "metadata_common.h"
30#include "replaygain.h"
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000031
32/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
33 * start of the file, which should be true in all cases where we need to skip it.
34 * Returns true if successfully skipped or not skipped, and false if
35 * something went wrong while skipping.
36 */
37bool skip_id3v2(int fd, struct mp3entry *id3)
38{
39 char buf[4];
40
41 read(fd, buf, 4);
42 if (memcmp(buf, "ID3", 3) == 0)
43 {
44 /* We have found an ID3v2 tag at the start of the file - find its
45 length and then skip it. */
46 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
47 return false;
48
49 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
50 return false;
51
52 return true;
53 } else {
54 lseek(fd, 0, SEEK_SET);
55 id3->first_frame_offset = 0;
56 return true;
57 }
58}
59
60
61/* Read a string from the file. Read up to size bytes, or, if eos != -1,
62 * until the eos character is found (eos is not stored in buf, unless it is
63 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
64 * Returns number of chars read or -1 on read error.
65 */
66long read_string(int fd, char* buf, long buf_size, int eos, long size)
67{
68 long read_bytes = 0;
69 char c;
70
71 while (size != 0)
72 {
73 if (read(fd, &c, 1) != 1)
74 {
75 read_bytes = -1;
76 break;
77 }
78
79 read_bytes++;
80 size--;
81
82 if ((eos != -1) && (eos == (unsigned char) c))
83 {
84 break;
85 }
86
87 if (buf_size > 1)
88 {
89 *buf++ = c;
90 buf_size--;
91 }
92 }
93
94 *buf = 0;
95 return read_bytes;
96}
97
Marcoen Hirschberge097b5f2007-06-16 18:40:07 +000098#ifdef ROCKBOX_LITTLE_ENDIAN
Dave Chapmanc7282472007-07-03 09:25:36 +000099/* Read an unsigned 32-bit integer from a big-endian file. */
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000100int read_uint32be(int fd, unsigned int* buf)
101{
102 size_t n;
103
104 n = read(fd, (char*) buf, 4);
105 *buf = betoh32(*buf);
106 return n;
107}
Dave Chapmanc7282472007-07-03 09:25:36 +0000108#else
109/* Read unsigned integers from a little-endian file. */
110int read_uint16le(int fd, uint16_t* buf)
111{
112 size_t n;
113
114 n = read(fd, (char*) buf, 2);
115 *buf = letoh16(*buf);
116 return n;
117}
118int read_uint32le(int fd, uint32_t* buf)
119{
120 size_t n;
121
122 n = read(fd, (char*) buf, 4);
123 *buf = letoh32(*buf);
124 return n;
125}
126int read_uint64le(int fd, uint64_t* buf)
127{
128 size_t n;
129 uint8_t data[8];
130 int i;
131
132 n = read(fd, data, 8);
133
134 for (i=7, *buf=0; i>=0; i--) {
135 *buf <<= 8;
136 *buf |= data[i];
137 }
138
139 return n;
140}
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000141#endif
142
143/* Read an unaligned 32-bit little endian long from buffer. */
144unsigned long get_long_le(void* buf)
145{
146 unsigned char* p = (unsigned char*) buf;
147
148 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
149}
150
151/* Read an unaligned 16-bit little endian short from buffer. */
152unsigned short get_short_le(void* buf)
153{
154 unsigned char* p = (unsigned char*) buf;
155
156 return p[0] | (p[1] << 8);
157}
158
159/* Read an unaligned 32-bit big endian long from buffer. */
160unsigned long get_long_be(void* buf)
161{
162 unsigned char* p = (unsigned char*) buf;
163
164 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
165}
166
167/* Read an unaligned 32-bit little endian long from buffer. */
168long get_slong(void* buf)
169{
170 unsigned char* p = (unsigned char*) buf;
171
172 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
173}
174
175static char* skip_space(char* str)
176{
177 while (isspace(*str))
178 {
179 str++;
180 }
181
182 return str;
183}
184
185unsigned long get_itunes_int32(char* value, int count)
186{
187 static const char hexdigits[] = "0123456789ABCDEF";
188 const char* c;
189 int r = 0;
190
191 while (count-- > 0)
192 {
193 value = skip_space(value);
194
195 while (*value && !isspace(*value))
196 {
197 value++;
198 }
199 }
200
201 value = skip_space(value);
202
203 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
204 {
205 r = (r << 4) | (c - hexdigits);
206 value++;
207 }
208
209 return r;
210}
211
212/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
213 * String values to keep are written to buf. Returns number of bytes written
214 * to buf (including end nil).
215 */
216long parse_tag(const char* name, char* value, struct mp3entry* id3,
217 char* buf, long buf_remaining, enum tagtype type)
218{
219 long len = 0;
220 char** p;
221
222 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
223 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
224 {
225 id3->tracknum = atoi(value);
226 p = &(id3->track_string);
227 }
Dan Evertonf4a61f02007-08-03 10:00:42 +0000228 else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
229 {
230 id3->discnum = atoi(value);
231 p = &(id3->disc_string);
232 }
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000233 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
234 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
235 {
236 /* Date's can be in any format in Vorbis. However most of them
237 * are in ISO8601 format so if we try and parse the first part
238 * of the tag as a number, we should get the year. If we get crap,
239 * then act like we never parsed it.
240 */
241 id3->year = atoi(value);
242 if (id3->year < 1900)
243 { /* yeah, not likely */
244 id3->year = 0;
245 }
246 p = &(id3->year_string);
247 }
248 else if (strcasecmp(name, "title") == 0)
249 {
250 p = &(id3->title);
251 }
252 else if (strcasecmp(name, "artist") == 0)
253 {
254 p = &(id3->artist);
255 }
256 else if (strcasecmp(name, "album") == 0)
257 {
258 p = &(id3->album);
259 }
260 else if (strcasecmp(name, "genre") == 0)
261 {
262 p = &(id3->genre_string);
263 }
264 else if (strcasecmp(name, "composer") == 0)
265 {
266 p = &(id3->composer);
267 }
268 else if (strcasecmp(name, "comment") == 0)
269 {
270 p = &(id3->comment);
271 }
272 else if (strcasecmp(name, "albumartist") == 0)
273 {
274 p = &(id3->albumartist);
275 }
276 else if (strcasecmp(name, "album artist") == 0)
277 {
278 p = &(id3->albumartist);
279 }
280 else if (strcasecmp(name, "ensemble") == 0)
281 {
282 p = &(id3->albumartist);
283 }
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000284 else if (strcasecmp(name, "grouping") == 0)
285 {
286 p = &(id3->grouping);
287 }
288 else if (strcasecmp(name, "content group") == 0)
289 {
290 p = &(id3->grouping);
291 }
292 else if (strcasecmp(name, "contentgroup") == 0)
293 {
294 p = &(id3->grouping);
295 }
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000296 else
297 {
298 len = parse_replaygain(name, value, id3, buf, buf_remaining);
299 p = NULL;
300 }
301
302 if (p)
303 {
304 len = strlen(value);
305 len = MIN(len, buf_remaining - 1);
306
307 if (len > 0)
308 {
309 strncpy(buf, value, len);
310 buf[len] = 0;
311 *p = buf;
312 len++;
313 }
314 else
315 {
316 len = 0;
317 }
318 }
319
320 return len;
321}
322