Commit bdf41071 authored by J. Alexander Treuman's avatar J. Alexander Treuman

Rewrote id3Dup to search for tags manually. Now libid3tag will actually tell us…

Rewrote id3Dup to search for tags manually. Now libid3tag will actually tell us the version of the tag we got. As an added benefit we also do fewer reads/mallocs when scanning mp3s during database update/creation. git-svn-id: https://svn.musicpd.org/mpd/trunk@4277 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent 30df7d49
......@@ -252,7 +252,9 @@ void mp3_getReplayGainInfo(struct id3_tag * tag, ReplayGainInfo ** infoPtr) {
*infoPtr = NULL;
}
}
#endif
#ifdef HAVE_ID3TAG
static void mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize, MpdTag ** mpdTag, ReplayGainInfo ** replayGainInfo) {
struct id3_tag * id3Tag = NULL;
id3_length_t count;
......
......@@ -43,6 +43,10 @@
#endif
#ifdef HAVE_ID3TAG
#define isId3v1(tag) (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1)
/* Size of the buffer to use for peeking at tag headers. We reuse this buffer
if the whole tag fits in it, so make it big to avoid a malloc(). */
#define ID3_TAG_BUFLEN 1024
#ifndef ID3_FRAME_COMPOSER
#define ID3_FRAME_COMPOSER "TCOM"
#endif
......@@ -181,29 +185,149 @@ MpdTag * parseId3Tag(struct id3_tag * tag) {
}
#endif
MpdTag * id3Dup(char * file) {
MpdTag * ret = NULL;
#ifdef HAVE_ID3TAG
struct id3_file * id3_file;
static int fillBuffer(void *buf, size_t size, FILE *stream,
long offset, int whence)
{
if (fseek(stream, offset, whence) != 0) return 0;
return fread(buf, 1, size, stream);
}
#endif
#ifdef HAVE_ID3TAG
static int getId3v2FooterSize(FILE * stream, long offset, int whence)
{
id3_byte_t buf[ID3_TAG_QUERYSIZE];
int bufsize;
bufsize = fillBuffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
if (bufsize <= 0) return 0;
return id3_tag_query(buf, bufsize);
}
#endif
#ifdef HAVE_ID3TAG
static struct id3_tag * getId3Tag(FILE * stream, long offset, int whence)
{
struct id3_tag * tag;
id3_byte_t * buf[ID3_TAG_BUFLEN];
id3_byte_t * mbuf;
int tagsize;
int bufsize;
int mbufsize;
/* It's ok if we get less than we asked for */
bufsize = fillBuffer(buf, ID3_TAG_BUFLEN, stream, offset, whence);
if (bufsize <= 0) return NULL;
/* Look for a tag header */
tagsize = id3_tag_query((const id3_byte_t *)buf, bufsize);
if (tagsize <= 0) return NULL;
if (tagsize <= bufsize) {
/* Got an id3 tag, and it fits in buf */
tag = id3_tag_parse((const id3_byte_t *)buf, tagsize);
} else {
/* Got an id3tag that overflows buf, so get a new one */
mbuf = malloc(tagsize);
if (!mbuf) return NULL;
mbufsize = fillBuffer(mbuf, tagsize, stream, offset, whence);
if (mbufsize < tagsize) {
free(mbuf);
return NULL;
}
id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
tag = id3_tag_parse((const id3_byte_t *)mbuf, tagsize);
if(!id3_file) {
DEBUG("id3Dup: Failed to open file: '%s', %s\n",file, strerror(errno));
free(mbuf);
}
return tag;
}
#endif
#ifdef HAVE_ID3TAG
static struct id3_tag * findId3TagFromBeginning(FILE * stream)
{
struct id3_tag * tag;
struct id3_tag * seektag;
struct id3_frame * frame;
int seek;
tag = getId3Tag(stream, 0, SEEK_SET);
if (!tag) {
return NULL;
} else if (isId3v1(tag)) {
/* id3v1 tags don't belong here */
id3_tag_delete(tag);
return NULL;
}
tag = id3_file_tag(id3_file);
if(!tag) {
id3_file_close(id3_file);
/* We have an id3v2 tag, so let's look for SEEK frames */
while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
/* Found a SEEK frame, get it's value */
seek = id3_field_getint(id3_frame_field(frame, 0));
if (seek < 0) break;
/* Get the tag specified by the SEEK frame */
seektag = getId3Tag(stream, seek, SEEK_CUR);
if (!seektag || isId3v1(seektag)) break;
/* Replace the old tag with the new one */
id3_tag_delete(tag);
tag = seektag;
}
return tag;
}
#endif
#ifdef HAVE_ID3TAG
static struct id3_tag * findId3TagFromEnd(FILE * stream)
{
struct id3_tag * tag;
struct id3_tag * v1tag;
int tagsize;
/* Get an id3v1 tag from the end of file for later use */
v1tag = getId3Tag(stream, -128, SEEK_END);
/* Get the id3v2 tag size from the footer (located before v1tag) */
tagsize = getId3v2FooterSize(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
if (tagsize >= 0) return v1tag;
/* Get the tag which the footer belongs to */
tag = getId3Tag(stream, tagsize, SEEK_CUR);
if (!tag) return v1tag;
/* We have an id3v2 tag, so ditch v1tag */
id3_tag_delete(v1tag);
return tag;
}
#endif
MpdTag * id3Dup(char * file) {
MpdTag * ret = NULL;
#ifdef HAVE_ID3TAG
struct id3_tag * tag;
FILE * stream;
stream = fopen(file, "r");
if (!stream) {
DEBUG("id3Dup: Failed to open file: '%s', %s\n",file, strerror(errno));
return NULL;
}
ret = parseId3Tag(tag);
tag = findId3TagFromBeginning(stream);
if (!tag) tag = findId3TagFromEnd(stream);
id3_file_close(id3_file);
fclose(stream);
if (!tag) return NULL;
ret = parseId3Tag(tag);
id3_tag_delete(tag);
#endif
return ret;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment