aboutsummaryrefslogtreecommitdiff
path: root/src/tag_ape.c
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-02-28 16:44:41 +0100
committerMax Kellermann <max@duempel.org>2009-02-28 16:44:41 +0100
commit4a2b315ab6bcf9afc0718be980915870a4ee8f1f (patch)
tree41c1a0dbac60f2e53b4b7453bfdf9ffb1003f7ae /src/tag_ape.c
parentcabbf7ab4a97e5f173b5fd4deb3fab4e66538586 (diff)
tag: moved APE code to tag_ape.c
Diffstat (limited to 'src/tag_ape.c')
-rw-r--r--src/tag_ape.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/tag_ape.c b/src/tag_ape.c
new file mode 100644
index 00000000..c38b07a5
--- /dev/null
+++ b/src/tag_ape.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * 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_ape.h"
+#include "tag.h"
+
+#include <glib.h>
+
+#include <stdio.h>
+
+struct tag *
+tag_ape_load(const char *file)
+{
+ struct tag *ret = NULL;
+ FILE *fp;
+ int tagCount;
+ char *buffer = NULL;
+ char *p;
+ size_t tagLen;
+ size_t size;
+ unsigned long flags;
+ int i;
+ char *key;
+
+ struct {
+ unsigned char id[8];
+ uint32_t version;
+ uint32_t length;
+ uint32_t tagCount;
+ unsigned char flags[4];
+ unsigned char reserved[8];
+ } footer;
+
+ const 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 = (size_t)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 (GUINT32_FROM_LE(footer.version) != 2000)
+ goto fail;
+
+ /* find beginning of ape tag */
+ tagLen = GUINT32_FROM_LE(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 = g_malloc(tagLen);
+ if (fread(buffer, 1, tagLen, fp) != tagLen)
+ goto fail;
+
+ /* read tags */
+ tagCount = GUINT32_FROM_LE(footer.tagCount);
+ p = buffer;
+ while (tagCount-- && tagLen > 10) {
+ size = GUINT32_FROM_LE(*(const uint32_t *)p);
+ p += 4;
+ tagLen -= 4;
+ flags = GUINT32_FROM_LE(*(const uint32_t *)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)
+ 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 = tag_new();
+ tag_add_item_n(ret, tagItems[i],
+ p, size);
+ }
+ }
+ }
+ p += size;
+ tagLen -= size;
+ }
+
+fail:
+ if (fp)
+ fclose(fp);
+ g_free(buffer);
+ return ret;
+}