From 01b708bc13d082079beb794a11e138b2ad890f83 Mon Sep 17 00:00:00 2001 From: Warren Dukes Date: Mon, 7 Mar 2005 00:51:21 +0000 Subject: add support for parsing ape tags in musepack files git-svn-id: https://svn.musicpd.org/mpd/trunk@3030 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- src/inputPlugins/mpc_plugin.c | 47 ++++++++++++++++--- src/tag.c | 107 ++++++++++++++++++++++++++++++++++++++++++ src/tag.h | 2 + src/utils.c | 8 ++++ src/utils.h | 2 + 5 files changed, 159 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c index 45ef0bd16..9687eba6c 100644 --- a/src/inputPlugins/mpc_plugin.c +++ b/src/inputPlugins/mpc_plugin.c @@ -47,7 +47,7 @@ static mpc_int32_t mpc_read_cb(void * vdata, void * ptr, mpc_int32_t size) { while(1) { ret = readFromInputStream(data->inStream, ptr, 1, size); if(ret == 0 && !inputStreamAtEOF(data->inStream) && - !data->dc->stop) + (data->dc && !data->dc->stop)) { my_usleep(10000); } @@ -272,17 +272,50 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc, return 0; } +static float mpcGetTime(char * file) { + InputStream inStream; + float time = -1; + + mpc_reader reader; + mpc_streaminfo info; + MpcCallbackData data; + + data.inStream = &inStream; + data.dc = NULL; + + reader.read = mpc_read_cb; + reader.seek = mpc_seek_cb; + reader.tell = mpc_tell_cb; + reader.get_size = mpc_getsize_cb; + reader.canseek = mpc_canseek_cb; + reader.data = &data; + + mpc_streaminfo_init(&info); + + if(openInputStream(&inStream, file) < 0) return -1; + + if(mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) { + closeInputStream(&inStream); + return -1; + } + + time = mpc_streaminfo_get_length(&info); + + closeInputStream(&inStream); + + return time; +} + static MpdTag * mpcTagDup(char * file) { MpdTag * ret = NULL; - FILE * fp; - - fp = fopen(file,"r"); - if(!fp) return NULL; + float time = mpcGetTime(file); - /* get tag info here */ + if(time < 0) return NULL; + ret = apeDup(file); + if(!ret) ret = id3Dup(file); if(!ret) ret = newMpdTag(); - ret->time = 0; + ret->time = time; return ret; } diff --git a/src/tag.c b/src/tag.c index 7b1b8e837..41d76087c 100644 --- a/src/tag.c +++ b/src/tag.c @@ -217,6 +217,113 @@ MpdTag * id3Dup(char * file) { return ret; } +MpdTag * apeDup(char * file) { + MpdTag * ret = NULL; + FILE * fp = NULL; + int tagCount; + unsigned char * buffer = NULL; + unsigned char * p; + int tagLen; + int size; + unsigned long flags; + int i; + unsigned char * key; + + struct { + unsigned char id[8]; + unsigned char version[4]; + unsigned char length[4]; + unsigned char tagCount[4]; + unsigned char flags[4]; + unsigned char reserved[8]; + } footer; + + char * apeItems[7] = + { + "title", + "artist", + "album", + "comment", + "genre", + "track", + "year" + }; + + int tagItems[7] = + { + TAG_ITEM_TITLE, + TAG_ITEM_ARTIST, + TAG_ITEM_ALBUM, + TAG_ITEM_COMMENT, + TAG_ITEM_GENRE, + TAG_ITEM_TRACK, + TAG_ITEM_DATE, + }; + + fp = fopen(file, "r"); + if(!fp) return NULL; + + /* determine if file has an apeV2 tag */ + if(fseek(fp, 0, SEEK_END)) goto fail; + size = ftell(fp); + if(fseek(fp, size-sizeof(footer), SEEK_SET)) goto fail; + if(fread(&footer, 1, sizeof(footer), fp) != sizeof(footer)) goto fail; + if(memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0) goto fail; + if(readLEuint32(footer.version) != 2000) goto fail; + + /* find begining of ape tag */ + tagLen = readLEuint32(footer.length); + if(tagLen < sizeof(footer)) goto fail; + if(fseek(fp, size-tagLen, SEEK_SET)) goto fail; + + /* read tag into buffer */ + tagLen -= sizeof(footer); + buffer = malloc(tagLen); + if(fread(buffer, 1, tagLen, fp) != tagLen) goto fail; + + /* read tags */ + tagCount = readLEuint32(footer.tagCount); + p = buffer; + while(tagCount-- && tagLen > 10) { + size = readLEuint32(p); + p += 4; + tagLen -= 4; + flags = readLEuint32(p); + p += 4; + tagLen -= 4; + + /* get the key */ + key = p; + while(tagLen-size > 0 && *p != '\0') { + p++; + tagLen--; + } + p++; + tagLen--; + + /* get the value */ + if(tagLen-size < 0) goto fail; + + /* we only care about utf-8 text tags */ + if(!(flags & (0x3 << 1))) { + for(i = 0; i < 7; i++) { + if(strcasecmp(key, apeItems[i]) == 0) { + if(!ret) ret = newMpdTag(); + addItemToMpdTagWithLen( + ret, tagItems[i], p, size); + } + } + } + p += size; + tagLen -= size; + } + +fail: + if(fp) fclose(fp); + if(buffer) free(buffer); + return ret; +} + MpdTag * newMpdTag() { MpdTag * ret = malloc(sizeof(MpdTag)); ret->items = NULL; diff --git a/src/tag.h b/src/tag.h index ffe0c0d49..6720f818d 100644 --- a/src/tag.h +++ b/src/tag.h @@ -64,6 +64,8 @@ typedef struct _MpdTag { MpdTag * parseId3Tag(struct id3_tag *); #endif +MpdTag * apeDup(char * file); + MpdTag * id3Dup(char * file); MpdTag * newMpdTag(); diff --git a/src/utils.c b/src/utils.c index a057fa33f..32b079353 100644 --- a/src/utils.c +++ b/src/utils.c @@ -92,3 +92,11 @@ char * appendToString(char * dest, const char * src) { return dest; } + +unsigned long readLEuint32(const unsigned char *p) +{ + return ((unsigned long) p[0] << 0) | + ((unsigned long) p[1] << 8) | + ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24); +} + diff --git a/src/utils.h b/src/utils.h index 545f1653d..b4a236db7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -35,4 +35,6 @@ int ipv6Supported(); char * appendToString(char * dest, const char * src); +unsigned long readLEuint32(const unsigned char * p); + #endif -- cgit v1.2.3