add global proxy / cache settings to httpget class. This removes the need of passing...
[Rockbox.git] / apps / metadata.c
blob3abbd74c35fa32300a48173a2031af344309d197
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Dave Chapman
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <inttypes.h>
25 #include "system.h"
26 #include "playback.h"
27 #include "debug.h"
28 #include "logf.h"
29 #include "cuesheet.h"
31 #if CONFIG_CODEC == SWCODEC
33 /* For trailing tag stripping */
34 #include "buffering.h"
36 #include "metadata/metadata_common.h"
37 #include "metadata/metadata_parsers.h"
39 #endif /* CONFIG_CODEC == SWCODEC */
42 /* Simple file type probing by looking at the filename extension. */
43 unsigned int probe_file_format(const char *filename)
45 char *suffix;
46 unsigned int i;
48 suffix = strrchr(filename, '.');
50 if (suffix == NULL)
52 return AFMT_UNKNOWN;
55 /* skip '.' */
56 suffix++;
58 for (i = 1; i < AFMT_NUM_CODECS; i++)
60 /* search extension list for type */
61 const char *ext = audio_formats[i].ext_list;
65 if (strcasecmp(suffix, ext) == 0)
67 return i;
70 ext += strlen(ext) + 1;
72 while (*ext != '\0');
75 return AFMT_UNKNOWN;
78 /* Get metadata for track - return false if parsing showed problems with the
79 * file that would prevent playback.
81 bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
83 #if CONFIG_CODEC == SWCODEC
84 unsigned char* buf;
85 #endif
87 /* Clear the mp3entry to avoid having bogus pointers appear */
88 memset(id3, 0, sizeof(struct mp3entry));
90 /* Take our best guess at the codec type based on file extension */
91 id3->codectype = probe_file_format(trackname);
93 /* Load codec specific track tag information and confirm the codec type. */
94 switch (id3->codectype)
96 case AFMT_MPA_L1:
97 case AFMT_MPA_L2:
98 case AFMT_MPA_L3:
99 if (!get_mp3_metadata(fd, id3, trackname))
101 return false;
104 break;
106 #if CONFIG_CODEC == SWCODEC
107 case AFMT_FLAC:
108 if (!get_flac_metadata(fd, id3))
110 return false;
113 break;
115 case AFMT_WMA:
116 if (!get_asf_metadata(fd, id3))
118 return false;
120 break;
122 case AFMT_APE:
123 if (!get_monkeys_metadata(fd, id3))
125 return false;
127 read_ape_tags(fd, id3);
128 break;
130 case AFMT_MPC:
131 if (!get_musepack_metadata(fd, id3))
132 return false;
133 read_ape_tags(fd, id3);
134 break;
136 case AFMT_OGG_VORBIS:
137 if (!get_ogg_metadata(fd, id3))/*detects and handles Ogg/Speex files*/
139 return false;
142 break;
144 case AFMT_SPEEX:
145 if (!get_ogg_metadata(fd, id3))
147 return false;
150 break;
152 case AFMT_PCM_WAV:
153 if (!get_wave_metadata(fd, id3))
155 return false;
158 break;
160 case AFMT_WAVPACK:
161 if (!get_wavpack_metadata(fd, id3))
163 return false;
166 read_ape_tags(fd, id3); /* use any apetag info we find */
167 break;
169 case AFMT_A52:
170 if (!get_a52_metadata(fd, id3))
172 return false;
175 break;
177 case AFMT_ALAC:
178 case AFMT_AAC:
179 if (!get_mp4_metadata(fd, id3))
181 return false;
184 break;
186 case AFMT_SHN:
187 id3->vbr = true;
188 id3->filesize = filesize(fd);
189 if (!skip_id3v2(fd, id3))
191 return false;
193 /* TODO: read the id3v2 header if it exists */
194 break;
196 case AFMT_SID:
197 if (!get_sid_metadata(fd, id3))
199 return false;
201 break;
203 case AFMT_SPC:
204 if (!get_spc_metadata(fd, id3))
206 DEBUGF("get_spc_metadata error\n");
207 return false;
209 id3->filesize = filesize(fd);
210 id3->genre_string = id3_get_num_genre(36);
211 break;
213 case AFMT_ADX:
214 if (!get_adx_metadata(fd, id3))
216 DEBUGF("get_adx_metadata error\n");
217 return false;
220 break;
222 case AFMT_NSF:
223 buf = (unsigned char *)id3->path;
224 if ((lseek(fd, 0, SEEK_SET) < 0) || ((read(fd, buf, 8)) < 8))
226 DEBUGF("lseek or read failed\n");
227 return false;
229 id3->vbr = false;
230 id3->filesize = filesize(fd);
231 if (memcmp(buf,"NESM",4) && memcmp(buf,"NSFE",4)) return false;
232 break;
234 case AFMT_AIFF:
235 if (!get_aiff_metadata(fd, id3))
237 return false;
240 break;
242 #endif /* CONFIG_CODEC == SWCODEC */
244 default:
245 /* If we don't know how to read the metadata, assume we can't play
246 the file */
247 return false;
248 break;
251 /* We have successfully read the metadata from the file */
253 #ifndef __PCTOOL__
254 if (cuesheet_is_enabled() && look_for_cuesheet_file(trackname, NULL))
256 id3->cuesheet_type = 1;
258 #endif
260 lseek(fd, 0, SEEK_SET);
261 strncpy(id3->path, trackname, sizeof(id3->path));
263 return true;
266 #if CONFIG_CODEC == SWCODEC
267 void strip_tags(int handle_id)
269 static const unsigned char tag[] = "TAG";
270 static const unsigned char apetag[] = "APETAGEX";
271 size_t len, version;
272 void *tail;
274 if (bufgettail(handle_id, 128, &tail) != 128)
275 return;
277 if (memcmp(tail, tag, 3) == 0)
279 /* Skip id3v1 tag */
280 logf("Cutting off ID3v1 tag");
281 bufcuttail(handle_id, 128);
284 /* Get a new tail, as the old one may have been cut */
285 if (bufgettail(handle_id, 32, &tail) != 32)
286 return;
288 /* Check for APE tag (look for the APE tag footer) */
289 if (memcmp(tail, apetag, 8) != 0)
290 return;
292 /* Read the version and length from the footer */
293 version = get_long_le(&((unsigned char *)tail)[8]);
294 len = get_long_le(&((unsigned char *)tail)[12]);
295 if (version == 2000)
296 len += 32; /* APEv2 has a 32 byte header */
298 /* Skip APE tag */
299 logf("Cutting off APE tag (%ldB)", len);
300 bufcuttail(handle_id, len);
302 #endif /* CONFIG_CODEC == SWCODEC */