Make the leave-usb-mode paragraph a bit less technical. Fix accidental missing words...
[kugel-rb.git] / apps / metadata / metadata_common.c
blob09f0f94a88a86181dea23630692a5856159e56c4
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"
32 #include "misc.h"
34 /* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
35 * start of the file, which should be true in all cases where we need to skip it.
36 * Returns true if successfully skipped or not skipped, and false if
37 * something went wrong while skipping.
39 bool skip_id3v2(int fd, struct mp3entry *id3)
41 char buf[4];
43 read(fd, buf, 4);
44 if (memcmp(buf, "ID3", 3) == 0)
46 /* We have found an ID3v2 tag at the start of the file - find its
47 length and then skip it. */
48 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
49 return false;
51 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
52 return false;
54 return true;
55 } else {
56 lseek(fd, 0, SEEK_SET);
57 id3->first_frame_offset = 0;
58 return true;
63 /* Read a string from the file. Read up to size bytes, or, if eos != -1,
64 * until the eos character is found (eos is not stored in buf, unless it is
65 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
66 * Returns number of chars read or -1 on read error.
68 long read_string(int fd, char* buf, long buf_size, int eos, long size)
70 long read_bytes = 0;
71 char c;
73 while (size != 0)
75 if (read(fd, &c, 1) != 1)
77 read_bytes = -1;
78 break;
81 read_bytes++;
82 size--;
84 if ((eos != -1) && (eos == (unsigned char) c))
86 break;
89 if (buf_size > 1)
91 *buf++ = c;
92 buf_size--;
96 *buf = 0;
97 return read_bytes;
100 #ifdef ROCKBOX_LITTLE_ENDIAN
101 /* Read an unsigned 32-bit integer from a big-endian file. */
102 int read_uint32be(int fd, unsigned int* buf)
104 size_t n;
106 n = read(fd, (char*) buf, 4);
107 *buf = betoh32(*buf);
108 return n;
110 #else
111 /* Read unsigned integers from a little-endian file. */
112 int read_uint16le(int fd, uint16_t* buf)
114 size_t n;
116 n = read(fd, (char*) buf, 2);
117 *buf = letoh16(*buf);
118 return n;
120 int read_uint32le(int fd, uint32_t* buf)
122 size_t n;
124 n = read(fd, (char*) buf, 4);
125 *buf = letoh32(*buf);
126 return n;
128 int read_uint64le(int fd, uint64_t* buf)
130 size_t n;
131 uint8_t data[8];
132 int i;
134 n = read(fd, data, 8);
136 for (i=7, *buf=0; i>=0; i--) {
137 *buf <<= 8;
138 *buf |= data[i];
141 return n;
143 #endif
145 /* Read an unaligned 32-bit little endian long from buffer. */
146 unsigned long get_long_le(void* buf)
148 unsigned char* p = (unsigned char*) buf;
150 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
153 /* Read an unaligned 16-bit little endian short from buffer. */
154 unsigned short get_short_le(void* buf)
156 unsigned char* p = (unsigned char*) buf;
158 return p[0] | (p[1] << 8);
161 /* Read an unaligned 32-bit big endian long from buffer. */
162 unsigned long get_long_be(void* buf)
164 unsigned char* p = (unsigned char*) buf;
166 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
169 /* Read an unaligned 32-bit little endian long from buffer. */
170 long get_slong(void* buf)
172 unsigned char* p = (unsigned char*) buf;
174 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
177 unsigned long get_itunes_int32(char* value, int count)
179 static const char hexdigits[] = "0123456789ABCDEF";
180 const char* c;
181 int r = 0;
183 while (count-- > 0)
185 value = skip_whitespace(value);
187 while (*value && !isspace(*value))
189 value++;
193 value = skip_whitespace(value);
195 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
197 r = (r << 4) | (c - hexdigits);
198 value++;
201 return r;
204 /* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
205 * String values to keep are written to buf. Returns number of bytes written
206 * to buf (including end nil).
208 long parse_tag(const char* name, char* value, struct mp3entry* id3,
209 char* buf, long buf_remaining, enum tagtype type)
211 long len = 0;
212 char** p;
214 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
215 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
217 id3->tracknum = atoi(value);
218 p = &(id3->track_string);
220 else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
222 id3->discnum = atoi(value);
223 p = &(id3->disc_string);
225 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
226 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
228 /* Date's can be in any format in Vorbis. However most of them
229 * are in ISO8601 format so if we try and parse the first part
230 * of the tag as a number, we should get the year. If we get crap,
231 * then act like we never parsed it.
233 id3->year = atoi(value);
234 if (id3->year < 1900)
235 { /* yeah, not likely */
236 id3->year = 0;
238 p = &(id3->year_string);
240 else if (strcasecmp(name, "title") == 0)
242 p = &(id3->title);
244 else if (strcasecmp(name, "artist") == 0)
246 p = &(id3->artist);
248 else if (strcasecmp(name, "album") == 0)
250 p = &(id3->album);
252 else if (strcasecmp(name, "genre") == 0)
254 p = &(id3->genre_string);
256 else if (strcasecmp(name, "composer") == 0)
258 p = &(id3->composer);
260 else if (strcasecmp(name, "comment") == 0)
262 p = &(id3->comment);
264 else if (strcasecmp(name, "albumartist") == 0)
266 p = &(id3->albumartist);
268 else if (strcasecmp(name, "album artist") == 0)
270 p = &(id3->albumartist);
272 else if (strcasecmp(name, "ensemble") == 0)
274 p = &(id3->albumartist);
276 else if (strcasecmp(name, "grouping") == 0)
278 p = &(id3->grouping);
280 else if (strcasecmp(name, "content group") == 0)
282 p = &(id3->grouping);
284 else if (strcasecmp(name, "contentgroup") == 0)
286 p = &(id3->grouping);
288 else if (strcasecmp(name, "musicbrainz_trackid") == 0
289 || strcasecmp(name, "http://musicbrainz.org") == 0 )
291 p = &(id3->mb_track_id);
293 else
295 len = parse_replaygain(name, value, id3, buf, buf_remaining);
296 p = NULL;
299 if (p)
301 len = strlen(value);
302 len = MIN(len, buf_remaining - 1);
304 if (len > 0)
306 strncpy(buf, value, len);
307 buf[len] = 0;
308 *p = buf;
309 len++;
311 else
313 len = 0;
317 return len;