aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/src/tag.c
diff options
context:
space:
mode:
authorJ. Alexander Treuman <jat@spatialrift.net>2007-05-28 15:50:45 +0000
committerJ. Alexander Treuman <jat@spatialrift.net>2007-05-28 15:50:45 +0000
commit4e05a161e54fe05902b99eff521aa0759b102f05 (patch)
tree9014ab8ce74e4fb2f0115c5518c62879bc269324 /trunk/src/tag.c
parente45bc035931b2c9ef13b85f98a3d4833a8dec8a9 (diff)
downloadmpd-4e05a161e54fe05902b99eff521aa0759b102f05.tar.gz
mpd-4e05a161e54fe05902b99eff521aa0759b102f05.tar.xz
mpd-4e05a161e54fe05902b99eff521aa0759b102f05.zip
Making branch for 0.13.0 fixes.
git-svn-id: https://svn.musicpd.org/mpd/branches/branch-0.13.0-fixes@6330 09075e82-0dd4-0310-85a5-a0d7c8717e4f
Diffstat (limited to 'trunk/src/tag.c')
-rw-r--r--trunk/src/tag.c646
1 files changed, 0 insertions, 646 deletions
diff --git a/trunk/src/tag.c b/trunk/src/tag.c
deleted file mode 100644
index 92a597d0e..000000000
--- a/trunk/src/tag.c
+++ /dev/null
@@ -1,646 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * 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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "tag.h"
-#include "path.h"
-#include "myfprintf.h"
-#include "utils.h"
-#include "utf8.h"
-#include "log.h"
-#include "inputStream.h"
-#include "conf.h"
-#include "charConv.h"
-#include "tagTracker.h"
-#include "mpd_types.h"
-#include "gcc.h"
-#include "song.h"
-
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#ifdef HAVE_ID3TAG
-# define isId3v1(tag) (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1)
-# ifndef ID3_FRAME_COMPOSER
-# define ID3_FRAME_COMPOSER "TCOM"
-# endif
-# ifndef ID3_FRAME_PERFORMER
-# define ID3_FRAME_PERFORMER "TOPE"
-# endif
-# ifndef ID3_FRAME_DISC
-# define ID3_FRAME_DISC "TPOS"
-# endif
-#endif
-
-char *mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] = {
- "Artist",
- "Album",
- "Title",
- "Track",
- "Name",
- "Genre",
- "Date",
- "Composer",
- "Performer",
- "Comment",
- "Disc"
-};
-
-static mpd_sint8 ignoreTagItems[TAG_NUM_OF_ITEM_TYPES];
-
-void initTagConfig(void)
-{
- int quit = 0;
- char *temp;
- char *s;
- char *c;
- ConfigParam *param;
- int i;
-
- /* parse the "metadata_to_use" config parameter below */
-
- memset(ignoreTagItems, 0, TAG_NUM_OF_ITEM_TYPES);
- ignoreTagItems[TAG_ITEM_COMMENT] = 1; /* ignore comments by default */
-
- param = getConfigParam(CONF_METADATA_TO_USE);
-
- if (!param)
- return;
-
- memset(ignoreTagItems, 1, TAG_NUM_OF_ITEM_TYPES);
-
- if (0 == strcasecmp(param->value, "none"))
- return;
-
- temp = c = s = xstrdup(param->value);
- while (!quit) {
- if (*s == ',' || *s == '\0') {
- if (*s == '\0')
- quit = 1;
- *s = '\0';
- for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
- if (strcasecmp(c, mpdTagItemKeys[i]) == 0) {
- ignoreTagItems[i] = 0;
- break;
- }
- }
- if (strlen(c) && i == TAG_NUM_OF_ITEM_TYPES) {
- FATAL("error parsing metadata item \"%s\" at "
- "line %i\n", c, param->line);
- }
- s++;
- c = s;
- }
- s++;
- }
-
- free(temp);
-}
-
-void printTagTypes(int fd)
-{
- int i;
-
- for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
- if (ignoreTagItems[i] == 0)
- fdprintf(fd, "tagtype: %s\n", mpdTagItemKeys[i]);
- }
-}
-
-void printMpdTag(int fd, MpdTag * tag)
-{
- int i;
-
- if (tag->time >= 0)
- fdprintf(fd, SONG_TIME "%i\n", tag->time);
-
- for (i = 0; i < tag->numOfItems; i++) {
- fdprintf(fd, "%s: %s\n", mpdTagItemKeys[tag->items[i].type],
- tag->items[i].value);
- }
-}
-
-#ifdef HAVE_ID3TAG
-static MpdTag *getID3Info(struct id3_tag *tag, char *id, int type, MpdTag * mpdTag)
-{
- struct id3_frame const *frame;
- id3_ucs4_t const *ucs4;
- id3_utf8_t *utf8;
- id3_latin1_t *isostr;
- union id3_field const *field;
- unsigned int nstrings;
- int i;
- char *encoding;
-
- frame = id3_tag_findframe(tag, id, 0);
- if (!frame || frame->nfields < 2)
- return mpdTag;
-
- field = &frame->fields[1];
- nstrings = id3_field_getnstrings(field);
-
- for (i = 0; i < nstrings; i++) {
- ucs4 = id3_field_getstrings(field, i);
- if (!ucs4)
- continue;
-
- if (type == TAG_ITEM_GENRE)
- ucs4 = id3_genre_name(ucs4);
-
- if (isId3v1(tag) &&
- (encoding = getConfigParamValue(CONF_ID3V1_ENCODING))) {
- isostr = id3_ucs4_latin1duplicate(ucs4);
- if (mpd_unlikely(!isostr))
- continue;
- setCharSetConversion("UTF-8", encoding);
- utf8 = (id3_utf8_t *)convStrDup((char *)isostr);
- if (!utf8) {
- DEBUG("Unable to convert %s string to UTF-8: "
- "'%s'\n", encoding, isostr);
- free(isostr);
- continue;
- }
- free(isostr);
- } else {
- utf8 = id3_ucs4_utf8duplicate(ucs4);
- if (mpd_unlikely(!utf8))
- continue;
- }
-
- if (mpdTag == NULL)
- mpdTag = newMpdTag();
- addItemToMpdTag(mpdTag, type, (char *)utf8);
-
- free(utf8);
- }
-
- return mpdTag;
-}
-#endif
-
-#ifdef HAVE_ID3TAG
-MpdTag *parseId3Tag(struct id3_tag * tag)
-{
- MpdTag *ret = NULL;
-
- ret = getID3Info(tag, ID3_FRAME_ARTIST, TAG_ITEM_ARTIST, ret);
- ret = getID3Info(tag, ID3_FRAME_TITLE, TAG_ITEM_TITLE, ret);
- ret = getID3Info(tag, ID3_FRAME_ALBUM, TAG_ITEM_ALBUM, ret);
- ret = getID3Info(tag, ID3_FRAME_TRACK, TAG_ITEM_TRACK, ret);
- ret = getID3Info(tag, ID3_FRAME_YEAR, TAG_ITEM_DATE, ret);
- ret = getID3Info(tag, ID3_FRAME_GENRE, TAG_ITEM_GENRE, ret);
- ret = getID3Info(tag, ID3_FRAME_COMPOSER, TAG_ITEM_COMPOSER, ret);
- ret = getID3Info(tag, ID3_FRAME_PERFORMER, TAG_ITEM_PERFORMER, ret);
- ret = getID3Info(tag, ID3_FRAME_COMMENT, TAG_ITEM_COMMENT, ret);
- ret = getID3Info(tag, ID3_FRAME_DISC, TAG_ITEM_DISC, ret);
-
- return ret;
-}
-#endif
-
-#ifdef HAVE_ID3TAG
-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 queryBuf[ID3_TAG_QUERYSIZE];
- id3_byte_t *tagBuf;
- int tagSize;
- int queryBufSize;
- int tagBufSize;
-
- /* It's ok if we get less than we asked for */
- queryBufSize = fillBuffer(queryBuf, ID3_TAG_QUERYSIZE,
- stream, offset, whence);
- if (queryBufSize <= 0) return NULL;
-
- /* Look for a tag header */
- tagSize = id3_tag_query(queryBuf, queryBufSize);
- if (tagSize <= 0) return NULL;
-
- /* Found a tag. Allocate a buffer and read it in. */
- tagBuf = xmalloc(tagSize);
- if (!tagBuf) return NULL;
-
- tagBufSize = fillBuffer(tagBuf, tagSize, stream, offset, whence);
- if (tagBufSize < tagSize) {
- free(tagBuf);
- return NULL;
- }
-
- tag = id3_tag_parse(tagBuf, tagBufSize);
-
- free(tagBuf);
-
- 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;
- }
-
- /* 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;
- }
-
- tag = findId3TagFromBeginning(stream);
- if (!tag)
- tag = findId3TagFromEnd(stream);
-
- fclose(stream);
-
- if (!tag)
- return NULL;
- ret = parseId3Tag(tag);
- id3_tag_delete(tag);
-#endif
- return ret;
-}
-
-MpdTag *apeDup(char *file)
-{
- MpdTag *ret = NULL;
- FILE *fp = NULL;
- int tagCount;
- char *buffer = NULL;
- char *p;
- int tagLen;
- int size;
- unsigned long flags;
- int i;
- 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 beginning 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);
- if (tagLen <= 0)
- goto fail;
- buffer = xmalloc(tagLen);
- if (fread(buffer, 1, tagLen, fp) != tagLen)
- goto fail;
-
- /* read tags */
- tagCount = readLEuint32(footer.tagCount);
- p = buffer;
- while (tagCount-- && tagLen > 10) {
- size = readLEuint32((unsigned char *)p);
- p += 4;
- tagLen -= 4;
- flags = readLEuint32((unsigned char *)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(void)
-{
- MpdTag *ret = xmalloc(sizeof(MpdTag));
- ret->items = NULL;
- ret->time = -1;
- ret->numOfItems = 0;
- return ret;
-}
-
-static void deleteItem(MpdTag * tag, int index)
-{
- assert(index < tag->numOfItems);
- tag->numOfItems--;
-
- removeTagItemString(tag->items[index].type, tag->items[index].value);
- /* free(tag->items[index].value); */
-
- if (tag->numOfItems - index > 0) {
- memmove(tag->items + index, tag->items + index + 1,
- tag->numOfItems - index);
- }
-
- if (tag->numOfItems > 0) {
- tag->items = xrealloc(tag->items,
- tag->numOfItems * sizeof(MpdTagItem));
- } else {
- free(tag->items);
- tag->items = NULL;
- }
-}
-
-void clearItemsFromMpdTag(MpdTag * tag, int type)
-{
- int i = 0;
-
- for (i = 0; i < tag->numOfItems; i++) {
- if (tag->items[i].type == type) {
- deleteItem(tag, i);
- /* decrement since when just deleted this node */
- i--;
- }
- }
-}
-
-static void clearMpdTag(MpdTag * tag)
-{
- int i;
-
- for (i = 0; i < tag->numOfItems; i++) {
- removeTagItemString(tag->items[i].type, tag->items[i].value);
- /* free(tag->items[i].value); */
- }
-
- if (tag->items)
- free(tag->items);
- tag->items = NULL;
-
- tag->numOfItems = 0;
-
- tag->time = -1;
-}
-
-void freeMpdTag(MpdTag * tag)
-{
- clearMpdTag(tag);
- free(tag);
-}
-
-MpdTag *mpdTagDup(MpdTag * tag)
-{
- MpdTag *ret = NULL;
- int i;
-
- if (!tag)
- return NULL;
-
- ret = newMpdTag();
- ret->time = tag->time;
-
- for (i = 0; i < tag->numOfItems; i++) {
- addItemToMpdTag(ret, tag->items[i].type, tag->items[i].value);
- }
-
- return ret;
-}
-
-int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2)
-{
- int i;
-
- if (tag1 == NULL && tag2 == NULL)
- return 1;
- else if (!tag1 || !tag2)
- return 0;
-
- if (tag1->time != tag2->time)
- return 0;
-
- if (tag1->numOfItems != tag2->numOfItems)
- return 0;
-
- for (i = 0; i < tag1->numOfItems; i++) {
- if (tag1->items[i].type != tag2->items[i].type)
- return 0;
- if (strcmp(tag1->items[i].value, tag2->items[i].value)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-#define fixUtf8(str) { \
- if(str && !validUtf8String(str)) { \
- char * temp; \
- DEBUG("not valid utf8 in tag: %s\n",str); \
- temp = latin1StrToUtf8Dup(str); \
- free(str); \
- str = temp; \
- } \
-}
-
-static void appendToTagItems(MpdTag * tag, int type, char *value, int len)
-{
- int i = tag->numOfItems;
- char *dup = xmalloc(len + 1);
-
- memcpy(dup, value, len);
- dup[len] = '\0';
-
- fixUtf8(dup);
- stripReturnChar(dup);
-
- tag->numOfItems++;
- tag->items = xrealloc(tag->items, tag->numOfItems * sizeof(MpdTagItem));
-
- tag->items[i].type = type;
- tag->items[i].value = getTagItemString(type, dup);
-
- free(dup);
-}
-
-void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char *value, int len)
-{
- if (ignoreTagItems[itemType])
- return;
-
- if (!value || !len)
- return;
-
- /* we can't hold more than 255 items */
- if (tag->numOfItems == 255)
- return;
-
- appendToTagItems(tag, itemType, value, len);
-}