Re-added libspc which got dropped in a black hole.
[kugel-rb.git] / apps / metadata / metadata_common.c
blob94ff212ceae39030ac232459eb811fd2ba4f2996
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Dave Chapman
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <inttypes.h>
27 #include "system.h"
28 #include "metadata.h"
29 #include "metadata_common.h"
30 #include "metadata_parsers.h"
31 #include "replaygain.h"
33 /* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
34 * start of the file, which should be true in all cases where we need to skip it.
35 * Returns true if successfully skipped or not skipped, and false if
36 * something went wrong while skipping.
38 bool skip_id3v2(int fd, struct mp3entry *id3)
40 char buf[4];
42 read(fd, buf, 4);
43 if (memcmp(buf, "ID3", 3) == 0)
45 /* We have found an ID3v2 tag at the start of the file - find its
46 length and then skip it. */
47 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
48 return false;
50 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
51 return false;
53 return true;
54 } else {
55 lseek(fd, 0, SEEK_SET);
56 id3->first_frame_offset = 0;
57 return true;
62 /* Read a string from the file. Read up to size bytes, or, if eos != -1,
63 * until the eos character is found (eos is not stored in buf, unless it is
64 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
65 * Returns number of chars read or -1 on read error.
67 long read_string(int fd, char* buf, long buf_size, int eos, long size)
69 long read_bytes = 0;
70 char c;
72 while (size != 0)
74 if (read(fd, &c, 1) != 1)
76 read_bytes = -1;
77 break;
80 read_bytes++;
81 size--;
83 if ((eos != -1) && (eos == (unsigned char) c))
85 break;
88 if (buf_size > 1)
90 *buf++ = c;
91 buf_size--;
95 *buf = 0;
96 return read_bytes;
99 #ifdef ROCKBOX_LITTLE_ENDIAN
100 /* Read an unsigned 32-bit integer from a big-endian file. */
101 int read_uint32be(int fd, unsigned int* buf)
103 size_t n;
105 n = read(fd, (char*) buf, 4);
106 *buf = betoh32(*buf);
107 return n;
109 #else
110 /* Read unsigned integers from a little-endian file. */
111 int read_uint16le(int fd, uint16_t* buf)
113 size_t n;
115 n = read(fd, (char*) buf, 2);
116 *buf = letoh16(*buf);
117 return n;
119 int read_uint32le(int fd, uint32_t* buf)
121 size_t n;
123 n = read(fd, (char*) buf, 4);
124 *buf = letoh32(*buf);
125 return n;
127 int read_uint64le(int fd, uint64_t* buf)
129 size_t n;
130 uint8_t data[8];
131 int i;
133 n = read(fd, data, 8);
135 for (i=7, *buf=0; i>=0; i--) {
136 *buf <<= 8;
137 *buf |= data[i];
140 return n;
142 #endif
144 /* Read an unaligned 32-bit little endian long from buffer. */
145 unsigned long get_long_le(void* buf)
147 unsigned char* p = (unsigned char*) buf;
149 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
152 /* Read an unaligned 16-bit little endian short from buffer. */
153 unsigned short get_short_le(void* buf)
155 unsigned char* p = (unsigned char*) buf;
157 return p[0] | (p[1] << 8);
160 /* Read an unaligned 32-bit big endian long from buffer. */
161 unsigned long get_long_be(void* buf)
163 unsigned char* p = (unsigned char*) buf;
165 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
168 /* Read an unaligned 32-bit little endian long from buffer. */
169 long get_slong(void* buf)
171 unsigned char* p = (unsigned char*) buf;
173 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
176 static char* skip_space(char* str)
178 while (isspace(*str))
180 str++;
183 return str;
186 unsigned long get_itunes_int32(char* value, int count)
188 static const char hexdigits[] = "0123456789ABCDEF";
189 const char* c;
190 int r = 0;
192 while (count-- > 0)
194 value = skip_space(value);
196 while (*value && !isspace(*value))
198 value++;
202 value = skip_space(value);
204 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
206 r = (r << 4) | (c - hexdigits);
207 value++;
210 return r;
213 /* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
214 * String values to keep are written to buf. Returns number of bytes written
215 * to buf (including end nil).
217 long parse_tag(const char* name, char* value, struct mp3entry* id3,
218 char* buf, long buf_remaining, enum tagtype type)
220 long len = 0;
221 char** p;
223 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
224 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
226 id3->tracknum = atoi(value);
227 p = &(id3->track_string);
229 else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
231 id3->discnum = atoi(value);
232 p = &(id3->disc_string);
234 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
235 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
237 /* Date's can be in any format in Vorbis. However most of them
238 * are in ISO8601 format so if we try and parse the first part
239 * of the tag as a number, we should get the year. If we get crap,
240 * then act like we never parsed it.
242 id3->year = atoi(value);
243 if (id3->year < 1900)
244 { /* yeah, not likely */
245 id3->year = 0;
247 p = &(id3->year_string);
249 else if (strcasecmp(name, "title") == 0)
251 p = &(id3->title);
253 else if (strcasecmp(name, "artist") == 0)
255 p = &(id3->artist);
257 else if (strcasecmp(name, "album") == 0)
259 p = &(id3->album);
261 else if (strcasecmp(name, "genre") == 0)
263 p = &(id3->genre_string);
265 else if (strcasecmp(name, "composer") == 0)
267 p = &(id3->composer);
269 else if (strcasecmp(name, "comment") == 0)
271 p = &(id3->comment);
273 else if (strcasecmp(name, "albumartist") == 0)
275 p = &(id3->albumartist);
277 else if (strcasecmp(name, "album artist") == 0)
279 p = &(id3->albumartist);
281 else if (strcasecmp(name, "ensemble") == 0)
283 p = &(id3->albumartist);
285 else if (strcasecmp(name, "grouping") == 0)
287 p = &(id3->grouping);
289 else if (strcasecmp(name, "content group") == 0)
291 p = &(id3->grouping);
293 else if (strcasecmp(name, "contentgroup") == 0)
295 p = &(id3->grouping);
297 else if (strcasecmp(name, "musicbrainz_trackid") == 0
298 || strcasecmp(name, "http://musicbrainz.org") == 0 )
300 p = &(id3->mb_track_id);
302 else
304 len = parse_replaygain(name, value, id3, buf, buf_remaining);
305 p = NULL;
308 if (p)
310 len = strlen(value);
311 len = MIN(len, buf_remaining - 1);
313 if (len > 0)
315 strncpy(buf, value, len);
316 buf[len] = 0;
317 *p = buf;
318 len++;
320 else
322 len = 0;
326 return len;