summaryrefslogtreecommitdiff
path: root/apps/metadata/metadata_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata/metadata_common.c')
-rw-r--r--apps/metadata/metadata_common.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c
new file mode 100644
index 0000000000..00b03841f9
--- /dev/null
+++ b/apps/metadata/metadata_common.c
@@ -0,0 +1,273 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <ctype.h>
23#include <inttypes.h>
24
25#include "system.h"
26#include "id3.h"
27#include "metadata_common.h"
28#include "replaygain.h"
29#include "atoi.h"
30
31/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
32 * start of the file, which should be true in all cases where we need to skip it.
33 * Returns true if successfully skipped or not skipped, and false if
34 * something went wrong while skipping.
35 */
36bool skip_id3v2(int fd, struct mp3entry *id3)
37{
38 char buf[4];
39
40 read(fd, buf, 4);
41 if (memcmp(buf, "ID3", 3) == 0)
42 {
43 /* We have found an ID3v2 tag at the start of the file - find its
44 length and then skip it. */
45 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
46 return false;
47
48 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
49 return false;
50
51 return true;
52 } else {
53 lseek(fd, 0, SEEK_SET);
54 id3->first_frame_offset = 0;
55 return true;
56 }
57}
58
59
60/* Read a string from the file. Read up to size bytes, or, if eos != -1,
61 * until the eos character is found (eos is not stored in buf, unless it is
62 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
63 * Returns number of chars read or -1 on read error.
64 */
65long read_string(int fd, char* buf, long buf_size, int eos, long size)
66{
67 long read_bytes = 0;
68 char c;
69
70 while (size != 0)
71 {
72 if (read(fd, &c, 1) != 1)
73 {
74 read_bytes = -1;
75 break;
76 }
77
78 read_bytes++;
79 size--;
80
81 if ((eos != -1) && (eos == (unsigned char) c))
82 {
83 break;
84 }
85
86 if (buf_size > 1)
87 {
88 *buf++ = c;
89 buf_size--;
90 }
91 }
92
93 *buf = 0;
94 return read_bytes;
95}
96
97/* Read an unsigned 32-bit integer from a big-endian file. */
98#ifdef ROCKBOX_BIG_ENDIAN
99#define read_uint32be(fd,buf) read((fd), (buf), 4)
100#else
101int read_uint32be(int fd, unsigned int* buf)
102{
103 size_t n;
104
105 n = read(fd, (char*) buf, 4);
106 *buf = betoh32(*buf);
107 return n;
108}
109#endif
110
111/* Read an unaligned 32-bit little endian long from buffer. */
112unsigned long get_long_le(void* buf)
113{
114 unsigned char* p = (unsigned char*) buf;
115
116 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
117}
118
119/* Read an unaligned 16-bit little endian short from buffer. */
120unsigned short get_short_le(void* buf)
121{
122 unsigned char* p = (unsigned char*) buf;
123
124 return p[0] | (p[1] << 8);
125}
126
127/* Read an unaligned 32-bit big endian long from buffer. */
128unsigned long get_long_be(void* buf)
129{
130 unsigned char* p = (unsigned char*) buf;
131
132 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
133}
134
135/* Read an unaligned 32-bit little endian long from buffer. */
136long get_slong(void* buf)
137{
138 unsigned char* p = (unsigned char*) buf;
139
140 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
141}
142
143static char* skip_space(char* str)
144{
145 while (isspace(*str))
146 {
147 str++;
148 }
149
150 return str;
151}
152
153unsigned long get_itunes_int32(char* value, int count)
154{
155 static const char hexdigits[] = "0123456789ABCDEF";
156 const char* c;
157 int r = 0;
158
159 while (count-- > 0)
160 {
161 value = skip_space(value);
162
163 while (*value && !isspace(*value))
164 {
165 value++;
166 }
167 }
168
169 value = skip_space(value);
170
171 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
172 {
173 r = (r << 4) | (c - hexdigits);
174 value++;
175 }
176
177 return r;
178}
179
180/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
181 * String values to keep are written to buf. Returns number of bytes written
182 * to buf (including end nil).
183 */
184long parse_tag(const char* name, char* value, struct mp3entry* id3,
185 char* buf, long buf_remaining, enum tagtype type)
186{
187 long len = 0;
188 char** p;
189
190 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
191 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
192 {
193 id3->tracknum = atoi(value);
194 p = &(id3->track_string);
195 }
196 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
197 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
198 {
199 /* Date's can be in any format in Vorbis. However most of them
200 * are in ISO8601 format so if we try and parse the first part
201 * of the tag as a number, we should get the year. If we get crap,
202 * then act like we never parsed it.
203 */
204 id3->year = atoi(value);
205 if (id3->year < 1900)
206 { /* yeah, not likely */
207 id3->year = 0;
208 }
209 p = &(id3->year_string);
210 }
211 else if (strcasecmp(name, "title") == 0)
212 {
213 p = &(id3->title);
214 }
215 else if (strcasecmp(name, "artist") == 0)
216 {
217 p = &(id3->artist);
218 }
219 else if (strcasecmp(name, "album") == 0)
220 {
221 p = &(id3->album);
222 }
223 else if (strcasecmp(name, "genre") == 0)
224 {
225 p = &(id3->genre_string);
226 }
227 else if (strcasecmp(name, "composer") == 0)
228 {
229 p = &(id3->composer);
230 }
231 else if (strcasecmp(name, "comment") == 0)
232 {
233 p = &(id3->comment);
234 }
235 else if (strcasecmp(name, "albumartist") == 0)
236 {
237 p = &(id3->albumartist);
238 }
239 else if (strcasecmp(name, "album artist") == 0)
240 {
241 p = &(id3->albumartist);
242 }
243 else if (strcasecmp(name, "ensemble") == 0)
244 {
245 p = &(id3->albumartist);
246 }
247 else
248 {
249 len = parse_replaygain(name, value, id3, buf, buf_remaining);
250 p = NULL;
251 }
252
253 if (p)
254 {
255 len = strlen(value);
256 len = MIN(len, buf_remaining - 1);
257
258 if (len > 0)
259 {
260 strncpy(buf, value, len);
261 buf[len] = 0;
262 *p = buf;
263 len++;
264 }
265 else
266 {
267 len = 0;
268 }
269 }
270
271 return len;
272}
273