51b45d5602
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18814 a1c6a512-1295-4272-9138-f99709370657
263 lines
6.6 KiB
C
263 lines
6.6 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2008 Dominik Wenger
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "system.h"
|
|
#include "metadata.h"
|
|
#include "metadata_common.h"
|
|
#include "metadata_parsers.h"
|
|
#include "rbunicode.h"
|
|
#include "debug.h"
|
|
|
|
#define MAX_SONGS 32
|
|
|
|
static bool parse_dec(int *retval, const char *p, int minval, int maxval)
|
|
{
|
|
int r = 0;
|
|
do {
|
|
char c = *p;
|
|
if (c >= '0' && c <= '9')
|
|
r = 10 * r + c - '0';
|
|
else
|
|
return false;
|
|
if (r > maxval)
|
|
return false;
|
|
} while (*++p != '\0');
|
|
if (r < minval)
|
|
return false;
|
|
*retval = r;
|
|
return true;
|
|
}
|
|
|
|
static bool parse_text(char *retval, const char *p)
|
|
{
|
|
int i;
|
|
if (*p != '"')
|
|
return false;
|
|
p++;
|
|
if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"')
|
|
return true;
|
|
i = 0;
|
|
while (*p != '"') {
|
|
if (i >= 127)
|
|
return false;
|
|
if (*p == '\0')
|
|
return false;
|
|
retval[i++] = *p++;
|
|
}
|
|
retval[i] = '\0';
|
|
return true;
|
|
}
|
|
|
|
static int ASAP_ParseDuration(const char *s)
|
|
{
|
|
int r;
|
|
if (*s < '0' || *s > '9')
|
|
return -1;
|
|
r = *s++ - '0';
|
|
if (*s >= '0' && *s <= '9')
|
|
r = 10 * r + *s++ - '0';
|
|
if (*s == ':') {
|
|
s++;
|
|
if (*s < '0' || *s > '5')
|
|
return -1;
|
|
r = 60 * r + (*s++ - '0') * 10;
|
|
if (*s < '0' || *s > '9')
|
|
return -1;
|
|
r += *s++ - '0';
|
|
}
|
|
r *= 1000;
|
|
if (*s != '.')
|
|
return r;
|
|
s++;
|
|
if (*s < '0' || *s > '9')
|
|
return r;
|
|
r += 100 * (*s++ - '0');
|
|
if (*s < '0' || *s > '9')
|
|
return r;
|
|
r += 10 * (*s++ - '0');
|
|
if (*s < '0' || *s > '9')
|
|
return r;
|
|
r += *s - '0';
|
|
return r;
|
|
}
|
|
|
|
static bool read_asap_string(char* source,char** buf,char** buffer_end,char** dest)
|
|
{
|
|
if(parse_text(*buf,source) == false) return false;
|
|
|
|
/* set dest pointer */
|
|
*dest = *buf;
|
|
|
|
/* move buf ptr */
|
|
*buf += strlen(*buf)+1;
|
|
|
|
/* check size */
|
|
if(*buf >= *buffer_end)
|
|
{
|
|
DEBUGF("Buffer full\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool parse_sap_header(int fd,struct mp3entry* id3,int file_len)
|
|
{
|
|
int module_index = 0;
|
|
int sap_signature = -1;
|
|
int duration_index = 0;
|
|
unsigned char cur_char = 0;
|
|
int i;
|
|
|
|
/* set defaults */
|
|
int numSongs=1;
|
|
int defSong=0;
|
|
int numChannels=1;
|
|
int durations[MAX_SONGS];
|
|
int loops[MAX_SONGS];
|
|
for (i = 0; i < MAX_SONGS; i++) {
|
|
durations[i] = -1;
|
|
loops[i] = 0;
|
|
}
|
|
|
|
/* use id3v2 buffer for our strings */
|
|
char* buffer = id3->id3v2buf;
|
|
char* buffer_end = id3->id3v2buf + ID3V2_BUF_SIZE;
|
|
|
|
/* parse file */
|
|
while (1)
|
|
{
|
|
char line[256];
|
|
char *p;
|
|
|
|
if (module_index + 8 >= file_len)
|
|
return false;
|
|
/* read a char */
|
|
read(fd,&cur_char,1);
|
|
/* end of header */
|
|
if (cur_char == 0xff)
|
|
break;
|
|
|
|
i = 0;
|
|
while (cur_char != 0x0d)
|
|
{
|
|
line[i++] = cur_char;
|
|
module_index++;
|
|
if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1)
|
|
return false;
|
|
/* read a char */
|
|
read(fd,&cur_char,1);
|
|
}
|
|
if (++module_index >= file_len )
|
|
return false;
|
|
/* read a char */
|
|
read(fd,&cur_char,1);
|
|
if ( cur_char != 0x0a)
|
|
return false;
|
|
|
|
line[i] = '\0';
|
|
for (p = line; *p != '\0'; p++) {
|
|
if (*p == ' ') {
|
|
*p++ = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* parse tags */
|
|
if(strcmp(line, "SAP") == 0)
|
|
sap_signature = 1;
|
|
if (sap_signature == -1)
|
|
return false;
|
|
if (strcmp(line,"AUTHOR") == 0)
|
|
{
|
|
if(read_asap_string(p,&buffer,&buffer_end,&id3->artist) == false)
|
|
return false;
|
|
}
|
|
else if(strcmp(line,"NAME")==0)
|
|
{
|
|
if(read_asap_string(p,&buffer,&buffer_end,&id3->title) == false)
|
|
return false;
|
|
}
|
|
else if(strcmp(line,"DATE")==0)
|
|
{
|
|
if(read_asap_string(p,&buffer,&buffer_end,&id3->year_string) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(line,"SONGS")==0)
|
|
{
|
|
if (parse_dec(&numSongs, p,1,MAX_SONGS) == false )
|
|
return false;
|
|
}
|
|
else if (strcmp(line,"DEFSONG")==0)
|
|
{
|
|
if (parse_dec(&defSong, p,0,MAX_SONGS) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(line,"STEREO")==0)
|
|
{
|
|
numChannels = 2;
|
|
}
|
|
else if (strcmp(line,"TIME") == 0)
|
|
{
|
|
int durationTemp = ASAP_ParseDuration(p);
|
|
if (durationTemp < 0 || duration_index >= MAX_SONGS)
|
|
return false;
|
|
durations[duration_index] = durationTemp;
|
|
if (strstr(p, "LOOP") != NULL)
|
|
loops[duration_index] = 1;
|
|
duration_index++;
|
|
}
|
|
}
|
|
|
|
/* set length: */
|
|
int length = durations[defSong];
|
|
if (length < 0)
|
|
length = 180 * 1000;
|
|
id3->length = length;
|
|
|
|
lseek(fd,0,SEEK_SET);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool get_asap_metadata(int fd, struct mp3entry* id3)
|
|
{
|
|
|
|
int filelength = filesize(fd);
|
|
|
|
if(parse_sap_header(fd,id3,filelength) == false)
|
|
{
|
|
DEBUGF("parse sap header failed.\n");
|
|
return false;
|
|
}
|
|
|
|
id3->bitrate = 706;
|
|
id3->frequency = 44100;
|
|
|
|
id3->vbr = false;
|
|
id3->filesize = filelength;
|
|
|
|
return true;
|
|
}
|